diff --git a/.gitignore b/.gitignore index 796b96d1..aa724b77 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store /build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/Documents/BLACKLIST.md b/Documents/BLACKLIST.md deleted file mode 100644 index 582ccef6..00000000 --- a/Documents/BLACKLIST.md +++ /dev/null @@ -1,20 +0,0 @@ -# 黑名单 -H2O2的黑名单。[Switch to English](./BLACKLIST_en.md) -## 简体中文 -提示:本黑名单将在GitHub进行公开展示,目的是为了让各位远离这种人,切忌进行人身攻击!! -Top1 凛 QQ:2105432657 -双氧水捐赠前榜一用户,用各种低俗语言、图片内涵作者,并且仅因为一个小小的误会以恶意语言攻击H2O2官方群内群友,态度极差,影响极其恶劣,目前已取消榜一资格并将捐款打回。 -Top2 神虚 QQ:23273646 -在H2O内测阶段恶意攻击巡查组成员导致账号受限,以报酬的形式要求其他Boat开发者对内测App进行脱壳、破解,并且企图将定制版本启动器版权抹去并包装成自己所开发的应用进行宣传(未得逞)。 -Top3 赐 QQ:1025477808 -无知、无脑喷,无版权意识、法盲,洗白违规外传内测人员。 -Top4 天某人 QQ:2761463537 -未经许可随意宣传H2O群引来大量xxs,并且造成了严重的内测外传现象。 -Top5 旧人旧事 QQ:891230642 -违规高价倒卖Boat_H2O。 -Top6 D QQ:2026617389 -此人除了外传以外,拿到授权后无法无天,还反咬boat,最后还要向作者卖惨。给了他好多次机会了还不珍惜,真的太可恶了QAQ... -Top7 小山游戏指南 QQ:3517469060 -非法获取并违规传播处于内测阶段的Open4ES光影,并恶意攻击H2O2作者。 -## 其他注意事项 -注意下面这个人冒充H2O作者的人(hi QQ:3475451191,还有两个冒充我的(QAQ QQ:2567196103; 恰似星 沉大海 QQ:2670284282),请认准唯一QQ号:2252719826。) diff --git a/Documents/BLACKLIST_en.md b/Documents/BLACKLIST_en.md deleted file mode 100644 index d26cb70f..00000000 --- a/Documents/BLACKLIST_en.md +++ /dev/null @@ -1,20 +0,0 @@ -# BlackList -The BlackList Of H2O2. [Switch to Chinese](./BLACKLIST.md) -## English(en-us.utf8) -Warning:This BlackList should be publicly dispalyed on GitHub in order to keep everyone away from such people. *Do Not Use Cyber Violence!!* -### Top1 "凛" QQ:2105432657 -Previous top 1 donate user of H2O2; Tons of vulgar language; Made a lot of vulgar images; Use vulgar language to attack the H2O2 user group just caused a litte misunderstanding; The attitude is very terrible and made a bad effect to H2O2 ecology; We returned all donations and canceled his top 1 identity. -### Top2 "神虚" QQ:23273646 -Vicious assault the mumbers or H2O2 search & research team and made the account be limited; Bribery of other Boat developers to unshell & decrypt the H2O2 test software in the form of payment and tried to wipe off copyright information of the custom version laucnher make it as his own software and propaganda it.(Unsucceed) -### Top3 "赐" QQ:1025477808 -Ignorant; Presumptuous curse without thinking; Have no copyright awareness; Legal blindness; Tried to clear the charge of illegal spreader of close test files. -### Top4 "天某人" QQ:2761463537 -Attract a lot of annoying kids to H2O2 QQ group by propaganda it unlicensed and made a terrible file leakage event. -### Top5 "旧人旧事" QQ:891230642 -Sell H2O2 in a high price illegally. -### Top6 "D" QQ:2026617389 -Leak the files; Lawless action after authorization and attacked H2O2 back; After all he tried to get the sympathy of author and whatever how many times that we gave him more chance he always do the same thing.(It is so bad QAQ !!!!) -### Top7 "小山游戏指南" QQ:3517469060 -Illegal acquisition and dissemination of Open4Es shader files which in the close testing; Vicious assault the shader author and H2O2 author. -## Other matters needing attention. -Attention, those people were faking identity ("hi" QQ:3475451191; "QAQ" QQ:2567196103; "恰似星 沉大海" QQ:2670284282) And the only ture QQ:2252719826. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f288702d..00000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - 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 index bff374c1..09fcce45 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# Boat_H2O2 Pro -Boat-v4 app Material Design Edition. (Ver.3) -Now is on BETA for Minecraft downloading and Xbox logining. +# 关于新项目 +**原项目已经停更,请移步到衍生项目[Boat_H2CO3](https://github.com/bilicainiaohh/Boat_H2CO3)。** +本项目与衍生项目基于[BoatAPP](https://github.com/AOF-Dev/Boat)完成,所有相关修改请遵守GPL-2协议进行开源。 diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 66a1c131..e9d8af21 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,32 +1,68 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' +} android { - compileSdkVersion 27 - buildToolsVersion "27.1.1" + compileSdk 31 defaultConfig { - applicationId "com.koishi.launcher.h2o2" - minSdkVersion 16 - targetSdkVersion 21 - versionCode 514 - versionName "2.1.93" + applicationId "org.koishi.launcher.h2o2pro" + minSdk 28 + targetSdk 29 + versionCode 1024 + versionName "3.3.13" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lint { + baseline = file("lint-baseline.xml") + } } dependencies { - compile 'com.android.support:appcompat-v7:27.1.1' - compile 'com.android.support:design:27.1.1' - compile 'com.android.support:cardview-v7:25.2.0' - implementation 'net.lingala.zip4j:zip4j:1.3.2' - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'cat.ereza:customactivityoncrash:2.2.0' - compile project(':lfilepickerlibrary') - compile project(':boat') - -} + + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation "androidx.browser:browser:1.3.0" + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.navigation:navigation-fragment:2.2.2' + implementation 'androidx.navigation:navigation-ui:2.2.2' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'androidx.preference:preference:1.1.1' + implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'com.afollestad.material-dialogs:commons:0.9.0.2' + implementation 'com.android.billingclient:billing:3.0.3' + implementation 'com.github.bumptech.glide:glide:4.9.0' + implementation 'com.google.android.material:material:1.5.0-alpha04' + implementation 'com.google.dagger:hilt-android:2.37' + implementation 'com.ashokvarma.android:bottom-navigation-bar:2.2.0' + + implementation 'cat.ereza:customactivityoncrash:2.2.0' + + implementation project(path: ':boat') + implementation project(path: ':shell') + implementation project(path: ':markdown') + + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + testImplementation 'junit:junit:4.+' + + implementation 'com.alibaba:fastjson:1.2.2' + //implementation 'com.google.code.gson:gson:2.8.2' + implementation 'com.squareup.okhttp3:okhttp:4.8.0' +} \ No newline at end of file diff --git a/app/libs/MCAssetsDownloader.jar b/app/libs/MCAssetsDownloader.jar new file mode 100644 index 00000000..18480be1 Binary files /dev/null and b/app/libs/MCAssetsDownloader.jar differ diff --git a/app/libs/common-1.1.0-1.jar b/app/libs/common-1.1.0-1.jar deleted file mode 100644 index 8dd53cdd..00000000 Binary files a/app/libs/common-1.1.0-1.jar and /dev/null differ diff --git a/app/libs/gson-2.8.2.jar b/app/libs/gson-2.8.2.jar new file mode 100644 index 00000000..d0d030c6 Binary files /dev/null and b/app/libs/gson-2.8.2.jar differ diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml new file mode 100644 index 00000000..fa086b45 --- /dev/null +++ b/app/lint-baseline.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e69de29b..481bb434 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ff84f92b..518906f1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,111 +1,103 @@ - - - + + + + + + + + - - - - + android:name="android.permission.MANAGE_EXTERNAL_STORAGE" + tools:ignore="ScopedStorage" /> + + - + android:requestLegacyExternalStorage="true" + android:supportsRtl="true" + android:theme="@style/AppBaseTheme"> - - - - - - - - - - + android:name=".LogcatActivity" + android:screenOrientation="portrait" + android:label="@string/log_title" + android:theme="@style/AppBaseTheme.NoActionBar"/> - + android:name=".SettingsActivity" + android:label="@string/settings" + android:theme="@style/AppBaseTheme.NoActionBar.Settings" /> + - + android:name=".HomeActivity" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar" + android:windowSoftInputMode="adjustPan" /> - + android:name=".ModsActivity" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar" /> - + android:name=".VersionsActivity" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar" /> - + android:name=".InstructionActivity" + android:label="" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar" /> - + android:name=".TerminalActivity" + android:label="@string/menu_terminal" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar" /> + android:name=".WelcomeActivity" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar"> + + + + + - + android:name=".MainActivity" + android:configChanges="uiMode" + android:label="@string/app_name" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar" + android:windowSoftInputMode="stateHidden" /> - - - - - - - - - - - + android:name="com.mistake.revision.VanillaActivity" + android:label="Minecraft" + android:screenOrientation="portrait" + android:theme="@style/AppBaseTheme.NoActionBar" /> + + + + + + + + - - + + \ No newline at end of file diff --git a/app/src/main/assets/Sans.ttf b/app/src/main/assets/Sans.ttf new file mode 100644 index 00000000..54485787 Binary files /dev/null and b/app/src/main/assets/Sans.ttf differ diff --git a/app/src/main/assets/authlib/authlib-injector-1.1.39.jar b/app/src/main/assets/authlib/authlib-injector-1.1.39.jar new file mode 100644 index 00000000..834e5422 Binary files /dev/null and b/app/src/main/assets/authlib/authlib-injector-1.1.39.jar differ diff --git a/app/src/main/assets/boat.zip b/app/src/main/assets/boat.zip index 000d425e..1203de3c 100644 Binary files a/app/src/main/assets/boat.zip and b/app/src/main/assets/boat.zip differ diff --git a/app/src/main/assets/h2o2.zip b/app/src/main/assets/h2o2.zip index 811b4b2a..1169113a 100644 Binary files a/app/src/main/assets/h2o2.zip and b/app/src/main/assets/h2o2.zip differ diff --git a/app/src/main/assets/pack.zip b/app/src/main/assets/pack.zip new file mode 100644 index 00000000..1203de3c Binary files /dev/null and b/app/src/main/assets/pack.zip differ diff --git a/app/src/main/ic_launcher_app_logo-playstore.png b/app/src/main/ic_launcher_app_logo-playstore.png new file mode 100644 index 00000000..c63bf953 Binary files /dev/null and b/app/src/main/ic_launcher_app_logo-playstore.png differ diff --git a/app/src/main/ic_launcher_boat_logo-playstore.png b/app/src/main/ic_launcher_boat_logo-playstore.png new file mode 100644 index 00000000..035c3381 Binary files /dev/null and b/app/src/main/ic_launcher_boat_logo-playstore.png differ diff --git a/app/src/main/ic_launcher_h2o2_logo-playstore.png b/app/src/main/ic_launcher_h2o2_logo-playstore.png new file mode 100644 index 00000000..d7c9cb49 Binary files /dev/null and b/app/src/main/ic_launcher_h2o2_logo-playstore.png differ diff --git a/app/src/main/ic_launcher_logo-playstore.png b/app/src/main/ic_launcher_logo-playstore.png new file mode 100644 index 00000000..83f0ac97 Binary files /dev/null and b/app/src/main/ic_launcher_logo-playstore.png differ diff --git a/app/src/main/java/com/download/service/downloader/DownloadListner.java b/app/src/main/java/com/download/service/downloader/DownloadListner.java new file mode 100644 index 00000000..cba4e1df --- /dev/null +++ b/app/src/main/java/com/download/service/downloader/DownloadListner.java @@ -0,0 +1,17 @@ +package com.download.service.downloader; + +/** + * 下载监听 + * + * @author Cheny + */ +public interface DownloadListner +{ + + + void onFinished(); + void onProgress(float progress,long i ,long s); + void onPause(); + void onCancel(); +} + diff --git a/app/src/main/java/com/download/service/downloader/DownloadManager.java b/app/src/main/java/com/download/service/downloader/DownloadManager.java new file mode 100644 index 00000000..aa8ccbfd --- /dev/null +++ b/app/src/main/java/com/download/service/downloader/DownloadManager.java @@ -0,0 +1,200 @@ +package com.download.service.downloader; + +import android.os.Environment; +import android.text.TextUtils; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.*; +import java.util.Map.*; +/** + * 下载管理器,断点续传 + * + * @author Cheny + + */ +public class DownloadManager { + + + private DownloadTask mDownloadTasks1; + private DownloadTask mDownloadTasks2; + private DownloadTask mDownloadTasks3; + + + + private static final String TAG = "DownloadManager"; + private FilePoint mfilepoint1; + private FilePoint mfilepoint2; + private FilePoint mfilepoint3; + + private static DownloadManager mInstance; + + + public static DownloadManager getInstance() {//管理器初始化 + if (mInstance == null) { + synchronized (DownloadManager.class) { + if (mInstance == null) { + mInstance = new DownloadManager(); + } + } + } + return mInstance; + } + + + public DownloadManager() { + + } + public boolean get1(){ + return mDownloadTasks1.isDownloading(); + } + public boolean get2(){ + return mDownloadTasks1.isDownloading(); + } + public boolean get3(){ + return mDownloadTasks1.isDownloading(); + } + public boolean download1_stop_start(){ + if(mDownloadTasks1!=null){ + if (!mDownloadTasks1.isDownloading()) { + mDownloadTasks1.start(); + return true; + } else { + + mDownloadTasks1.pause(); + return false; + } + }else{ + return false; + } + + } + public boolean download2_stop_start(){ + if(mDownloadTasks2!=null){ + if (!mDownloadTasks2.isDownloading()) { + mDownloadTasks2.start(); + return true; + } else { + + mDownloadTasks2.pause(); + return false; + } + }else{ + return false; + } + + } + public boolean download3_stop_start(){ + if(mDownloadTasks3!=null){ + if (!mDownloadTasks3.isDownloading()) { + mDownloadTasks3.start(); + return true; + } else { + + mDownloadTasks3.pause(); + return false; + } + }else{ + return false; + } + + } + + + + public String getFileName(String url) { + return url.substring(url.lastIndexOf("/") + 1); + } + + //mDownloadTasks.pause(); + + + + + public void add1(String url, String filePath, String fileName,int a,Object object,int size, DownloadListner l) { + + if (TextUtils.isEmpty(fileName)) { + fileName = getFileName(url); + } + mfilepoint1=new FilePoint(url, filePath, fileName,a,object,size); + mDownloadTasks1= new DownloadTask(mfilepoint1, l); + + } + public void add2(String url, String filePath, String fileName,int a,Object object,int size, DownloadListner l) { + + if (TextUtils.isEmpty(fileName)) { + fileName = getFileName(url); + } + mfilepoint2=new FilePoint(url, filePath, fileName,a,object,size); + mDownloadTasks2= new DownloadTask(mfilepoint2, l); + + } + public void add3(String url, String filePath, String fileName,int a,Object object,int size, DownloadListner l) { + + if (TextUtils.isEmpty(fileName)) { + fileName = getFileName(url); + } + mfilepoint3=new FilePoint(url, filePath, fileName,a,object,size); + mDownloadTasks3= new DownloadTask(mfilepoint3, l); + + } + + + + + public FilePoint Self_destruction1() { + + if(mDownloadTasks1!=null){ + mDownloadTasks1.cancel(); + return mfilepoint1; + }else{ + + return null; + } + /*for (Map.Entry entry : mDownloadTasks.entrySet()) { + //System.out.println("key= " + + " and value= " + ); + String a=entry.getKey(); + DownloadTask b = entry.getValue(); + b.cancel(); + }*/ + + } + public FilePoint Self_destruction2() { + + if(mDownloadTasks2!=null){ + mDownloadTasks2.cancel(); + return mfilepoint2; + }else{ + + return null; + } + /*for (Map.Entry entry : mDownloadTasks.entrySet()) { + //System.out.println("key= " + + " and value= " + ); + String a=entry.getKey(); + DownloadTask b = entry.getValue(); + b.cancel(); + }*/ + + } + public FilePoint Self_destruction3() { + + if(mDownloadTasks3!=null){ + mDownloadTasks3.cancel(); + return mfilepoint3; + }else{ + + return null; + } + /*for (Map.Entry entry : mDownloadTasks.entrySet()) { + //System.out.println("key= " + + " and value= " + ); + String a=entry.getKey(); + DownloadTask b = entry.getValue(); + b.cancel(); + }*/ + + } + + + +} diff --git a/app/src/main/java/com/download/service/downloader/DownloadTask.java b/app/src/main/java/com/download/service/downloader/DownloadTask.java new file mode 100644 index 00000000..ec1d4163 --- /dev/null +++ b/app/src/main/java/com/download/service/downloader/DownloadTask.java @@ -0,0 +1,322 @@ +package com.download.service.downloader; + +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.util.concurrent.atomic.AtomicInteger; +import okhttp3.Call; +import okhttp3.Response; +import okhttp3.*; + +/** + * Created by Cheny on 2017/4/29. + */ + +public class DownloadTask extends Handler { + + private final int THREAD_COUNT = 4;//线程数 + private FilePoint mPoint; + private long mFileLength; + + private volatile boolean isDownloading = false; + private AtomicInteger childCanleCount = new AtomicInteger(0);//子线程取消数量 + private AtomicInteger childPauseCount = new AtomicInteger(0);//子线程暂停数量 + private AtomicInteger childFinshCount = new AtomicInteger(0);//子线程完成数量 + private HttpUtil mHttpUtil; + private long[] mProgress; + private File[] mCacheFiles; + private File mTmpFile;//临时占位文件 + private volatile boolean pause;//是否暂停 + private volatile boolean cancel;//是否取消下载 + private static final int MSG_PROGRESS = 1;//进度 + private static final int MSG_FINISH = 2;//完成下载 + private static final int MSG_PAUSE = 3;//暂停 + private static final int MSG_CANCEL = 4;//暂停 + private DownloadListner mListner;//下载回调监听 + + + /** + * 任务管理器初始化数据 + * + * @param point + * @param l + */ + public DownloadTask(FilePoint point, DownloadListner l) { + this.mPoint = point; + this.mListner = l; + this.mProgress = new long[THREAD_COUNT]; + this.mCacheFiles = new File[THREAD_COUNT]; + + this.mHttpUtil =HttpUtil.getInstance(); + + + } + + /** + * 任务回调消息 + * + * @param msg + */ + @Override + public void handleMessage(Message msg) { + if (null == mListner) { + return; + } + switch (msg.what) { + case MSG_PROGRESS://进度 + long progress = 0; + for (int i = 0, length = mProgress.length; i < length; i++) { + progress += mProgress[i]; + } + mListner.onProgress(progress * 1.0f / mFileLength,progress,mFileLength); + break; + case MSG_PAUSE://暂停 + if (confirmStatus(childPauseCount)) return; + resetStutus(); + mListner.onPause(); + break; + case MSG_FINISH://完成 + if (confirmStatus(childFinshCount)) return; + mTmpFile.renameTo(new File(mPoint.getFilePath(), mPoint.getFileName()));//下载完毕后,重命名目标文件名 + resetStutus(); + mListner.onFinished(); + break; + case MSG_CANCEL://取消 + if (confirmStatus(childCanleCount)) return; + resetStutus(); + mProgress = new long[THREAD_COUNT]; + mListner.onCancel(); + break; + + + + } + } + + private static final String TAG = "DownloadTask"; + + public synchronized void start() { + try { + Log.e(TAG, "start: " + isDownloading + "\t" + mPoint.getUrl()); + if (isDownloading) return; + isDownloading = true; + mHttpUtil.getContentLength(mPoint.getUrl(), new okhttp3.Callback() { + @Override + public void onResponse(Call call, Response response) throws IOException { + Log.e(TAG, "start: " + response.code() + "\t isDownloading:" + isDownloading + "\t" + mPoint.getUrl()); + if (response.code() != 200) { + close(response.body()); + resetStutus(); + + + + return; + } + + + // 获取资源大小 + mFileLength = response.body().contentLength(); + + + close(response.body()); + // 在本地创建一个与资源同样大小的文件来占位 + mTmpFile = new File(mPoint.getFilePath(), mPoint.getFileName() + ".tmp"); + if (!mTmpFile.getParentFile().exists()) mTmpFile.getParentFile().mkdirs(); + RandomAccessFile tmpAccessFile = new RandomAccessFile(mTmpFile, "rw"); + tmpAccessFile.setLength(mFileLength);//长度0修复 + /*将下载任务分配给每个线程*/ + long blockSize = mFileLength / THREAD_COUNT;// 计算每个线程理论上下载的数量. + + /*为每个线程配置并分配任务*/ + for (int threadId = 0; threadId < THREAD_COUNT; threadId++) { + long startIndex = threadId * blockSize; // 线程开始下载的位置 + long endIndex = (threadId + 1) * blockSize - 1; // 线程结束下载的位置 + if (threadId == (THREAD_COUNT - 1)) { // 如果是最后一个线程,将剩下的文件全部交给这个线程完成 + endIndex = mFileLength - 1; + } + download(startIndex, endIndex, threadId);// 开启线程下载 + } + + } + + @Override + public void onFailure(Call call, IOException e) { + Log.e(TAG, "start:Exception " + e.getMessage() + "\n" + mPoint.getUrl()); + resetStutus(); + + + + + + } + }); + } catch (IOException e) { + e.printStackTrace(); + resetStutus(); + + + } + } + + private void download(final long startIndex, final long endIndex, final int threadId) throws IOException { + long newStartIndex = startIndex; + // 分段请求网络连接,分段将文件保存到本地. + // 加载下载位置缓存文件 + final File cacheFile = new File(mPoint.getFilePath(), "thread" + threadId + "_" + mPoint.getFileName() + ".cache"); + mCacheFiles[threadId] = cacheFile; + final RandomAccessFile cacheAccessFile = new RandomAccessFile(cacheFile, "rwd"); + if (cacheFile.exists()) {// 如果文件存在 + String startIndexStr = cacheAccessFile.readLine(); + try { + newStartIndex = Integer.parseInt(startIndexStr);//重新设置下载起点 + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + final long finalStartIndex = newStartIndex; + mHttpUtil.downloadFileByRange(mPoint.getUrl(), finalStartIndex, endIndex, new okhttp3.Callback() { + @Override + public void onResponse(Call call, Response response) throws IOException { + Log.e(TAG, "download: " + response.code() + "\t isDownloading:" + isDownloading + "\t" + mPoint.getUrl()); + if (response.code() != 206) {// 206:请求部分资源成功码 + resetStutus(); + + + + return; + } + InputStream is = response.body().byteStream();// 获取流 + RandomAccessFile tmpAccessFile = new RandomAccessFile(mTmpFile, "rw");// 获取前面已创建的文件. + tmpAccessFile.seek(finalStartIndex);// 文件写入的开始位置. + /* 将网络流中的文件写入本地*/ + byte[] buffer = new byte[1024 << 2]; + int length = -1; + int total = 0;// 记录本次下载文件的大小 + long progress = 0; + while ((length = is.read(buffer)) > 0) { + if (cancel) { + //关闭资源 + close(cacheAccessFile, is, response.body()); + cleanFile(cacheFile); + sendEmptyMessage(MSG_CANCEL); + return; + } + if (pause) { + //关闭资源 + close(cacheAccessFile, is, response.body()); + //发送暂停消息 + sendEmptyMessage(MSG_PAUSE); + return; + } + tmpAccessFile.write(buffer, 0, length); + total += length; + progress = finalStartIndex + total; + + //将当前现在到的位置保存到文件中 + cacheAccessFile.seek(0); + cacheAccessFile.write((progress + "").getBytes("UTF-8")); + //发送进度消息 + mProgress[threadId] = progress - startIndex; + sendEmptyMessage(MSG_PROGRESS); + } + //关闭资源 + close(cacheAccessFile, is, response.body()); + // 删除临时文件 + cleanFile(cacheFile); + //发送完成消息 + sendEmptyMessage(MSG_FINISH); + } + + @Override + public void onFailure(Call call, IOException e) { + isDownloading = false; + + + + + } + }); + } + + /** + * 关闭资源 + * + * @param closeables + */ + private void close(Closeable... closeables) { + int length = closeables.length; + try { + for (int i = 0; i < length; i++) { + Closeable closeable = closeables[i]; + if (null != closeable) + closeables[i].close(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + for (int i = 0; i < length; i++) { + closeables[i] = null; + } + } + } + + /** + * 删除临时文件 + */ + private void cleanFile(File... files) { + for (int i = 0, length = files.length; i < length; i++) { + if (null != files[i]) + files[i].delete(); + } + } + + /** + * 暂停 + */ + public void pause() { + pause = true; + } + + /** + * 取消 + */ + public void cancel() { + cancel = true; + cleanFile(mTmpFile); + if (!isDownloading) { + if (null != mListner) { + cleanFile(mCacheFiles); + resetStutus(); + mListner.onCancel(); + } + } + } + + /** + * 重置下载状态 + */ + private void resetStutus() { + pause = false; + cancel = false; + isDownloading = false; + } + + /** + * 确认下载状态 + * + * @param count + * @return + */ + private boolean confirmStatus(AtomicInteger count) { + return count.incrementAndGet() % THREAD_COUNT != 0; + } + + public boolean isDownloading() { + return isDownloading; + } +} diff --git a/app/src/main/java/com/download/service/downloader/FilePoint.java b/app/src/main/java/com/download/service/downloader/FilePoint.java new file mode 100644 index 00000000..6ebe0bb6 --- /dev/null +++ b/app/src/main/java/com/download/service/downloader/FilePoint.java @@ -0,0 +1,71 @@ +package com.download.service.downloader; + +/** + * Created by Cheny on 2017/4/29. + */ +public class FilePoint { + private String fileName;//文件名 + private String url;//下载地址 + private String filePath; + + private int a ; + + private Object object; + + private int size;//下载目录 + + public FilePoint(String url) { + this.url = url; + } + public FilePoint(String filePath, String url) { + this.filePath = filePath; + this.url = url; + } + + public FilePoint(String url, String filePath, String fileName) { + this.url = url; + this.filePath = filePath; + this.fileName = fileName; + } + public FilePoint(String url, String filePath, String fileName, int a,Object object,int size) { + this.url = url; + this.filePath = filePath; + this.fileName = fileName; + this.a=a; + this.object=object; + this.size=size; + } + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + public int getA() { + return a; + } + public Object getObject() { + return object; + } + public int getSize() { + return size; + } + +} diff --git a/app/src/main/java/com/download/service/downloader/HttpUtil.java b/app/src/main/java/com/download/service/downloader/HttpUtil.java new file mode 100644 index 00000000..b1be0cc6 --- /dev/null +++ b/app/src/main/java/com/download/service/downloader/HttpUtil.java @@ -0,0 +1,105 @@ +package com.download.service.downloader; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Request.Builder; +public class HttpUtil { + private OkHttpClient mOkHttpClient; + private static HttpUtil mInstance; + private final static long CONNECT_TIMEOUT = 60;//超时时间,秒 + private final static long READ_TIMEOUT = 60;//读取时间,秒 + private final static long WRITE_TIMEOUT = 60;//写入时间,秒 + + /** + * @param url 下载链接 + * @param startIndex 下载起始位置 + * @param endIndex 结束为止 + * @param callback 回调 + * @throws IOException + */ + public void downloadFileByRange(String url, long startIndex, long endIndex, Callback callback) throws IOException { + // 创建一个Request + // 设置分段下载的头信息。 Range:做分段数据请求,断点续传指示下载的区间。格式: Range bytes=0-1024或者bytes:0-1024 + Request request = new Request.Builder().header("RANGE", "bytes=" + startIndex + "-" + endIndex) + .url(url) + .build(); + doAsync(request, callback); + + + + + } + + public void getContentLength(String url, Callback callback) throws IOException { + // 创建一个Request + Request request = new Request.Builder().addHeader("Accept-Encoding", "identity") + + .url(url) + .build(); + doAsync(request, callback); + } + + /** + * 异步请求 + */ + private void doAsync(Request request, Callback callback) throws IOException { + //创建请求会话 + Call call = mOkHttpClient.newCall(request); + //同步执行会话请求 + call.enqueue(callback); + } + + /** + * 同步请求 + */ + private Response doSync(Request request) throws IOException { + + //创建请求会话 + Call call = mOkHttpClient.newCall(request); + //同步执行会话请求 + return call.execute(); + } + + + /** + * @return HttpUtil实例对象 + */ + public static HttpUtil getInstance() { + if (null == mInstance) { + synchronized (HttpUtil.class) { + if (null == mInstance) { + mInstance = new HttpUtil(); + } + } + } + return mInstance; + } + + /** + * 构造方法,配置OkHttpClient + */ + public HttpUtil() { + //创建okHttpClient对象 + OkHttpClient.Builder builder = new OkHttpClient.Builder() + .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) + .writeTimeout(READ_TIMEOUT, TimeUnit.SECONDS) + .readTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS); + mOkHttpClient = builder.build(); + } + + + public static void sendOkHttpRequest(String str, Callback callback) { + new OkHttpClient().newCall(new Builder().url(str).build()).enqueue(callback); + } + + + + +} + diff --git a/app/src/main/java/com/download/service/util/AssetsUtil.java b/app/src/main/java/com/download/service/util/AssetsUtil.java new file mode 100644 index 00000000..a8b615c3 --- /dev/null +++ b/app/src/main/java/com/download/service/util/AssetsUtil.java @@ -0,0 +1,49 @@ +package com.download.service.util; + +public class AssetsUtil +{ + private String name; + private String hash; + private int size; + private boolean download; + public AssetsUtil(){ + } + + public String gethash(){ + + return hash; + } + + + + public int getsize(){ + + return size; + } + public String getname(){ + + return name; + } + public boolean get(){ + + return download; + } + + public void set(boolean a){ + download=a; + } + public void setname(String a){ + name=a; + } + public void sethash(String a){ + hash=a; + } + public void setsize(int a){ + size=a; + } + + + + + +} diff --git a/app/src/main/java/com/download/service/util/Config.java b/app/src/main/java/com/download/service/util/Config.java new file mode 100644 index 00000000..e0beb2d5 --- /dev/null +++ b/app/src/main/java/com/download/service/util/Config.java @@ -0,0 +1,132 @@ +package com.download.service.util; + +public class Config +{ + public Config(){ + + } + + private String auth_uuid; + private String extraMinecraftFlags; + private String auth_player_name; + private String auth_session; + private String extraJavaFlags; + private String home; + private String runtimePath; + private String auth_access_token; + private String currentVersion; + private String game_assets; + private String user_type; + private String game_directory; + private String user_properties; + private String assets_root; + + public void setauth_uuid(String a){ + auth_uuid=a; + }; + public void setextraMinecraftFlags(String a){ + extraMinecraftFlags=a; + }; + public void setauth_player_name(String a){ + auth_player_name=a; + }; + public void setauth_session(String a){ + auth_session=a; + }; + public void setextraJavaFlags(String a){ + extraJavaFlags=a; + }; + public void sethome(String a){ + home=a; + }; + public void setruntimePath(String a){ + runtimePath=a; + }; + public void setauth_access_token(String a){ + auth_access_token=a; + }; + public void setcurrentVersion(String a){ + currentVersion=a; + }; + public void setgame_assets(String a){ + game_assets=a; + }; + public void setuser_type(String a){ + user_type=a; + }; + public void setgame_directory(String a){ + game_directory=a; + }; + public void setuser_properties(String a){ + user_properties=a; + }; + public void setassets_root(String a){ + assets_root=a; + }; + + public String setauth_uuid() + { + return auth_uuid; + }; + public String setextraMinecraftFlags() + {return extraMinecraftFlags; + }; + public String setauth_player_name() + {return auth_player_name; + }; + public String setauth_session() + {return auth_session; + }; + public String setextraJavaFlags() + {return extraJavaFlags; + }; + public String sethome() + {return home; + }; + public String setruntimePath() + {return runtimePath; + }; + public String setauth_access_token() + {return auth_access_token; + }; + public String setcurrentVersion() + {return currentVersion; + }; + public String setgame_assets() + {return game_assets; + }; + public String setuser_type() + {return user_type; + }; + public String setgame_directory() + {return game_directory; + }; + public String setuser_properties() + {return user_properties; + }; + public String setassets_root() + {return assets_root; + }; + +} + + +/* +"auth_uuid":"00000000-0000-0000-0000-000000000000" +"extraMinecraftFlags":"" +"auth_player_name":"Fire" +"auth_session":"0" +"extraJavaFlags":"-server -Xms500M -Xmx500M" +"home":"/storage/emulated/0/boat" +"runtimePath":"/data/user/0/cosine.boat/app_runtime" +"auth_access_token":"0" +"currentVersion":"/storage/emulated/0/boat/gamedir/versions/1.7.10" +"game_assets":"/storage/emulated/0/boat/gamedir/assets/virtual/legacy" +"user_type":"mojang" +"game_directory":"/storage/emulated/0/boat/gamedir" +"user_properties":"{}" +"assets_root":"/storage/emulated/0/boat/gamedir/assets" + + + +*/ diff --git a/app/src/main/java/com/download/service/util/LibrariesUtil.java b/app/src/main/java/com/download/service/util/LibrariesUtil.java new file mode 100644 index 00000000..e8bd9b67 --- /dev/null +++ b/app/src/main/java/com/download/service/util/LibrariesUtil.java @@ -0,0 +1,52 @@ +package com.download.service.util; + +public class LibrariesUtil +{ + private String name; + private String url; + private String path; + private int size; + private boolean download; + public LibrariesUtil(){ + + } + + + public String getname(){ + + return name; + } + public String geturl(){ + + return url; + } + public String getpath(){ + + return path; + } + public int getsize(){ + + return size; + } + public boolean get(){ + return download; + } + public void setname(String a){ + name=a; + } + public void seturl(String a){ + url=a; + } + public void setpath(String a){ + path=a; + } + public void setsize(int a){ + size=a; + } + public void set(boolean a){ + download=a; + } + + + +} diff --git a/app/src/main/java/com/download/service/util/VersionAssetsUtil.java b/app/src/main/java/com/download/service/util/VersionAssetsUtil.java new file mode 100644 index 00000000..077d781d --- /dev/null +++ b/app/src/main/java/com/download/service/util/VersionAssetsUtil.java @@ -0,0 +1,49 @@ +package com.download.service.util; + +public class VersionAssetsUtil +{ + private String hash; + private int size; + + public VersionAssetsUtil(){ + + } + + public String gethash(){ + + return hash; + } + public int getsize(){ + + return size; + } + + public void sethash(String a){ + hash=a; + } + public void setsize(int a){ + size=a; + } + /* + { + "objects":{ + "icons/icon_16x16.png": { + "hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a" + , "size": 3665} + , "icons/icon_32x32.png": { + "hash": "92750c5f93c312ba9ab413d546f32190c56d6f1f" + , "size": 5362} + , "icons/minecraft.icns": { + "hash": "991b421dfd401f115241601b2b373140a8d78572" + , "size": 114786} + , "minecraft/icons/icon_16x16.png": { + "hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a" + , "size": 3665} + , "minecraft/icons/icon_32x32.png": { + "hash": "92750c5f93c312ba9ab413d546f32190c56d6f1f" + , "size": 5362} + , "minecraft/icons/minecraft.icns": { + "hash": + + */ +} diff --git a/app/src/main/java/com/download/service/util/VersionUtil.java b/app/src/main/java/com/download/service/util/VersionUtil.java new file mode 100644 index 00000000..8506bd55 --- /dev/null +++ b/app/src/main/java/com/download/service/util/VersionUtil.java @@ -0,0 +1,40 @@ +package com.download.service.util; + +public class VersionUtil +{ + private String id; + private String url; + private String type; + + public VersionUtil(){ + + } + public String id(){ + + return id; + } + public String url(){ + + return url; + } + public String type(){ + + return type; + } + + public void id(String a){ + id=a; + } + public void url(String a){ + url=a; + } + + public void type(String a){ + type=a; + } + + + + + +} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/MainActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/MainActivity.java deleted file mode 100644 index 7cd8353c..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/MainActivity.java +++ /dev/null @@ -1,478 +0,0 @@ -package com.koishi.launcher.h2o2; - -import android.content.Intent; -import android.os.Bundle; -import android.support.design.widget.NavigationView; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; -import org.json.JSONObject; - -import com.koishi.launcher.h2o2.R; - -import com.koishi.launcher.h2o2.func.AboutActivity; -import com.koishi.launcher.h2o2.func.CustomActivity; -import com.koishi.launcher.h2o2.func.DonateActivity; -import com.koishi.launcher.h2o2.func.ExecuteActivity; -import com.koishi.launcher.h2o2.func.KeysActivity; -import com.koishi.launcher.h2o2.func.ModsActivity; -import com.koishi.launcher.h2o2.func.PacksActivity; -import com.koishi.launcher.h2o2.func.TexturesActivity; -import com.koishi.launcher.h2o2.func.WorldsActivity; -import android.widget.TextView; -import cosine.boat.LauncherActivity; -import cosine.boat.LauncherActivityMk; -import android.widget.Toast; -import android.widget.Button; -import com.koishi.launcher.h2o2.func.DownloadActivity; -import android.view.Menu; -import com.koishi.launcher.h2o2.func.LogActivity; -import com.koishi.launcher.h2o2.func.LoginActivity; -import android.widget.CheckBox; -import android.content.SharedPreferences; -import android.widget.CompoundButton; -import android.net.Uri; - -/** - * NavigationView在Toolbar下方展示 - */ -public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { - - public Spinner spinner; - public TextView dirshow,vet; - public Button gomc,gorun; - //public CheckBox mcb1,mcb2,rbsec; - public String d; - public String key = "WU-rXtRn13-vvqalABXEM_wYcDi7Oj3F"; - public String title,hcf; - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.m_log: - Intent i = new Intent(this, LogActivity.class); - startActivity(i); - break; - case R.id.m_logout: - Intent i2 = new Intent(this, LoginActivity.class); - startActivity(i2); - break; - default: - break; - } - return true; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - Intent intent = this.getIntent(); - d = intent.getStringExtra("noplay"); - title = getResources().getString(R.string.app_name); - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - toolbar.setTitle(title); - /* - mcb1 = (CheckBox)findViewById(R.id.mcb1); - mcb2 = (CheckBox)findViewById(R.id.mcb2); - rbsec = (CheckBox)findViewById(R.id.rbsec); - */ - - - if (d.equals("nofunc")){ - DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); - ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, R.string.navigation_drawer_open, R.string.navigation_drawer_close); - drawer.setDrawerListener(toggle); - toggle.syncState();//该方法会自动和Toolbar关联, 将开关的图片显示在了Toolbar上 - drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); - //mcb1.setEnabled(false); - //rbsec.setEnabled(false); - //mcb1.setChecked(false); - //rbsec.setChecked(false); - toolbar.setSubtitle("Demo Mode!"); - - }else{ - DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); - ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); - drawer.setDrawerListener(toggle); - toggle.syncState();//该方法会自动和Toolbar关联, 将开关的图片显示在了Toolbar上 - toolbar.setSubtitle("2.1.93"); - - /* - SharedPreferences sp = getSharedPreferences("times", MODE_PRIVATE); - final SharedPreferences.Editor edit = sp.edit(); - - boolean isCheckeds= sp.getBoolean("isCheckeds", false); - if (isCheckeds) { - mcb1.setChecked(true); - } - mcb1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { - if (isChecked) { - edit.putBoolean("isCheckeds", true); - edit.commit(); - } else { - edit.putBoolean("isCheckeds", false); - edit.commit(); - } - } - }); - - SharedPreferences sp2 = getSharedPreferences("times2", MODE_PRIVATE); - final SharedPreferences.Editor edit2 = sp2.edit(); - - boolean isChecked= sp2.getBoolean("isChecked", false); - if (isChecked) { - rbsec.setChecked(true); - } - rbsec.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { - if (isChecked) { - edit2.putBoolean("isChecked", true); - edit2.commit(); - } else { - edit2.putBoolean("isChecked", false); - edit2.commit(); - } - } - }); - } - */ - //DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); - //这是带Home旋转开关按钮 - - //这是不带Home旋转开关按钮 -// ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, R.string.navigation_drawer_open, R.string.navigation_drawer_close); - - NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); - navigationView.setNavigationItemSelectedListener(this); - - - //TextView - dirshow = (TextView)findViewById(R.id.dirshow); - dirshow.setText(dirs()); - - hcf = cp1(); - - gomc = (Button)findViewById(R.id.gomc); - gorun = (Button)findViewById(R.id.gorun); - - vet = (TextView)findViewById(R.id.vet); - - //mcb2.setEnabled(false); - - check(); - - haveFile(); - - -} - } - - public boolean joinQQGroup(String key) { - Intent intent = new Intent(); - intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3D" + key)); - // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - try { - startActivity(intent); - return true; - } catch (Exception e) { - // 未安装手Q或安装的版本不支持 - return false; - } - } - - public void list() { - final Spinner list=(Spinner) findViewById(R.id.ver); - File versionlist = new File(dirshow.getText().toString() + "/versions"); - final String[] ver = versionlist.list() ; - ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, ver); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - - list.setAdapter(adapter); - list.setOnItemSelectedListener(new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView p1, View p2, int p3, long p4) { - if (!((String)p1.getItemAtPosition(p3)).equals("Null")) { - setVersion((String)p1.getItemAtPosition(p3)); - } - String str = (String) list.getSelectedItem(); - vet.setText("Minecraft\n"+str); - - } - @Override - public void onNothingSelected(AdapterView p1) { - } - }); - list.setSelection(adapter.getPosition(ve())); - } - - public void check() { - boolean tmp = fileIsExists(dirshow.getText().toString()); - boolean tmp2 = fileIsExists("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - boolean tmp3 = fileIsExists("/sdcard/games/com.koishi.launcher/h2o2/gamedir"); - if (tmp) { - if (tmp2) { - if (tmp3) { - list(); - } else { - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_19), Toast.LENGTH_SHORT).show(); - Intent i5 = new Intent(this, PacksActivity.class); - startActivity(i5); - } - } else { - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_19), Toast.LENGTH_SHORT).show(); - Intent i5 = new Intent(this, PacksActivity.class); - startActivity(i5); - } - } else { - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_18), Toast.LENGTH_SHORT).show(); - Intent i5 = new Intent(this, PacksActivity.class); - startActivity(i5); - } - } - - public void setVersion(String version) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("currentVersion"); - json.put("currentVersion", dirshow.getText().toString() + "/versions/" + version.trim()); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/config.txt")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - public String ve() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - if (str.equals("")) { - return "null"; - } - JSONObject json=new JSONObject(str); - String cnt=json.getString("currentVersion"); - return cnt.substring(cnt.indexOf("versions") + 9); - } catch (Exception e) { - return e.toString(); - } - } - - public String dirs() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("game_directory"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - private String cp1() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("mouseMode"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - @Override - public void onBackPressed() { - DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); - if (drawer.isDrawerOpen(GravityCompat.START)) { - drawer.closeDrawer(GravityCompat.START); - } else { - - } - } - - @Override - protected void onResume() { - super.onResume(); - dirshow.setText(dirs()); - check(); - hcf = cp1(); - haveFile(); - } - - @SuppressWarnings("StatementWithEmptyBody") - @Override - public boolean onNavigationItemSelected(MenuItem item) { - // Handle navigation view item clicks here. - switch (item.getItemId()) { - case R.id.m1: - - break; - case R.id.m2: - Intent i2 = new Intent(this, ExecuteActivity.class); - startActivity(i2); - break; - case R.id.m3: - Intent i3 = new Intent(this, CustomActivity.class); - startActivity(i3); - break; - case R.id.m4: - Intent i4 = new Intent(this, KeysActivity.class); - startActivity(i4); - break; - case R.id.m5: - Intent i5 = new Intent(this, PacksActivity.class); - startActivity(i5); - break; - case R.id.m6: - Intent i6 = new Intent(this, WorldsActivity.class); - startActivity(i6); - break; - case R.id.m7: - Intent i7 = new Intent(this, TexturesActivity.class); - startActivity(i7); - break; - case R.id.m8: - Intent i8 = new Intent(this, ModsActivity.class); - startActivity(i8); - break; - case R.id.m9: - Intent i9 = new Intent(this, DonateActivity.class); - startActivity(i9); - break; - case R.id.m10: - Intent i10 = new Intent(this, AboutActivity.class); - startActivity(i10); - break; - case R.id.jqq: - joinQQGroup(key); - break; - case R.id.jds: - Intent intent = new Intent(); - intent.setData(Uri.parse("https://discord.gg/Ktw9sYx879"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - break; - default: - break; - } - DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); - drawer.closeDrawer(GravityCompat.START); - return true; - } - - public void start(View view) { - File file = new File(dirshow.getText().toString() + "/versions"); - boolean tmp = fileIsExists("/data/data/com.koishi.launcher.h2o2/app_runtime/libopenal.so.1"); - final String aa = vet.getText().toString(); - if (file.exists() && file.isDirectory()) { - if (file.list().length == 0) { - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_13), Toast.LENGTH_SHORT).show(); - } - } - if (file.list().length > 0) { - if (!tmp) { - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_12), Toast.LENGTH_SHORT).show(); - } - if (tmp) { - if (aa.equals("")) { - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_14), Toast.LENGTH_SHORT).show(); - } else { - if (hcf.equals("true")) { - String a = "switch"; - Intent i = new Intent(this, LauncherActivityMk.class); - i.putExtra("data", a); - startActivity(i); - } else { - Intent i0 = new Intent(this, LauncherActivity.class); - startActivity(i0); - } - } - } - } - } - - public void mc(View view) { - Intent i5 = new Intent(this, PacksActivity.class); - startActivity(i5); - } - - public void runtime(View view) { - Intent ir = new Intent(this, ExecuteActivity.class); - startActivity(ir); - } - - public void haveFile() { - File file = new File(dirshow.getText().toString() + "/versions"); - boolean tmp = fileIsExists("/data/data/com.koishi.launcher.h2o2/app_runtime/libopenal.so.1"); - if (file.exists() && file.isDirectory()) { - if (file.list().length == 0) { - gomc.setText(getResources().getString(R.string.menu_13)); - gomc.setTextColor(0xffff0000); - } else { - gomc.setTextColor(getResources().getColor(R.color.colorPrimary)); - gomc.setText(getResources().getString(R.string.menu_15)); - } - - } - if (!tmp) { - gorun.setText(getResources().getString(R.string.menu_12)); - gorun.setTextColor(0xffff0000); - } else { - gorun.setTextColor(getResources().getColor(R.color.colorPrimary)); - gorun.setText(getResources().getString(R.string.menu_16)); - } - } - public boolean fileIsExists(String strFile) { - try { - File f=new File(strFile); - if (!f.exists()) { - return false; - } - - } catch (Exception e) { - return false; - } - - return true; - } -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/SplashActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/SplashActivity.java deleted file mode 100644 index 2fa0bfd8..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/SplashActivity.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.koishi.launcher.h2o2; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.provider.Settings; -import android.support.v7.app.AppCompatActivity; -import android.view.WindowManager; -import android.os.Environment; -import java.io.IOException; -import android.content.Context; -import java.io.File; -import java.io.InputStream; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipEntry; -import java.io.FileOutputStream; -import android.text.TextUtils; -import com.koishi.launcher.h2o2.func.LoginActivity; -import java.io.FileWriter; -import android.widget.Toast; -import com.koishi.launcher.h2o2.func.InitialActivity; - -public class SplashActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.activity_splash); - setcfg(); - /*activity继承AppCompatActivity使用getSupportActionBar().hide()来隐藏ActionBar,且 - * 必须写在 setContentView后面,如果在styles.xml中设置了NoTitleBar就不用写。*/ - /*getSupportActionBar().hide();*/ - boolean tmp = fileIsExists("/sdcard/games/com.koishi.launcher/h2o2/gamedir"); - boolean tmp2 = fileIsExists("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - - if (tmp && tmp2){ - start(); - }else{ - try { - output(SplashActivity.this, "h2o2.zip", Environment.getExternalStorageDirectory() + "/games/com.koishi.launcher/h2o2" ); - } catch (IOException e) { - e.printStackTrace(); - } - start(); - } - - - } - - public void start(){ - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - boolean tmp3 = fileIsExists("/data/data/com.koishi.launcher.h2o2/app_runtime/libopenal.so.1"); - if (tmp3){ - Intent intent1=new Intent(SplashActivity.this,LoginActivity.class); - startActivity(intent1); - SplashActivity.this.finish(); - }else{ - Intent intent1=new Intent(SplashActivity.this,InitialActivity.class); - startActivity(intent1); - SplashActivity.this.finish(); - } - - } - },3000);//3000表示延迟的毫秒数。 - } - private void output(Context context, String assetName, String outputDirectory) throws IOException { - File file = new File(outputDirectory); - if (!file.exists()) { - file.mkdirs(); - } - - InputStream inputStream = null; - inputStream = context.getAssets().open(assetName); - ZipInputStream zipInputStream = new ZipInputStream(inputStream); - ZipEntry zipEntry = zipInputStream.getNextEntry(); - byte[] buffer = new byte[1024 * 1024]; - int count = 0; - while (zipEntry != null) { - //如果是一个目录 - if (zipEntry.isDirectory()) { - //String name = zipEntry.getName(); - //name = name.substring(0, name.length() - 1); - file = new File(outputDirectory + File.separator + zipEntry.getName()); - file.mkdir(); - } else { - //如果是文件 - file = new File(outputDirectory + File.separator - + zipEntry.getName()); - //创建该文件 - file.createNewFile(); - FileOutputStream fileOutputStream = new FileOutputStream(file); - while ((count = zipInputStream.read(buffer)) > 0) { - fileOutputStream.write(buffer, 0, count); - } - - fileOutputStream.close(); - } - //定位到下一个文件入口 - zipEntry = zipInputStream.getNextEntry(); - - } - zipInputStream.close(); - } - - private void setcfg(){ - boolean tmp3 = fileIsExists("/storage/emulated/0/games/com.koishi.launcher/h2o2/h2ocfg.json"); - if(!tmp3){ - try { - FileWriter fr=new FileWriter("/storage/emulated/0/games/com.koishi.launcher/h2o2/h2ocfg.json"); - fr.write("{\"mouseMode\":\"false\",\"backToRightClick\":\"false\",\"jumpToLeft\":\"false\",\"email\":\"\",\"password\":\"\",\"dontEsc\":\"false\"}"); - fr.close(); - System.out.println("success"); - } catch (IOException e) - { - System.out.println(e); - Toast.makeText(SplashActivity.this, e.toString(), Toast.LENGTH_SHORT).show(); - } - } - } - - private File renameFile(String oldPath, String newPath) { - if (TextUtils.isEmpty(oldPath)) { - return null; - } - - if (TextUtils.isEmpty(newPath)) { - return null; - } - File oldFile = new File(oldPath); - File newFile = new File(newPath); - boolean b = oldFile.renameTo(newFile); - File file2 = new File(newPath); - return file2; - } - - public boolean fileIsExists(String strFile) { - try { - File f=new File(strFile); - if (!f.exists()) { - return false; - } - - } catch (Exception e) { - return false; - } - - return true; - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/AboutActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/AboutActivity.java deleted file mode 100644 index c945f820..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/AboutActivity.java +++ /dev/null @@ -1,234 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.app.AlertDialog; -import android.widget.TextView; -import android.text.method.LinkMovementMethod; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; - -public class AboutActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_about); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar10); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - } - public void a1(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.menu_10)); - builder.setIcon(R.drawable.ic_boat); - builder.setMessage(getResources().getString(R.string.menu_10_1)); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - - - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - } - public void a2(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.m102)); - builder.setIcon(R.drawable.ic_boat); - builder.setMessage(getResources().getString(R.string.menu_10_2)); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - } - public void a3(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.m103)); - builder.setIcon(R.drawable.ic_boat); - builder.setMessage(getResources().getString(R.string.menu_10_3)); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - - - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - } - public void a4(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.m104)); - builder.setIcon(R.drawable.ic_boat); - builder.setMessage(getResources().getString(R.string.menu_10_4)); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - - - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - } - public void boat(View view) { - Intent intent = new Intent(); - intent.setData(Uri.parse("https://github.com/AOF-Dev/BoatApp"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - } - public void h2o(View view) { - Intent intent = new Intent(); - intent.setData(Uri.parse("https://github.com/NaCln4c1/Boat_H2O-v4"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - } - public void box(View view) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.m105)); - builder.setIcon(R.drawable.ic_boat); - builder.setMessage(getResources().getString(R.string.m107)); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - builder.setNegativeButton(getResources().getString(R.string.m108), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - go(); - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - } - public void lfp(View view) { - Intent intent = new Intent(); - intent.setData(Uri.parse("https://github.com/leonHua/LFilePicker"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - } - public void auth(View view) { - Intent intent = new Intent(); - intent.setData(Uri.parse("http://www.coolapk.com/u/1996447"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - } - public void go(){ - Intent intent = new Intent(); - intent.setData(Uri.parse("https://github.com/AOF-Dev/MCinaBox"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/CustomActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/CustomActivity.java deleted file mode 100644 index 39d6291f..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/CustomActivity.java +++ /dev/null @@ -1,661 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.widget.EditText; -import android.widget.TextView; -import android.text.TextWatcher; -import android.text.Editable; -import android.os.Handler; -import java.io.FileInputStream; -import org.json.JSONObject; -import java.io.FileWriter; -import java.io.File; -import android.support.v7.app.AlertDialog; -import android.content.DialogInterface; -import android.app.ActivityManager; -import android.app.ActivityManager.MemoryInfo; -import android.content.Context; -import java.text.DecimalFormat; -import android.widget.Switch; -import android.widget.CompoundButton; -import android.support.v7.widget.CardView; -import android.widget.LinearLayout; -import android.view.ViewGroup; -import android.os.Message; -import android.widget.Toast; - -public class CustomActivity extends AppCompatActivity { - - public TextView name,mem,c_p1,c_p2,c_p3,c_p4; - public TextView mdl; - - public Switch c_sw1,c_sw2,c_sw3,c_sw4; - public CardView ccc; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_custom); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar3); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - name = (TextView)findViewById(R.id.name); - name.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - name(p1.toString()); - - } - - }); - name.setText(nam()); - - mem = (TextView)findViewById(R.id.mem); - mem.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - mem(p1.toString()); - } - }); - mem.setText(me()); - this.mdl = (TextView)findViewById(R.id.mdl); - ramInfo(); - final Handler handler=new Handler(); - final Runnable runnable=new Runnable() { - @Override - public void run() { - // TODO Auto-generated method stub - //要做的事情 - ramInfo(); - handler.postDelayed(this, 1000); // 1秒后执行 - } - }; - handler.postDelayed(runnable, 1000);//1秒执行一次runnable - - ccc = (CardView)findViewById(R.id.ccc); - c_p1 = (TextView)findViewById(R.id.c_p1); - c_p1.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - c_p1(p1.toString()); - } - }); - c_p1.setText(cp1()); - - c_p2 = (TextView)findViewById(R.id.c_p2); - c_p2.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - c_p2(p1.toString()); - } - }); - c_p2.setText(cp2()); - - c_p3 = (TextView)findViewById(R.id.c_p3); - c_p3.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - c_p3(p1.toString()); - } - }); - c_p3.setText(cp3()); - - c_p4 = (TextView)findViewById(R.id.c_p4); - c_p4.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - c_p4(p1.toString()); - } - }); - c_p4.setText(cp4()); - - c_sw1 = (Switch)findViewById(R.id.c_sw1); - c_sw1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - c_p1.setText("true"); - c_sw2.setEnabled(true); - } else { - c_p1.setText("false"); - c_sw2.setEnabled(false); - } - } - }); - - c_sw2 = (Switch)findViewById(R.id.c_sw2); - c_sw2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - c_p2.setText("true"); - } else { - c_p2.setText("false"); - } - } - }); - c_sw3 = (Switch)findViewById(R.id.c_sw3); - c_sw3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - c_p3.setText("true"); - } else { - c_p3.setText("false"); - } - } - }); - - c_sw4 = (Switch)findViewById(R.id.c_sw4); - c_sw4.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - c_p4.setText("true"); - } else { - c_p4.setText("false"); - } - } - }); - - String cp01= cp1(); - String cp02= cp2(); - String cp03= cp3(); - String cp04= cp4(); - - if (cp01.equals("true")) { - c_sw1.setChecked(true); - c_sw2.setEnabled(true); - ccc.setEnabled(true); - } else { - c_sw1.setChecked(false); - c_sw2.setEnabled(false); - ccc.setEnabled(false); - } - - if (cp02.equals("true")) { - c_sw2.setChecked(true); - } else { - c_sw2.setChecked(false); - } - - if (cp03.equals("true")) { - c_sw3.setChecked(true); - } else { - c_sw3.setChecked(false); - } - - if (cp04.equals("true")) { - c_sw4.setChecked(true); - } else { - c_sw4.setChecked(false); - } - - } - private void name(String player) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("auth_player_name"); - json.put("auth_player_name", player); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/config.txt")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - private String nam() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("auth_player_name"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - private void mem(String nc) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("extraJavaFlags"); - json.put("extraJavaFlags", nc); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/config.txt")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - private String me() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("extraJavaFlags"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - private void c_p1(String p1) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("mouseMode"); - json.put("mouseMode", p1); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - private String cp1() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("mouseMode"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - private void c_p2(String p2) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("backToRightClick"); - json.put("backToRightClick", p2); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - private String cp2() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("backToRightClick"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - private void c_p3(String p3) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("jumpToLeft"); - json.put("jumpToLeft", p3); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - private String cp3() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("jumpToLeft"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - private void c_p4(String p4) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("dontEsc"); - json.put("dontEsc", p4); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - private String cp4() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/h2ocfg.json"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("dontEsc"); - } catch (Exception e) { - System.out.println(e); - } - return "Error"; - } - - public void setName(View view) { - final EditText editText = new EditText(CustomActivity.this); - editText.setText(name.getText().toString()); - AlertDialog.Builder dialog = new AlertDialog.Builder(CustomActivity.this); - dialog.setTitle("ID"); - dialog.setView(editText, 50, 0, 50, 0); - - dialog.setCancelable(true); - dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - name.setText(editText.getText().toString()); - } - }); - dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - dialog.show(); - } - - public void sc1(View view){ - if (c_sw1.isChecked()){ - c_sw1.setChecked(false); - c_sw2.setEnabled(false); - ccc.setEnabled(false); - - }else{ - c_sw1.setChecked(true); - c_sw2.setEnabled(true); - ccc.setEnabled(true); - } - - } - - public void sc2(View view){ - if (c_sw2.isChecked()){ - c_sw2.setChecked(false); - - }else{ - c_sw2.setChecked(true); - - } - - } - - public void sc3(View view){ - if (c_sw3.isChecked()){ - c_sw3.setChecked(false); - - }else{ - c_sw3.setChecked(true); - - } - - } - - public void sc4(View view){ - if (c_sw4.isChecked()){ - c_sw4.setChecked(false); - - }else{ - c_sw4.setChecked(true); - - } - - } - - public void del(View view){ - AlertDialog alertDialog1 = new AlertDialog.Builder(CustomActivity.this) - .setTitle(getResources().getString(R.string.menu_5_adt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(getResources().getString(R.string.menu_5_adm)) - .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - new Thread(new Runnable(){ - @Override - public void run() { - //String file2= "/data/data/com.koishi.launcher.h2o2/app_runtime"; - killlist(); - /* - File file = new File(file2); - if(file.isDirectory()){ - deleteDirectory(file2); - } - if(file.isFile()){ - deleteFile(file2); - } - */ - han.sendEmptyMessage(0); - } - }).start(); - - } - }) - .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - - alertDialog1.show(); - } - private void killlist() { - File file2=new File("/data/data/" + getPackageName() + "/app_runtime/"); - deleteDirWihtFile(file2); - } - private void deleteDirWihtFile(File file2) { - if (file2 == null || !file2.exists() || !file2.isDirectory()) - return; - for (File file :file2.listFiles()) { - if (file.isFile()) - file.delete(); - else if (file.isDirectory()) - deleteDirWihtFile(file); - - } - file2.delete(); - } - - public boolean deleteDirectory(String filePath) { - boolean flag = false; - //如果filePath不以文件分隔符结尾,自动添加文件分隔符 - if (!filePath.endsWith(File.separator)) { - filePath = filePath + File.separator; - } - File dirFile = new File(filePath); - if (!dirFile.exists() || !dirFile.isDirectory()) { - return false; - } - flag = true; - File[] files = dirFile.listFiles(); - //遍历删除文件夹下的所有文件(包括子目录) - for (int i = 0; i < files.length; i++) { - if (files[i].isFile()) { - //删除子文件 - flag = deleteFile(files[i].getAbsolutePath()); - if (!flag) break; - } else { - //删除子目录 - flag = deleteDirectory(files[i].getAbsolutePath()); - if (!flag) break; - } - } - if (!flag) return false; - //删除当前空目录 - return dirFile.delete(); - } - Handler han=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_del), Toast.LENGTH_SHORT).show(); - } - }}; - public void setJVM(View view) { - final EditText editText = new EditText(CustomActivity.this); - editText.setText(mem.getText().toString()); - AlertDialog.Builder dialog = new AlertDialog.Builder(CustomActivity.this); - dialog.setTitle("Jvm Flags"); - dialog.setView(editText, 50, 0, 50, 0); - dialog.setCancelable(true); - dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mem.setText(editText.getText().toString()); - } - }); - dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - dialog.show(); - } - private void ramInfo() { - ActivityManager am=(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); - MemoryInfo mi=new MemoryInfo(); - am.getMemoryInfo(mi); - String[] available=fileSize(mi.availMem); - String[] total=fileSize(mi.totalMem); - mdl.setText("RAM " + available[0] + available[1] + "/" + total[0] + total[1]); - } - private String[] fileSize(long size) { - String str=""; - if (size >= 1000) { - str = "KB"; - size /= 1000; - if (size >= 1000) { - str = "MB"; - size /= 1000; - } - } - /*将每3个数字用,分隔如:1,000*/ - DecimalFormat formatter=new DecimalFormat(); - formatter.setGroupingSize(3); - String result[]=new String[2]; - result[0] = formatter.format(size); - result[1] = str; - return result; - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/DonateActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/DonateActivity.java deleted file mode 100644 index f64c02cb..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/DonateActivity.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.widget.ImageView; -import android.app.AlertDialog; -import android.view.View.OnClickListener; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -public class DonateActivity extends AppCompatActivity { - - private String [] data = {"🥇 异星之尘","🥈 Yoyo ​Yukari","🥉 小绿","4. SakerVeLib","5. JiuXia2025","6. 小航","7. B站Minecraft菠萝君","8. 热心市民","9. 余情","10. 余生","11. Vindows95","12. YJ","13. 眼角一丝安逸"}; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_donate); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar9); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - ArrayAdapter arrayAdapter= new ArrayAdapter ( - DonateActivity.this, android.R.layout.simple_list_item_1,data); - ListView listView = (ListView) findViewById(R.id.listview); - listView.setAdapter(arrayAdapter); - - } - public void vx(View view) { - ImageView image = new ImageView(this); - image.setImageResource(R.drawable.qr); - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.menu_5_adt)); - builder.setIcon(R.drawable.ic_boat); - builder.setView(image); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - } - }); - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - } - public void afd(View view) { - Intent intent = new Intent(); - intent.setData(Uri.parse("https://afdian.net/@boat-h2o"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - } - public void prt(View view) { - Intent intent = new Intent(); - intent.setData(Uri.parse("https://www.patreon.com/boatapp_h2o"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/DownloadActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/DownloadActivity.java deleted file mode 100644 index 2781eebf..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/DownloadActivity.java +++ /dev/null @@ -1,310 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.View; - -import com.koishi.launcher.h2o2.R; -import org.json.JSONObject; -import java.io.FileInputStream; -import android.app.ProgressDialog; -import com.leon.lfilepickerlibrary.LFilePicker; -import android.os.Handler; -import android.os.Message; -import java.io.File; -import android.widget.Toast; -import com.koishi.launcher.h2o2.tools.Consant; -import java.io.IOException; -import java.io.OutputStream; -import java.io.InputStream; -import java.util.zip.ZipFile; -import java.nio.charset.Charset; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.io.FileOutputStream; -import java.io.BufferedOutputStream; -import android.content.Intent; -import android.app.Activity; -import java.util.List; -import android.text.TextUtils; - -public class DownloadActivity extends AppCompatActivity { - - String a; - private ProgressDialog pd; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_download); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar0); - setSupportActionBar(toolbar); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - pd = new ProgressDialog(DownloadActivity.this); - pd.setMessage("Waiting..."); - pd.setIndeterminate(true); - pd.setCancelable(false); - a = t(); - } - private String t() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("game_directory"); - } catch (Exception e) { - System.out.println(e); - } - return "None"; - } - - public void imp (View view){ - new LFilePicker().withActivity(this) - .withRequestCode(Consant.REQUESTCODE_FROM_FRAGMENT) - .withMutilyMode(false) - .withFileFilter(new String[]{"zip"}) - .withTheme(R.style.LFileTheme) - .withTitle("Open From Packs") - .start(); - - - } - public void gomana(View view){ - - } - - Handler han2=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - boolean tmp = fileIsExists("/sdcard/games/com.koishi.launcher/tmp/boat/gamedir"); - if (tmp) { - renameFile("/sdcard/games/com.koishi.launcher/tmp/boat","/sdcard/games/com.koishi.launcher/tmp/h2o2"); - String pathname = "/sdcard/games/com.koishi.launcher/tmp/h2o2"; - final File file = new File(pathname); - //复制到的位置 - String topathname = "/sdcard/games/com.koishi.launcher"; - final File toFile = new File(topathname); - new Thread(new Runnable(){ - @Override - public void run() { - try { - copy(file, toFile); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - han4.sendEmptyMessage(0); - } - - }).start(); - } else { - new Thread(new Runnable(){ - @Override - public void run() { - File file2=new File("/sdcard/games/com.koishi.launcher/tmp"); - deleteDirWihtFile(file2); - han3.sendEmptyMessage(0); - } - }).start(); - } - } - }}; - Handler han3=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - pd.hide(); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttdn), Toast.LENGTH_SHORT).show(); - } - }}; - - Handler han4=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - pd.hide(); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttd), Toast.LENGTH_SHORT).show(); - } - }}; - - public static void unzip(String zipFilePath, String targetPath) - throws IOException { - OutputStream os = null; - InputStream is = null; - ZipFile zipFile = null; - try { - //获取要解压的文件,指定解压格式 - zipFile = new ZipFile(zipFilePath, Charset.forName("GBK")); - Enumeration entryEnum = zipFile.entries(); - if (null != entryEnum) { - ZipEntry zipEntry = null; - while (entryEnum.hasMoreElements()) { - zipEntry = (ZipEntry) entryEnum.nextElement(); - if (zipEntry.getSize() > 0) { - File targetFile = new File(targetPath - + File.separator + zipEntry.getName()); - os = new BufferedOutputStream(new FileOutputStream(targetFile)); - is = zipFile.getInputStream(zipEntry); - byte[] buffer = new byte[4096]; - int readLen = 0; - while ((readLen = is.read(buffer, 0, 4096)) >= 0) { - os.write(buffer, 0, readLen); - os.flush(); - } - is.close(); - os.close(); - } - //如果是文件夹,则创建文件夹 - if (zipEntry.isDirectory()) { - String pathTemp = targetPath + File.separator - + zipEntry.getName(); - File file = new File(pathTemp); - file.mkdirs(); - } - } - } - } catch (IOException ex) { - throw ex; - } finally { - //关闭流 - if (null != zipFile) { - zipFile.close(); - zipFile = null; - } - if (null != is) { - is.close(); - } - if (null != os) { - os.close(); - } - } - } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK) { - if (requestCode == Consant.REQUESTCODE_FROM_FRAGMENT) { - List list = data.getStringArrayListExtra("paths"); - for (final String s : list) { - pd.show(); - new Thread(new Runnable(){ - @Override - public void run() { - try { - unzip(s, "/sdcard/games/com.koishi.launcher/tmp"); - han2.sendEmptyMessage(0); - } catch (IOException e) { - } - - } - }).start(); - } - } - } - } - private void deleteDirWihtFile(File file2) { - if (file2 == null || !file2.exists() || !file2.isDirectory()) - return; - for (File file :file2.listFiles()) { - if (file.isFile()) - file.delete(); - else if (file.isDirectory()) - deleteDirWihtFile(file); - - } - file2.delete(); - } - - public static void copy(File file, File toFile) throws Exception { - byte[] b = new byte[1024]; - int a; - FileInputStream fis; - FileOutputStream fos; - if (file.isDirectory()) { - String filepath = file.getAbsolutePath(); - filepath = filepath.replaceAll("\\\\", "/"); - String toFilepath = toFile.getAbsolutePath(); - toFilepath = toFilepath.replaceAll("\\\\", "/"); - int lastIndexOf = filepath.lastIndexOf("/"); - toFilepath = toFilepath + filepath.substring(lastIndexOf , filepath.length()); - File copy=new File(toFilepath); - //复制文件夹 - if (!copy.exists()) { - copy.mkdir(); - } - //遍历文件夹 - for (File f : file.listFiles()) { - copy(f, copy); - } - } else { - if (toFile.isDirectory()) { - String filepath = file.getAbsolutePath(); - filepath = filepath.replaceAll("\\\\", "/"); - String toFilepath = toFile.getAbsolutePath(); - toFilepath = toFilepath.replaceAll("\\\\", "/"); - int lastIndexOf = filepath.lastIndexOf("/"); - toFilepath = toFilepath + filepath.substring(lastIndexOf , filepath.length()); - - //写文件 - File newFile = new File(toFilepath); - fis = new FileInputStream(file); - fos = new FileOutputStream(newFile); - while ((a = fis.read(b)) != -1) { - fos.write(b, 0, a); - } - } else { - //写文件 - fis = new FileInputStream(file); - fos = new FileOutputStream(toFile); - while ((a = fis.read(b)) != -1) { - fos.write(b, 0, a); - } - } - - } - } - - public boolean fileIsExists(String strFile) { - try { - File f=new File(strFile); - if (!f.exists()) { - return false; - } - - } catch (Exception e) { - return false; - } - - return true; - } - private File renameFile(String oldPath, String newPath) { - if (TextUtils.isEmpty(oldPath)) { - return null; - } - - if (TextUtils.isEmpty(newPath)) { - return null; - } - File oldFile = new File(oldPath); - File newFile = new File(newPath); - boolean b = oldFile.renameTo(newFile); - File file2 = new File(newPath); - return file2; - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/ExecuteActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/ExecuteActivity.java deleted file mode 100644 index 8dc6a4b7..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/ExecuteActivity.java +++ /dev/null @@ -1,290 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.TextView; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.IOException; -import android.os.Message; -import android.os.Handler; -import android.text.Html; -import java.io.File; -import com.koishi.launcher.h2o2.tools.Utils; -import android.support.v7.app.AlertDialog; -import android.content.DialogInterface; -import com.leon.lfilepickerlibrary.LFilePicker; -import com.koishi.launcher.h2o2.tools.Consant; -import android.content.Intent; -import android.app.Activity; -import java.util.List; - -public class ExecuteActivity extends AppCompatActivity implements View.OnClickListener { - - public Button excuteButton; - public TextView inputText; - public TextView outputText; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_execute); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar2); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - this.excuteButton=(Button)findViewById(R.id.launcher_excute_button); - this.inputText=(TextView)findViewById(R.id.launcher_input_text); - this.outputText=(TextView)findViewById(R.id.launcher_output_text); - - this.excuteButton.setOnClickListener(this); - - this.mHandler = new MyHandler(); - } - private String result = ""; - private String error =""; - public void excuteCommand(final String args[]) { - new Thread(){ - @Override - public void run() { - try { - Process p = new ProcessBuilder(args).start(); - BufferedReader bri=new BufferedReader(new InputStreamReader(p.getInputStream())); - - result = ""; - String linei; - while ((linei = bri.readLine()) != null) { - result = result + "\n" + linei; - - } - - BufferedReader bre=new BufferedReader(new InputStreamReader(p.getErrorStream())); - - error = ""; - String linee; - while ((linee = bre.readLine()) != null) { - error = error + "\n" + linee; - - } - - p.waitFor(); - int e = p.exitValue(); - - Message endMsg=new Message(); - endMsg.what = e; - mHandler.sendMessage(endMsg); - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }.start(); - } - //Output Text Message - private MyHandler mHandler; - private class MyHandler extends Handler { - @Override - public void handleMessage(Message msg) { - - switch (msg.what) { - case -1: - String str0 = "\nNo such file!\n"; - outputText.append(Html.fromHtml(str0)); - outputText.append("\n"); - break; - case -2: - outputText.append("Installing...\n"); - break; - case -3: - outputText.append("Package has been extracted in " + getDir("runtime", 0).getAbsolutePath() + "\n"); - break; - case -4: - outputText.append("Try to set executing permission: true\n"); - break; - case -5: - outputText.append("Try to set executing permission: false\n"); - break; - case -6: - outputText.append("Setting up property...\n"); - break; - case -7: - outputText.append("Install Finished. Now checking the runtime file if exists...\n"); - break; - case -8: - String str2 = "Install successfully\n"; - outputText.append(Html.fromHtml(str2)); - outputText.append("\n"); - break; - case -9: - String str1 = "Wrong runtime have been installed."; - outputText.append(Html.fromHtml(str1)); - outputText.append("\n"); - break; - case -10: - outputText.append("Now deleting...\n"); - break; - case -11: - outputText.append("Done.\n"); - break; - default: - outputText.append(result + "\n"); - outputText.append("\n"); - outputText.append(error + "\n"); - outputText.append("Command process exited with value: " + msg.what + "\n"); - } - } - } - public boolean mode = false; - @Override - public void onClick(View p1){ - if (p1 == excuteButton){ - if (!mode) { - if (!inputText.getText().equals("")) { - String packagePath = inputText.getText().toString(); - install(packagePath); - } - } else { - if (!inputText.getText().equals("")) { - String cmd = inputText.getText().toString(); - excuteCommand(cmd.split(" ")); - - } - } - } - } - public void setdir(View view){ - final EditText editText = new EditText(ExecuteActivity.this); - AlertDialog.Builder dialog = new AlertDialog.Builder(ExecuteActivity.this); - dialog.setTitle("Directory of runtime"); - dialog.setView(editText, 50, 0, 50, 0); - dialog.setCancelable(true); - dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - inputText.setText(editText.getText().toString()); - } - }); - dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); - dialog.show(); - } - public void install(final String packagePath) { - new Thread(){ - @Override - public void run() { - Message endMsg = null; - File packageFile = new File(packagePath); - if (!packageFile.exists()) { - endMsg = new Message(); - mHandler.sendMessage(endMsg); - endMsg.what = -1; - - - } else { - { - endMsg = new Message(); - endMsg.what = -2; - mHandler.sendMessage(endMsg); - } - Utils.extractTarXZ(packagePath, getDir("runtime", 0)); - endMsg = new Message(); - endMsg.what = -3; - mHandler.sendMessage(endMsg); - - if (Utils.setExecutable(getDir("runtime", 0))) { - endMsg = new Message(); - endMsg.what = -4; - mHandler.sendMessage(endMsg); - } else { - endMsg = new Message(); - endMsg.what = -5; - mHandler.sendMessage(endMsg); - } - endMsg = new Message(); - endMsg.what = -6; - mHandler.sendMessage(endMsg); - - endMsg = new Message(); - endMsg.what = -7; - mHandler.sendMessage(endMsg); - - if (!new File("/data/data/com.koishi.launcher.h2o2/app_runtime/libopenal.so.1").exists()) { - - endMsg = new Message(); - endMsg.what = -9; - mHandler.sendMessage(endMsg); - endMsg = new Message(); - endMsg.what = -10; - mHandler.sendMessage(endMsg); - killlist(); - endMsg = new Message(); - endMsg.what = -11; - mHandler.sendMessage(endMsg); - - } else { - - endMsg = new Message(); - endMsg.what = -8; - mHandler.sendMessage(endMsg); } - } - } - }.start(); - } - public void goset (View view){ - new LFilePicker().withActivity(this) - .withRequestCode(Consant.REQUESTCODE_FROM_FRAGMENT) - .withMutilyMode(false) - .withFileFilter(new String[]{"tar.xz"}) - .withTheme(R.style.LFileTheme) - .withTitle("Open From Packs") - .start(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK) { - if (requestCode == Consant.REQUESTCODE_FROM_FRAGMENT) { - List list = data.getStringArrayListExtra("paths"); - for (final String s : list) { - inputText.setText(s); - - } - } - } - } - - private void killlist() { - File file2=new File("/data/data/" + getPackageName() + "/app_runtime/"); - deleteDirWihtFile(file2); - } - private void deleteDirWihtFile(File file2) { - if (file2 == null || !file2.exists() || !file2.isDirectory()) - return; - for (File file :file2.listFiles()) { - if (file.isFile()) - file.delete(); - else if (file.isDirectory()) - deleteDirWihtFile(file); - - } - file2.delete(); - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/KeysActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/KeysActivity.java deleted file mode 100644 index 94985257..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/KeysActivity.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import com.koishi.launcher.h2o2.R; -import android.view.View; - -public class KeysActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_keys); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar4); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/LoginActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/LoginActivity.java deleted file mode 100644 index 2d76ff7c..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/LoginActivity.java +++ /dev/null @@ -1,809 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - - -import android.app.Activity; -import android.content.Context; -import android.os.Build; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.PopupWindow; -import android.widget.SimpleAdapter; -import android.widget.TextView; -import android.widget.Toast; - -import android.content.res.Configuration; -import android.content.res.Resources; -import android.util.DisplayMetrics; - -import com.koishi.launcher.h2o2.R; -import com.koishi.launcher.h2o2.tools.DBHelper; -import com.koishi.launcher.h2o2.tools.LoginTask; -import android.os.Handler; -import android.os.Message; -import android.content.Intent; - -import android.view.Menu; -import android.view.MenuItem; -import android.view.KeyEvent; -import android.view.WindowManager; -import java.io.FileInputStream; -import org.json.JSONObject; -import java.io.FileWriter; -import java.io.File; -import android.graphics.drawable.shapes.OvalShape; -import android.graphics.drawable.ShapeDrawable; - -import android.widget.ImageView; -import android.widget.ProgressBar; -import com.koishi.launcher.h2o2.MainActivity; -import android.widget.CompoundButton; -import android.support.v7.widget.CardView; -import android.net.Uri; -import android.widget.PopupMenu; -import java.util.Locale; - -public class LoginActivity extends Activity implements OnClickListener { - private EditText mUserName; - private EditText mPassword,信息,信息2,信息0; - private ImageView img1; - private Button mLoginButton,offline,newacc,ls; - private ImageButton mDropDown; - private DBHelper dbHelper; - private CheckBox mCheckBox,info; - private PopupWindow popView; - private TextView logt; - private MyAdapter dropDownAdapter; - - private PopupMenu popupMenu; - - private CardView userinfo,inputcv; - - private ProgressBar pb; - - private boolean run = false; - private final Handler handler = new Handler(); - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_login, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.register: - Intent intent = new Intent(); - intent.setData(Uri.parse("https://www.minecraft.net/zh-hans/store/minecraft-java-edition/buy"));//Url - intent.setAction(Intent.ACTION_VIEW); - this.startActivity(intent); - break; - default: - break; - } - return true; - } - - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - finish(); - return true; - } else if (event.getKeyCode() == KeyEvent.KEYCODE_HOME) { - finish(); - return true; - } else if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) { - finish(); - return true; - } else if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) { - finish(); - return true; - } else { - return super.dispatchKeyEvent(event); - } - } - - - - static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; - static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; - static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; - static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; - static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist"; - - - public void onReceive(Context arg0, Intent arg1) { - String action = arg1.getAction(); - //按下Home键会发送ACTION_CLOSE_SYSTEM_DIALOGS的广播 - if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { - - String reason = arg1.getStringExtra(SYSTEM_DIALOG_REASON_KEY); - if (reason != null) { - if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) { - // 短按home键 - finish(); - } else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { - // RECENT_APPS键 - finish(); - } - } - } - } - - @Override - public void onResume() { - super.onResume(); - - - } - - @Override - public void onPause() { - super.onPause(); - - } - /* - public void setLanguage(View v){ - popupMenu.show(); - } - - public void switchEnglish() { - switchLanguage(Locale.ENGLISH); - } - - public void switchChinese() { - switchLanguage(Locale.CHINESE); - } - - public void switchJapanese() { - switchLanguage(Locale.JAPAN); - } - - private void switchLanguage(Locale locale) { - DisplayMetrics metrics = getResources().getDisplayMetrics(); - Configuration configuration = getResources().getConfiguration(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - configuration.setLocale(locale); - } else { - configuration.locale = locale; - } - getResources().updateConfiguration(configuration, metrics); - //重新启动Activity - Intent intent = new Intent(this, LoginActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - startActivity(intent); - } - */ - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_login); - - run = true; - handler.postDelayed(task, 1000); - - 信息 = (EditText)findViewById(R.id.msg); - 信息2 = (EditText)findViewById(R.id.msg2); - 信息0 = (EditText)findViewById(R.id.msg0); - - pb = (ProgressBar)findViewById(R.id.pb); - - logt = (TextView)findViewById(R.id.login_text); - img1 = (ImageView)findViewById(R.id.img1); - - //ls = (Button)findViewById(R.id.sl); - /* - popupMenu = new PopupMenu(this, ls);//button是popupMenu的宿主,也可以是其他任意view - popupMenu.getMenuInflater().inflate(R.menu.menu_language, popupMenu.getMenu()); - - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.l_zhcn: - switchChinese(); - break; - case R.id.l_enus: - switchEnglish(); - break; - case R.id.l_ja: - switchJapanese(); - break; - default: - break; - } - return true; - } - }); - */ - - - 信息2.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - uuid(p1.toString()); - - } - - - }); - 信息2.setText(uid()); - 信息.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - name(p1.toString()); - - } - - - }); - 信息.setText(nam()); - 信息0.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - token(p1.toString()); - - } - - - }); - 信息0.setText(tok()); - - inputcv = (CardView)findViewById(R.id.inputcv); - - this.offline = (Button)findViewById(R.id.offline); - - offline.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (dbHelper.queryAllUserName().length > 0) { - String havefunc = "havefunc"; - Intent intent3 = new Intent(LoginActivity.this, MainActivity.class); - intent3.putExtra("noplay",havefunc); - startActivity(intent3);// TODO: Implement this method - LoginActivity.this.finish(); - }else{ - //信息0.setText("0000"); - //String nofunc = "nofunc"; - String nofunc = "havefunc"; - Intent intent3 = new Intent(LoginActivity.this, MainActivity.class); - intent3.putExtra("noplay",nofunc); - startActivity(intent3);// TODO: Implement this method - LoginActivity.this.finish(); - } - - } - }); - - this.newacc = (Button)findViewById(R.id.newacc); - newacc.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - newacc.getBackground().setAlpha(90); - 信息2.setText(""); - 信息0.setText(""); - newacc.setEnabled(false); - mUserName.setVisibility(View.VISIBLE); - mPassword.setVisibility(View.VISIBLE); - mCheckBox.setVisibility(View.VISIBLE); - mDropDown.setVisibility(View.VISIBLE); - inputcv.setVisibility(View.VISIBLE); - info.setVisibility(View.VISIBLE); - img1.setVisibility(View.GONE); - logt.setVisibility(View.GONE); - } - }); - - info = (CheckBox)findViewById(R.id.infocb); - info.setChecked(false); - info.setEnabled(false); - info.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){ - @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - // TODO Auto-generated method stub - if(isChecked){ - userinfo.setVisibility(View.VISIBLE); - 信息2.setText(uid()); - 信息.setText(uid()); - 信息0.setText(uid()); - }else{ - userinfo.setVisibility(View.GONE); - } - } - }); - - initWidget(); - - - - final String id = 信息.getText().toString(); - if (!id.equals("")) { - } else { - 信息.setText("Player"); - } - logt.setText(getResources().getString(R.string.login_welcome) + "\n" + 信息.getText().toString()); - - - - userinfo = (CardView)findViewById(R.id.userinfo); - - - } - - private final Runnable task = new Runnable() { - @Override - public void run() { - // TODO Auto-generated method stub - if (run) { - - handler.postDelayed(this, 1000); - } - } - }; - - public void hideinfo(View view){ - userinfo.setVisibility(View.GONE); - info.setChecked(false); - } - - private void initWidget() { - dbHelper = new DBHelper(this); - if (dbHelper.queryAllUserName().length <= 0) { - //offline.setText("Demo"); - } - mUserName = (EditText) findViewById(R.id.username); - mPassword = (EditText) findViewById(R.id.password); - mLoginButton = (Button) findViewById(R.id.login); - mDropDown = (ImageButton) findViewById(R.id.dropdown_button); - mCheckBox = (CheckBox) findViewById(R.id.remember); - mLoginButton.setOnClickListener(this); - mDropDown.setOnClickListener(this); - initLoginUserName(); - - final String password = mPassword.getText().toString(); - if (!password.equals("")) { - mUserName.setVisibility(View.GONE); - mPassword.setVisibility(View.GONE); - mCheckBox.setVisibility(View.GONE); - mDropDown.setVisibility(View.GONE); - inputcv.setVisibility(View.GONE); - info.setVisibility(View.GONE); - img1.setVisibility(View.VISIBLE); - logt.setVisibility(View.VISIBLE); - } else { - newacc.getBackground().setAlpha(90); - newacc.setEnabled(false); - mUserName.setVisibility(View.VISIBLE); - mPassword.setVisibility(View.VISIBLE); - mCheckBox.setVisibility(View.VISIBLE); - mDropDown.setVisibility(View.VISIBLE); - inputcv.setVisibility(View.VISIBLE); - info.setVisibility(View.VISIBLE); - img1.setVisibility(View.GONE); - logt.setVisibility(View.GONE); - } - - - } - - private void initLoginUserName() { - String[] usernames = dbHelper.queryAllUserName(); - if (usernames.length > 0) { - String tempName = usernames[usernames.length - 1]; - mUserName.setText(tempName); - mUserName.setSelection(tempName.length()); - String tempPwd = dbHelper.queryPasswordByName(tempName); - int checkFlag = dbHelper.queryIsSavedByName(tempName); - if (checkFlag == 0) { - mCheckBox.setChecked(false); - } else if (checkFlag == 1) { - mCheckBox.setChecked(true); - } - mPassword.setText(tempPwd); - } - mUserName.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - mPassword.setText(""); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - - } - - @Override - public void afterTextChanged(Editable s) { - - } - }); - } - - String[] 用户信息; - - public void doLogin() { - final String userName = mUserName.getText().toString(); - final String password = mPassword.getText().toString(); - if (!userName.equals("") && !password.equals("")) { - Toast.makeText(LoginActivity.this, "Please wait...", 1000).show(); - mLoginButton.setEnabled(false); - pb.setVisibility(View.VISIBLE); - mLoginButton.getBackground().setAlpha(90); - //登录操作为耗时操作,必须放到线程中执行 - new Thread(new Runnable(){ - @Override - public void run() { - if (!LoginTask.checkif(LoginTask.get("auth_access_token"))) { - //token不可用 - //调用LoginTask - 用户信息 = LoginTask.login(userName, password); - 登录信息检测.sendEmptyMessage(0); - } else { - //token可用,无需调用登录 - 登录信息检测.sendEmptyMessage(1); - } - - - } - }).start(); - } else { - Toast.makeText(LoginActivity.this, "None", 1000).show(); - } - - } - - @Override - public void onClick(View v) { - - if (v == mLoginButton) { - doLogin(); - } - if (v == mDropDown) { - if (popView != null) { - if (!popView.isShowing()) { - popView.showAsDropDown(mUserName); - } else { - popView.dismiss(); - } - } else { - if (dbHelper.queryAllUserName().length > 0) { - initPopView(dbHelper.queryAllUserName()); - if (!popView.isShowing()) { - popView.showAsDropDown(mUserName); - } else { - popView.dismiss(); - } - } else { - Toast.makeText(this, "None", Toast.LENGTH_LONG).show(); - } - - } - } - - - - } -//隐藏输入信息 - private void uuid(String 玩家id) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("auth_uuid"); - json.put("auth_uuid", 玩家id); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/config.txt")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - private String uid() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("auth_uuid"); - } catch (Exception e) { - System.out.println(e); - } - return "config.txt not found."; - } - private void name(String 玩家) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("auth_player_name"); - json.put("auth_player_name", 玩家); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/config.txt")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - private String nam() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("auth_player_name"); - } catch (Exception e) { - System.out.println(e); - } - return "config.txt not found."; - } - private void token(String 玩) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("auth_access_token"); - json.put("auth_access_token", 玩); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/config.txt")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - private String tok() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("auth_access_token"); - } catch (Exception e) { - System.out.println(e); - } - return "config.txt not found."; - } - - private void initPopView(String[] usernames) { - List> list = new ArrayList>(); - for (int i = 0; i < usernames.length; i++) { - HashMap map = new HashMap(); - map.put("name", usernames[i]); - map.put("drawable", R.drawable.xicon); - list.add(map); - } - dropDownAdapter = new MyAdapter(this, list, R.layout.dropdown_item, - new String[] { "name", "drawable" }, new int[] { R.id.textview, - R.id.delete }); - ListView listView = new ListView(this); - listView.setAdapter(dropDownAdapter); - - popView = new PopupWindow(listView, mUserName.getWidth(), - ViewGroup.LayoutParams.WRAP_CONTENT, true); - popView.setFocusable(true); - popView.setOutsideTouchable(true); - popView.setBackgroundDrawable(getResources().getDrawable(R.drawable.pwbg)); - // popView.showAsDropDown(mUserName); - } - - class MyAdapter extends SimpleAdapter { - - private List> data; - - public MyAdapter(Context context, List> data, - int resource, String[] from, int[] to) { - super(context, data, resource, from, to); - this.data = data; - } - - @Override - public int getCount() { - return data.size(); - } - - @Override - public Object getItem(int position) { - return position; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(final int position, View convertView, - ViewGroup parent) { - System.out.println(position); - ViewHolder holder; - if (convertView == null) { - holder = new ViewHolder(); - convertView = LayoutInflater.from(LoginActivity.this).inflate( - R.layout.dropdown_item, null); - holder.btn = (ImageButton) convertView - .findViewById(R.id.delete); - holder.tv = (TextView) convertView.findViewById(R.id.textview); - convertView.setTag(holder); - } else { - holder = (ViewHolder) convertView.getTag(); - } - holder.tv.setText(data.get(position).get("name").toString()); - holder.tv.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - String[] usernames = dbHelper.queryAllUserName(); - mUserName.setText(usernames[position]); - mPassword.setText(dbHelper - .queryPasswordByName(usernames[position])); - popView.dismiss(); - } - }); - holder.btn.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - String[] usernames = dbHelper.queryAllUserName(); - if (usernames.length > 0) { - dbHelper.delete(usernames[position]); - popView.dismiss(); - } - String[] newusernames = dbHelper.queryAllUserName(); - if (newusernames.length > 0) { - initPopView(newusernames); - popView.showAsDropDown(mUserName); - } else { - popView.dismiss(); - popView = null; - } - } - }); - return convertView; - } - } - - @Override - public void onBackPressed() { - - } - - Handler 登录信息检测=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - if (用户信息 == null) { - Toast.makeText(LoginActivity.this, 用户信息[0], 1000).show(); - mCheckBox.setChecked(false); - mLoginButton.setEnabled(true); - pb.setVisibility(View.GONE); - mLoginButton.getBackground().setAlpha(255); - logt.setText(":("); - } else if (用户信息.length == 1) { - //用户信息长度为1时说明出现了错误,使用toast输出错误信息 - Toast.makeText(LoginActivity.this, "Failed", 1000).show(); - mCheckBox.setChecked(false); - mLoginButton.setEnabled(true); - pb.setVisibility(View.GONE); - mLoginButton.getBackground().setAlpha(255); - logt.setText(":("); - } else { - - final String resultAc = mUserName.getText().toString(); - final String resultPw = mPassword.getText().toString(); - if (mCheckBox.isChecked()) { - dbHelper.insertOrUpdate(resultAc, resultPw, 1); - } else { - dbHelper.insertOrUpdate(resultAc, "", 0); - } - - //以下三行用于将获取的登录信息写入config.txt - //需要添加文件操作权限 -// LoginTask.set("auth_access_token", userCon[0]); -// LoginTask.set("auth_player_name", userCon[1]); -// LoginTask.set("auth_uuid", userCon[2]); - - //将获取到的token等显示出来 - 信息.setText(用户信息[1]); - 信息2.setText(用户信息[2]); - 信息0.setText(用户信息[0]); - pb.setVisibility(View.GONE); - String havefunc = "havefunc"; - Toast.makeText(LoginActivity.this, "Done", 1000).show(); - Intent intent = new Intent(LoginActivity.this, MainActivity.class); - intent.putExtra("noplay",havefunc); - startActivity(intent);// TODO: Implement this method - finish(); - - - } - } else { - //token可用就显示登录成功 - final String resultAc = mUserName.getText().toString(); - final String resultPw = mPassword.getText().toString(); - pb.setVisibility(View.GONE); - if (mCheckBox.isChecked()) { - dbHelper.insertOrUpdate(resultAc, resultPw, 1); - } else { - dbHelper.insertOrUpdate(resultAc, "", 0); - } - Toast.makeText(LoginActivity.this, "Done", 1000).show(); - String havefunc = "havefunc"; - Intent intent2 = new Intent(LoginActivity.this, MainActivity.class); - intent2.putExtra("noplay",havefunc); - startActivity(intent2);// TODO: Implement this method - - } - - }}; - - class ViewHolder { - private TextView tv; - private ImageButton btn; - } - - @Override - protected void onStop() { - super.onStop(); - - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/ModsActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/ModsActivity.java deleted file mode 100644 index a4472ff7..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/ModsActivity.java +++ /dev/null @@ -1,533 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import android.app.*; -import android.os.*; -import android.widget.*; -import java.io.*; -import java.util.*; -import android.view.*; -import android.view.View.*; -import java.util.zip.*; -import android.webkit.*; -import java.nio.file.*; -import android.app.AlertDialog.*; -import android.content.*; -import android.widget.AdapterView.*; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.text.TextWatcher; -import android.text.Editable; -import org.json.JSONObject; -import com.leon.lfilepickerlibrary.LFilePicker; -import com.koishi.launcher.h2o2.tools.Consant; -import java.nio.charset.Charset; -import android.util.Log; - -public class ModsActivity extends AppCompatActivity { - - private ListView listview4; - private ArrayList mlist; - private File file; - private String Path,string; - private ProgressDialog pd; -// private MyAdapter myAdapter; - - private String tv = t(); - - private int ings; - public boolean modes = false; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_m, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.ladd_m: - new LFilePicker().withActivity(this) - .withRequestCode(Consant.REQUESTCODE_FROM_FRAGMENT) - .withMutilyMode(true) - .withFileFilter(new String[]{"jar"}) - .withTheme(R.style.LFileTheme) - .withTitle("Open From Packs") - .start(); - - break; - case R.id.dela_m: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.menu_5_adt)); - builder.setMessage(getResources().getString(R.string.menu_5_delall)); - builder.setIcon(R.drawable.ic_boat); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new Thread(new Runnable(){ - @Override - public void run() { - String file2= tv + "/mods"; - File file = new File(file2); - if (file.isDirectory()) { - deleteDirectory(file2); - } - if (file.isFile()) { - deleteFile(file2); - } - han.sendEmptyMessage(0); - } - }).start(); - dialog.dismiss(); - } - }); - //设置反面按钮 - builder.setNegativeButton("No No No", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - break; - default: - break; - } - return true; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_mods); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar8); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - creatfile(); - Path = tv+"/mods"; - string = Path + "/"; - listview4=(ListView)findViewById(R.id.runtimelistview4); - pd = new ProgressDialog(ModsActivity.this); - pd.setMessage("Waiting..."); - pd.setIndeterminate(true); - pd.setCancelable(false); - listviews(); - //"/data/data/net.zhuoweizhang.boardwalk/app_runtime"; - file = new File(string); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", ">/+-*|"); - map.put("img",R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(ModsActivity.this, list, - R.layout.list_m, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview4.setAdapter(sa); - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(string+"/"+targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img",over(targetFile.getName())); - }else if(filess==null){ - map.put("img",R.drawable.wen); - } - else{ - map.put("img",over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(ModsActivity.this, list, - R.layout.list_m, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview4.setAdapter(sa); - listview4.setOnItemLongClickListener(new OnItemLongClickListener(){ - @Override - public boolean onItemLongClick(AdapterView p1, View p2, int p3, long p4) - { - Object Texts=listview4.getItemAtPosition(p3); - Map entry = (Map)Texts; - final String Text= (String) entry.get("text"); - String bo=Text+"/"; - String go=string+bo; - String dui="/sdcard/"; - AlertDialog alertDialog1 = new AlertDialog.Builder(listview4.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(getResources().getString(R.string.menu_5_adm)) - .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - pd.show(); - new Thread(new Runnable(){ - @Override - public void run() { - String file2= Path + "/" + Text; - File file = new File(file2); - if(file.isDirectory()){ - deleteDirectory(file2); - } - if(file.isFile()){ - deleteFile(file2); - } - han.sendEmptyMessage(0); - } - }).start(); - - } - }) - .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - - alertDialog1.show(); - return true; - } - }); - } - Handler han=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Filelistview(Path + "/"); - pd.hide(); - } - }}; - Handler han2=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Filelistview(Path + "/"); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttd), Toast.LENGTH_SHORT).show(); - } - }}; - private void listviews() { - listview4.setOnItemClickListener(new AdapterView.OnItemClickListener(){ - private ArrayList urls; - Boolean fil; - int Folder,contain; - private File[] files; - private String boing; - @Override - public void onItemClick(AdapterView p1, View p2, int p3, long p4) { - Object Texts=listview4.getItemAtPosition(p3); - Map entry = (Map)Texts; - String Text= (String) entry.get("text"); - boing = Text + "/"; - - } - });} - private void Filelistview(String to) { - string = to; - file = new File(to); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "None", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", "Empty"); - map.put("img", R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(ModsActivity.this, list, - R.layout.list_m, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview4.setAdapter(sa); - return; - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(to + "/" + targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img", over(targetFile.getName())); - } else if (filess == null) { - map.put("img", R.drawable.wen); - } else { - map.put("img", over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(ModsActivity.this, list, - R.layout.list_m, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1}); - - listview4.setAdapter(sa); - } - private void creatfile(){ - String dir = tv;// 需要创建的目录,sdcard目录一定存在,所以只用判断一级目录 - File file = new File(dir+"/mods"); - if (!file.exists())// 判断当前目录是否存在,存在返回true,否则返回false - file.mkdir(); // 如果不存在则创建目录 - return; - } - - private int over(String text) { - /* - if (text.indexOf(".sh") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".tar") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".gz") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".png") != -1) { - ings = R.drawable.vpver; - } else if (text.indexOf(".mp3") != -1) { - ings = R.drawable.vmnvff; - } else if (text.indexOf(".log") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".obj") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".mtl") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".json") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".re") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".bat") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".apk") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".rc") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".zip") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".xml") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".so") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".html") != -1) { - ings = R.drawable.vpouy; - } else if (text.indexOf(".txt") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".js") != -1) { - ings = R.drawable.vqw; - } else */ if (text.indexOf(".jar") != -1) { - ings = R.drawable.jar; - } /* else if (text.indexOf(".cfg") != -1) { - ings = R.drawable.vnfdr; - } else if (text.indexOf(".ttf") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf(">/+-*|") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf("Empty") != -1) { - ings = R.drawable.timg; - } else { - ings = R.drawable.verrt; - } - */ - return ings; - } - public void showDirectory(View view) { - AlertDialog alertDialog2 = new AlertDialog.Builder(listview4.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adtt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(Path) - .setPositiveButton("Ok", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - alertDialog2.show(); - - } - @Override - public void onResume() { - super.onResume(); - creatfile(); - Filelistview(Path + "/"); - } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK) { - if (requestCode == Consant.REQUESTCODE_FROM_FRAGMENT) { - List list = data.getStringArrayListExtra("paths"); - for (final String s : list) { - String pathname = s; - final File file = new File(pathname); - //复制到的位置 - String topathname = tv + "/mods"; - final File toFile = new File(topathname); - new Thread(new Runnable(){ - @Override - public void run() { - try { - copy(file, toFile); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - han2.sendEmptyMessage(0); - } - - }).start(); - } - } - } - } - private String t() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("game_directory"); - } catch (Exception e) { - System.out.println(e); - } - return "None"; - } - public boolean deleteFile(String filePath) { - File file = new File(filePath); - if (file.isFile() && file.exists()) { - return file.delete(); - } - return false; - } - - public static void copy(File file, File toFile) throws Exception { - byte[] b = new byte[1024]; - int a; - FileInputStream fis; - FileOutputStream fos; - if (file.isDirectory()) { - String filepath = file.getAbsolutePath(); - filepath = filepath.replaceAll("\\\\", "/"); - String toFilepath = toFile.getAbsolutePath(); - toFilepath = toFilepath.replaceAll("\\\\", "/"); - int lastIndexOf = filepath.lastIndexOf("/"); - toFilepath = toFilepath + filepath.substring(lastIndexOf , filepath.length()); - File copy=new File(toFilepath); - //复制文件夹 - if (!copy.exists()) { - copy.mkdir(); - } - //遍历文件夹 - for (File f : file.listFiles()) { - copy(f, copy); - } - } else { - if (toFile.isDirectory()) { - String filepath = file.getAbsolutePath(); - filepath = filepath.replaceAll("\\\\", "/"); - String toFilepath = toFile.getAbsolutePath(); - toFilepath = toFilepath.replaceAll("\\\\", "/"); - int lastIndexOf = filepath.lastIndexOf("/"); - toFilepath = toFilepath + filepath.substring(lastIndexOf , filepath.length()); - - //写文件 - File newFile = new File(toFilepath); - fis = new FileInputStream(file); - fos = new FileOutputStream(newFile); - while ((a = fis.read(b)) != -1) { - fos.write(b, 0, a); - } - } else { - //写文件 - fis = new FileInputStream(file); - fos = new FileOutputStream(toFile); - while ((a = fis.read(b)) != -1) { - fos.write(b, 0, a); - } - } - - } - } - - - - /** - * 删除文件夹以及目录下的文件 - * @param filePath 被删除目录的文件路径 - * @return 目录删除成功返回true,否则返回false - */ - public boolean deleteDirectory(String filePath) { - boolean flag = false; - //如果filePath不以文件分隔符结尾,自动添加文件分隔符 - if (!filePath.endsWith(File.separator)) { - filePath = filePath + File.separator; - } - File dirFile = new File(filePath); - if (!dirFile.exists() || !dirFile.isDirectory()) { - return false; - } - flag = true; - File[] files = dirFile.listFiles(); - //遍历删除文件夹下的所有文件(包括子目录) - for (int i = 0; i < files.length; i++) { - if (files[i].isFile()) { - //删除子文件 - flag = deleteFile(files[i].getAbsolutePath()); - if (!flag) break; - } else { - //删除子目录 - flag = deleteDirectory(files[i].getAbsolutePath()); - if (!flag) break; - } - } - if (!flag) return false; - //删除当前空目录 - return dirFile.delete(); - } -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/PacksActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/PacksActivity.java deleted file mode 100644 index 0d470a16..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/PacksActivity.java +++ /dev/null @@ -1,778 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import android.app.*; -import android.os.*; -import android.widget.*; -import java.io.*; -import java.util.*; -import android.view.*; -import android.view.View.*; -import java.util.zip.*; -import android.webkit.*; -import java.nio.file.*; -import android.app.AlertDialog.*; -import android.content.*; -import android.widget.AdapterView.*; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.text.TextWatcher; -import android.text.Editable; -import org.json.JSONObject; -import com.leon.lfilepickerlibrary.LFilePicker; -import com.koishi.launcher.h2o2.tools.Consant; -import java.nio.charset.Charset; - -public class PacksActivity extends AppCompatActivity implements View.OnClickListener { - - private ListView listview1; - private ArrayList mlist; - private File file; - private String Path,string; - private TextView tv; - private ProgressDialog pd; -// private MyAdapter myAdapter; - - private ImageButton btnCancel,btnSet,btnNew; - private EditText packName; - private LinearLayout ll5; - - private int ings; - public boolean modes = false; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.m5_add: - packName.setText(""); - check(); - ll5.setVisibility(View.INVISIBLE); - packName.setVisibility(View.VISIBLE); - btnSet.setVisibility(View.VISIBLE); - btnNew.setVisibility(View.VISIBLE); - btnCancel.setVisibility(View.VISIBLE); - break; - case R.id.m5_dn: - - break; - - case R.id.m5_ref: - Filelistview(Path + "/"); - break; - default: - break; - } - return true; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_packs); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar5); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - listview1 = (ListView)findViewById(R.id.runtimeListView1); - - btnSet = (ImageButton)findViewById(R.id.btnset); - btnCancel = (ImageButton)findViewById(R.id.btncancel); - btnNew = (ImageButton)findViewById(R.id.btnnew); - btnSet.setOnClickListener(this); - btnCancel.setOnClickListener(this); - btnNew.setOnClickListener(this); - ll5 = (LinearLayout)findViewById(R.id.ll5); - packName = (EditText)findViewById(R.id.pn); - packName.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - check(); - } - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - check(); - } - }); - pd = new ProgressDialog(PacksActivity.this); - pd.setMessage("Waiting..."); - pd.setIndeterminate(true); - pd.setCancelable(false); -// listview1.setAdapter(myAdapter); - listviews(); - tv = (TextView)findViewById(R.id.tv_dir); - tv.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { - } - - @Override - public void afterTextChanged(Editable p1) { - tv(p1.toString()); - } - }); - tv.setText(t()); - creatfile(); - Path = "/storage/emulated/0/games/com.koishi.launcher/packs"; - string = Path + "/"; - //"/data/data/net.zhuoweizhang.boardwalk/app_runtime"; - file = new File(string); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", ">/+-*|"); - map.put("img", R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(PacksActivity.this, list, - R.layout.list, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview1.setAdapter(sa); - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(string + "/" + targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img", over(targetFile.getName())); - } else if (filess == null) { - map.put("img", R.drawable.wen); - } else { - map.put("img", over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(PacksActivity.this, list, - R.layout.list, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview1.setAdapter(sa); - listview1.setOnItemLongClickListener(new OnItemLongClickListener(){ - @Override - public boolean onItemLongClick(AdapterView p1, View p2, int p3, long p4) { - Object Texts=listview1.getItemAtPosition(p3); - Map entry = (Map)Texts; - final String Text= (String) entry.get("text"); - String bo=Text + "/"; - String go=string + bo; - String dui="/sdcard/"; - AlertDialog alertDialog1 = new AlertDialog.Builder(listview1.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(getResources().getString(R.string.menu_5_adm)) - .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - pd.show(); - tv.setText("/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"); - new Thread(new Runnable(){ - @Override - public void run() { - String file2= Path + "/" + Text; - File file = new File(file2); - if (file.isDirectory()) { - deleteDirectory(file2); - } - if (file.isFile()) { - deleteFile(file2); - } - han.sendEmptyMessage(0); - } - }).start(); - - } - }) - .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - - alertDialog1.show(); - return true; - } - }); - } - private void check() { - final String s = packName.getText().toString(); - if (s.equals("")) { - btnSet.setEnabled(false); - btnNew.setEnabled(false); - } else { - btnSet.setEnabled(true); - btnNew.setEnabled(true); - } - } - private void listviews() { - listview1.setOnItemClickListener(new AdapterView.OnItemClickListener(){ - private ArrayList urls; - Boolean fil; - int Folder,contain; - private File[] files; - private String boing; - @Override - public void onItemClick(AdapterView p1, View p2, int p3, long p4) { - Object Texts=listview1.getItemAtPosition(p3); - Map entry = (Map)Texts; - String Text= (String) entry.get("text"); - boing = Text + "/"; - tv.setText("/storage/emulated/0/games/com.koishi.launcher/packs/" + Text + "/boat/gamedir"); - } - });} - private void Filelistview(String to) { - string = to; - file = new File(to); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "No permission", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", "Empty"); - map.put("img", R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(PacksActivity.this, list, - R.layout.list, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview1.setAdapter(sa); - return; - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(to + "/" + targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img", over(targetFile.getName())); - } else if (filess == null) { - map.put("img", R.drawable.wen); - } else { - map.put("img", over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(PacksActivity.this, list, - R.layout.list, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1}); - - listview1.setAdapter(sa); - } - private void creatfile() { - String dir = "/sdcard/games/com.koishi.launcher/packs"; // 需要创建的目录,sdcard目录一定存在,所以只用判断一级目录 - File file = new File(dir); - if (!file.exists())// 判断当前目录是否存在,存在返回true,否则返回false - file.mkdir(); // 如果不存在则创建目录 - return; - } - - private int over(String text) { - /* - if (text.indexOf(".sh") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".tar") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".gz") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".png") != -1) { - ings = R.drawable.vpver; - } else if (text.indexOf(".mp3") != -1) { - ings = R.drawable.vmnvff; - } else if (text.indexOf(".log") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".obj") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".mtl") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".json") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".re") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".bat") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".apk") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".rc") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".zip") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".xml") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".so") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".html") != -1) { - ings = R.drawable.vpouy; - } else if (text.indexOf(".txt") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".js") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".jar") != -1) { - ings = R.drawable.file; - } else if (text.indexOf(".cfg") != -1) { - ings = R.drawable.vnfdr; - } else if (text.indexOf(".ttf") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf(">/+-*|") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf("Empty") != -1) { - ings = R.drawable.timg; - } else { - ings = R.drawable.verrt; - } - */ - return ings; - } - public void showDirectory(View view) { - AlertDialog alertDialog2 = new AlertDialog.Builder(listview1.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adtt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(Path) - .setPositiveButton("Ok", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - alertDialog2.show(); - - } - - Handler han=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - creatfile(); - Filelistview(Path + "/"); - pd.hide(); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_tt), Toast.LENGTH_SHORT).show(); - } - }}; - Handler han2=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - boolean tmp = fileIsExists("/sdcard/games/com.koishi.launcher/packs/" + packName.getText().toString() + "/boat/gamedir"); - if (tmp) { - Filelistview(Path + "/"); - pd.hide(); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttd), Toast.LENGTH_SHORT).show(); - } else { - new Thread(new Runnable(){ - @Override - public void run() { - File file2=new File("/sdcard/games/com.koishi.launcher/packs/" + packName.getText().toString()); - deleteDirWihtFile(file2); - han3.sendEmptyMessage(0); - } - }).start(); - } - } - }}; - Handler han3=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Filelistview(Path + "/"); - pd.hide(); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttdn), Toast.LENGTH_SHORT).show(); - } - }}; - public void onClick(View v) { - if (v == btnSet) { - new LFilePicker().withActivity(this) - .withRequestCode(Consant.REQUESTCODE_FROM_FRAGMENT) - .withMutilyMode(false) - .withFileFilter(new String[]{"zip"}) - .withTheme(R.style.LFileTheme) - .withTitle("Open From Packs") - .start(); - - } - if (v == btnCancel) { - ll5.setVisibility(View.VISIBLE); - packName.setVisibility(View.GONE); - btnSet.setVisibility(View.GONE); - btnNew.setVisibility(View.GONE); - btnCancel.setVisibility(View.GONE); - } - if (v == btnNew) { - try { - output(PacksActivity.this, "boat.zip", Environment.getExternalStorageDirectory() + "/games/com.koishi.launcher/packs/" + packName.getText().toString()); - } catch (IOException e) { - e.printStackTrace(); - } - ll5.setVisibility(View.VISIBLE); - packName.setVisibility(View.GONE); - btnSet.setVisibility(View.GONE); - btnNew.setVisibility(View.GONE); - btnCancel.setVisibility(View.GONE); - Filelistview(Path + "/"); - } - - } - /* - class MyAdapter extends BaseAdapter { - private Context mContext; - private ArrayList mList; - private LayoutInflater mInflater; - - public MyAdapter(Context mContext, ArrayList mList) { - super(); - this.mContext = mContext; - this.mList = mList; - mInflater = LayoutInflater.from(mContext); - } - - @Override - public int getCount() { - // TODO Auto-generated method stub - return mlist.size(); - } - - @Override - public Object getItem(int position) { - // TODO Auto-generated method stub - return position; - } - - @Override - public long getItemId(int position) { - return position; - } - - - @Override - public int getViewTypeCount() { - return 2; - } - - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - // System.out.println("position-->"+position+" ---convertView--"+convertView); - convertView = mInflater.inflate(R.layout.list, parent, false); - btnDel=convertView.findViewById(R.id.btnDel); - btnDel.setOnClickListener(new OnClickListener(){ - @Override - public void onClick(View p1) { - File file2=new File("/sdcard/games/com.koishi.launcher/packs"+mList.get(position)); - deleteDirWihtFile(file2); - Filelistview(Path+"/"); - } - }); - return convertView; - } - - } - private void deleteDirWihtFile(File file2) { - if (file2 == null || !file2.exists() || !file2.isDirectory()) - return; - for (File file :file2.listFiles()) { - if (file.isFile()) - file.delete(); - else if (file.isDirectory()) - deleteDirWihtFile(file); - - } - file2.delete(); - } - */ - - private void deleteDirWihtFile(File file2) { - if (file2 == null || !file2.exists() || !file2.isDirectory()) - return; - for (File file :file2.listFiles()) { - if (file.isFile()) - file.delete(); - else if (file.isDirectory()) - deleteDirWihtFile(file); - - } - file2.delete(); - } - - private void tv(String dir) { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - json.remove("game_directory"); - json.remove("game_assets"); - json.remove("assets_root"); - json.remove("currentVersion"); - json.put("game_directory", dir); - json.put("game_assets", dir + "/assets/virtual/legacy"); - json.put("assets_root", dir + "/assets"); - json.put("currentVersion", dir + "/versions"); - FileWriter fr=new FileWriter(new File("/sdcard/games/com.koishi.launcher/h2o2/config.txt")); - fr.write(json.toString()); - fr.close(); - } catch (Exception e) { - System.out.println(e); - } - } - - private String t() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("game_directory"); - } catch (Exception e) { - System.out.println(e); - } - return "None"; - } - - public void setDefault(View view) { - boolean tmp = fileIsExists("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); - boolean tmp2 = fileIsExists("/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"); - if (!tmp){ - try { - output(PacksActivity.this, "h2o2.zip", Environment.getExternalStorageDirectory() + "/games/com.koishi.launcher/h2o2/"); - } catch (IOException e) { - - } - } - if (!tmp2){ - try { - output(PacksActivity.this, "h2o2.zip", Environment.getExternalStorageDirectory() + "/games/com.koishi.launcher/h2o2/"); - } catch (IOException e) { - - } - } - tv.setText("/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttt), Toast.LENGTH_SHORT).show(); - } - -// Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show(); - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK) { - if (requestCode == Consant.REQUESTCODE_FROM_FRAGMENT) { - List list = data.getStringArrayListExtra("paths"); - for (final String s : list) { - pd.show(); - new Thread(new Runnable(){ - @Override - public void run() { - try { - unzip(s, "/sdcard/games/com.koishi.launcher/packs/" + packName.getText().toString()); - han2.sendEmptyMessage(0); - } catch (IOException e) { - } - - } - }).start(); - } - } - } - } - - - @Override - public void onResume() { - super.onResume(); - creatfile(); - Filelistview(Path + "/"); - ll5.setVisibility(View.VISIBLE); - packName.setVisibility(View.GONE); - btnSet.setVisibility(View.GONE); - btnNew.setVisibility(View.GONE); - btnCancel.setVisibility(View.GONE); - } - - public static void unzip(String zipFilePath, String targetPath) - throws IOException { - OutputStream os = null; - InputStream is = null; - ZipFile zipFile = null; - try { - //获取要解压的文件,指定解压格式 - zipFile = new ZipFile(zipFilePath, Charset.forName("GBK")); - Enumeration entryEnum = zipFile.entries(); - if (null != entryEnum) { - ZipEntry zipEntry = null; - while (entryEnum.hasMoreElements()) { - zipEntry = (ZipEntry) entryEnum.nextElement(); - if (zipEntry.getSize() > 0) { - File targetFile = new File(targetPath - + File.separator + zipEntry.getName()); - os = new BufferedOutputStream(new FileOutputStream(targetFile)); - is = zipFile.getInputStream(zipEntry); - byte[] buffer = new byte[4096]; - int readLen = 0; - while ((readLen = is.read(buffer, 0, 4096)) >= 0) { - os.write(buffer, 0, readLen); - os.flush(); - } - is.close(); - os.close(); - } - //如果是文件夹,则创建文件夹 - if (zipEntry.isDirectory()) { - String pathTemp = targetPath + File.separator - + zipEntry.getName(); - File file = new File(pathTemp); - file.mkdirs(); - } - } - } - } catch (IOException ex) { - throw ex; - } finally { - //关闭流 - if (null != zipFile) { - zipFile.close(); - zipFile = null; - } - if (null != is) { - is.close(); - } - if (null != os) { - os.close(); - } - } - } - private void output(Context context, String assetName, String outputDirectory) throws IOException { - File file = new File(outputDirectory); - if (!file.exists()) { - file.mkdirs(); - } - - InputStream inputStream = null; - inputStream = context.getAssets().open(assetName); - ZipInputStream zipInputStream = new ZipInputStream(inputStream); - ZipEntry zipEntry = zipInputStream.getNextEntry(); - byte[] buffer = new byte[1024 * 1024]; - int count = 0; - while (zipEntry != null) { - //如果是一个目录 - if (zipEntry.isDirectory()) { - //String name = zipEntry.getName(); - //name = name.substring(0, name.length() - 1); - file = new File(outputDirectory + File.separator + zipEntry.getName()); - file.mkdir(); - } else { - //如果是文件 - file = new File(outputDirectory + File.separator - + zipEntry.getName()); - //创建该文件 - file.createNewFile(); - FileOutputStream fileOutputStream = new FileOutputStream(file); - while ((count = zipInputStream.read(buffer)) > 0) { - fileOutputStream.write(buffer, 0, count); - } - - fileOutputStream.close(); - } - //定位到下一个文件入口 - zipEntry = zipInputStream.getNextEntry(); - - } - zipInputStream.close(); - } - public boolean fileIsExists(String strFile) { - try { - File f=new File(strFile); - if (!f.exists()) { - return false; - } - - } catch (Exception e) { - return false; - } - - return true; - } - public boolean deleteFile(String filePath) { - File file = new File(filePath); - if (file.isFile() && file.exists()) { - return file.delete(); - } - return false; - } - - /** - * 删除文件夹以及目录下的文件 - * @param filePath 被删除目录的文件路径 - * @return 目录删除成功返回true,否则返回false - */ - public boolean deleteDirectory(String filePath) { - boolean flag = false; - //如果filePath不以文件分隔符结尾,自动添加文件分隔符 - if (!filePath.endsWith(File.separator)) { - filePath = filePath + File.separator; - } - File dirFile = new File(filePath); - if (!dirFile.exists() || !dirFile.isDirectory()) { - return false; - } - flag = true; - File[] files = dirFile.listFiles(); - //遍历删除文件夹下的所有文件(包括子目录) - for (int i = 0; i < files.length; i++) { - if (files[i].isFile()) { - //删除子文件 - flag = deleteFile(files[i].getAbsolutePath()); - if (!flag) break; - } else { - //删除子目录 - flag = deleteDirectory(files[i].getAbsolutePath()); - if (!flag) break; - } - } - if (!flag) return false; - //删除当前空目录 - return dirFile.delete(); - } -} - diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/TexturesActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/TexturesActivity.java deleted file mode 100644 index 8fceb70a..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/TexturesActivity.java +++ /dev/null @@ -1,528 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import android.app.*; -import android.os.*; -import android.widget.*; -import java.io.*; -import java.util.*; -import android.view.*; -import android.view.View.*; -import java.util.zip.*; -import android.webkit.*; -import java.nio.file.*; -import android.app.AlertDialog.*; -import android.content.*; -import android.widget.AdapterView.*; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.text.TextWatcher; -import android.text.Editable; -import org.json.JSONObject; -import com.leon.lfilepickerlibrary.LFilePicker; -import com.koishi.launcher.h2o2.tools.Consant; -import java.nio.charset.Charset; -import android.util.Log; -import com.koishi.launcher.h2o2.tools.FileUtil; -public class TexturesActivity extends AppCompatActivity { - - private ListView listview3; - private ArrayList mlist; - private File file; - private String Path,string; - private String tv = t(); - private ProgressDialog pd; -// private MyAdapter myAdapter; - - private int ings; - public boolean modes = false; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_t, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.ladd_t: - new LFilePicker().withActivity(this) - .withRequestCode(Consant.REQUESTCODE_FROM_FRAGMENT) - .withMutilyMode(true) - .withFileFilter(new String[]{"zip"}) - .withTheme(R.style.LFileTheme) - .withTitle("Open From Packs") - .start(); - - break; - case R.id.dela_t: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.menu_5_adt)); - builder.setMessage(getResources().getString(R.string.menu_5_delall)); - builder.setIcon(R.drawable.ic_boat); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new Thread(new Runnable(){ - @Override - public void run() { - String file2= tv + "/resourcepacks"; - File file = new File(file2); - if (file.isDirectory()) { - deleteDirectory(file2); - } - if (file.isFile()) { - deleteFile(file2); - } - han.sendEmptyMessage(0); - } - }).start(); - dialog.dismiss(); - } - }); - //设置反面按钮 - builder.setNegativeButton("No No No", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - break; - default: - break; - } - return true; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_textures); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar7); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - creatfile(); - Path = tv + "/resourcepacks"; - string = Path + "/"; - listview3 = (ListView)findViewById(R.id.runtimelistview3); - pd = new ProgressDialog(TexturesActivity.this); - pd.setMessage("Waiting..."); - pd.setIndeterminate(true); - pd.setCancelable(false); - listviews(); - //"/data/data/net.zhuoweizhang.boardwalk/app_runtime"; - file = new File(string); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", ">/+-*|"); - map.put("img", R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(TexturesActivity.this, list, - R.layout.list_t, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview3.setAdapter(sa); - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(string + "/" + targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img", over(targetFile.getName())); - } else if (filess == null) { - map.put("img", R.drawable.wen); - } else { - map.put("img", over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(TexturesActivity.this, list, - R.layout.list_t, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview3.setAdapter(sa); - listview3.setOnItemLongClickListener(new OnItemLongClickListener(){ - @Override - public boolean onItemLongClick(AdapterView p1, View p2, int p3, long p4) { - Object Texts=listview3.getItemAtPosition(p3); - Map entry = (Map)Texts; - final String Text= (String) entry.get("text"); - String bo=Text + "/"; - String go=string + bo; - String dui="/sdcard/"; - AlertDialog alertDialog1 = new AlertDialog.Builder(listview3.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(getResources().getString(R.string.menu_5_adm)) - .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - pd.show(); - new Thread(new Runnable(){ - @Override - public void run() { - String file2= Path + "/" + Text; - File file = new File(file2); - if (file.isDirectory()) { - deleteDirectory(file2); - } - if (file.isFile()) { - deleteFile(file2); - } - han.sendEmptyMessage(0); - } - }).start(); - - } - }) - .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - - alertDialog1.show(); - return true; - } - }); - } - Handler han=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Filelistview(Path + "/"); - pd.hide(); - } - }}; - Handler han2=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Filelistview(Path + "/"); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttd), Toast.LENGTH_SHORT).show(); - } - }}; - private void listviews() { - listview3.setOnItemClickListener(new AdapterView.OnItemClickListener(){ - private ArrayList urls; - Boolean fil; - int Folder,contain; - private File[] files; - private String boing; - @Override - public void onItemClick(AdapterView p1, View p2, int p3, long p4) { - Object Texts=listview3.getItemAtPosition(p3); - Map entry = (Map)Texts; - String Text= (String) entry.get("text"); - boing = Text + "/"; - } - });} - private void Filelistview(String to) { - string = to; - file = new File(to); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "None", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", "Empty"); - map.put("img", R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(TexturesActivity.this, list, - R.layout.list_t, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview3.setAdapter(sa); - return; - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(to + "/" + targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img", over(targetFile.getName())); - } else if (filess == null) { - map.put("img", R.drawable.wen); - } else { - map.put("img", over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(TexturesActivity.this, list, - R.layout.list_t, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1}); - - listview3.setAdapter(sa); - } - private void creatfile() { - String dir = tv; // 需要创建的目录,sdcard目录一定存在,所以只用判断一级目录 - File file = new File(dir + "/resourcepacks"); - if (!file.exists())// 判断当前目录是否存在,存在返回true,否则返回false - file.mkdir(); // 如果不存在则创建目录 - return; - } - - private int over(String text) { - /* - if (text.indexOf(".sh") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".tar") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".gz") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".png") != -1) { - ings = R.drawable.vpver; - } else if (text.indexOf(".mp3") != -1) { - ings = R.drawable.vmnvff; - } else if (text.indexOf(".log") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".obj") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".mtl") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".json") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".re") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".bat") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".apk") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".rc") != -1) { - ings = R.drawable.viihgv; - } else */ if (text.indexOf(".zip") != -1) { - ings = R.drawable.wen; - } /* else if (text.indexOf(".xml") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".so") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".html") != -1) { - ings = R.drawable.vpouy; - } else if (text.indexOf(".txt") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".js") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".jar") != -1) { - ings = R.drawable.file; - } else if (text.indexOf(".cfg") != -1) { - ings = R.drawable.vnfdr; - } else if (text.indexOf(".ttf") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf(">/+-*|") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf("Empty") != -1) { - ings = R.drawable.timg; - } else { - ings = R.drawable.verrt; - } - */ - return ings; - } - public void showDirectory(View view) { - AlertDialog alertDialog2 = new AlertDialog.Builder(listview3.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adtt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(Path) - .setPositiveButton("Ok", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - alertDialog2.show(); - - } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK) { - if (requestCode == Consant.REQUESTCODE_FROM_FRAGMENT) { - List list = data.getStringArrayListExtra("paths"); - for (final String s : list) { - String pathname = s; - final File file = new File(pathname); - //复制到的位置 - String topathname = tv + "/resourcepacks"; - final File toFile = new File(topathname); - new Thread(new Runnable(){ - @Override - public void run() { - try { - copy(file, toFile); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - han2.sendEmptyMessage(0); - } - - }).start(); - } - } - } - } - @Override - public void onResume() { - super.onResume(); - creatfile(); - Filelistview(Path + "/"); - } - public static void copy(File file, File toFile) throws Exception { - byte[] b = new byte[1024]; - int a; - FileInputStream fis; - FileOutputStream fos; - if (file.isDirectory()) { - String filepath = file.getAbsolutePath(); - filepath = filepath.replaceAll("\\\\", "/"); - String toFilepath = toFile.getAbsolutePath(); - toFilepath = toFilepath.replaceAll("\\\\", "/"); - int lastIndexOf = filepath.lastIndexOf("/"); - toFilepath = toFilepath + filepath.substring(lastIndexOf , filepath.length()); - File copy=new File(toFilepath); - //复制文件夹 - if (!copy.exists()) { - copy.mkdir(); - } - //遍历文件夹 - for (File f : file.listFiles()) { - copy(f, copy); - } - } else { - if (toFile.isDirectory()) { - String filepath = file.getAbsolutePath(); - filepath = filepath.replaceAll("\\\\", "/"); - String toFilepath = toFile.getAbsolutePath(); - toFilepath = toFilepath.replaceAll("\\\\", "/"); - int lastIndexOf = filepath.lastIndexOf("/"); - toFilepath = toFilepath + filepath.substring(lastIndexOf , filepath.length()); - - //写文件 - File newFile = new File(toFilepath); - fis = new FileInputStream(file); - fos = new FileOutputStream(newFile); - while ((a = fis.read(b)) != -1) { - fos.write(b, 0, a); - } - } else { - //写文件 - fis = new FileInputStream(file); - fos = new FileOutputStream(toFile); - while ((a = fis.read(b)) != -1) { - fos.write(b, 0, a); - } - } - - } - } - private String t() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("game_directory"); - } catch (Exception e) { - System.out.println(e); - } - return "None"; - } - public boolean deleteFile(String filePath) { - File file = new File(filePath); - if (file.isFile() && file.exists()) { - return file.delete(); - } - return false; - } - - - /** - * 删除文件夹以及目录下的文件 - * @param filePath 被删除目录的文件路径 - * @return 目录删除成功返回true,否则返回false - */ - public boolean deleteDirectory(String filePath) { - boolean flag = false; - //如果filePath不以文件分隔符结尾,自动添加文件分隔符 - if (!filePath.endsWith(File.separator)) { - filePath = filePath + File.separator; - } - File dirFile = new File(filePath); - if (!dirFile.exists() || !dirFile.isDirectory()) { - return false; - } - flag = true; - File[] files = dirFile.listFiles(); - //遍历删除文件夹下的所有文件(包括子目录) - for (int i = 0; i < files.length; i++) { - if (files[i].isFile()) { - //删除子文件 - flag = deleteFile(files[i].getAbsolutePath()); - if (!flag) break; - } else { - //删除子目录 - flag = deleteDirectory(files[i].getAbsolutePath()); - if (!flag) break; - } - } - if (!flag) return false; - //删除当前空目录 - return dirFile.delete(); - } -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/WorldsActivity.java b/app/src/main/java/com/koishi/launcher/h2o2/func/WorldsActivity.java deleted file mode 100644 index 29b05492..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/WorldsActivity.java +++ /dev/null @@ -1,536 +0,0 @@ -package com.koishi.launcher.h2o2.func; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import android.app.*; -import android.os.*; -import android.widget.*; -import java.io.*; -import java.util.*; -import android.view.*; -import android.view.View.*; -import java.util.zip.*; -import android.webkit.*; -import java.nio.file.*; -import android.app.AlertDialog.*; -import android.content.*; -import android.widget.AdapterView.*; - -import com.koishi.launcher.h2o2.R; -import android.view.View; -import android.text.TextWatcher; -import android.text.Editable; -import org.json.JSONObject; -import com.leon.lfilepickerlibrary.LFilePicker; -import com.koishi.launcher.h2o2.tools.Consant; -import java.nio.charset.Charset; -import android.util.Log; - -public class WorldsActivity extends AppCompatActivity { - - private ListView listview2; - private ArrayList mlist; - private File file; - private String Path,string; - private String tv = t(); - private ProgressDialog pd; -// private MyAdapter myAdapter; - - - private int ings; - public boolean modes = false; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu2, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.ladd: - new LFilePicker().withActivity(this) - .withRequestCode(Consant.REQUESTCODE_FROM_FRAGMENT) - .withMutilyMode(false) - .withFileFilter(new String[]{"zip"}) - .withTheme(R.style.LFileTheme) - .withTitle("Open From Packs") - .start(); - - break; - case R.id.dela: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getResources().getString(R.string.menu_5_adt)); - builder.setMessage(getResources().getString(R.string.menu_5_delall)); - builder.setIcon(R.drawable.ic_boat); - //点击对话框以外的区域是否让对话框消失 - builder.setCancelable(true); - //设置正面按钮 - builder.setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new Thread(new Runnable(){ - @Override - public void run() { - String file2= tv + "/saves"; - File file = new File(file2); - if (file.isDirectory()) { - deleteDirectory(file2); - } - if (file.isFile()) { - deleteFile(file2); - } - han.sendEmptyMessage(0); - } - }).start(); - dialog.dismiss(); - } - }); - //设置反面按钮 - builder.setNegativeButton("No No No", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - //对话框显示的监听事件 - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - - } - }); - //对话框消失的监听事件 - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - - } - }); - //显示对话框 - dialog.show(); - - break; - default: - break; - } - return true; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_worlds); - - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar6); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - creatfile(); - Path = tv+"/saves"; - string = Path + "/"; - listview2=(ListView)findViewById(R.id.runtimelistview2); - pd = new ProgressDialog(WorldsActivity.this); - pd.setMessage("Waiting..."); - pd.setIndeterminate(true); - pd.setCancelable(false); - listviews(); - //"/data/data/net.zhuoweizhang.boardwalk/app_runtime"; - file = new File(string); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", ">/+-*|"); - map.put("img",R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(WorldsActivity.this, list, - R.layout.list_w, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview2.setAdapter(sa); - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(string+"/"+targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img",over(targetFile.getName())); - }else if(filess==null){ - map.put("img",R.drawable.wen); - } - else{ - map.put("img",over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(WorldsActivity.this, list, - R.layout.list_w, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview2.setAdapter(sa); - listview2.setOnItemLongClickListener(new OnItemLongClickListener(){ - @Override - public boolean onItemLongClick(AdapterView p1, View p2, int p3, long p4) - { - Object Texts=listview2.getItemAtPosition(p3); - Map entry = (Map)Texts; - final String Text= (String) entry.get("text"); - String bo=Text+"/"; - String go=string+bo; - String dui="/sdcard/"; - AlertDialog alertDialog1 = new AlertDialog.Builder(listview2.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(getResources().getString(R.string.menu_5_adm)) - .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - pd.show(); - new Thread(new Runnable(){ - @Override - public void run() { - String file2= Path + "/" + Text; - File file = new File(file2); - if(file.isDirectory()){ - deleteDirectory(file2); - } - if(file.isFile()){ - deleteFile(file2); - } - han.sendEmptyMessage(0); - } - }).start(); - - } - }) - .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - - alertDialog1.show(); - return true; - } - }); - } - Handler han=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Filelistview(Path + "/"); - pd.hide(); - } - }}; - Handler han2=new Handler(){ - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - Filelistview(Path + "/"); - pd.hide(); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.menu_5_ttd), Toast.LENGTH_SHORT).show(); - } - }}; - private void listviews() { - listview2.setOnItemClickListener(new AdapterView.OnItemClickListener(){ - private ArrayList urls; - Boolean fil; - int Folder,contain; - private File[] files; - private String boing; - @Override - public void onItemClick(AdapterView p1, View p2, int p3, long p4) { - Object Texts=listview2.getItemAtPosition(p3); - Map entry = (Map)Texts; - String Text= (String) entry.get("text"); - boing = Text + "/"; - } - });} - private void Filelistview(String to) { - string = to; - file = new File(to); - File[] files = file.listFiles(); - if (files == null) { - Toast.makeText(this, "None", Toast.LENGTH_SHORT).show(); - List> list = new ArrayList>(); - Map map; - map = new HashMap(); - map.put("text", "Empty"); - map.put("img", R.drawable.timg); - list.add(map); - SimpleAdapter sa = new SimpleAdapter(WorldsActivity.this, list, - R.layout.list_w, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1 }); - listview2.setAdapter(sa); - return; - } - List> list = new ArrayList>(); - Map map; - Arrays.sort(files); - for (File targetFile : files) { - map = new HashMap(); - map.put("text", targetFile.getName()); - File filesss=new File(to + "/" + targetFile.getName()); - File[] filess = filesss.listFiles(); - if (filesss.isDirectory()) { - map.put("img", R.drawable.folder); - } else if (filesss.isFile()) { - map.put("img", over(targetFile.getName())); - } else if (filess == null) { - map.put("img", R.drawable.wen); - } else { - map.put("img", over(targetFile.getName())); - } - list.add(map); - } - SimpleAdapter sa = new SimpleAdapter(WorldsActivity.this, list, - R.layout.list_w, new String[] { "img", "text" }, - new int[] { R.id.listImageView1, R.id.listTextView1}); - - listview2.setAdapter(sa); - } - private void creatfile(){ - String dir = tv; // 需要创建的目录,sdcard目录一定存在,所以只用判断一级目录 - File file = new File(dir+"/saves"); - if (!file.exists())// 判断当前目录是否存在,存在返回true,否则返回false - file.mkdir(); // 如果不存在则创建目录 - return; - } - - private int over(String text) { - /* - if (text.indexOf(".sh") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".tar") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".gz") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".png") != -1) { - ings = R.drawable.vpver; - } else if (text.indexOf(".mp3") != -1) { - ings = R.drawable.vmnvff; - } else if (text.indexOf(".log") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".obj") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".mtl") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".json") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".re") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".bat") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".apk") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".rc") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".zip") != -1) { - ings = R.drawable.wen; - } else if (text.indexOf(".xml") != -1) { - ings = R.drawable.vrty; - } else if (text.indexOf(".so") != -1) { - ings = R.drawable.viihgv; - } else if (text.indexOf(".html") != -1) { - ings = R.drawable.vpouy; - } else if (text.indexOf(".txt") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".js") != -1) { - ings = R.drawable.vqw; - } else if (text.indexOf(".jar") != -1) { - ings = R.drawable.file; - } else if (text.indexOf(".cfg") != -1) { - ings = R.drawable.vnfdr; - } else if (text.indexOf(".ttf") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf(">/+-*|") != -1) { - ings = R.drawable.verrt; - } else if (text.indexOf("Empty") != -1) { - ings = R.drawable.timg; - } else { - ings = R.drawable.verrt; - } - */ - return ings; - } - public void showDirectory(View view) { - AlertDialog alertDialog2 = new AlertDialog.Builder(listview2.getContext()) - .setTitle(getResources().getString(R.string.menu_5_adtt))//标题 - .setIcon(R.drawable.ic_boat)//图标 - .setMessage(Path) - .setPositiveButton("Ok", new DialogInterface.OnClickListener() {//添加"Yes"按钮 - @Override - public void onClick(DialogInterface dialogInterface, int i) { - //TODO - } - }) - .create(); - alertDialog2.show(); - - } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK) { - if (requestCode == Consant.REQUESTCODE_FROM_FRAGMENT) { - List list = data.getStringArrayListExtra("paths"); - for (final String s : list) { - pd.show(); - new Thread(new Runnable(){ - @Override - public void run() { - try { - unzip(s, tv+ "/saves"); - han2.sendEmptyMessage(0); - } catch (IOException e) { - } - - } - }).start(); - } - } - } - } - @Override - public void onResume() { - super.onResume(); - creatfile(); - Filelistview(Path + "/"); - } - private String t() { - try { - FileInputStream in=new FileInputStream("/sdcard/games/com.koishi.launcher/h2o2/config.txt"); - byte[] b=new byte[in.available()]; - in.read(b); - in.close(); - String str=new String(b); - JSONObject json=new JSONObject(str); - return json.getString("game_directory"); - } catch (Exception e) { - System.out.println(e); - } - return "None"; - } - public boolean deleteFile(String filePath) { - File file = new File(filePath); - if (file.isFile() && file.exists()) { - return file.delete(); - } - return false; - } - - public static void unzip(String zipFilePath, String targetPath) - throws IOException { - OutputStream os = null; - InputStream is = null; - ZipFile zipFile = null; - try { - //获取要解压的文件,指定解压格式 - zipFile = new ZipFile(zipFilePath, Charset.forName("GBK")); - Enumeration entryEnum = zipFile.entries(); - if (null != entryEnum) { - ZipEntry zipEntry = null; - while (entryEnum.hasMoreElements()) { - zipEntry = (ZipEntry) entryEnum.nextElement(); - if (zipEntry.getSize() > 0) { - File targetFile = new File(targetPath - + File.separator + zipEntry.getName()); - os = new BufferedOutputStream(new FileOutputStream(targetFile)); - is = zipFile.getInputStream(zipEntry); - byte[] buffer = new byte[4096]; - int readLen = 0; - while ((readLen = is.read(buffer, 0, 4096)) >= 0) { - os.write(buffer, 0, readLen); - os.flush(); - } - is.close(); - os.close(); - } - //如果是文件夹,则创建文件夹 - if (zipEntry.isDirectory()) { - String pathTemp = targetPath + File.separator - + zipEntry.getName(); - File file = new File(pathTemp); - file.mkdirs(); - } - } - } - } catch (IOException ex) { - throw ex; - } finally { - //关闭流 - if (null != zipFile) { - zipFile.close(); - zipFile = null; - } - if (null != is) { - is.close(); - } - if (null != os) { - os.close(); - } - } - } - - - - /** - * 删除文件夹以及目录下的文件 - * @param filePath 被删除目录的文件路径 - * @return 目录删除成功返回true,否则返回false - */ - public boolean deleteDirectory(String filePath) { - boolean flag = false; - //如果filePath不以文件分隔符结尾,自动添加文件分隔符 - if (!filePath.endsWith(File.separator)) { - filePath = filePath + File.separator; - } - File dirFile = new File(filePath); - if (!dirFile.exists() || !dirFile.isDirectory()) { - return false; - } - flag = true; - File[] files = dirFile.listFiles(); - //遍历删除文件夹下的所有文件(包括子目录) - for (int i = 0; i < files.length; i++) { - if (files[i].isFile()) { - //删除子文件 - flag = deleteFile(files[i].getAbsolutePath()); - if (!flag) break; - } else { - //删除子目录 - flag = deleteDirectory(files[i].getAbsolutePath()); - if (!flag) break; - } - } - if (!flag) return false; - //删除当前空目录 - return dirFile.delete(); - } -} - - - diff --git a/app/src/main/java/com/koishi/launcher/h2o2/tools/FileUtil.java b/app/src/main/java/com/koishi/launcher/h2o2/tools/FileUtil.java deleted file mode 100644 index 4630b8de..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/tools/FileUtil.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.koishi.launcher.h2o2.tools; - -import java.util.zip.ZipFile; -import java.io.File; -import java.io.IOException; -import java.util.*; -import java.util.zip.*; -import java.io.*; -import java.nio.charset.*; -public class FileUtil -{ - public static boolean dirCopy(String srcPath, String destPath) { - File src = new File(srcPath); - if (!new File(destPath).exists()) { - new File(destPath).mkdirs(); - } - for (File s : src.listFiles()) { - if (s.isFile()) { - fileCopy(s.getPath(), destPath + File.separator + s.getName()); - } else { - dirCopy(s.getPath(), destPath + File.separator + s.getName()); - } - } - return true; - } - - public static boolean fileCopy(String srcPath, String destPath) { - File src = new File(srcPath); - File dest = new File(destPath); - try - { - InputStream is = new BufferedInputStream(new FileInputStream(src)); - OutputStream out =new BufferedOutputStream(new FileOutputStream(dest)); - byte[] flush = new byte[1024]; - int len = -1; - while ((len = is.read(flush)) != -1) { - out.write(flush, 0, len); - } - out.flush(); - out.close(); - is.close(); - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - // 删除文件或文件夹以及文件夹下所有文件 - public static boolean delDir(String dirPath) { - try{ - File dirFile = new File(dirPath); - if (!dirFile.exists()) { - return false; - } - if (dirFile.isFile()) { - dirFile.delete(); - return true; - } - File[] files = dirFile.listFiles(); - if(files==null){ - return false; - } - for (int i = 0; i < files.length; i++) { - delDir(files[i].toString()); - } - dirFile.delete(); - return true; - }catch(Exception e){ - return false; - } - } - //第一个参数就是需要解压的文件,第二个就是解压的目录 - public static boolean unZip(String zipFile, String folderPath) { - ZipFile zfile= null; - try { - //转码为GBK格式,支持中文 - zfile = new ZipFile(zipFile); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - Enumeration zList=zfile.entries(); - ZipEntry ze=null; - byte[] buf=new byte[1024]; - while(zList.hasMoreElements()){ - ze=(ZipEntry)zList.nextElement(); - //列举的压缩文件里面的各个文件,判断是否为目录 - if(ze.isDirectory()){ - String dirstr = folderPath + ze.getName(); - dirstr.trim(); - File f=new File(dirstr); - f.mkdir(); - continue; - } - OutputStream os= null; - FileOutputStream fos = null; - // ze.getName()会返回 script/start.script这样的,是为了返回实体的File - File realFile = getRealFileName(folderPath, ze.getName()); - try { - fos = new FileOutputStream(realFile); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return false; - } - os = new BufferedOutputStream(fos); - InputStream is= null; - try { - is = new BufferedInputStream(zfile.getInputStream(ze)); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - int readLen=0; - //进行一些内容复制操作 - try { - while ((readLen=is.read(buf, 0, 1024))!=-1) { - os.write(buf, 0, readLen); - } - } catch (IOException e) { - e.printStackTrace(); - return false; - } - try { - is.close(); - os.close(); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - } - try { - zfile.close(); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - return true; - } - - /** - * 给定根目录,返回一个相对路径所对应的实际文件名. - * @param baseDir 指定根目录 - * @param absFileName 相对路径名,来自于ZipEntry中的name - * @return java.io.File 实际的文件 - */ - private static File getRealFileName(String baseDir, String absFileName){ - String[] dirs=absFileName.split("/"); - File ret = new File(baseDir); - String substr = null; - - if(dirs.length>1){ - for (int i = 0; i < dirs.length-1;i++) { - substr = dirs[i]; - ret=new File(ret, substr); - } - - if(!ret.exists()) - ret.mkdirs(); - substr = dirs[dirs.length-1]; - ret=new File(ret, substr); - return ret; - }else{ - ret = new File(ret,absFileName); - } - return ret; - } - -} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/tools/Utils.java b/app/src/main/java/com/koishi/launcher/h2o2/tools/Utils.java deleted file mode 100644 index ecbee3ae..00000000 --- a/app/src/main/java/com/koishi/launcher/h2o2/tools/Utils.java +++ /dev/null @@ -1,264 +0,0 @@ -package com.koishi.launcher.h2o2.tools; - -import java.io.*; -import java.util.*; -import android.content.res.*; -import org.apache.commons.compress.compressors.xz.*; -import org.apache.commons.compress.archivers.tar.*; -import org.apache.commons.compress.archivers.examples.*; -import org.apache.commons.compress.archivers.*; -import org.apache.commons.compress.utils.*; - -public final class Utils { - - - public static File createFile(String filePath){ - File file = new File(filePath); - return Utils.createFile(file); - } - public static File createFile(File file){ - if (file.exists()){ - file.delete(); - } - file.getParentFile().mkdirs(); - - try - { - file.createNewFile(); - } - catch (IOException e) - { - e.printStackTrace(); - return null; - } - return file; - } - public static byte[] readFile(String filePath){ - return Utils.readFile(new File(filePath)); - } - public static byte[] readFile(File file){ - FileInputStream fis = null; - try{ - - fis=new FileInputStream(file); - byte result[]=new byte[(int)file.length()]; - fis.read(result); - fis.close(); - return result; - }catch(Exception e){ - - e.printStackTrace(); - } - finally{ - if (fis != null){ - try - { - fis.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - } - return null; - } - - - - public static boolean writeFile(File file, byte[] bytes){ - - file = Utils.createFile(file); - - if (file == null){ - return false; - } - FileOutputStream fos = null; - try{ - fos = new FileOutputStream(file); - fos.write(bytes); - fos.flush(); - fos.close(); - return true; - }catch(Exception e){ - e.printStackTrace(); - } - finally{ - if (fos != null){ - try - { - fos.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - } - return false; - } - public static boolean writeFile(File file, String str){ - - boolean retval = false; - try - { - retval = Utils.writeFile(file, str.getBytes("UTF-8")); - } - catch (UnsupportedEncodingException e) - { - e.printStackTrace(); - } - return retval; - } - - public static boolean writeFile(String outFile, String str){ - return writeFile(new File(outFile), str); - } - - public static boolean extractAsset(AssetManager am, String src, File targetFile ){ - FileOutputStream fos = null; - InputStream is = null; - - try - { - targetFile = Utils.createFile(targetFile); - - fos = new FileOutputStream(targetFile); - - is = am.open(src); - byte[] buf = new byte[1024]; - int count = 0; - - while ((count = is.read(buf)) != -1) { - fos.write(buf, 0, count); - } - - fos.flush(); - fos.close(); - is.close(); - return true; - } - catch (IOException e) - { - e.printStackTrace(); - - - - return false; - } - finally{ - - if (is != null){ - try - { - is.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - if (fos != null){ - try - { - fos.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - } - - - - } - public static boolean extractAsset(AssetManager am, String src, String target ){ - return extractAsset(am, src, new File(target)); - } - - public static void extractTarXZ(File tarFile, File destDir){ - - FileInputStream fis = null; - XZCompressorInputStream xzcis = null; - TarArchiveInputStream tais = null; - - OutputStream fos = null; - try { - fis = new FileInputStream(tarFile); - xzcis = new XZCompressorInputStream(fis); - tais = new TarArchiveInputStream(xzcis, 1024); - - TarArchiveEntry entry; - while((entry = tais.getNextTarEntry()) != null){ - File target = new File(destDir, entry.getName()); - if (entry.isDirectory()) { - target.mkdirs(); - } else { - fos = new FileOutputStream(target); - - IOUtils.copy(tais, fos); - fos.flush(); - fos.close(); - } - } - - tais.close(); - xzcis.close(); - fis.close(); - - } catch (IOException e) { - e.printStackTrace(); - }finally { - try { - if(fis != null){ - fis.close(); - } - if(fos != null){ - fos.close(); - } - if(xzcis != null){ - xzcis.close(); - } - if(tais != null){ - tais.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - - } - - - public static void extractTarXZ(String tar, File destDir){ - extractTarXZ(new File(tar), destDir); - } - public static void extractTarXZ(File tarFile, String dir){ - extractTarXZ(tarFile, new File(dir)); - } - - public static void extractTarXZ(String tar, String dir){ - extractTarXZ(new File(tar), new File(dir)); - } - - public static boolean setExecutable(File file){ - boolean retval = true; - if (file.isDirectory()){ - File subFiles[] = file.listFiles(); - for (File subFile : subFiles){ - retval = retval && setExecutable(subFile); - } - } - retval = retval && file.setExecutable(true); - return retval; - } - - public static boolean setExecutable(String file){ - return setExecutable(new File(file)); - } -} - - diff --git a/app/src/main/java/com/mistake/revision/BUG.java b/app/src/main/java/com/mistake/revision/BUG.java new file mode 100644 index 00000000..a43da863 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/BUG.java @@ -0,0 +1,126 @@ +package com.mistake.revision; + +import android.app.Application; +import android.app.Activity; +import android.os.Bundle; +import android.content.Context; +import java.io.Writer; +import java.io.StringWriter; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import android.widget.*; +import java.io.*; + +public class BUG extends Application implements Application.ActivityLifecycleCallbacks +{ + @Override + public void onActivityCreated(Activity p1, Bundle p2) + { + // TODO: Implement this method + + } + + @Override + public void onActivityStarted(Activity p1) + { + // TODO: Implement this method + } + + @Override + public void onActivityResumed(Activity p1) + { + // TODO: Implement this method + + } + + @Override + public void onActivityPaused(Activity p1) + { + // TODO: Implement this method + + } + + @Override + public void onActivityStopped(Activity p1) + { + // TODO: Implement this method + } + + @Override + public void onActivitySaveInstanceState(Activity p1, Bundle p2) + { + // TODO: Implement this method + } + + @Override + public void onActivityDestroyed(Activity p1) + { + // TODO: Implement this method + } + + + + @Override + public void onCreate() + { + + super.onCreate(); + + + this.registerActivityLifecycleCallbacks(this); + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){ + + private byte[] bug; +//设置默认的未捕获的异常处理程序 + @Override + public void uncaughtException(Thread p1, Throwable p2) + { + + + + + Writer i = new StringWriter(); + p2.printStackTrace(new PrintWriter(i)); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + p2.printStackTrace(new PrintStream(baos)); + bug=baos.toByteArray(); + + try { + FileOutputStream f=new FileOutputStream("/sdcard/boat/error.log"); + + //f.write(i.toString().getBytes()); + + + f.write(bug); + + + f.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + //Utils.writeFile("/sdcard/boat/err.log",i.toString()); + // TODO: Implement this method + } + }); + + //instance = this; + // 在设置文件名参数时,不要带 “.xml” 后缀,android会自动添加 + //SpUtils.getInstance(this,"setting"); + } + + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + + + + + + } +} diff --git a/app/src/main/java/com/mistake/revision/BaseDialogFragment/BaseDialogFragmnet.java b/app/src/main/java/com/mistake/revision/BaseDialogFragment/BaseDialogFragmnet.java new file mode 100644 index 00000000..db2057fe --- /dev/null +++ b/app/src/main/java/com/mistake/revision/BaseDialogFragment/BaseDialogFragmnet.java @@ -0,0 +1,202 @@ +package com.mistake.revision.BaseDialogFragment; + +import android.os.Handler; +import android.view.View; +import android.view.Window; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import java.util.Objects; +import android.view.WindowManager; +import android.graphics.drawable.ColorDrawable; +import android.graphics.Color; +import android.widget.ImageView; +import android.os.Bundle; + +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +public class BaseDialogFragmnet extends DialogFragment { + + public static final Handler HANDLER = new Handler(); + private Object mView; + private View mRootView; + private float mAlpha; + private boolean mAutoDismiss; + private boolean mCancelable; + private Window window; + private int mAnimation; + private int mGravity; + private SparseArray mClickArray; + private SparseArray mSetText; + private SparseArray mSetImage; + + BaseDialogFragmnet(Object view, float alpha, boolean autoDismiss, boolean cancelable, int animation, int gravity) { + this.mView = view; + this.mAlpha = alpha; + this.mAutoDismiss = autoDismiss; + this.mCancelable = cancelable; + this.mAnimation = animation; + this.mGravity = gravity; + mClickArray = new SparseArray<>(); + mSetText = new SparseArray<>(); + mSetImage = new SparseArray<>(); + } + + public static BaseDialogFragmnet newInstance(Object view, float alpha, + boolean mAutoDismiss, boolean cancelable, + int animation, int gravity) { + return new BaseDialogFragmnet(view, alpha, mAutoDismiss, cancelable, animation, gravity); + } + + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + window = Objects.requireNonNull(getDialog()).getWindow(); + if (window != null) { + if (mView instanceof Integer) { + this.mRootView = inflater.inflate((Integer) mView, (ViewGroup) window.findViewById(android.R.id.content), false); + } else if (mView instanceof View) { + this.mRootView = (View) mView; + } else { + throw new NullPointerException("Not Layout File "); + } + create(); + } + return mRootView; + } + + public static DialogBuilder Builder() { + return new DialogBuilder(); + } + + /** + * 设置背景遮盖层开关 + */ + public void setBackgroundDimEnabled(boolean enabled) { + if (window != null) { + if (enabled) { + window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + } + } + } + + /** + * 设置背景遮盖层的透明度(前提条件是背景遮盖层开关必须是为开启状态) + */ + public void setBackgroundDimAmount(float dimAmount) { + if (window != null) { + window.setDimAmount(dimAmount); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mSetText != null) { + mSetText.clear(); + mSetText = null; + } + if (mClickArray != null) { + mClickArray.clear(); + mClickArray = null; + } + if (mRootView != null) { + mRootView = null; + } + } + + /** + * 对点击事件进行处理 + */ + private final class ViewOnClick implements View.OnClickListener { + private final BaseDialogFragmnet dialog; + private final OnListener listener; + + ViewOnClick(BaseDialogFragmnet dialog, OnListener listener) { + this.dialog = dialog; + this.listener = listener; + } + + @Override + public void onClick(View view) { + if (!mAutoDismiss) { + listener.onClick(dialog, view); + } + } + } + + /** + * 对事件进行监听, + */ + public interface OnListener { + void onClick(BaseDialogFragmnet dialog, View view); + } + + /** + * 设置 文本 + * + * @param Id id + * @param strings 内容 + */ + public BaseDialogFragmnet setText(@IdRes int Id, String strings) { + mSetText.put(Id, strings); + return this; + } + + /** + * 设置 图片 + * + * @param Id id + * @param url 内容 + */ + public BaseDialogFragmnet setImageUrl(@IdRes int Id, String url) { + mSetImage.put(Id, url); + return this; + } + + /** + * 监听事件 + */ + public BaseDialogFragmnet setListener(int id, OnListener listener) { + mClickArray.put(id, listener); + return this; + } + + + private void setLocation() { + WindowManager.LayoutParams attributes = window.getAttributes(); + attributes.alpha = mAlpha; + attributes.gravity = mGravity; + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + window.setAttributes(attributes); + } + + /** + * 延时发送,在指定的时间执行 + */ + public void postAtTime(long uptimeMillis, Runnable run) { + HANDLER.postDelayed(run, uptimeMillis); + } + + private void create() { + setLocation(); + initView(mRootView); + setCancelable(mCancelable); + window.setWindowAnimations(mAnimation); + } + + /** + * 空实现,如果dialog的逻辑过于复杂,则可以继承此类,实现此方法。 + * 这个方法可用于绑定 view 进行一些初始化等操作 + */ + public void initView(View view) { + + } +} + diff --git a/app/src/main/java/com/mistake/revision/BaseDialogFragment/DialogBuilder.java b/app/src/main/java/com/mistake/revision/BaseDialogFragment/DialogBuilder.java new file mode 100644 index 00000000..a27b2b55 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/BaseDialogFragment/DialogBuilder.java @@ -0,0 +1,91 @@ +package com.mistake.revision.BaseDialogFragment; + +import androidx.annotation.StyleRes; + +import java.lang.reflect.Constructor; + +public class DialogBuilder { + + private Object view; + private float mAlpha = 1; + private boolean mAutoDismiss = false; + private boolean mCancelable = true; + private int mAnimation = 0; + private int mGravity; + + public Class tClass; + + public DialogBuilder() { + } + + public DialogBuilder(Class tClass) { + this.tClass = tClass; + } + + /** + * 设置布局资源,可以为 ID,也可以是 View + */ + public DialogBuilder setContentView(Object view) { + this.view = view; + return this; + } + + /** + * 设置透明度透明度 + * + * @param alpha 从 0 - 1 + */ + public DialogBuilder setAlpha(float alpha) { + this.mAlpha = alpha; + return this; + } + + /** + * 若为 true 所有的点击事件都不起作用,否则相反 + */ + public DialogBuilder setAutoDismiss(boolean autoDismiss) { + this.mAutoDismiss = autoDismiss; + return this; + } + + /** + * 若为 false,对话框不可取消 + */ + public DialogBuilder setCancelable(boolean cancelable) { + this.mCancelable = cancelable; + return this; + } + + /** + * 设置动画 + */ + public DialogBuilder setAnimation(@StyleRes int animation) { + this.mAnimation = animation; + return this; + } + + /** + * 设置对话框位置 + */ + public DialogBuilder setGravity(int gravity) { + this.mGravity = gravity; + return this; + } + + /** + * @return 对话框的实例 + */ + public T build() { + if (tClass != null) { + try { + Constructor constructor = tClass.getConstructor( + Object.class, float.class, boolean.class, boolean.class, int.class,int.class); + return constructor.newInstance(view, mAlpha, mAutoDismiss, mCancelable,mAnimation,mGravity); + } catch (Exception e) { + throw new RuntimeException("创建 "+tClass.getName()+" 失败,原因可能是构造参数有问题:"+e.getMessage()); + } + } else { + return (T) BaseDialogFragmnet.newInstance(view, mAlpha, mAutoDismiss, mCancelable,mAnimation,mGravity); + } + } +} diff --git a/app/src/main/java/com/mistake/revision/DialogFragmentDownloadMinecraft.java b/app/src/main/java/com/mistake/revision/DialogFragmentDownloadMinecraft.java new file mode 100644 index 00000000..4b17114e --- /dev/null +++ b/app/src/main/java/com/mistake/revision/DialogFragmentDownloadMinecraft.java @@ -0,0 +1,39 @@ +package com.mistake.revision; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import org.koishi.launcher.h2o2pro.R; + +public class DialogFragmentDownloadMinecraft extends DialogFragment +{ + + private String version; + private String homepath; + private String address; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View base = inflater.inflate(R.layout.dialog_fragment_download_minecraft,container,false); // 此处的布局文件是普通的线性布局(此博客忽略) + getDialog().requestWindowFeature(STYLE_NO_TITLE); + setCancelable(false); + + version = getArguments().getString("version"); + homepath = getArguments().getString("game"); + address= getArguments().getString("address"); + + //loading_config(version, homepath, address); + + return base; + } + +} + diff --git a/app/src/main/java/com/mistake/revision/Download/DownloadFragment.java b/app/src/main/java/com/mistake/revision/Download/DownloadFragment.java new file mode 100644 index 00000000..fffba5e3 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/Download/DownloadFragment.java @@ -0,0 +1,1212 @@ +package com.mistake.revision.Download; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.io.FileInputStream; + +import java.io.FileWriter; +import java.io.File; +import android.widget.EditText; +import android.text.TextWatcher; +import android.text.Editable; +import android.widget.CheckBox; +import android.content.SharedPreferences; +import android.widget.CompoundButton; +import android.content.Context; +import com.download.service.downloader.DownloadManager; +import com.download.service.util.*; +import java.util.*; +import android.widget.*; +import android.graphics.*; +import android.os.*; +import java.io.*; +import com.alibaba.fastjson.*; +import com.mistake.revision.*; +import com.download.service.downloader.*; +import com.google.gson.*; +import okhttp3.*; +import com.google.gson.reflect.*; +import android.view.Window; +import android.graphics.drawable.ColorDrawable; +import android.util.DisplayMetrics; +import android.view.WindowManager; +import android.view.Gravity; +import android.content.res.Configuration; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import org.koishi.launcher.h2o2pro.R; + +public class DownloadFragment extends DialogFragment +{ + + + private DownloadManager mDownloadManager; + + private ArrayListlibraries; + private ArrayListassets; + + private TextView mlist; + private TextView mpath1,mpath2, mpath3; + private ProgressBar mpath_progress1, mpath_progress2, mpath_progress3; + private TextView overall_progress, stages_progress; + + private TextView title; + + private ImageButton close; + private ImageButton pause_start1,pause_start2,pause_start3; + + private Button btnCancel; +// + private static String Source_address; + private static String + API_Version_client_server_json, + API_Assets, + API_Libraries, + API_Manifest_Version_json; + + private static String + game_directory, + assets_root; + + private static String + Version, + Version_assets, + Version_json, + Version_jar, + //Version_url, + Version_libraries; + private String assets_id; + private String Txt; + + private ArrayList Temporary;//临时数据 + + private int libraries_loader_size=0; + private int libraries_loading_size=0; + private int assets_loader_size=0; + private int assets_loading_size=0; + + private boolean download1=false; + private boolean download2=false; + private boolean download3=false; + + private String version; + private String homepath; + private String address; + + + private String ReadString(String sourcePath){ + + StringBuffer sb = new StringBuffer(); + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(sourcePath)); + String str; + while((str = br.readLine()) != null) { + sb.append(str); + sb.append("\r\n"); + } + br.close(); + }catch(Exception e){ + setText(e.toString()); + } + + return sb.toString(); + + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View base = inflater.inflate(R.layout.download,container,false); // 此处的布局文件是普通的线性布局(此博客忽略) + getDialog().requestWindowFeature(STYLE_NO_TITLE); + setCancelable(false); + mpath1=(TextView)basefindViewById(base,R.id.downloadTextView1); + mpath2=(TextView)basefindViewById(base,R.id.downloadTextView2); + mpath3=(TextView)basefindViewById(base,R.id.downloadTextView3); + mpath_progress1=(ProgressBar)base.findViewById(R.id.downloadProgressBar1); + mpath_progress2=(ProgressBar)base.findViewById(R.id.downloadProgressBar2); + mpath_progress3=(ProgressBar)base.findViewById(R.id.downloadProgressBar3); + overall_progress=(TextView)basefindViewById(base,R.id.downloadTextView4); + stages_progress=(TextView)basefindViewById(base,R.id.downloadTextView5); + mlist=(TextView)basefindViewById(base,R.id.downloadTextView6); + //title=(TextView)basefindViewById(base,R.id.downloadTextView7); + close=(ImageButton)base.findViewById(R.id.downloadImageButton1); + pause_start1=(ImageButton)base.findViewById(R.id.downloadImageButton2); + pause_start2=(ImageButton)base.findViewById(R.id.downloadImageButton3); + pause_start3=(ImageButton)base.findViewById(R.id.downloadImageButton4); + btnCancel = (Button)base.findViewById(R.id.btn_cancel); +// + close.setVisibility(View.GONE); + pause_start1.setOnClickListener(onclick); + pause_start2.setOnClickListener(onclick); + pause_start3.setOnClickListener(onclick); + btnCancel.setOnClickListener(onclick); +// + mpath_progress1.setProgress(0); + mpath_progress2.setProgress(0); + mpath_progress3.setProgress(0); + mpath1.setText(""); + mpath2.setText(""); + mpath3.setText(""); + + version = getArguments().getString("version"); + homepath = getArguments().getString("game"); + address= getArguments().getString("address"); + + loading_config(version, homepath, address); + + return base; + } + + public void loading_config(String version,String homepath,String address){ + //Open_notice_Service(); + + mDownloadManager=DownloadManager.getInstance();//必须的 + + //Version = "1.7.10";//下载版本--->manifest_version_json + //game_directory = "/storage/emulated/0/boat/gamedir";//主游戏目录->结尾不带"/" + //Source_address = "https://download.mcbbs.net";//需要提供的源->结尾不带"/" + Version = version;//下载版本--->manifest_version_json + game_directory = homepath;//主游戏目录->结尾不带"/" + Source_address = address;//需要提供的源->结尾不带"/" +//一个都不能有误-传入前检测下 + API_Version_client_server_json = Source_address + "/version/"; + API_Assets = Source_address + "/assets/"; + API_Libraries = Source_address + "/maven/"; + API_Manifest_Version_json = Source_address + "/mc/game/version_manifest.json"; + + assets_root = game_directory+"/assets"; + Version_jar = game_directory+"/versions/"+Version+"/"+ Version+".jar"; + Version_json = game_directory+"/versions/"+Version+"/"+ Version+".json"; + // + Version_libraries = game_directory+"/libraries/"; + Version_assets = assets_root+"/"; + + /*{ + "assets_root":"/storage/emulated/0/boat/gamedir/assets", + "auth_access_token":"0", + "auth_player_name":"Steve", + "auth_session":"0", + "auth_uuid":"00000000-0000-0000-0000-000000000000", + "currentVersion":"/storage/emulated/0/boat/gamedir/versions/1.7.10", + "extraJavaFlags":"-server -Xms500M -Xmx500M", + "extraMinecraftFlags":"", + "game_assets":"/storage/emulated/0/boat/gamedir/assets/virtual/legacy", + "game_directory":"/storage/emulated/0/boat/gamedir", + "home":"/storage/emulated/0/boat", + "runtimePath":"/data/user/0/cosine.boat/app_runtime/32", + "user_properties":"{}", + "user_type":"mojang" + }*/ +//起点 + mhandler.sendEmptyMessage(0);//一切的开端 + + } + + @Override + public void onStart() { + super.onStart(); + /* Window win = getDialog().getWindow(); + DisplayMetrics dm = new DisplayMetrics(); + getActivity().getWindowManager().getDefaultDisplay().getMetrics( dm ); + WindowManager.LayoutParams params = win.getAttributes(); + params.gravity = Gravity.CENTER; + // 使用ViewGroup.LayoutParams,以便Dialog 宽度充满整个屏幕 + params.width = ViewGroup.LayoutParams.WRAP_CONTENT; + params.height = ViewGroup.LayoutParams.WRAP_CONTENT; + win.setAttributes(params);*/ + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + // 横屏时取高度为宽度,高度为为 warp_content + int screenWidth = displayMetrics.widthPixels; + int screenHeight = displayMetrics.heightPixels; + ViewGroup.LayoutParams params = getDialog().getWindow().getAttributes(); + + if(screenWidth>screenHeight){ + params.width = (int)(screenHeight*1.1f); + //params.height = (int)(screenHeight*0.9f); + }else{ + params.width = (int)(screenWidth*0.8f); + //params.height = (int)(screenHeight*0.4f); + } + + getDialog().getWindow().setAttributes((WindowManager.LayoutParams) params); + super.onConfigurationChanged(newConfig); + } + + @Override + public void onResume() { + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + // 横屏时取高度为宽度,高度为为 warp_content + int screenWidth = displayMetrics.widthPixels; + int screenHeight = displayMetrics.heightPixels; + ViewGroup.LayoutParams params = getDialog().getWindow().getAttributes(); + + if(screenWidth>screenHeight){ + params.width = (int)(screenHeight*0.9f); + //params.height = (int)(screenHeight*0.6f); + }else{ + params.width = (int)(screenWidth*0.9f); + //params.height = (int)(screenHeight*0.6f); + } + + getDialog().getWindow().setAttributes((WindowManager.LayoutParams) params); + super.onResume(); + + } + + + private View.OnClickListener onclick=new View.OnClickListener(){ + + @Override + public void onClick(View p1) + { + if(p1==pause_start1){ + //谨慎点击 + download1(mDownloadManager.Self_destruction1()); + + }else if(p1==pause_start2){ + //谨慎点击 + download2(mDownloadManager.Self_destruction2()); + + }else if(p1==pause_start3){ + //谨慎点击 + download3(mDownloadManager.Self_destruction3()); + + }else if (p1 == btnCancel) { + getDialog().dismiss(); + } + } + }; + +//字体颜色 + private TextView basefindViewById(View base,int id){ + TextView a=base.findViewById(id); + a.setTextColor(Color.GRAY); + return a; + } + + private Handler mhandler=new Handler(){ + @Override + public void handleMessage(Message msg) { + switch(msg.what){ + case 1000: + if(Temporary.size()>=1){ + if(!download1){ + mhandler.sendEmptyMessage(101); + setlibraries(); + }else{ + if(!download2){ + mhandler.sendEmptyMessage(101); + setlibraries(); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + setlibraries(); + }else{ + + } + } + } + }else{ + setlibraries(); + Message msg1=new Message(); + msg1.what=8; + msg1.arg1=5; + mhandler.sendMessage(msg1); + } + break; + case 2000: + if(Temporary.size()>=1){ + if(!download1){ + mhandler.sendEmptyMessage(101); + setassets(); + }else{ + if(!download2){ + mhandler.sendEmptyMessage(101); + setassets(); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + setassets(); + }else{ + + } + } + } + }else{ + setassets(); + Message msg2=new Message(); + msg2.what=8; + msg2.arg1=6; + mhandler.sendMessage(msg2); + } + break; + case 0: + mhandler.sendEmptyMessageAtTime(1, 500); + break; + case 1: + setText("(Download):"+Version+"!"); + Dwonload_Version_json(Version,API_Version_client_server_json+Version+"/json"); + + break; + case 2: + Txt = ReadString(game_directory + "/versions/" + Version + "/" + Version + ".json"); + //String Url=API_Version_client_server_json + Version + "/client"; + Download_client_Assets(Txt); + break; + case 3: + VersionLibraries(Txt); + VersionAssets(ReadString(Version_assets + "indexes/" + assets_id + ".json")); + break; + case 4: + run_download_libraries(); + break; + case 101: + //if(Temporary.get(0)instanceof AssetsUtil){ + + object_turn_assets(API_Assets); + object_turn_libraries(); + + //}else if(Temporary.get(0) instanceof LibrariesUtil){ + + //object_turn_libraries(); + //} + + break; + case 5: + run_download_assets(); + break; + case 6: + /* + for(LibrariesUtil a:libraries){ + append(Turn_Url(APILibraries_bmclapi,a.getname())); + append(Turn_Path(Version_libraries,a.getname())); + }*/ + + mpath_progress1.setProgress(100); + mpath_progress2.setProgress(100); + mpath_progress3.setProgress(100); + mpath1.setText(getResources().getString(R.string.download_done)+Version); + mpath2.setText(getResources().getString(R.string.download_done)+Version); + mpath3.setText(getResources().getString(R.string.download_done)+Version); + append(getResources().getString(R.string.download_done)+Version,100,100); + + //-可自定义个回调机制- + + break; + case 8: + if(!download2&&!download3&&!download1){ + mhandler.sendEmptyMessage(3); + } + break; + case 9: + //网页文件无法下载调用 + /*try + { + msg.obj; + } + catch (IOException e) + { + setText(e.toString()); + }*/ + break; + case 10: + /*notif.contentView.setTextViewText(R.id.noticeTextView1,(String)msg.obj); + notif.contentView.setTextViewText(R.id.noticeTextView2,overall_progress.getText().toString()); + notif.contentView.setTextViewText(R.id.noticeTextView3,stages_progress.getText().toString()); + notif.contentView.setProgressBar(R.id.noticeProgressBar1,msg.arg2,msg.arg1 , false); + manager.notify(1, notif); */ + break; + } + super.handleMessage(msg); + } + }; + private void object_turn_libraries() + { + // 1 0 11 01 1 02 10 32 0 12 0 22 03 + try{ + ArrayList list=new ArrayList<>(); + if(Temporary.size()>1){ + LibrariesUtil rock=(LibrariesUtil) Temporary.get(0); + String url=rock.geturl(); + String path = Path(rock.getpath()); + String name = Path_name(rock.getpath()); + if (!download1){ + download_manager_1(url,path,name,1000,name,rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((LibrariesUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download2){ + download_manager_2(url,path,name,1000,name,rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((LibrariesUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download1){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download3){ + download_manager_3(url,path,name,1000,name,rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((LibrariesUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + //list2.clear(); + + } + }//true未加载 + } + } + } + }else{ + LibrariesUtil rock=(LibrariesUtil) Temporary.get(0); + String url=rock.geturl(); + String path = Path(rock.getpath()); + String name = Path_name(rock.getpath()); + if(!download1){ + download_manager_1(url,path,name,1000,name,rock.getsize()); + Temporary.remove(0); + }else{ + if(!download2){ + download_manager_2(url,path,name,1000,name,rock.getsize()); + Temporary.remove(0); + }else{ + if(!download3){ + download_manager_3(url,path,name,1000,name,rock.getsize()); + Temporary.remove(0); + }else{ + + } + } + } + } + + }catch(Exception e){ + setText(e.toString()); + } + + } + private void object_turn_assets(String Assets) + { + //10 11 01 10 21 03 2 0 1 20 22 03 + try{ + ArrayList list=new ArrayList<>(); + if(Temporary.size()>1){ + AssetsUtil rock=(AssetsUtil) Temporary.get(0); + String url=Assets+rock.gethash().substring(0,2)+"/"+ rock.gethash(); + String path = Version_assets+"objects/"+rock.gethash().substring(0,2); + String name = rock.gethash(); + if(!download1){ + download_manager_1(url,path,name,2000,rock.getname(),rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((AssetsUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download2){ + download_manager_2(url,path,name,2000,rock.getname(),rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((AssetsUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download1){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download3){ + download_manager_3(url,path,name,2000,rock.getname(),rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((AssetsUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + //list2.clear(); + } + }//true未加载 + } + } + } + }else if(Temporary.size()==1){ + AssetsUtil rock=(AssetsUtil) Temporary.get(0); + String url=Assets+rock.gethash().substring(0,2)+"/"+ rock.gethash(); + String path = Version_assets+"objects/"+rock.gethash().substring(0,2); + String name = rock.gethash(); + if(!download1){ + download_manager_1(url,path,name,2000,rock.getname(),rock.getsize()); + Temporary.remove(0); + }else{ + if(!download2){ + download_manager_2(url,path,name,2000,rock.getname(),rock.getsize()); + Temporary.remove(0); + }else{ + if(!download3){ + download_manager_3(url,path,name,2000,rock.getname(),rock.getsize()); + Temporary.remove(0); + }else{ + + } + } + } + } + + }catch(Exception e){ + setText(e.toString()); + } + } + private void Dwonload_Version_json(String id, String url){ + File e=new File(Version_json); + if(!e.exists()){ + download_manager_1(url,game_directory+"/versions/"+id,Version+".json",2,"Version->"+Version+"->json",0) ; + }else{ + if(e.isDirectory()){ + //文件夹怎么删除? + e.delete(); + download_manager_1(url,game_directory+"/versions/"+id,Version+".json",2,"Version->"+Version+"->json",0) ; + }else{ + mpath1.setText("Version->"+Version+"->json"); + mpath_progress1.setProgress(100);//留空白不好看 + mhandler.sendEmptyMessage(2); + } + } + } + public void Get_okHttp_Response_body_string(String url1,final int msg1) + { + HttpUtil.sendOkHttpRequest(url1, new okhttp3.Callback(){ + @Override + public void onFailure(Call call, final IOException e) { + //网络错误 + } + @Override + public void onResponse(Call p1, Response p2) throws IOException + { + final String url_string=p2.body().string(); + new Thread(){ + public void run(){ + Message msg = new Message(); + msg.what = msg1; + msg.obj = url_string; + //获取网页? + mhandler.sendMessage(msg); + } + }.start(); + } + }); + } + + private void Download_client_Assets(String json){ + try{ + JSONObject objects=JSON.parseObject(json); + JSONObject client= objects.getJSONObject("downloads"); + JSONObject main= client.getJSONObject("client"); + + String Url=(String) main.get("url"); + int size=Integer.valueOf((Integer) main.get("size")); + + + JSONObject assetindex= objects.getJSONObject("assetIndex"); + assets_id=(String)assetindex.get("id"); + String url=((String)assetindex.get("url")); + File version_assetindex=new File(Version_assets+"indexes/"+(String)assetindex.get("id")+".json"); + File version_client=new File(Version_jar); + + + if(!version_client.exists()&&!version_assetindex.exists()){ + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + download_manager_3(url,Version_assets+"indexes",(String)assetindex.get("id")+".json",8,"Version->"+assets_id+"->assets->json",0); + }else if(!version_client.exists()&&version_assetindex.exists()){ + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + //同上 + mpath3.setText("Version->"+assets_id+"->assets->json"); + mpath_progress3.setProgress(100); + }else if(version_client.exists()&&!version_assetindex.exists()){ + download_manager_3(url,Version_assets+"indexes",(String)assetindex.get("id")+".json",8,"Version->"+assets_id+"->assets->json",0); + //同上 + mpath2.setText("Version->"+Version+"->jar"); + mpath_progress2.setProgress(100); + }else if(version_client.exists()&&version_assetindex.exists()){ + if(version_client.isDirectory()){ + version_client.delete(); + //文件夹如何删除? + setText("Client error"); + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + }else{ + if(version_client.length()!=(int)main.get("size")){ + + version_client.delete(); + setText("Client error"); + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + }else{ + + mpath2.setText("Version->"+Version+"->jar"); + mpath_progress2.setProgress(100); + + mpath3.setText("Version->"+assets_id+"->assets->json"); + mpath_progress3.setProgress(100); + Message msg=new Message(); + msg.what=8; + msg.arg1=3; + mhandler.sendMessage(msg); + + + + } + } + } + }catch(Exception e){ + setText(e.toString()); + + //此情况是解析发生错误一般null + } + + } + //https://bmclapi2.bangbang93.com/version/1.7.10/server client json + private String Turn_Url(String api,String a){ + String b=a.substring(0, a.lastIndexOf(":")); + String c=a.substring(a.lastIndexOf(":")+1); + String d=b.substring(b.lastIndexOf(":")+1)+"-"+c+".jar"; + String e=b.substring(0, a.lastIndexOf(":")); + String f=e.replace(".","/"); + String g=f.replace(":","/"); + return api+g+"/"+c+"/"+d; + } + private String Turn_Path(String api,String a){ + //此为拼接 + String b=a.substring(0, a.lastIndexOf(":")); + String c=a.substring(a.lastIndexOf(":")+1); + String d=b.substring(b.lastIndexOf(":")+1)+"-"+c+".jar"; + String e=b.substring(0, a.lastIndexOf(":")); + String f=e.replace(".","/"); + String g=f.replace(":","/"); + return api+g+"/"+c+"/"+d; + } + + + + + //这就是解析version获取libraries数据 + private void VersionLibraries(String json){ + if(json==null){ + mhandler.sendEmptyMessage(3); + //此为无解析数据-重新下载 + return; + }else{ + JSONObject version_json = JSON.parseObject(json); + JSONArray version_libraries = version_json.getJSONArray("libraries"); + libraries=new ArrayList(); + for (int i = 0 ; i < version_libraries.size();i++){ + JSONObject key = (JSONObject)version_libraries.get(i); + JSONObject downloads = (JSONObject)key.get("downloads"); + JSONObject artifact=(JSONObject)downloads.get("artifact"); + if(artifact!=null){ + LibrariesUtil util =new LibrariesUtil(); + util.setname((String)key.get("name")); + util.setpath((String)artifact.get("path")); + util.seturl((String)artifact.get("url")); + util.setsize((int)artifact.get("size")); + util.set(true); + libraries.add(util); + }else{ + /*LibrariesUtil util =new LibrariesUtil(); + util.setname((String)key.get("name")); + util.setpath(""); + util.seturl(""); + util.setsize(0); + util.set(false); + libraries.add(util); + */ + //针对不存在srtifact-不处理 + } + /* + JSONObject downloads = (JSONObject)key.get("downloads"); + JSONObject artifact=(JSONObject)downloads.get("artifact"); + if(artifact!=null){ + util.setpath((String)artifact.get("path")); + util.seturl(((String)artifact.get("url")).replace(APILibraries,Libraries)); + util.setsize((int)artifact.get("size")); + util.set(true); + }else{ + } + get_libraries_list.add(util);*/ + } + mhandler.sendEmptyMessage(4); + } + } + //同上 + public void VersionAssets(String json){ + if(json==null){ + mhandler.sendEmptyMessage(2); + return; + } + try { + //String json= ReadString("/sdcard/assets.json"); + JSONObject assetindex=JSON.parseObject(json); + JSONObject objects= assetindex.getJSONObject("objects"); + String turn_txt=objects.toJSONString(); + Gson gson = new Gson(); + Map map = gson.fromJson(turn_txt,new TypeToken>() {}.getType()); + assets=new ArrayList(); + for (Map.Entry entry : map.entrySet()) { + //System.out.println("key= " + + " and value= " + ); + AssetsUtil util=new AssetsUtil(); + util.setname(entry.getKey()); + util.sethash(entry.getValue().gethash()); + util.setsize(entry.getValue().getsize()); + util.set(true); + assets.add(util); + } + } catch (Exception e) { + //e.toString(); + //建议重载 + setText(e.toString()); + } + } + private String Path_name(String path){ + return path.substring(path.lastIndexOf("/")+1); + } + private String Path(String path){ + return path.substring(0, path.lastIndexOf("/")); + } + + + private void append(String name,int a,int b){ + Message msg = new Message(); + + msg.what =10; + msg.obj=name; + msg.arg1=a; + msg.arg2=b; + mhandler.sendMessage(msg); + setText(name); + + } + private void setText(String a){ + mlist.append(a+"\n"); + } + + + //尺寸 + private String turn_Length(long len){ + if(len<1024){ + return len+"B"; + } + if(len<1024*1024){ + return String.format("%.2f%s",(len/1024.0),"K"); + } + if(len<1024*1024*1024) + return String.format("%.2f%s",(len/(1024*1024.0)),"M"); + return String.format("%.2f%s",(len/(1024*1024*1024.0)),"G"); + } + + private void run_download_libraries(){ + success_libraries=0; + overall_libraries=0; + Temporary=new ArrayList(); + ArrayList unexists_File_Manager=new ArrayList(); + for(LibrariesUtil util:libraries){ + if(util.get()){ + File file=new File(Version_libraries+util.getpath()); + util.setpath(file.getAbsolutePath()); + + util.seturl(Turn_Url(API_Libraries,util.getname())); + + if(file.exists()){ + if(file.isDirectory()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + }else{ + if(file.length()!=util.getsize()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + } + }else{ + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + }else{ + File file=new File(Turn_Path(Version_libraries,util.getname())); + util.setpath(file.getAbsolutePath()); + /* + util.seturl(Turn_Url(APILibraries,util.getname())); + + if(file.exists()){ + if(file.isDirectory()){ + file.delete(); + unexists_File_Manager.add(util); + }else{ + //此为数据缺失 + } + }else{ + unexists_File_Manager.add(util); + }*/ + + } + } + if(unexists_File_Manager.size()>=1){ + libraries_loader_size=unexists_File_Manager.size(); + + Temporary=unexists_File_Manager; + mhandler.sendEmptyMessageDelayed(1000,800); + }else{ + mhandler.sendEmptyMessage(5); + } + } + private void download_status1(boolean status){ + if(status){ + pause_start1.setBackgroundResource(R.drawable.download_pause); + }else{ + pause_start1.setBackgroundResource(R.drawable.download_play); + } + + }private void download_status2(boolean status){ + if(status){ + pause_start2.setBackgroundResource(R.drawable.download_pause); + }else{ + pause_start2.setBackgroundResource(R.drawable.download_play); + } + + }private void download_status3(boolean status){ + if(status){ + pause_start3.setBackgroundResource(R.drawable.download_pause); + }else{ + pause_start3.setBackgroundResource(R.drawable.download_play); + } + + } + + + private void run_download_assets(){ + success_libraries=0; + overall_libraries=0; + Temporary=new ArrayList(); + ArrayList unexists_File_Manager=new ArrayList(); + for(AssetsUtil util:assets){ + if(util.get()){ + File file=new File(Version_assets+"objects/"+util.gethash().substring(0,2)+"/"+util.gethash()); + if(file.exists()){ + if(file.isDirectory()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + }else{ + if(file.length()!=util.getsize()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + } + }else{ + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + } + } + if(unexists_File_Manager.size()>=1){ + assets_loader_size=unexists_File_Manager.size(); + Temporary=unexists_File_Manager; + mhandler.sendEmptyMessageDelayed(2000,800); + }else{ + mhandler.sendEmptyMessage(6); + } + } + + + private void download1(FilePoint f){ + + if(null!=f){ + download_manager_1( + f.getUrl(),//链接 + f.getFilePath(),//路径 + f.getFileName(),//文件名 + f.getA(), + f.getObject(), + f.getSize()); + + //完全移植 + setText("重新下载>"+f.getObject()); + //选择继续or选择新下载 + + } + + } + private void download2(FilePoint f){ + if(null!=f){ + download_manager_2( + f.getUrl(),//链接 + f.getFilePath(),//路径 + f.getFileName(),//文件名 + f.getA(), + f.getObject(), + f.getSize()); + + //完全移植 + setText("重新下载>"+f.getObject()); + //选择继续or选择新下载 + } + + + } + private void download3(FilePoint f){ + if(null!=f){ + download_manager_3( + f.getUrl(),//链接 + f.getFilePath(),//路径 + f.getFileName(),//文件名 + f.getA(), + f.getObject(), + f.getSize()); + + //完全移植 + setText("重新下载>"+f.getObject()); + //选择继续or选择新下载 + } + + + } + private void download_manager_1(//第一个通道 + final String url,//链接 + final String path,//路径 + final String name,//文件名 + final int a, + final Object object, + final int size + ) { + mDownloadManager.add1(url, path, name,a,object, size,new DownloadListner() { + + + @Override + public void onFinished() { + download1=false; + if(a==2000){ + assets_loading_size+=1; + append((String)object,assets_loading_size,assets_loader_size); + }else if(a==1000){ + libraries_loading_size+=1; + + append((String)object,libraries_loading_size,libraries_loader_size); + } + + success_libraries+=size;//共用-针对下载成功的不起作用 + mhandler.sendEmptyMessage(a); + + } + @Override + public void onProgress(float progress, long i, long s) + { + mpath_progress1.setProgress((int) (progress * 100)); + mpath1.setText(object+":"+turn_Length(i) + File.pathSeparatorChar+turn_Length(s)); + + } + @Override + public void onPause() {//暂停 + setText(object+"Pause"); + + } + @Override + public void onCancel() {//取消 + setText(object+"Cancel"); + + } + }); + download1=true; + download_status1(mDownloadManager.download1_stop_start()); + + } + private void download_manager_2(//第一个通道 + final String url,//链接 + final String path,//路径 + final String name,//文件名 + final int a, + final Object object, + final int size + + ) { + mDownloadManager.add2(url, path, name, a, object,size ,new DownloadListner() { + + + + @Override + public void onFinished() { + download2=false; + if(a==2000){ + assets_loading_size+=1; + + append((String)object,assets_loading_size,assets_loader_size); + }else if(a==1000){ + libraries_loading_size+=1; + append((String)object,libraries_loading_size,libraries_loader_size); + } + success_libraries+=size; + + mhandler.sendEmptyMessage(a); + + } + @Override + public void onProgress(float progress, long i, long s) + { + mpath_progress2.setProgress((int) (progress * 100)); + mpath2.setText(object+":"+turn_Length(i) + File.pathSeparatorChar+turn_Length(s)); + + } + @Override + public void onPause() {//暂停 + setText(object+"Pause"); + } + @Override + public void onCancel() {//取消 + setText(object+"Cancel"); + } + }); + download2=true; + download_status2(mDownloadManager.download2_stop_start()); + + + } + private void download_manager_3(//第一个通道 + final String url,//链接 + final String path,//路径 + final String name,//文件名 + final int a, + final Object object, + final int size + ) { + mDownloadManager.add3(url, path, name,a,object,size, new DownloadListner() { + + + + @Override + public void onFinished() { + download3=false; + if(a==2000){ + assets_loading_size+=1; + + append((String)object,assets_loading_size,assets_loader_size); + }else if(a==1000){ + libraries_loading_size+=1; + append((String)object,libraries_loading_size,libraries_loader_size); + } + success_libraries+=size; + + mhandler.sendEmptyMessage(a); + } + @Override + public void onProgress(float progress, long i, long s) + { + mpath_progress3.setProgress((int) (progress * 100)); + mpath3.setText(object+":"+turn_Length(i) + File.pathSeparatorChar+turn_Length(s)); + + } + @Override + public void onPause() {//暂停 + setText(object+"Pause"); + } + @Override + public void onCancel() {//取消 + setText(object+"Cancel"); + } + }); + download3=true; + download_status3(mDownloadManager.download3_stop_start()); + + } + private void setlibraries(){ + //overall_progress.setText(getResources().getString(R.string.total)+libraries_loading_size+"/"+libraries_loader_size); + stages_progress.setText(turn_Length(success_libraries)+File.pathSeparatorChar+turn_Length(overall_libraries)); + } + private void setassets(){ + //overall_progress.setText(getResources().getString(R.string.total)+assets_loading_size+"/"+assets_loader_size); + stages_progress.setText(turn_Length(success_libraries)+File.pathSeparatorChar+turn_Length(overall_libraries)); + + } + private long overall_libraries; + private long success_libraries;//同上-assets共用-迷惑行为 +/* + private NotificationManager manager; + private Notification notif; + + private void Open_notice_Service(){ + + manager = (NotificationManager)getActivity().getSystemService(getActivity().NOTIFICATION_SERVICE); + notif = new Notification(); + notif.icon = R.drawable.java; + notif.tickerText = "新通知"; + //通知栏显示所用到的布局文件 + notif.contentView = new RemoteViews(getActivity().getPackageName(), R.layout.notice); + manager.notify(1, notif); + + }*/ + //不太需要? +} + diff --git a/app/src/main/java/com/mistake/revision/Download/DownloadService.java b/app/src/main/java/com/mistake/revision/Download/DownloadService.java new file mode 100644 index 00000000..b2405137 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/Download/DownloadService.java @@ -0,0 +1,1340 @@ +package com.mistake.revision.Download; + + +import com.download.service.util.Config; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.io.File; +import java.io.BufferedReader; +import java.io.FileReader; +import android.app.*; +import android.os.*; +import android.widget.*; +import com.alibaba.fastjson.*; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Request.Builder; +import com.download.service.util.*; +import com.download.service.*; +import com.download.service.downloader.DownloadManager; +import java.util.*; +import java.io.*; +import android.content.*; +import android.view.*; +import android.graphics.*; +import android.provider.*; +import com.mistake.revision.adapter.*; +import android.view.View.*; +import android.view.WindowManager.*; + +import androidx.annotation.RequiresApi; + +import java.nio.charset.*; +import com.download.service.downloader.*; + +import org.koishi.launcher.h2o2pro.R; + +public class DownloadService extends Service +{ + + //API_version_manifest_json="http://launchermeta.mojang.com/mc/game/version_manifest.json"; + //API_version_manifest_json_bmclapi="https://bmclapi2.bangbang93.com/mc/game/version_manifest.json"; + //API_version_manifest_json_mcbbs="https://download.mcbbs.net/mc/game/version_manifest.json"; + + //"https://launchermeta.mojang.com/"; + //"https://launcher.mojang.com/"; + //bmclapi="https://bmclapi2.bangbang93.com/"; + //mcbbs="https://download.mcbbs.net/"; + + //API_Assets="http://resources.download.minecraft.net/"; + //API:Assets_bmclapi="https://bmclapi2.bangbang93.com/assets/"; + //API_Assets_mcbbs="https://download.mcbbs.net/assets/"; + + //API_Libraries="https://libraries.minecraft.net/"; + //API_Libraries_bmclapi="https://bmclapi2.bangbang93.com/maven/"; + //API:Libraries_mcbbs="https://download.mcbbs.net/maven/"; + + //version_json_server_client_bmclapi="https://bmclapi2.bangbang93.com/version/"; + //version_json_server_client_mcbbs="https://download.mcbbs.net/version/"; + + private DownloadManager mDownloadManager; + + private ArrayListlibraries; + private ArrayListassets; + + + private View base; + + private TextView mlist; + private TextView mpath1,mpath2, mpath3; + private ProgressBar mpath_progress1, mpath_progress2, mpath_progress3; + private TextView overall_progress, stages_progress; + + //private boolean switch_api; + + private TextView title; + private LinearLayout mwindow; + private Button button; + private WindowManager.LayoutParams layoutparams_button; + + private ImageButton close; + private ImageButton pause_start1,pause_start2,pause_start3; +// + private static String Source_address; + private static String + API_Version_client_server_json, + API_Assets, + API_Libraries, + API_Manifest_Version_json; + + private static String + game_directory, + assets_root; + + private static String + Version, + Version_assets, + Version_json, + Version_jar, + //Version_url, + Version_libraries; + + private String assets_id; + + private String Txt; + + + + //某读取文本 + private String ReadString(String sourcePath){ + + StringBuffer sb = new StringBuffer(); + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(sourcePath)); + String str; + while((str = br.readLine()) != null) { + sb.append(str); + sb.append("\r\n"); + } + br.close(); + }catch(Exception e){ + setText(e.toString()); + } + + return sb.toString(); + + } + + + + private boolean download1=false; + private boolean download2=false; + private boolean download3=false; + public static boolean isStarted = false; + private WindowManager windowManager; + private WindowManager.LayoutParams layoutParams; + private ArrayList Temporary; + private int libraries_loader_size=0; + private int libraries_loading_size=0; + private int assets_loader_size=0; + private int assets_loading_size=0; + @RequiresApi(api = Build.VERSION_CODES.M) + @Override + public void onCreate() { + super.onCreate(); + isStarted = true; + windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); + layoutParams = new WindowManager.LayoutParams(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + + } else { + layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; + + } + layoutParams.format = PixelFormat.RGBA_8888; + layoutParams.gravity = Gravity.LEFT | Gravity.TOP; + layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + + int height = windowManager.getDefaultDisplay().getHeight(); + int width = windowManager.getDefaultDisplay().getWidth(); + + if(height>width){ + layoutParams.width = width*9/10; + layoutParams.height = width*8/10; + layoutParams.x = (width/2)-(layoutParams.width/2); + layoutParams.y = (height/2)-(layoutParams.height/2); + }else{ + layoutParams.width = height*9/10; + layoutParams.height = height*8/10; + layoutParams.x = (width/2)-(layoutParams.width/2); + layoutParams.y = (height/2)-(layoutParams.height/2); + } + layoutParams.alpha=0.8f; + mDownloadManager = new DownloadManager(); + + + showWindow(); + Open_notice_Service(); + + //只被调用一次 + + } + @Override + public IBinder onBind(Intent intent) { + return null; + } + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + loading(intent); + return super.onStartCommand(intent, flags, startId); + } + + private void loading(Intent intent) + { + + loading_config( + intent.getExtras().getString("version"), + intent.getExtras().getString("game"), + intent.getExtras().getString("address")); + + + + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private void showWindow() { + if (Settings.canDrawOverlays(this)) { + try{ + LayoutInflater layoutInflater = LayoutInflater.from(this); + base = layoutInflater.inflate(R.layout.download, null); + mpath1=(TextView)basefindViewById(R.id.downloadTextView1); + mpath2=(TextView)basefindViewById(R.id.downloadTextView2); + mpath3=(TextView)basefindViewById(R.id.downloadTextView3); + mpath_progress1=(ProgressBar)base.findViewById(R.id.downloadProgressBar1); + mpath_progress2=(ProgressBar)base.findViewById(R.id.downloadProgressBar2); + mpath_progress3=(ProgressBar)base.findViewById(R.id.downloadProgressBar3); + overall_progress=(TextView)basefindViewById(R.id.downloadTextView4); + stages_progress=(TextView)basefindViewById(R.id.downloadTextView5); + mlist=(TextView)basefindViewById(R.id.downloadTextView6); + //title=(TextView)basefindViewById(R.id.downloadTextView7); + close=(ImageButton)base.findViewById(R.id.downloadImageButton1); + pause_start1=(ImageButton)base.findViewById(R.id.downloadImageButton2); + pause_start2=(ImageButton)base.findViewById(R.id.downloadImageButton3); + pause_start3=(ImageButton)base.findViewById(R.id.downloadImageButton4); + + + + + + close.setOnClickListener(onclick); + pause_start1.setOnClickListener(onclick); + pause_start2.setOnClickListener(onclick); + pause_start3.setOnClickListener(onclick); + + + + mwindow=(LinearLayout)base.findViewById(R.id.downloadLinearLayout1); + mwindow.setOnTouchListener(window); + button=new Button(this); + button.setBackgroundResource(R.drawable.ic_h2o2_low_px); + button.setVisibility(View.GONE); + layoutparams_button=new WindowManager.LayoutParams(); + layoutparams_button.copyFrom(layoutParams); + layoutparams_button.width=64; + layoutparams_button.height=64; + button.setOnTouchListener(window); + button.setOnClickListener(onclick); + windowManager.addView(button,layoutparams_button); + windowManager.addView(base,layoutParams); + + + + mpath_progress1.setProgress(0); + mpath_progress2.setProgress(0); + mpath_progress3.setProgress(0); + mpath1.setText(""); + mpath2.setText(""); + mpath3.setText(""); + + + + + + }catch(Exception e){ + Toast.makeText(this,e.toString(),Toast.LENGTH_SHORT).show(); + + + + } + } + } + + public void loading_config(String version,String homepath,String address){ + + + + //Version = "1.7.10";//下载版本--->manifest_version_json + //game_directory = "/storage/emulated/0/boat/gamedir";//主游戏目录->结尾不带"/" + //Source_address = "https://download.mcbbs.net";//需要提供的源->结尾不带"/" + Version = version;//下载版本--->manifest_version_json + game_directory = homepath;//主游戏目录->结尾不带"/" + Source_address = address;//需要提供的源->结尾不带"/" + + + API_Version_client_server_json = Source_address + "/version/"; + API_Assets = Source_address + "/assets/"; + API_Libraries = Source_address + "/maven/"; + API_Manifest_Version_json = Source_address + "/mc/game/version_manifest.json"; + + assets_root = game_directory+"/assets"; + Version_jar = game_directory+"/versions/"+Version+"/"+ Version+".jar"; + Version_json = game_directory+"/versions/"+Version+"/"+ Version+".json"; + //Version_url=url; + Version_libraries = game_directory+"/libraries/"; + Version_assets = assets_root+"/"; + + + //如何终结 + + + + /*{ + "assets_root":"/storage/emulated/0/boat/gamedir/assets", + "auth_access_token":"0", + "auth_player_name":"Steve", + "auth_session":"0", + "auth_uuid":"00000000-0000-0000-0000-000000000000", + "currentVersion":"/storage/emulated/0/boat/gamedir/versions/1.7.10", + "extraJavaFlags":"-server -Xms500M -Xmx500M", + "extraMinecraftFlags":"", + "game_assets":"/storage/emulated/0/boat/gamedir/assets/virtual/legacy", + "game_directory":"/storage/emulated/0/boat/gamedir", + "home":"/storage/emulated/0/boat", + "runtimePath":"/data/user/0/cosine.boat/app_runtime/32", + "user_properties":"{}", + "user_type":"mojang" + }*/ + + + + mhandler.sendEmptyMessage(0); + + } + + + + + + private View.OnTouchListener window= new View.OnTouchListener(){ + + private int x; + private int y; + private long Time1; + private int movedX=0; + private int movedY=0; + private long Time2; + + @Override + public boolean onTouch(View v, MotionEvent event) + { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + x = (int) event.getRawX(); + y = (int) event.getRawY(); + Time1 = System.currentTimeMillis(); + break; + case MotionEvent.ACTION_MOVE: + int nowX = (int) event.getRawX(); + int nowY = (int) event.getRawY(); + movedX = nowX - x; + movedY = nowY - y; + Time2 = System.currentTimeMillis() - Time1; + x = nowX; + y = nowY; + layoutParams.x = layoutParams.x + movedX; + layoutParams.y = layoutParams.y + movedY; + windowManager.updateViewLayout(base, layoutParams); + layoutparams_button.x = layoutparams_button.x + movedX; + layoutparams_button.y = layoutparams_button.y + movedY; + windowManager.updateViewLayout(button, layoutparams_button); + + break; + case MotionEvent.ACTION_UP: + if(Time2<100){ + + } + + break; + } + return false; + } + }; + private View.OnClickListener onclick=new View.OnClickListener(){ + + @Override + public void onClick(View p1) + { + if(p1==close){ + base.setVisibility(View.GONE); + button.setVisibility(View.VISIBLE); + + + }else if(p1==pause_start1){ + + download1(mDownloadManager.Self_destruction1()); + + + + }else if(p1==pause_start2){ + + download2(mDownloadManager.Self_destruction2()); + + }else if(p1==pause_start3){ + + download3(mDownloadManager.Self_destruction3()); + + + + + } + + else if(p1==button){ + base.setVisibility(View.VISIBLE); + button.setVisibility(View.GONE); + + } + + } + }; + + + private TextView basefindViewById(int id){ + TextView a=base.findViewById(id); + a.setTextColor(Color.GRAY); + return a; + } + + + private void append(String name,int a,int b){ + Message msg = new Message(); + + msg.what =10; + msg.obj=name; + msg.arg1=a; + msg.arg2=b; + mhandler.sendMessage(msg); + setText(name); + + } + private void setText(String a){ + mlist.append(a+"\n"); + } + private String turn_Length(long len){ + if(len<1024){ + return len+"B"; + } + if(len<1024*1024){ + return String.format("%.2f%s",(len/1024.0),"K"); + } + if(len<1024*1024*1024) + return String.format("%.2f%s",(len/(1024*1024.0)),"M"); + return String.format("%.2f%s",(len/(1024*1024*1024.0)),"G"); + } + + private void run_download_libraries(){ + success_libraries=0; + overall_libraries=0; + Temporary=new ArrayList(); + ArrayList unexists_File_Manager=new ArrayList(); + for(LibrariesUtil util:libraries){ + if(util.get()){ + File file=new File(Version_libraries+util.getpath()); + util.setpath(file.getAbsolutePath()); + + util.seturl(Turn_Url(API_Libraries,util.getname())); + + if(file.exists()){ + if(file.isDirectory()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + }else{ + if(file.length()!=util.getsize()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + } + }else{ + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + }else{ + /*File file=new File(Turn_Path(Version_libraries,util.getname())); + util.setpath(file.getAbsolutePath()); + if(switch_api){ + util.seturl(Turn_Url(APILibraries_bmclapi,util.getname())); + }else{ + util.seturl(Turn_Url(APILibraries,util.getname())); + } + if(file.exists()){ + if(file.isDirectory()){ + file.delete(); + unexists_File_Manager.add(util); + }else{ + //此为数据缺失 + } + }else{ + unexists_File_Manager.add(util); + }*/ + + } + } + if(unexists_File_Manager.size()>=1){ + libraries_loader_size=unexists_File_Manager.size(); + + Temporary=unexists_File_Manager; + mhandler.sendEmptyMessageDelayed(1000,800); + }else{ + mhandler.sendEmptyMessage(5); + } + } + private void download_status1(boolean status){ + if(status){ + pause_start1.setBackgroundResource(R.drawable.download_pause); + }else{ + pause_start1.setBackgroundResource(R.drawable.download_play); + } + + }private void download_status2(boolean status){ + if(status){ + pause_start2.setBackgroundResource(R.drawable.download_pause); + }else{ + pause_start2.setBackgroundResource(R.drawable.download_play); + } + + }private void download_status3(boolean status){ + if(status){ + pause_start3.setBackgroundResource(R.drawable.download_pause); + }else{ + pause_start3.setBackgroundResource(R.drawable.download_play); + } + + } + + + private void run_download_assets(){ + success_libraries=0; + overall_libraries=0; + Temporary=new ArrayList(); + ArrayList unexists_File_Manager=new ArrayList(); + for(AssetsUtil util:assets){ + if(util.get()){ + File file=new File(Version_assets+"objects/"+util.gethash().substring(0,2)+"/"+util.gethash()); + if(file.exists()){ + if(file.isDirectory()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + }else{ + if(file.length()!=util.getsize()){ + file.delete(); + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + } + }else{ + unexists_File_Manager.add(util); + overall_libraries+=util.getsize(); + } + } + } + if(unexists_File_Manager.size()>=1){ + assets_loader_size=unexists_File_Manager.size(); + Temporary=unexists_File_Manager; + mhandler.sendEmptyMessageDelayed(2000,800); + }else{ + mhandler.sendEmptyMessage(6); + } + } + + + private void download1(FilePoint f){ + + if(null!=f){ + download_manager_1( + f.getUrl(),//链接 + f.getFilePath(),//路径 + f.getFileName(),//文件名 + f.getA(), + f.getObject(), + f.getSize()); + + //完全移植 + setText("重新下载>"+f.getObject()); + //选择继续or选择新下载 + + } + + } + private void download2(FilePoint f){ + if(null!=f){ + download_manager_2( + f.getUrl(),//链接 + f.getFilePath(),//路径 + f.getFileName(),//文件名 + f.getA(), + f.getObject(), + f.getSize()); + + //完全移植 + setText("重新下载>"+f.getObject()); + //选择继续or选择新下载 + } + + + } + private void download3(FilePoint f){ + if(null!=f){ + download_manager_3( + f.getUrl(),//链接 + f.getFilePath(),//路径 + f.getFileName(),//文件名 + f.getA(), + f.getObject(), + f.getSize()); + + //完全移植 + setText("重新下载>"+f.getObject()); + //选择继续or选择新下载 + } + + + } + private void download_manager_1(//第一个通道 + final String url,//链接 + final String path,//路径 + final String name,//文件名 + final int a, + final Object object, + final int size + ) { + mDownloadManager.add1(url, path, name,a,object, size,new DownloadListner() { + + + @Override + public void onFinished() { + download1=false; + if(a==2000){ + assets_loading_size+=1; + append((String)object,assets_loading_size,assets_loader_size); + }else if(a==1000){ + libraries_loading_size+=1; + + append((String)object,libraries_loading_size,libraries_loader_size); + } + + success_libraries+=size; + mhandler.sendEmptyMessage(a); + + } + @Override + public void onProgress(float progress, long i, long s) + { + mpath_progress1.setProgress((int) (progress * 100)); + mpath1.setText(object+":"+turn_Length(i) + File.pathSeparatorChar+turn_Length(s)); + + } + @Override + public void onPause() {//暂停 + setText(object+"Pause"); + + } + @Override + public void onCancel() {//取消 + setText(object+"Cancel"); + + } + }); + download1=true; + download_status1(mDownloadManager.download1_stop_start()); + + } + private void download_manager_2(//第一个通道 + final String url,//链接 + final String path,//路径 + final String name,//文件名 + final int a, + final Object object, + final int size + + ) { + mDownloadManager.add2(url, path, name, a, object,size ,new DownloadListner() { + + + + @Override + public void onFinished() { + download2=false; + if(a==2000){ + assets_loading_size+=1; + + append((String)object,assets_loading_size,assets_loader_size); + }else if(a==1000){ + libraries_loading_size+=1; + append((String)object,libraries_loading_size,libraries_loader_size); + } + success_libraries+=size; + + mhandler.sendEmptyMessage(a); + + } + @Override + public void onProgress(float progress, long i, long s) + { + mpath_progress2.setProgress((int) (progress * 100)); + mpath2.setText(object+":"+turn_Length(i) + File.pathSeparatorChar+turn_Length(s)); + + } + @Override + public void onPause() {//暂停 + setText(object+"Pause"); + } + @Override + public void onCancel() {//取消 + setText(object+"Cancel"); + } + }); + download2=true; + download_status2(mDownloadManager.download2_stop_start()); + + + } + private void download_manager_3(//第一个通道 + final String url,//链接 + final String path,//路径 + final String name,//文件名 + final int a, + final Object object, + final int size + ) { + mDownloadManager.add3(url, path, name,a,object,size, new DownloadListner() { + + + + @Override + public void onFinished() { + download3=false; + if(a==2000){ + assets_loading_size+=1; + + append((String)object,assets_loading_size,assets_loader_size); + }else if(a==1000){ + libraries_loading_size+=1; + append((String)object,libraries_loading_size,libraries_loader_size); + } + success_libraries+=size; + + mhandler.sendEmptyMessage(a); + } + @Override + public void onProgress(float progress, long i, long s) + { + mpath_progress3.setProgress((int) (progress * 100)); + mpath3.setText(object+":"+turn_Length(i) + File.pathSeparatorChar+turn_Length(s)); + + } + @Override + public void onPause() {//暂停 + setText(object+"Pause"); + } + @Override + public void onCancel() {//取消 + setText(object+"Cancel"); + } + }); + download3=true; + download_status3(mDownloadManager.download3_stop_start()); + + } + private void setlibraries(){ + overall_progress.setText(getResources().getString(R.string.total)+libraries_loading_size+"/"+libraries_loader_size); + stages_progress.setText(turn_Length(success_libraries)+File.pathSeparatorChar+turn_Length(overall_libraries)); + } + private void setassets(){ + overall_progress.setText(getResources().getString(R.string.total)+assets_loading_size+"/"+assets_loader_size); + stages_progress.setText(turn_Length(success_libraries)+File.pathSeparatorChar+turn_Length(overall_libraries)); + + } + private long overall_libraries; + private long success_libraries; + + private NotificationManager manager; + private Notification notif; + + + + + private void Open_notice_Service(){ + + manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + notif = new Notification(); + notif.icon = R.drawable.java; + notif.tickerText = "新通知"; + //通知栏显示所用到的布局文件 + notif.contentView = new RemoteViews(getPackageName(), R.layout.notice); + manager.notify(1, notif); + + } + + + public Handler mhandler=new Handler(){ + @Override + public void handleMessage(Message msg) { + switch(msg.what){ + case 1000: + if(Temporary.size()>=1){ + if(!download1){ + mhandler.sendEmptyMessage(101); + setlibraries(); + }else{ + if(!download2){ + mhandler.sendEmptyMessage(101); + setlibraries(); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + setlibraries(); + }else{ + + } + } + } + }else{ + setlibraries(); + Message msg1=new Message(); + msg1.what=8; + msg1.arg1=5; + mhandler.sendMessage(msg1); + } + break; + case 2000: + if(Temporary.size()>=1){ + if(!download1){ + mhandler.sendEmptyMessage(101); + setassets(); + }else{ + if(!download2){ + mhandler.sendEmptyMessage(101); + setassets(); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + setassets(); + }else{ + + + } + } + } + }else{ + setassets(); + Message msg2=new Message(); + msg2.what=8; + msg2.arg1=6; + mhandler.sendMessage(msg2); + } + break; + case 0: + + mhandler.sendEmptyMessageAtTime(1, 500); + break; + case 1: + setText("(Download):"+Version+"!"); + Dwonload_Version_json(Version,API_Version_client_server_json+Version+"/json"); + + break; + case 2: + + + + Txt = ReadString(game_directory + "/versions/" + Version + "/" + Version + ".json"); + + + + //String Url=API_Version_client_server_json + Version + "/client"; + Download_client_Assets(Txt); + + + + + + + break; + case 3: + + + + VersionLibraries(Txt); + VersionAssets(ReadString(Version_assets + "indexes/" + assets_id + ".json")); + break; + case 4: + run_download_libraries(); + break; + case 101: + + if(Temporary.get(0)instanceof AssetsUtil){ + + object_turn_assets(API_Assets); + + }else if(Temporary.get(0) instanceof LibrariesUtil){ + object_turn_libraries(); + } + + break; + case 5: + run_download_assets(); + break; + case 6: + /* + for(LibrariesUtil a:libraries){ + append(Turn_Url(APILibraries_bmclapi,a.getname())); + append(Turn_Path(Version_libraries,a.getname())); + }*/ + + mpath_progress1.setProgress(100); + mpath_progress2.setProgress(100); + mpath_progress3.setProgress(100); + mpath1.setText("已完成"+Version+"下载"); + mpath2.setText("已完成"+Version+"下载"); + mpath3.setText("已完成"+Version+"下载"); + append("已完成"+Version+"下载",100,100); + break; + case 8: + if(!download2&&!download3&&!download1){ + mhandler.sendEmptyMessage(3); + } + break; + case 9: + //网页文件无法下载调用 + /*try + { + + msg.obj; + } + catch (IOException e) + { + setText(e.toString()); + }*/ + break; + case 10: + + + + + notif.contentView.setTextViewText(R.id.noticeTextView1,(String)msg.obj); + notif.contentView.setTextViewText(R.id.noticeTextView2,overall_progress.getText().toString()); + notif.contentView.setTextViewText(R.id.noticeTextView3,stages_progress.getText().toString()); + notif.contentView.setProgressBar(R.id.noticeProgressBar1,msg.arg2,msg.arg1 , false); + manager.notify(1, notif); + + + + + break; + } + super.handleMessage(msg); + } + }; + + + /* + private String[] turn(String [] a){ + + }*/ + private void object_turn_libraries() + { + //101101102103201202203 + try{ + ArrayList list=new ArrayList<>(); + if(Temporary.size()>1){ + LibrariesUtil rock=(LibrariesUtil) Temporary.get(0); + String url=rock.geturl(); + String path = Path(rock.getpath()); + String name = Path_name(rock.getpath()); + if (!download1){ + download_manager_1(url,path,name,1000,name,rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((LibrariesUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download2){ + download_manager_2(url,path,name,1000,name,rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((LibrariesUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download1){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download3){ + download_manager_3(url,path,name,1000,name,rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((LibrariesUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + //list2.clear(); + + } + }//true未加载 + } + } + } + }else{ + LibrariesUtil rock=(LibrariesUtil) Temporary.get(0); + String url=rock.geturl(); + String path = Path(rock.getpath()); + String name = Path_name(rock.getpath()); + if(!download1){ + download_manager_1(url,path,name,1000,name,rock.getsize()); + Temporary.remove(0); + }else{ + if(!download2){ + download_manager_2(url,path,name,1000,name,rock.getsize()); + Temporary.remove(0); + }else{ + if(!download3){ + download_manager_3(url,path,name,1000,name,rock.getsize()); + Temporary.remove(0); + }else{ + + } + } + } + } + + }catch(Exception e){ + setText(e.toString()); + } + + } + private void object_turn_assets(String Assets) + { + //10 11 01 10 21 03 2 0 1 20 22 03 + try{ + ArrayList list=new ArrayList<>(); + if(Temporary.size()>1){ + AssetsUtil rock=(AssetsUtil) Temporary.get(0); + String url=Assets+rock.gethash().substring(0,2)+"/"+ rock.gethash(); + String path = Version_assets+"objects/"+rock.gethash().substring(0,2); + String name = rock.gethash(); + if(!download1){ + download_manager_1(url,path,name,2000,rock.getname(),rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((AssetsUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download2){ + download_manager_2(url,path,name,2000,rock.getname(),rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((AssetsUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download1){ + mhandler.sendEmptyMessage(101); + }else{ + + } + }//true未加载 + }else{ + if(!download3){ + download_manager_3(url,path,name,2000,rock.getname(),rock.getsize()); + for (int i = 0; i < Temporary.size(); i++){ + if (i!=0){ + list.add((AssetsUtil)Temporary.get(i)); + } + } + Temporary=(ArrayList)list; + if(!download2){ + mhandler.sendEmptyMessage(101); + }else{ + if(!download3){ + mhandler.sendEmptyMessage(101); + }else{ + //list2.clear(); + } + }//true未加载 + } + } + } + }else if(Temporary.size()==1){ + AssetsUtil rock=(AssetsUtil) Temporary.get(0); + String url=Assets+rock.gethash().substring(0,2)+"/"+ rock.gethash(); + String path = Version_assets+"objects/"+rock.gethash().substring(0,2); + String name = rock.gethash(); + if(!download1){ + download_manager_1(url,path,name,2000,rock.getname(),rock.getsize()); + Temporary.remove(0); + }else{ + if(!download2){ + download_manager_2(url,path,name,2000,rock.getname(),rock.getsize()); + Temporary.remove(0); + }else{ + if(!download3){ + download_manager_3(url,path,name,2000,rock.getname(),rock.getsize()); + Temporary.remove(0); + }else{ + + } + } + } + } + + }catch(Exception e){ + setText(e.toString()); + } + } + private void Dwonload_Version_json(String id, String url){ + File e=new File(Version_json); + if(!e.exists()){ + download_manager_1(url,game_directory+"/versions/"+id,Version+".json",2,"Version->"+Version+"->json",0) ; + }else{ + if(e.isDirectory()){ + e.delete(); + download_manager_1(url,game_directory+"/versions/"+id,Version+".json",2,"Version->"+Version+"->json",0) ; + }else{ + mhandler.sendEmptyMessage(2); + } + } + } + public void Get_okHttp_Response_body_string(String url1,final int msg1) + { + HttpUtil.sendOkHttpRequest(url1, new okhttp3.Callback(){ + @Override + public void onFailure(Call call, final IOException e) { + // + } + @Override + public void onResponse(Call p1, Response p2) throws IOException + { + final String url=p2.body().string(); + new Thread(){ + public void run(){ + Message msg = new Message(); + msg.what = msg1; + msg.obj = url; + + mhandler.sendMessage(msg); + } + }.start(); + } + }); + } + + private void Download_client_Assets(String json){ + try{ + JSONObject objects=JSON.parseObject(json); + JSONObject client= objects.getJSONObject("downloads"); + JSONObject main= client.getJSONObject("client"); + + String Url=(String) main.get("url"); + int size=Integer.valueOf((Integer) main.get("size")); + + + JSONObject assetindex= objects.getJSONObject("assetIndex"); + assets_id=(String)assetindex.get("id"); + String url=((String)assetindex.get("url")); + File version_assetindex=new File(Version_assets+"indexes/"+(String)assetindex.get("id")+".json"); + File version_client=new File(Version_jar); + + + if(!version_client.exists()&&!version_assetindex.exists()){ + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + download_manager_3(url,Version_assets+"indexes",(String)assetindex.get("id")+".json",8,"Version->"+assets_id+"->assets->json",0); + }else if(!version_client.exists()&&version_assetindex.exists()){ + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + }else if(version_client.exists()&&!version_assetindex.exists()){ + download_manager_3(url,Version_assets+"indexes",(String)assetindex.get("id")+".json",8,"Version->"+assets_id+"->assets->json",0); + }else if(version_client.exists()&&version_assetindex.exists()){ + if(version_client.isDirectory()){ + version_client.delete(); + setText("已检测client文件错误!"); + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + }else{ + if(version_client.length()!=(int)main.get("size")){ + version_client.delete(); + setText("已检测client文件错误!"); + download_manager_2(Url,game_directory+"/versions/"+Version,Version+".jar",8,"Version->"+Version+"->jar",size); + }else{ + Message msg=new Message(); + msg.what=8; + msg.arg1=3; + mhandler.sendMessage(msg); + } + } + } + }catch(Exception e){ + setText(e.toString()); + } + + } + //https://bmclapi2.bangbang93.com/version/1.7.10/server client json + private String Turn_Url(String api,String a){ + String b=a.substring(0, a.lastIndexOf(":")); + String c=a.substring(a.lastIndexOf(":")+1); + String d=b.substring(b.lastIndexOf(":")+1)+"-"+c+".jar"; + String e=b.substring(0, a.lastIndexOf(":")); + String f=e.replace(".","/"); + String g=f.replace(":","/"); + return api+g+"/"+c+"/"+d; + } + private String Turn_Path(String api,String a){ + String b=a.substring(0, a.lastIndexOf(":")); + String c=a.substring(a.lastIndexOf(":")+1); + String d=b.substring(b.lastIndexOf(":")+1)+"-"+c+".jar"; + String e=b.substring(0, a.lastIndexOf(":")); + String f=e.replace(".","/"); + String g=f.replace(":","/"); + return api+g+"/"+c+"/"+d; + } + private void VersionLibraries(String json){ + if(json==null){ + mhandler.sendEmptyMessage(3); + return; + }else{ + JSONObject version_json = JSON.parseObject(json); + JSONArray version_libraries = version_json.getJSONArray("libraries"); + libraries=new ArrayList(); + for (int i = 0 ; i < version_libraries.size();i++){ + JSONObject key = (JSONObject)version_libraries.get(i); + JSONObject downloads = (JSONObject)key.get("downloads"); + JSONObject artifact=(JSONObject)downloads.get("artifact"); + if(artifact!=null){ + LibrariesUtil util =new LibrariesUtil(); + util.setname((String)key.get("name")); + util.setpath((String)artifact.get("path")); + util.seturl((String)artifact.get("url")); + util.setsize((int)artifact.get("size")); + util.set(true); + libraries.add(util); + }else{ + /*LibrariesUtil util =new LibrariesUtil(); + util.setname((String)key.get("name")); + util.setpath(""); + util.seturl(""); + util.setsize(0); + util.set(false); + libraries.add(util); + */ + } + /* + JSONObject downloads = (JSONObject)key.get("downloads"); + JSONObject artifact=(JSONObject)downloads.get("artifact"); + if(artifact!=null){ + util.setpath((String)artifact.get("path")); + util.seturl(((String)artifact.get("url")).replace(APILibraries,Libraries)); + util.setsize((int)artifact.get("size")); + util.set(true); + }else{ + } + get_libraries_list.add(util);*/ + } + mhandler.sendEmptyMessage(4); + } + } + public void VersionAssets(String json){ + if(json==null){ + mhandler.sendEmptyMessage(2); + return; + } + try { + //String json= ReadString("/sdcard/assets.json"); + JSONObject assetindex=JSON.parseObject(json); + JSONObject objects= assetindex.getJSONObject("objects"); + String turn_txt=objects.toJSONString(); + Gson gson = new Gson(); + Map map = gson.fromJson(turn_txt,new TypeToken>() {}.getType()); + assets=new ArrayList(); + for (Map.Entry entry : map.entrySet()) { + //System.out.println("key= " + + " and value= " + ); + AssetsUtil util=new AssetsUtil(); + util.setname(entry.getKey()); + util.sethash(entry.getValue().gethash()); + util.setsize(entry.getValue().getsize()); + util.set(true); + assets.add(util); + } + } catch (Exception e) { + //e.toString(); + //建议重载 + setText(e.toString()); + } + } + private String Path_name(String path){ + return path.substring(path.lastIndexOf("/")+1); + } + private String Path(String path){ + return path.substring(0, path.lastIndexOf("/")); + } + + + + + + + +} diff --git a/app/src/main/java/com/mistake/revision/LauncherSettingModel.java b/app/src/main/java/com/mistake/revision/LauncherSettingModel.java new file mode 100644 index 00000000..518a3798 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/LauncherSettingModel.java @@ -0,0 +1,90 @@ +package com.mistake.revision; + +public class LauncherSettingModel { + + public LauncherSettingModel(){ + //默认模板初始化 + super(); + + downloadType = "official"; + + /* + MinecraftParameter = new MinecraftParameter(); + MinecraftParameter.auth_uuid = "00000000-0000-0000-0000-000000000000"; + MinecraftParameter.extraMinecraftFlags = ""; + MinecraftParameter.auth_player_name = "Steve"; + MinecraftParameter.auth_session = "0"; + MinecraftParameter.extraJavaFlags = "-server -Xms850M -Xmx850M"; + MinecraftParameter.home = "/storage/emulated/0/games/com.koishi.launcher/h2o2"; + MinecraftParameter.runtimePath = "/data/user/0/cosine.boat/app_runtime/"; + MinecraftParameter.auth_access_token = "0"; + MinecraftParameter.currentVersion = "/storage/emulated/0/boat/gamedir/versions/"; + MinecraftParameter.game_assets = "/storage/emulated/0/boat/gamedir/assets/virtual/legacy"; + MinecraftParameter.user_type = "mojang"; + MinecraftParameter.game_directory = "/storage/emulated/0/boat/gamedir"; + MinecraftParameter.user_properties = "{}"; + MinecraftParameter.assets_root = "/storage/emulated/0/boat/gamedir/assets"; + */ + + } + + private String downloadType; //下载源:"office"官方 "bmclapi"国内BMCLAPI "mcbbs"国内MCBBS + private MinecraftParameter MinecraftParameter; //Config配置 + + //Config配置 + public class MinecraftParameter { + + private String auth_uuid; + private String extraMinecraftFlags; + private String auth_player_name; + private String auth_session; + private String extraJavaFlags; + private String home; + private String runtimePath; + private String auth_access_token; + private String currentVersion; + private String game_assets; + private String user_type; + private String game_directory; + private String user_properties; + private String assets_root; + + //Getter and Setter + public String getauth_uuid() { return auth_uuid; } + public void setauth_uuid(String auth_uuid) { this.auth_uuid = auth_uuid; } + public String getextraMinecraftFlags() { return extraMinecraftFlags; } + public void setextraMinecraftFlags(String extraMinecraftFlags) { this.extraMinecraftFlags = extraMinecraftFlags; } + public String getauth_player_name() { return auth_player_name; } + public void setauth_player_name(String auth_player_name) { this.auth_player_name = auth_player_name; } + public String getauth_session() { return auth_session; } + public void setauth_session(String auth_session) { this.auth_session = auth_session; } + public String getextraJavaFlags() { return extraJavaFlags; } + public void setextraJavaFlags(String extraJavaFlags) { this.extraJavaFlags = extraJavaFlags; } + public String gethome() { return home; } + public void sethome(String home) { this.home = home; } + public String getruntimePath() { return runtimePath; } + public void setruntimePath(String runtimePath) { this.runtimePath = runtimePath; } + public String getauth_access_token() { return auth_access_token; } + public void setauth_access_token(String auth_access_token) { this.auth_access_token = auth_access_token; } + public String getcurrentVersion() { return currentVersion; } + public void setcurrentVersion(String currentVersion) { this.currentVersion = currentVersion; } + public String getgame_assets() { return game_assets; } + public void setgame_assets(String game_assets) { this.game_assets = game_assets; } + public String getuser_type() { return user_type; } + public void getuser_type(String user_type) { this.user_type = user_type; } + public String getgame_directory() { return game_directory; } + public void setgame_directory(String game_directory) { this.game_directory = game_directory; } + public String getuser_properties() { return user_properties; } + public void setuser_properties(String user_properties) { this.user_properties = user_properties; } + public String getassets_root() { return assets_root; } + public void setassets_root(String assets_root) { this.assets_root = assets_root; } + } + + //Getter and Setter + public String getDownloadType() { return downloadType; } + public void setDownloadType(String downloadType) { this.downloadType = downloadType; } + + public MinecraftParameter getMinecraftParameter() { return MinecraftParameter; } + public void setMinecraftParameter(MinecraftParameter MinecraftParameter) { this.MinecraftParameter = MinecraftParameter; } + +} diff --git a/app/src/main/java/com/mistake/revision/VanillaActivity.java b/app/src/main/java/com/mistake/revision/VanillaActivity.java new file mode 100644 index 00000000..ccdb0fa2 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/VanillaActivity.java @@ -0,0 +1,596 @@ +package com.mistake.revision; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.DataSetObserver; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.provider.Settings; +import android.view.View; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONObject; +import com.download.service.downloader.HttpUtil; +import com.download.service.util.VersionUtil; +import com.mistake.revision.adapter.Version_List_Adpater; +import com.mistake.revision.view.PullListView; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import okhttp3.Call; +import okhttp3.Response; +import com.mistake.revision.Download.DownloadFragment; +import com.google.gson.Gson; +import java.lang.reflect.Type; +import com.google.gson.reflect.TypeToken; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.Objects; + +import android.view.MenuItem; +import android.view.Menu; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; + +import org.koishi.launcher.h2o2pro.HomeActivity; +import org.koishi.launcher.h2o2pro.R; +import org.koishi.launcher.h2o2pro.VersionsActivity; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; + +public class VanillaActivity extends AppCompatActivity +{ + + private LauncherSettingModel settingModel; + + private static final int REQUEST_EXTERNAL_STORAGE = 1; + private static String[] PERMISSIONS_STORAGE = { + "android.permission.READ_EXTERNAL_STORAGE", + "android.permission.WRITE_EXTERNAL_STORAGE" }; + private static final int REQUEST_OVERLAY = 4444; + + private Spinner spDownloadSourceMode; + private String download_source; + + private RadioGroup rgSelect; + private RadioButton rbRelease; + private RadioButton rbSnapshot; + private RadioButton rbOldbeta; + + private PullListView list; + private Version_List_Adpater adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + /* + String sys = GetGameJson.getAppCfg("followSys","true"); + if (sys.equals("true")){ + String getThemeType = GetGameJson.getAppCfg("theme","1"); + if (getThemeType.equals("0")){ + setTheme(R.style.AppTheme_NoActionBar); + } else if (getThemeType.equals("1")){ + setTheme(R.style.AppTheme_NoActionBar); + } else if (getThemeType.equals("2")){ + setTheme(R.style.PurpleTheme_NoActionBar); + } else if (getThemeType.equals("3")){ + setTheme(R.style.OrangeTheme_NoActionBar); + } else if (getThemeType.equals("4")){ + setTheme(R.style.RedTheme_NoActionBar); + } else if (getThemeType.equals("5")){ + setTheme(R.style.GreenTheme_NoActionBar); + } else if (getThemeType.equals("6")) { + setTheme(R.style.PinkTheme_NoActionBar); + } + } else { + String getDarkType = GetGameJson.getAppCfg("darkMode","1"); + if (getDarkType.equals("0")){ + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + String getThemeType = GetGameJson.getAppCfg("theme","1"); + if (getThemeType.equals("0")){ + setTheme(R.style.AppTheme_NoActionBar); + } else if (getThemeType.equals("1")){ + setTheme(R.style.AppTheme_NoActionBar); + } else if (getThemeType.equals("2")){ + setTheme(R.style.PurpleTheme_NoActionBar); + } else if (getThemeType.equals("3")){ + setTheme(R.style.OrangeTheme_NoActionBar); + } else if (getThemeType.equals("4")){ + setTheme(R.style.RedTheme_NoActionBar); + } else if (getThemeType.equals("5")){ + setTheme(R.style.GreenTheme_NoActionBar); + } else if (getThemeType.equals("6")) { + setTheme(R.style.PinkTheme_NoActionBar); + } + } else if (getDarkType.equals("1")){ + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + String getThemeType = GetGameJson.getAppCfg("theme","0"); + Window window = getWindow(); + if (getThemeType.equals("0")){ + setTheme(R.style.AppTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("1")){ + setTheme(R.style.BlueTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("2")){ + setTheme(R.style.PurpleTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("3")){ + setTheme(R.style.OrangeTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("4")){ + setTheme(R.style.RedTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("5")){ + setTheme(R.style.GreenTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("6")) { + setTheme(R.style.PinkTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + } + } + */ + + setContentView(R.layout.activity_download); + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + //getWindow().setStatusBarColor(getResources().getColor(R.color.material_blue_dark)); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + Typeface tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + TextView bigTitle= (TextView) toolbar.getChildAt(0); + bigTitle.setTypeface(tf); + bigTitle.setText("Minecraft"); + + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(v -> { + finish(); + startActivity(new Intent(VanillaActivity.this, HomeActivity.class)); + }); + + verifyStoragePermissions(this);//读写权限获取 + requestOverlayPermission();//悬浮窗权限获取 + //buildJsonData(); + //user(); + + spDownloadSourceMode = (Spinner)findViewById(R.id.sp_download_source_mode); + + rgSelect = (RadioGroup)findViewById(R.id.rg_select); + + rbRelease = (RadioButton)findViewById(R.id.rb_release); + rbSnapshot = (RadioButton)findViewById(R.id.rb_snapshot); + rbOldbeta = (RadioButton)findViewById(R.id.rb_old_beta); + + list =(PullListView)findViewById(R.id.loadingversionFileListView1); + + get("https://launchermeta.mojang.com/mc/game/version_manifest.json"); + rbRelease.setEnabled(false); + rbSnapshot.setEnabled(false); + rbOldbeta.setEnabled(false); + + rgSelect.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + /*if(adapter==null){ + get("https://download.mcbbs.net/mc/game/version_manifest.json"); + }{*/ + switch (checkedId){ + case R.id.rb_release: + adapter.setType(1); + //Toast.makeText(MainActivity.this, checkedId , Toast.LENGTH_SHORT).show(); + break; + case R.id.rb_snapshot: + adapter.setType(0); + break; + case R.id.rb_old_beta: + adapter.setType(2); + break; + default: + break; + } + } + }); + String[] mItems = getResources().getStringArray(R.array.download_source); + ArrayAdapter adapter_source = new ArrayAdapter<>(VanillaActivity.this, + android.R.layout.simple_spinner_dropdown_item, mItems); + spDownloadSourceMode.setAdapter(adapter_source); + spDownloadSourceMode.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + /* + * parent:指示spinner + * view:显示item的空间,这里指TextView + * position:被选中的item的位置 + * id:选中项的id + * */ + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + switch (position){ + case 0: + list.setAdapter(null); + rbRelease.setChecked(true); + rbRelease.setEnabled(false); + rbSnapshot.setEnabled(false); + rbOldbeta.setEnabled(false); + get("https://launchermeta.mojang.com/mc/game/version_manifest.json"); + download_source = "https://launchermeta.mojang.com"; + Toast.makeText(VanillaActivity.this, download_source , Toast.LENGTH_SHORT).show(); + break; + case 1: + list.setAdapter(null); + rbRelease.setChecked(true); + rbRelease.setEnabled(false); + rbSnapshot.setEnabled(false); + rbOldbeta.setEnabled(false); + get("https://download.mcbbs.net/mc/game/version_manifest.json"); + download_source = "https://download.mcbbs.net"; + Toast.makeText(VanillaActivity.this, download_source , Toast.LENGTH_SHORT).show(); + break; + case 2: + list.setAdapter(null); + rbRelease.setChecked(true); + rbRelease.setEnabled(false); + rbSnapshot.setEnabled(false); + rbOldbeta.setEnabled(false); + get("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json"); + download_source = "https://bmclapi2.bangbang93.com"; + Toast.makeText(VanillaActivity.this, download_source , Toast.LENGTH_SHORT).show(); + break; + default: + break; + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_vanilla, menu); + return true; + } + + @Override + public void onBackPressed() { + finish(); + startActivity(new Intent(VanillaActivity.this,HomeActivity.class)); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.download_ref: + if (spDownloadSourceMode.getSelectedItem().toString().equals(getString(R.string.spinner_official))) { + list.setAdapter(null); + rbRelease.setChecked(true); + get("https://launchermeta.mojang.com/mc/game/version_manifest.json"); + download_source = "https://launchermeta.mojang.com"; + //Toast.makeText(MainActivity.this, download_source , Toast.LENGTH_SHORT).show(); + } else if (spDownloadSourceMode.getSelectedItem().toString().equals(getString(R.string.spinner_mcbbs))) { + list.setAdapter(null); + rbRelease.setChecked(true); + get("https://download.mcbbs.net/mc/game/version_manifest.json"); + download_source = "https://download.mcbbs.net"; + //Toast.makeText(MainActivity.this, download_source , Toast.LENGTH_SHORT).show(); + } else if (spDownloadSourceMode.getSelectedItem().toString().equals(getString(R.string.spinner_bmclapi))){ + list.setAdapter(null); + rbRelease.setChecked(true); + get("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json"); + download_source = "https://bmclapi2.bangbang93.com"; + //Toast.makeText(MainActivity.this, download_source , Toast.LENGTH_SHORT).show(); + } + break; + default: + break; + } + return true; + } + + + public void set(String x){ + + Message msg = new Message(); + msg.what = 1; + msg.obj = x; + + mHandler.sendMessage(msg); + } + + private class MyHandler extends Handler{ + @Override + public void handleMessage(Message msg) + { + + switch (msg.what) + { + case 1: + getlist((String)msg.obj); + rbRelease.setEnabled(true); + rbSnapshot.setEnabled(true); + rbOldbeta.setEnabled(true); + break; + default: + break; + } + } + } + + private MyHandler mHandler=new MyHandler(); + + private void getlist(String json) + { + + ArrayList listItems=Online_Version_List(json); + adapter = new Version_List_Adpater(this, listItems,1);//初始化type1 + adapter.registerDataSetObserver(new DataSetObserver() { + @Override + public void onInvalidated() { + + } + }); + + list.setAdapter(adapter); + adapter.setOnItemDepartment(new Version_List_Adpater.OnItemDepartment(){ + + @Override + public void OnItemDepartmentItem(String type) + { + // TODO: Implement this method + } + + @Override + public void OnItemDepartmentItem(String id,String url) + { + + DownloadFragment showDialog = new DownloadFragment(); + Bundle bundle = new Bundle(); + bundle.putString("version",id); + bundle.putString("game",getDir()); + bundle.putString("address",download_source); + showDialog.setArguments(bundle); + showDialog.show(getSupportFragmentManager(),"show"); + + + /* + if(DownloadService.isStarted)return; + Intent i=new Intent(MainActivity.this,DownloadService.class); + Bundle bundle=new Bundle(); + bundle.putString("version",id); + bundle.putString("game","/sdcard/boat/gamedir"); + bundle.putString("address",download_source); + i.putExtras(bundle); + startService(i);*/ + + /* + Intent i=new Intent(MainActivity.this,DownloadService.class); + Bundle bundle=new Bundle(); + bundle.putString("version",id); + bundle.putString("game","/sdcard/boat/gamedir"); + bundle.putString("address",download_source); + i.putExtras(bundle); + startService(i);*/ + + } + }); + } + + public static String getDir() { + try { + FileInputStream in = new FileInputStream("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + org.json.JSONObject json = new org.json.JSONObject(str); + return json.getString("game_directory"); + } catch (Exception e) { + System.out.println(e); + } + return "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"; + } + + private void get(String url){ + HttpUtil.sendOkHttpRequest(url, new okhttp3.Callback(){ + @Override + public void onFailure(Call call, final IOException e) { + + } + @Override + public void onResponse(Call p1, Response p2) throws IOException + { + final String url=p2.body().string(); + new Thread(){ + public void run(){ + set(url); + } + }.start(); + } + }); + } + + public ArrayList Online_Version_List(String json) throws JSONException{ + ArrayList data_list=new ArrayList(); + if(json!=null){ + + JSONObject root = JSON.parseObject(json); + JSONArray branch = root.getJSONArray("versions"); + for (int i = 0 ; i < branch.size();i++){ + VersionUtil util=new VersionUtil(); + JSONObject value = (JSONObject)branch.get(i); + String brach_id = (String)value.get("id"); + String brach_type = (String)value.get("type"); + String brach_url=((String)value.get("url")); + + util.id(brach_id); + util.type(brach_type); + util.url(brach_url); + data_list.add(util); + } + + }else{ + + return null; + } + return data_list; + } + + public static void verifyStoragePermissions(Activity activity) { + + try { + //检测是否有写的权限 + int permission = ActivityCompat.checkSelfPermission(activity, + "android.permission.WRITE_EXTERNAL_STORAGE"); + if (permission != PackageManager.PERMISSION_GRANTED) { + // 没有写的权限,去申请写的权限,会弹出对话框 + ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void requestOverlayPermission() { + //if (Build.VERSION.SDK_INT >= 23) { + //if (!Settings.canDrawOverlays(VanillaActivity.this)) { + //Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + //Uri.parse("package:" + getPackageName())); + //startActivityForResult(intent, REQUEST_OVERLAY); + //} else { + + //} + //} + } + + /* + private void user(){ + LauncherSettingModel a = Read(ReadString("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt").toString()); + if(a!=null){ + settingModel.getMinecraftParameter().setauth_player_name("aaa"); + } + } + */ + + private String ReadString(String sourcePath){ + StringBuffer sb = new StringBuffer(); + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(sourcePath)); + String str; + while((str = br.readLine()) != null) { + sb.append(str); + sb.append("\r\n"); + } + br.close(); + } + catch(Exception e){ + Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + return null; + } + return sb.toString(); + } + + private LauncherSettingModel Read(String json) { + try{ + if(json!=null){ + Gson gson = new Gson(); + //要转化的类型 + //Type导入的是java.lang.reflect.Type的包 + //TypeToken导入的是 com.google.gson.reflect.TypeToken的包 + Type type = new TypeToken() { + }.getType(); + LauncherSettingModel pointList = gson.fromJson(json, type); + return pointList; + }else{ + return null; + } + } + catch(Exception e){ + Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + return null; + } + } + + /* + public void buildJsonData() { + settingModel = new LauncherSettingModel(); + + HashMap arrayMap = new HashMap(); + ArrayList arrayList = new ArrayList(); + arrayMap.put("auth_uuid", settingModel.getMinecraftParameter().getauth_uuid()); + arrayMap.put("extraMinecraftFlags", settingModel.getMinecraftParameter().getextraMinecraftFlags()); + arrayMap.put("auth_session", settingModel.getMinecraftParameter().getauth_session()); + arrayMap.put("home", settingModel.getMinecraftParameter().gethome()); + arrayMap.put("runtimePath", settingModel.getMinecraftParameter().getruntimePath()); + arrayMap.put("auth_access_token", settingModel.getMinecraftParameter().getauth_access_token()); + arrayMap.put("game_assets", settingModel.getMinecraftParameter().getgame_assets()); + arrayMap.put("user_type", settingModel.getMinecraftParameter().getuser_type()); + arrayMap.put("game_directory", settingModel.getMinecraftParameter().getgame_directory()); + arrayMap.put("user_properties", settingModel.getMinecraftParameter().getuser_properties()); + arrayMap.put("assets_root", settingModel.getMinecraftParameter().getassets_root()); + arrayMap.put("auth_player_name", settingModel.getMinecraftParameter().getauth_player_name()); + arrayMap.put("extraJavaFlags", settingModel.getMinecraftParameter().getextraJavaFlags()); + arrayList.add(arrayMap); + + Gson gson = new Gson(); + File file = new File("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + boolean r=false; + if (!file.exists()) { + for (int i = 0; i < arrayList.size(); i++) { + String a = settingModel.getMinecraftParameter().getextraJavaFlags(); + a = gson.toJson(arrayMap); + + settingModel.getMinecraftParameter().setauth_session("aaa");//此为写入Json + try { + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); + //FileWriter bufferedWriter=new FileWriter(new File("/sdcard/boat/config.txt")); + bufferedWriter.write(a); + bufferedWriter.flush(); + bufferedWriter.close(); + r=file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + if(r) { + Toast.makeText(this, "文件创建成功", Toast.LENGTH_SHORT).show(); + } + } + /* String auth_uuid = getPreferences(MODE_PRIVATE).getString("auth_uuid", "00000000-0000-0000-0000-000000000000").toString(); + String extraMinecraftFlags = getPreferences(MODE_PRIVATE).getString("extraMinecraftFlags", "").toString(); + String auth_session = getPreferences(MODE_PRIVATE).getString("auth_session", "0").toString(); + String home = getPreferences(MODE_PRIVATE).getString("home", "/sdcard/boat").toString(); + String runtimePath = getPreferences(MODE_PRIVATE).getString("runtimePath", "/data/user/0/cosine.boat/app_runtime").toString(); + String auth_access_token = getPreferences(MODE_PRIVATE).getString("auth_access_token", "0").toString(); + String game_assets = getPreferences(MODE_PRIVATE).getString("game_assets", "/storage/emulated/0/boat/gamedir/assets/virtual/legacy").toString(); + String user_type = getPreferences(MODE_PRIVATE).getString("user_type", "mojang").toString(); + String game_directory = getPreferences(MODE_PRIVATE).getString("game_directory", "/sdcard/boat/gamedir").toString(); + String user_properties = getPreferences(MODE_PRIVATE).getString("user_properties", "{}").toString(); + String assets_root = getPreferences(MODE_PRIVATE).getString("assets_root", "/sdcard/boat/gamedir/assets").toString(); + String auth_player_name = getPreferences(MODE_PRIVATE).getString("auth_player_name", "steve").toString(); + String extraJavaFlags = getPreferences(MODE_PRIVATE).getString("extraJavaFlags", "450").toString(); + extraJavaFlags = new StringBuffer().append(new StringBuffer().append(new StringBuffer().append(new StringBuffer().append("-client -Xms").append(extraJavaFlags).toString()).append("M -Xmx").toString()).append(extraJavaFlags).toString()).append("M").toString();*/ + //ArrayMap arrayMap = new ArrayMap(); + + //} + //} +} + diff --git a/app/src/main/java/com/mistake/revision/adapter/Version_List_Adpater.java b/app/src/main/java/com/mistake/revision/adapter/Version_List_Adpater.java new file mode 100644 index 00000000..7bc174d6 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/adapter/Version_List_Adpater.java @@ -0,0 +1,165 @@ +package com.mistake.revision.adapter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.database.DataSetObserver; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.*; +import android.widget.RadioGroup.*; +import android.view.*; +import java.lang.reflect.*; +import com.download.service.util.*; +import com.download.service.*; + +import org.koishi.launcher.h2o2pro.R; + +public class Version_List_Adpater extends BaseAdapter { + + protected final Context mContext; + protected final LayoutInflater mInflater; + private List overall; + private Listrelease; + private Listsnapshot; + private Listold_alpha; + private List display; + private Map viewMap = new HashMap(); + public OnItemDepartment listener = null; + public Version_List_Adpater(Context context,List overall ,int type){ + mContext = context; + + this.overall = overall; + display=new ArrayList(); + + release=new ArrayList<>(); + old_alpha=new ArrayList<>(); + snapshot=new ArrayList<>(); + + for(VersionUtil util:overall){ + if(util.type().equals(context.getString(R.string.ver_type_release))){ + release.add(util); + }else if(util.type().equals("snapshot")){ + snapshot.add(util); + }else if(util.type().indexOf("old") != -1){ + old_alpha.add(util); + } + } + if(type==0){ + display= snapshot; + }else if(type==1){ + display= release; + }else if(type==2){ + display= old_alpha; + } + mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + public void setType(int type){ + if(type==0){ + display= snapshot; + }else if(type==1){ + display= release; + }else if(type==2){ + display= old_alpha; + } + + notifyDataSetInvalidated(); + + } + public int getCount() { + return getList().size(); + } + + public Object getItem(int position) { + return getList().get(position); + } + + public long getItemId(int position) { + return position; + } + public boolean hasStableIds() { + + return false; + } + public boolean isEmpty() { + + return false; + } + public int getItemViewType(int arg0) { + + return arg0; + } + public boolean areAllItemsEnabled() { + + return false; + } + public boolean isEnabled(int arg0) { + + return true; + } + public View getView(final int arg0, View arg1, ViewGroup arg2) { + final VersionUtil file = getList().get(arg0); + final String id=file.id().toLowerCase(); + String type=file.type().toLowerCase(); + + + RelativeLayout madapter = this.viewMap.get(arg0); + final ViewHolder viewh; + if (madapter == null) { + madapter = (RelativeLayout) mInflater.inflate(R.layout.version_item, null); + viewh = new ViewHolder(); + viewh.item=(LinearLayout)madapter.findViewById(R.id.download_ver_item); + viewh.idText=(TextView)madapter.findViewById(R.id.id); + viewh.typeText=(TextView)madapter.findViewById(R.id.type); + viewh.item.setOnClickListener(p1 -> listener.OnItemDepartmentItem( + id + , null)); + madapter.setTag(viewh); + } else { + viewh = (ViewHolder) madapter.getTag(); + } + viewh.idText.setText(id); + viewh.typeText.setText(type); + if (type.equals("release")){ + viewh.typeText.setText(R.string.download_release); + } else if (type.equals("snapshot")){ + viewh.typeText.setText(R.string.download_snapshot); + } else { + viewh.typeText.setText(R.string.download_old_beta); + } + viewMap.put(arg0, madapter); + return madapter; + } + class ViewHolder + { + public LinearLayout item; + public TextView idText,typeText; + + } + protected List getList() { + return display; + } + public interface OnItemDepartment{ + public abstract void OnItemDepartmentItem(String type); + public abstract void OnItemDepartmentItem(String id,String url); + + + } + + public void setOnItemDepartment(OnItemDepartment onItemDepartment) { + this.listener = onItemDepartment; + } + +} + diff --git a/app/src/main/java/com/mistake/revision/view/PullListView.java b/app/src/main/java/com/mistake/revision/view/PullListView.java new file mode 100644 index 00000000..e7d75e66 --- /dev/null +++ b/app/src/main/java/com/mistake/revision/view/PullListView.java @@ -0,0 +1,279 @@ +package com.mistake.revision.view; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.widget.ListView; + +public class PullListView extends ListView implements OnTouchListener{ + /**初始可拉动Y轴方向距离*/ + private static final int MAX_Y_OVER_SCROLL_DISTANCE = 100; + + private Context mContext; + + /**实际可上下拉动Y轴上的距离*/ + private int mMaxYOverScrollDistance; + + private float mStartY = -1; + /**开始计算的时候,第一个或者最后一个item是否可见的*/ + private boolean mCalcOnItemVisible = false; + /**是否开始计算*/ + private boolean mStartCalc = false; + + /**用户自定义的OnTouchListener类*/ + private OnTouchListener mTouchListener; + + /**上拉和下拉监听事件*/ + private OnPullListener mPullListener; + + private int mScrollY = 0; + private int mLastMotionY = 0; + private int mDeltaY = 0; + /**是否在进行动画*/ + private boolean mIsAnimationRunning = false; + /**手指是否离开屏幕*/ + private boolean mIsActionUp = false; + /**是否支持显示下拉刷新loading*/ + private boolean mEnableRefreshHeader = false; + /**是否支持加载更多loading*/ + private boolean mEnableLoadingMoreHeader = false; + + private View mDefaultRefreshViewHeader; + private View mDefaultLoadingMore; + + public PullListView(Context context){ + this(context, null); + } + + public PullListView(Context context, AttributeSet attrs) { + this(context, attrs, -1); + } + + public PullListView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mContext = context; + super.setOnTouchListener(this); + initBounceListView(); + } + + + private void initBounceListView(){ + final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); + final float density = metrics.density; + mMaxYOverScrollDistance = (int) (density * MAX_Y_OVER_SCROLL_DISTANCE); + } + + /** + * 覆盖父类的方法,设置OnTouchListener监听对象 + * @param listener 用户自定义的OnTouchListener监听对象 + * */ + public void setOnTouchListener(OnTouchListener listener) { + mTouchListener = listener; + } + + /** + * 设置上拉和下拉监听对象 + * @param listener 上拉和下拉监听对象 + * */ + public void setOnPullListener(OnPullListener listener){ + mPullListener = listener; + } + + public void scrollTo(int x, int y) { + super.scrollTo(x, y); + + mScrollY = y; + } + + /** + * 在滑动的过程中onTouch的ACTION_DOWN事件可能丢失,在这里进行初始值设置 + * */ + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mIsActionUp = false; + resetStatus(); + if(getFirstVisiblePosition() == 0 || (getLastVisiblePosition() == getAdapter().getCount()-1)) { + mStartY = event.getY(); + mStartCalc = true; + mCalcOnItemVisible = true; + }else{ + mStartCalc = false; + mCalcOnItemVisible = false; + } + + mLastMotionY = (int)event.getY(); + break; + default: + break; + } + return super.onInterceptTouchEvent(event); + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + /*用户自定义的触摸监听对象消费了事件,则不执行下面的上拉和下拉功能*/ + if(mTouchListener!=null && mTouchListener.onTouch(v, event)) { + return true; + } + + /*在做动画的时候禁止滑动列表*/ + if(mIsAnimationRunning) { + return true;//需要消费掉事件,否者会出现连续很快下拉或上拉无法回到初始位置的情况 + } + + switch (event.getAction()){ + case MotionEvent.ACTION_DOWN:{ + mIsActionUp = false; + resetStatus(); + if(getFirstVisiblePosition() == 0 || (getLastVisiblePosition() == getAdapter().getCount()-1)) { + mStartY = event.getY(); + mStartCalc = true; + mCalcOnItemVisible = true; + }else{ + mStartCalc = false; + mCalcOnItemVisible = false; + } + + mLastMotionY = (int)event.getY(); + } + case MotionEvent.ACTION_MOVE:{ + if(!mStartCalc && (getFirstVisiblePosition() == 0|| (getLastVisiblePosition() == getAdapter().getCount()-1))) { + mStartCalc = true; + mCalcOnItemVisible = false; + mStartY = event.getY(); + } + + final int y = (int) event.getY(); + mDeltaY = mLastMotionY - y; + mLastMotionY = y; + + if(Math.abs(mScrollY) >= mMaxYOverScrollDistance) { + if(mDeltaY * mScrollY > 0) { + mDeltaY = 0; + } + } + + break; + } + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP:{ + mIsActionUp = true; + float distance = event.getY() - mStartY; + checkIfNeedRefresh(distance); + + startBoundAnimate(); + } + } + + return false; + } + + protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, + boolean clampedY) { + if(mDeltaY == 0 || mIsActionUp) { + return; + } + scrollBy(0, mDeltaY/2); + } + + private void startBoundAnimate() { + mIsAnimationRunning = true; + final int scrollY = mScrollY; + int time = Math.abs(500*scrollY/mMaxYOverScrollDistance); + ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(time);//设置为动态时间 + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + float fraction = animator.getAnimatedFraction(); + scrollTo(0, scrollY - (int) (scrollY * fraction)); + + if((int)fraction == 1) { + scrollTo(0, 0); + resetStatus(); + } + } + }); + animator.start(); + + + + } + + + + + + + + + + + + private void resetStatus() { + mIsAnimationRunning = false; + mStartCalc = false; + mCalcOnItemVisible = false; + } + + /** + * 根据滑动的距离判断是否需要回调上拉或者下拉事件 + * @param distance 滑动的距离 + * */ + private void checkIfNeedRefresh(float distance) { + if(getChildCount() == 0) { + return; + } + if(distance > 0 && getFirstVisiblePosition() == 0) { //下拉 + View view = getChildAt(0); + if(view == null) { + return; + } + + float realDistance = distance; + if(!mCalcOnItemVisible) { + realDistance = realDistance - view.getHeight();//第一个item的高度不计算在内容 + } + if(realDistance > mMaxYOverScrollDistance) { + if(mPullListener != null){ + mPullListener.onPullDown(this); + } + } + } else if(distance < 0 && getLastVisiblePosition() == getAdapter().getCount()-1) {//上拉 + View view = getChildAt(getChildCount()-1); + if(view == null) { + return; + } + + float realDistance = -distance; + if(!mCalcOnItemVisible) { + realDistance = realDistance - view.getHeight();//最后一个item的高度不计算在内容 + } + if(realDistance > mMaxYOverScrollDistance) { + if(mPullListener != null){ + mPullListener.onPullUp(this); + } + } + } + } + + public interface OnPullListener{ + /** + * 下拉 + * */ + void onPullDown(View p); + /** + * 上拉 + * */ + void onPullUp(View p); + } +} + + + diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/HomeActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/HomeActivity.java new file mode 100644 index 00000000..54f2735b --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/HomeActivity.java @@ -0,0 +1,323 @@ +package org.koishi.launcher.h2o2pro; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.view.GravityCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Typeface; +import android.os.Bundle; +import android.os.Handler; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.tabs.TabLayout; + +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.ui.custom.CustomFragment; +import org.koishi.launcher.h2o2pro.ui.custom.FuncFragment; +import org.koishi.launcher.h2o2pro.ui.home.HomeFragment; +import org.koishi.launcher.h2o2pro.ui.install.InstallFragment; +import org.koishi.launcher.h2o2pro.ui.manager.ManagerFragment; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class HomeActivity extends AppCompatActivity { + + private ViewPager viewPager; + private LinearLayout l1,l2,l3,l4; + private FragmentPagerAdapter mPagerAdapter; + private SpannableStringBuilder style; + private TabLayout tabLayout; + private TextView bigTitle; + private Typeface tf; + private Toolbar toolbar; + + private ImageView iv1,iv2,iv3,iv4; + private TextView tv1,tv2,tv3,tv4; + List titles = new ArrayList<>(); + ArrayList< Fragment > fgLists; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home); + toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + bigTitle= (TextView) toolbar.getChildAt(0); + bigTitle.setTypeface(tf); + tabLayout = findViewById(R.id.home_tab); + titles.add("fragment1"); + titles.add("fragment2"); + titles.add("fragment3"); + titles.add("fragment4"); + initView(); + l1 = findViewById(R.id.home_nav_1); + l2 = findViewById(R.id.home_nav_2); + l3 = findViewById(R.id.home_nav_3); + l4 = findViewById(R.id.home_nav_4); + tv1 = findViewById(R.id.tv1); + tv2 = findViewById(R.id.tv2); + tv3 = findViewById(R.id.tv3); + tv4 = findViewById(R.id.tv4); + iv1 = findViewById(R.id.iv1); + iv2 = findViewById(R.id.iv2); + iv3 = findViewById(R.id.iv3); + iv4 = findViewById(R.id.iv4); + iv1.setImageDrawable(getResources().getDrawable(R.drawable.ic_btm_home)); + iv1.setSelected(true); + iv2.setImageDrawable(getResources().getDrawable(R.drawable.ic_btm_install)); + iv3.setImageDrawable(getResources().getDrawable(R.drawable.ic_btm_manager)); + iv4.setImageDrawable(getResources().getDrawable(R.drawable.ic_btm_custom)); + + l1.setOnClickListener(v->{ + viewPager.setCurrentItem(0); + style = new SpannableStringBuilder(getResources().getString(R.string.app_name)); + style.setSpan(new ForegroundColorSpan(getResources().getColor(cosine.boat.R.color.colorPrimary)), 0, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + style.setSpan(new ForegroundColorSpan(getResources().getColor(cosine.boat.R.color.appBlack_ff)), 10, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + bigTitle.setText(style); + iv1.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + iv2.setBackground(getResources().getDrawable(R.color.empty)); + iv3.setBackground(getResources().getDrawable(R.color.empty)); + iv4.setBackground(getResources().getDrawable(R.color.empty)); + }); + l2.setOnClickListener(v->{ + viewPager.setCurrentItem(1); + bigTitle.setText(getResources().getString(R.string.menu_install)); + bigTitle.setTextColor(getResources().getColor(R.color.appBlack_ff)); + iv1.setBackground(getResources().getDrawable(R.color.empty)); + iv2.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + iv3.setBackground(getResources().getDrawable(R.color.empty)); + iv4.setBackground(getResources().getDrawable(R.color.empty)); + }); + l3.setOnClickListener(v->{ + viewPager.setCurrentItem(2); + bigTitle.setText(getResources().getString(R.string.menu_manager)); + bigTitle.setTextColor(getResources().getColor(R.color.appBlack_ff)); + iv1.setBackground(getResources().getDrawable(R.color.empty)); + iv2.setBackground(getResources().getDrawable(R.color.empty)); + iv3.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + iv4.setBackground(getResources().getDrawable(R.color.empty)); + }); + l4.setOnClickListener(v->{ + viewPager.setCurrentItem(3); + bigTitle.setText(getResources().getString(R.string.menu_more)); + bigTitle.setTextColor(getResources().getColor(R.color.appBlack_ff)); + iv1.setBackground(getResources().getDrawable(R.color.empty)); + iv2.setBackground(getResources().getDrawable(R.color.empty)); + iv3.setBackground(getResources().getDrawable(R.color.empty)); + iv4.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + }); + } + + private void initView() { + /** + * viewpager初始化 + */ + viewPager = findViewById(R.id.main_viewpager); + /** + * ViewPager的监听 + */ + setViewPagerListener(); + /** + * fragment相关 + */ + initFragment(); + + //tab.setupWithViewPager(viewPager); + viewPager.setAdapter(mPagerAdapter); //设置适配器 + viewPager.setOffscreenPageLimit(4); //预加载所有页 + viewPager.setCurrentItem(0); + } + + private void initFragment() { + //底部导航栏有几项就有几个Fragment + fgLists = new ArrayList<>(4); + fgLists.add(new HomeFragment()); + fgLists.add(new InstallFragment()); + fgLists.add(new ManagerFragment()); + fgLists.add(new FuncFragment()); + //fgLists.add(new MoreFragment()); + + //设置适配器用于装载Fragment,ViewPager的好朋友 + mPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { + @Override + public Fragment getItem(int position) { + return fgLists.get(position); //得到Fragment + } + + @Override + public int getCount() { + return fgLists.size(); //得到数量 + } + + }; + + viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) { + @Override + public Fragment getItem(int position) { + return fgLists.get(position); + } + + @Override + public int getCount() { + return fgLists.size(); + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + super.destroyItem(container, position, object); + } + + @Nullable + @Override + public CharSequence getPageTitle(int position) { + + return titles.get(position); + } + }); + + tabLayout.setupWithViewPager(viewPager); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @SuppressLint("NonConstantResourceId") + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.action_settings) { + startActivity(new Intent(HomeActivity.this,SettingsActivity.class)); + //this.finish(); + } + /* + if (item.getItemId() == R.id.action_home) { + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> {navigationView.setCheckedItem(R.id.fragment_home); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_home)); + initFragment1(); + },350); + } + if (item.getItemId() == R.id.action_theme) { + drawer.closeDrawer(GravityCompat.START); + showTheme(); + } + + */ + return super.onOptionsItemSelected(item); + } + + //这里有3中滑动过程,我们用点击后就可以 + private void setViewPagerListener() { + viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (position == 0 && positionOffset == 0){ + style = new SpannableStringBuilder(getResources().getString(R.string.app_name)); + style.setSpan(new ForegroundColorSpan(getResources().getColor(cosine.boat.R.color.colorPrimary)), 0, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + style.setSpan(new ForegroundColorSpan(getResources().getColor(cosine.boat.R.color.appBlack_ff)), 10, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + bigTitle.setText(style); + } else if (position == 1){ + } else if (position == 2){ + } else if (position == 3){ + } + } + + @Override + public void onPageSelected(int position) { + //滑动页面后做的事,这里与BottomNavigationView结合,使其与正确page对应 + if (position == 0){ + style = new SpannableStringBuilder(getResources().getString(R.string.app_name)); + style.setSpan(new ForegroundColorSpan(getResources().getColor(cosine.boat.R.color.colorPrimary)), 0, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + style.setSpan(new ForegroundColorSpan(getResources().getColor(cosine.boat.R.color.appBlack_ff)), 10, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + bigTitle.setText(style); + iv1.setSelected(true); + iv2.setSelected(false); + iv3.setSelected(false); + iv4.setSelected(false); + iv1.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + iv2.setBackground(getResources().getDrawable(R.color.empty)); + iv3.setBackground(getResources().getDrawable(R.color.empty)); + iv4.setBackground(getResources().getDrawable(R.color.empty)); + } else if (position == 1){ + bigTitle.setText(getResources().getString(R.string.menu_install)); + bigTitle.setTextColor(getResources().getColor(R.color.appBlack_ff)); + iv1.setSelected(false); + iv2.setSelected(true); + iv3.setSelected(false); + iv4.setSelected(false); + iv1.setBackground(getResources().getDrawable(R.color.empty)); + iv2.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + iv3.setBackground(getResources().getDrawable(R.color.empty)); + iv4.setBackground(getResources().getDrawable(R.color.empty)); + } else if (position == 2){ + bigTitle.setText(getResources().getString(R.string.menu_manager)); + bigTitle.setTextColor(getResources().getColor(R.color.appBlack_ff)); + iv1.setSelected(false); + iv2.setSelected(false); + iv3.setSelected(true); + iv4.setSelected(false); + iv1.setBackground(getResources().getDrawable(R.color.empty)); + iv2.setBackground(getResources().getDrawable(R.color.empty)); + iv3.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + iv4.setBackground(getResources().getDrawable(R.color.empty)); + } else if (position == 3){ + bigTitle.setText(getResources().getString(R.string.menu_more)); + bigTitle.setTextColor(getResources().getColor(R.color.appBlack_ff)); + iv1.setSelected(false); + iv2.setSelected(false); + iv3.setSelected(false); + iv4.setSelected(true); + iv1.setBackground(getResources().getDrawable(R.color.empty)); + iv2.setBackground(getResources().getDrawable(R.color.empty)); + iv3.setBackground(getResources().getDrawable(R.color.empty)); + iv4.setBackground(getResources().getDrawable(R.drawable.ic_btm_selected_bg)); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + }); + } + + @Override + protected void onResume() { + super.onResume(); + //final boolean active = (getApplicationContext().getResources().getConfiguration().uiMode + //& Configuration.UI_MODE_NIGHT_YES)!= 0; + //if (active){ + //initView(); + //} else { + //initView(); + //} + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/koishi/launcher/h2o2/func/InitialActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/InitialActivity.java similarity index 63% rename from app/src/main/java/com/koishi/launcher/h2o2/func/InitialActivity.java rename to app/src/main/java/org/koishi/launcher/h2o2pro/InitialActivity.java index d064eb00..98e4eb2d 100644 --- a/app/src/main/java/com/koishi/launcher/h2o2/func/InitialActivity.java +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/InitialActivity.java @@ -1,48 +1,59 @@ -package com.koishi.launcher.h2o2.func; +package org.koishi.launcher.h2o2pro; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import android.os.Handler; +import android.os.Message; -import com.koishi.launcher.h2o2.R; -import android.view.View; +import androidx.appcompat.app.AppCompatActivity; +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.google.android.material.snackbar.Snackbar; -import android.app.*; -import android.content.*; -import android.widget.*; -import java.io.IOException; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; -import java.util.zip.ZipInputStream; import java.util.zip.ZipEntry; -import java.io.FileOutputStream; -import java.io.FileInputStream; -import android.os.Handler; -import android.os.Message; +import java.util.zip.ZipInputStream; public class InitialActivity extends AppCompatActivity { - + + public ConstraintLayout initial; + + @SuppressLint("HandlerLeak") + Handler han = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + Intent intent1 = new Intent(InitialActivity.this, HomeActivity.class); + intent1.putExtra("fragment", getResources().getString(R.string.menu_home)); + startActivity(intent1); + InitialActivity.this.finish(); + + } + }; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + //setTheme(R.style.Theme_Boat_H2O2_Custom_GREEN); setContentView(R.layout.activity_initial); - - new Thread(new Runnable(){ - @Override - public void run() - { - try { - unZip(InitialActivity.this, "app_runtime.zip", "/data/data/com.koishi.launcher.h2o2"); - han.sendEmptyMessage(0); - } catch (IOException e) { - e.printStackTrace(); - } - - } + initial = findViewById(R.id.initial_view); + new Thread(() -> { + try { + unZip(InitialActivity.this, "app_runtime.zip", "/data/data/org.koishi.launcher.h2o2pro"); + han.sendEmptyMessage(0); + } catch (IOException e) { + Snackbar.make(initial, e.toString(), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } }).start(); } - + private void unZip(Context context, String assetName, String outputDirectory) throws IOException { File file = new File(outputDirectory); if (!file.exists()) { @@ -81,16 +92,5 @@ private void unZip(Context context, String assetName, String outputDirectory) th } zipInputStream.close(); } - Handler han=new Handler(){ - @Override - public void handleMessage(Message msg) - { - super.handleMessage(msg); - Intent intent1=new Intent(InitialActivity.this,LoginActivity.class); - startActivity(intent1); - InitialActivity.this.finish(); - - } - }; - -} + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/InstructionActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/InstructionActivity.java new file mode 100644 index 00000000..ce1939d1 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/InstructionActivity.java @@ -0,0 +1,65 @@ +package org.koishi.launcher.h2o2pro; + +import android.view.Window; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.widget.Toolbar; +import androidx.browser.customtabs.CustomTabsIntent; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.widget.LinearLayout; + +import com.google.android.material.snackbar.Snackbar; +import com.yuan.lib_markdownview.MarkDownFileUtil; +import com.yuan.lib_markdownview.MarkdownWebView; + +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.tool.file.AppExecute; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Objects; + +public class InstructionActivity extends AppCompatActivity { + + public LinearLayout layout; + public MarkdownWebView markdownWebView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_instruction); + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + + Toolbar toolbar = findViewById(R.id.toolbar3); + setSupportActionBar(toolbar); + + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(v -> finish()); + + layout = findViewById(R.id.markdown_layout); + markdownWebView = findViewById(R.id.markdown_view); + + try { + markdownWebView.setText(MarkDownFileUtil.getString("/storage/emulated/0/games/com.koishi.launcher/h2o2/markdown", "info.md")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + } + + public void startBili(View v){ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(InstructionActivity.this, Uri.parse("https://b23.tv/ea3HRj\n")); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/LogcatActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/LogcatActivity.java new file mode 100644 index 00000000..d7e6393f --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/LogcatActivity.java @@ -0,0 +1,256 @@ +package org.koishi.launcher.h2o2pro; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.tabs.TabLayout; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +public class LogcatActivity extends AppCompatActivity { + + public LinearLayout logLay; + public ListView log,log2; + public TabLayout tab; + + //public TextView textList, li; + public List< String > clientTxt() { + //将读出来的一行行数据使用List存储 + String filePath = "/storage/emulated/0/games/com.koishi.launcher/h2o2/client_output.txt"; + + List newList = new ArrayList< String >(); + try { + File file = new File(filePath); + int count = 0;//初始化 key值 + if (file.isFile() && file.exists()) {//文件存在 + InputStreamReader isr = new InputStreamReader(new FileInputStream(file)); + BufferedReader br = new BufferedReader(isr); + String lineTxt = null; + while ((lineTxt = br.readLine()) != null) { + if (!"".equals(lineTxt)) { + String reds = lineTxt.split("\\+")[0]; //java 正则表达式 + newList.add(count, reds); + count++; + } + } + isr.close(); + br.close(); + } else { + Snackbar.make(logLay, "File not found.", Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return newList; + } + + public List< String > appTxt() { + //将读出来的一行行数据使用List存储 + String filePath = "/storage/emulated/0/games/com.koishi.launcher/h2o2/log.txt"; + + List newList = new ArrayList< String >(); + try { + File file = new File(filePath); + int count = 0;//初始化 key值 + if (file.isFile() && file.exists()) {//文件存在 + InputStreamReader isr = new InputStreamReader(new FileInputStream(file)); + BufferedReader br = new BufferedReader(isr); + String lineTxt = null; + while ((lineTxt = br.readLine()) != null) { + if (!"".equals(lineTxt)) { + String reds = lineTxt.split("\\+")[0]; //java 正则表达式 + newList.add(count, reds); + count++; + } + } + isr.close(); + br.close(); + } else { + Snackbar.make(logLay, "File not found.", Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return newList; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_log, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.logf: + initLogs(); + break; + case R.id.loga: + AlertDialog alertDialog1 = new AlertDialog.Builder(LogcatActivity.this) + .setTitle(getResources().getString(R.string.action))//标题 + .setIcon(R.drawable.ic_boat)//图标 + .setMessage("Boat log:\n/storage/emulated/0/games/com.koishi.launcher/h2o2/client_output.txt\nClient log:\n/storage/emulated/0/games/com.koishi.launcher/h2o2/log.txt") + .setNegativeButton("OK", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + } + }) + .create(); + + alertDialog1.show(); + break; + default: + break; + } + return true; + } + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_logcat); + + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + + logLay = findViewById(R.id.log_lay); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(v -> finish()); + + Typeface tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + TextView bigTitle= (TextView) toolbar.getChildAt(0); + bigTitle.setTypeface(tf); + bigTitle.setText(getResources().getString(R.string.log_title)); + + tab = findViewById(R.id.log_tab); + tab.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + + // tab.getPosition() 返回数字,从0开始 + // tab.getText() 返回字符串类型,从0开始 + if (tab.getPosition()==0){ + log(); + } + if (tab.getPosition()==1){ + log2(); + } + } + @Override + public void onTabUnselected(TabLayout.Tab tab) { + + } + @Override + public void onTabReselected(TabLayout.Tab tab) { + + } + }); + initLogs(); + log(); + } + + //textList = (TextView) findViewById(R.id.tl); + //textList.setText("Loading log..."); + //li = (TextView) findViewById(R.id.li); + + //li.setText(" 1"); + //li.setVisibility(View.GONE); + + /* + textList.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + if (s.length() != 0) { + String str = ""; + for (int i = 0; i < textList.getLineCount() + 1; i++) { + li.append(str + " " + (i + 1) + "\n"); + } + li.setText(str); + } + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (s.length() != 0) { + String str = ""; + for (int i = 0; i < textList.getLineCount() + 1; i++) { + li.append(str + " " + (i + 1) + "\n"); + + } + li.setText(str); + } + } + + @Override + public void afterTextChanged(Editable s) { + + } + }); + + */ + + + //new Handler().postDelayed(() -> log(), 500); + + public void log() { + log.setVisibility(View.VISIBLE); + log2.setVisibility(View.GONE); + + } + + public void log2() { + log.setVisibility(View.GONE); + log2.setVisibility(View.VISIBLE); + } + + public void initLogs(){ + log = findViewById(R.id.view_log); + ArrayAdapter< String > adapter = new ArrayAdapter<>(this, R.layout.log_list_item, clientTxt()); + log.setAdapter(adapter); + log2 = findViewById(R.id.view_log2); + ArrayAdapter< String > adapter2 = new ArrayAdapter<>(this, R.layout.log_list_item, appTxt()); + log2.setAdapter(adapter2); + } + + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/LoginActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/LoginActivity.java new file mode 100644 index 00000000..97edc314 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/LoginActivity.java @@ -0,0 +1,14 @@ +package org.koishi.launcher.h2o2pro; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; + +public class LoginActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/MainActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/MainActivity.java new file mode 100644 index 00000000..de6cc6f9 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/MainActivity.java @@ -0,0 +1,520 @@ +package org.koishi.launcher.h2o2pro; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.app.StatusBarManager; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.os.Handler; +import android.view.*; +import android.view.accessibility.AccessibilityEvent; +import android.widget.*; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.widget.Toolbar; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.fragment.app.FragmentTransaction; + +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.navigation.NavigationView; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textview.MaterialTextView; + +import org.json.JSONObject; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.ui.custom.CustomFragment; +import org.koishi.launcher.h2o2pro.ui.home.HomeFragment; +import org.koishi.launcher.h2o2pro.ui.install.InstallFragment; +import org.koishi.launcher.h2o2pro.ui.manager.ManagerFragment; +import org.koishi.launcher.h2o2pro.ui.version.VersionFragment; + +import java.io.FileInputStream; + +public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { + + //private AppBarConfiguration mAppBarConfiguration; + private DrawerLayout drawer; + private Dialog mDialog; + private Toolbar toolbar1; + + private HomeFragment homeFragment; + private Intent intent; + private VersionFragment versionFragment; + private ManagerFragment managerFragment; + private InstallFragment installFragment; + private CustomFragment customFragment; + + //private int mPrevSelectedId; + //private int mSelectedId; + private NavigationView navigationView; + private String fragmentId; + private View dialogBg; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //setTheme(R.style.RedTheme_NoActionBar); + + /* + String sys = GetGameJson.getAppCfg("followSys","true"); + if (sys.equals("true")){ + String getThemeType = GetGameJson.getAppCfg("theme","1"); + if (this.getApplicationContext().getResources().getConfiguration().uiMode==0x21){ + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + Window window = getWindow(); + if (getThemeType.equals("0")){ + setTheme(R.style.AppTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("1")){ + setTheme(R.style.BlueTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("2")){ + setTheme(R.style.PurpleTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("3")){ + setTheme(R.style.OrangeTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("4")){ + setTheme(R.style.RedTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("5")){ + setTheme(R.style.GreenTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("6")) { + setTheme(R.style.PinkTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + } else { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + if (getThemeType.equals("0")){ + setTheme(R.style.AppTheme_NoActionBar); + } else if (getThemeType.equals("1")){ + setTheme(R.style.BlueTheme_NoActionBar); + } else if (getThemeType.equals("2")){ + setTheme(R.style.PurpleTheme_NoActionBar); + } else if (getThemeType.equals("3")){ + setTheme(R.style.OrangeTheme_NoActionBar); + } else if (getThemeType.equals("4")){ + setTheme(R.style.RedTheme_NoActionBar); + } else if (getThemeType.equals("5")){ + setTheme(R.style.GreenTheme_NoActionBar); + } else if (getThemeType.equals("6")) { + setTheme(R.style.PinkTheme_NoActionBar); + } + } + + + } else { + String getDarkType = GetGameJson.getAppCfg("darkMode","1"); + if (getDarkType.equals("0")){ + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + String getThemeType = GetGameJson.getAppCfg("theme","1"); + if (getThemeType.equals("0")){ + setTheme(R.style.AppTheme_NoActionBar); + } else if (getThemeType.equals("1")){ + setTheme(R.style.BlueTheme_NoActionBar); + } else if (getThemeType.equals("2")){ + setTheme(R.style.PurpleTheme_NoActionBar); + } else if (getThemeType.equals("3")){ + setTheme(R.style.OrangeTheme_NoActionBar); + } else if (getThemeType.equals("4")){ + setTheme(R.style.RedTheme_NoActionBar); + } else if (getThemeType.equals("5")){ + setTheme(R.style.GreenTheme_NoActionBar); + } else if (getThemeType.equals("6")) { + setTheme(R.style.PinkTheme_NoActionBar); + } + } else if (getDarkType.equals("1")){ + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + String getThemeType = GetGameJson.getAppCfg("theme","0"); + Window window = getWindow(); + if (getThemeType.equals("0")){ + setTheme(R.style.AppTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("1")){ + setTheme(R.style.BlueTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("2")){ + setTheme(R.style.PurpleTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("3")){ + setTheme(R.style.OrangeTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("4")){ + setTheme(R.style.RedTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("5")){ + setTheme(R.style.GreenTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } else if (getThemeType.equals("6")) { + setTheme(R.style.PinkTheme_NoActionBar); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + } + } + */ + + setContentView(R.layout.activity_main); + + dialogBg = findViewById(R.id.dialog_bg); + + toolbar1 = findViewById(R.id.toolbar); + actionBar(); + navigationView = findViewById(R.id.nav_view); + navigationView.setNavigationItemSelectedListener(this); + + intent = getIntent(); + navigationView.setCheckedItem(R.id.fragment_home); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_home)); + initFragment1(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @SuppressLint("NonConstantResourceId") + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.action_settings) { + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> {navigationView.setCheckedItem(R.id.fragment_custom); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_more)); + initFragment5(); + },350); + } + /* + if (item.getItemId() == R.id.action_home) { + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> {navigationView.setCheckedItem(R.id.fragment_home); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_home)); + initFragment1(); + },350); + } + if (item.getItemId() == R.id.action_theme) { + drawer.closeDrawer(GravityCompat.START); + showTheme(); + } + + */ + return super.onOptionsItemSelected(item); + } + + public void actionBar() { + setSupportActionBar(toolbar1); + drawer = findViewById(R.id.drawer_layout); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar1, R.string.navigation_drawer_open, R.string.navigation_drawer_close); + drawer.setDrawerListener(toggle); + toggle.syncState(); + } + + @SuppressLint("NonConstantResourceId") + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.fragment_home: + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> { + navigationView.setCheckedItem(R.id.fragment_home); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_home)); + initFragment1(); + },350); + + break; + case R.id.fragment_version: + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> { + navigationView.setCheckedItem(R.id.fragment_version); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_ver)); + initFragment2(); + },350); + break; + case R.id.fragment_manager: + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> { + navigationView.setCheckedItem(R.id.fragment_manager); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_manager)); + initFragment3(); + },350); + break; + case R.id.fragment_install: + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> { + navigationView.setCheckedItem(R.id.fragment_install); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_install)); + initFragment4(); + },350); + break; + case R.id.fragment_custom: + drawer.closeDrawer(GravityCompat.START); + new Handler().postDelayed(() -> {navigationView.setCheckedItem(R.id.fragment_custom); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_more)); + initFragment5();},350); + break; + case R.id.activity_terminal: + new Handler().postDelayed(() -> { + startActivity(new Intent(this, TerminalActivity.class)); + },350); + break; + default: + break; + } + return true; + } + + @Override + public void onBackPressed() { + DrawerLayout drawer = findViewById(R.id.drawer_layout); + if (drawer.isDrawerOpen(GravityCompat.START)) { + drawer.closeDrawer(GravityCompat.START); + } else { + if (!getSupportActionBar().getTitle().equals(getResources().getString(R.string.menu_home))) { + navigationView.setCheckedItem(R.id.fragment_home); + getSupportActionBar().setTitle(getResources().getString(R.string.menu_home)); + initFragment1(); + drawer.closeDrawer(GravityCompat.START); + } else { + finish(); + } + } + } + + + @Override + protected void onResume() { + super.onResume(); + if (mDialog != null) { + mDialog.dismiss(); + } else { + + } + + } + + @Override + public void onWindowFocusChanged(boolean hasFocus){ + if (hasFocus){ + dialogBg.setVisibility(View.GONE); + }else{ + dialogBg.setVisibility(View.VISIBLE); + if (mDialog != null) { + mDialog.dismiss(); + } else { + } + } + } + + private void initFragment1() { + //开启事务,fragment的控制是由事务来实现的 + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); + //第一种方式(add),初始化fragment并添加到事务中,如果为null就new一个 + if (homeFragment == null) { + homeFragment = new HomeFragment(); + } + //transaction.replace(R.id.fragment_home, homeFragment); + transaction.replace(R.id.content, homeFragment); + //隐藏所有fragment + //hideFragment(transaction); + //显示需要显示的fragment + //transaction.show(homeFragment); + + //第二种方式(replace),初始化fragment +// if(f1 == null){ +// f1 = new MyFragment("消息"); +// } +// transaction.replace(R.id.main_frame_layout, f1); + + + //提交事务 + transaction.commit(); + } + + private void initFragment2() { + //FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + //transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); + //if (versionFragment == null) { + // versionFragment = new VersionFragment(); + //} + //transaction.replace(R.id.content, versionFragment); + //transaction.commit(); + startActivity(new Intent(MainActivity.this, VersionsActivity.class)); + } + + private void initFragment3() { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); + if (managerFragment == null) { + managerFragment = new ManagerFragment(); + } + transaction.replace(R.id.content, managerFragment); + transaction.commit(); + } + + private void initFragment4() { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); + if (installFragment == null) { + installFragment = new InstallFragment(); + } + transaction.replace(R.id.content, installFragment); + transaction.commit(); + } + + private void initFragment5() { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); + if (customFragment == null) { + customFragment = new CustomFragment(); + } + transaction.replace(R.id.content, customFragment); + transaction.commit(); + } + + public void showTheme() { + mDialog = new BottomSheetDialog(MainActivity.this,R.style.BottomSheetDialogStyle); + View dialogView = MainActivity.this.getLayoutInflater().inflate(R.layout.custom_dialog_theme, null,false); + mDialog.setContentView(dialogView); + //mDialog.getWindow().findViewById(R.id.design_bottom_sheet).setBackgroundColor(Color.TRANSPARENT); + ImageButton defaultButton = dialogView.findViewById(R.id.theme_default); + ImageButton blueButton = dialogView.findViewById(R.id.theme_blue); + ImageButton purpleButton = dialogView.findViewById(R.id.theme_purple); + ImageButton orangeButton = dialogView.findViewById(R.id.theme_orange); + ImageButton redButton = dialogView.findViewById(R.id.theme_red); + ImageButton greenButton = dialogView.findViewById(R.id.theme_green); + ImageButton pinkButton = dialogView.findViewById(R.id.theme_pink); + + String getThemeType = GetGameJson.getAppCfg("theme","1"); + if (getThemeType.equals("0")){ + defaultButton.setEnabled(false); + defaultButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_true)); + } else if (getThemeType.equals("1")){ + blueButton.setEnabled(false); + blueButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_true)); + } else if (getThemeType.equals("2")){ + purpleButton.setEnabled(false); + purpleButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_true)); + } else if (getThemeType.equals("3")){ + orangeButton.setEnabled(false); + orangeButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_true)); + } else if (getThemeType.equals("4")){ + redButton.setEnabled(false); + redButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_true)); + } else if (getThemeType.equals("5")){ + greenButton.setEnabled(false); + greenButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_true)); + } else if (getThemeType.equals("6")) { + pinkButton.setEnabled(false); + pinkButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_true)); + } + + SeekBar sk = dialogView.findViewById(R.id.if_dark); + String dark = GetGameJson.getAppCfg("darkMode","1"); + int dk = Integer.parseInt(dark); + sk.setProgress(dk); + sk.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + /** + * 拖动条停止拖动的时候调用 + */ + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } + /** + * 拖动条开始拖动的时候调用 + */ + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + /** + * 拖动条进度改变的时候调用 + */ + @Override + public void onProgressChanged(SeekBar seekBar, int progress, + boolean fromUser) { + //description.setText("当前进度:"+progress+"%"); + GetGameJson.setAppJson("darkMode",Integer.toString(progress)); + } + }); + + CheckBox cb = dialogView.findViewById(R.id.follow_sys); + String sys = GetGameJson.getAppCfg("followSys","true"); + if (sys.equals("true")) { + sk.setEnabled(false); + cb.setChecked(true); + } else { + sk.setEnabled(true); + cb.setChecked(false); + } + cb.setOnCheckedChangeListener((buttonView, isChecked) -> { + // 判断CheckBox是否被勾选了 + if (cb.isChecked()) {// CheckBox被勾选了 我们就把你的状态保存起来 + sk.setEnabled(false); + GetGameJson.setAppJson("followSys","true"); + } else { + sk.setEnabled(true); + GetGameJson.setAppJson("followSys","false"); + } + + }); + + defaultButton.setOnClickListener(v->{ + GetGameJson.setAppJson("theme","0"); + finish(); + startActivity(new Intent(MainActivity.this,MainActivity.class)); + }); + blueButton.setOnClickListener(v->{ + GetGameJson.setAppJson("theme","1"); + finish(); + startActivity(new Intent(MainActivity.this,MainActivity.class)); + }); + purpleButton.setOnClickListener(v->{ + GetGameJson.setAppJson("theme","2"); + finish(); + startActivity(new Intent(MainActivity.this,MainActivity.class)); + }); + orangeButton.setOnClickListener(v->{ + GetGameJson.setAppJson("theme","3"); + finish(); + startActivity(new Intent(MainActivity.this,MainActivity.class)); + }); + redButton.setOnClickListener(v->{ + GetGameJson.setAppJson("theme","4"); + finish(); + startActivity(new Intent(MainActivity.this,MainActivity.class)); + }); + greenButton.setOnClickListener(v->{ + GetGameJson.setAppJson("theme","5"); + finish(); + startActivity(new Intent(MainActivity.this,MainActivity.class)); + }); + pinkButton.setOnClickListener(v->{ + GetGameJson.setAppJson("theme","6"); + finish(); + startActivity(new Intent(MainActivity.this,MainActivity.class)); + }); + + WindowManager windowManager = MainActivity.this.getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + mDialog.show(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ModsActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ModsActivity.java new file mode 100644 index 00000000..e0c5075b --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ModsActivity.java @@ -0,0 +1,431 @@ +package org.koishi.launcher.h2o2pro; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ClipData; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.button.MaterialButton; +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.switchmaterial.SwitchMaterial; + +import org.koishi.launcher.h2o2pro.tool.GetGameJson; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +import static java.io.File.separator; + +public class ModsActivity extends AppCompatActivity { + + public LinearLayout modv; + public RecyclerView mModRecyclerView; + public String modDir; + + public ModsRecyclerAdapter mModAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_mods); + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + modv = findViewById(R.id.mods_view); + Toolbar toolbar = findViewById(R.id.toolbar); + String load = GetGameJson.getAppCfg("allVerLoad","false"); + if (load.equals("true")){ + toolbar.setTitle(getResources().getString(R.string.menu_mod_single)); + } else { + toolbar.setTitle(getResources().getString(R.string.menu_mod)); + } + setSupportActionBar(toolbar); + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(v -> { + finish(); + }); + Typeface tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + TextView bigTitle= (TextView) toolbar.getChildAt(0); + bigTitle.setTypeface(tf); + bigTitle.setText(getResources().getString(R.string.menu_mod)); + } + + public void start() { + File file=new File(modDir); + if(!file.exists()||!file.isDirectory()) + { + file.mkdir(); + } + Intent intent = new Intent(Intent.ACTION_GET_CONTENT);//意图:文件浏览器 + intent.setType("application/java-archive"); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);//关键!多选参数 + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(intent, 1); + } + + @SuppressLint("NewApi")//minSdkVersion需要在15以上 + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == Activity.RESULT_OK) { + Snackbar.make(modv, getResources().getString(R.string.start_add_mod), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + if (data.getData() != null) { + //单次点击未使用多选的情况 + try { + Uri uri = data.getData(); + //TODO 对获得的uri做解析 + //String path = getPath(getApplicationContext(),uri); + //TODO 对转换得到的真实路径path做相关处理 + String path = uri.getPath(); + path = path.replace("/document/primary:","/storage/emulated/0/"); + System.out.println(path); + String str1 = path; + str1 = str1.substring(str1.lastIndexOf("/")+1,str1.length()); + final String s1 = path; + final String s2 = modDir+"/"+str1; + new Thread(() -> { + copyFile(s1,s2); + han.sendEmptyMessage(0); + }).start(); + //dirresult.setText(path); + } catch (Exception e) { + } + } else { + //长按使用多选的情况 + ClipData clipData = data.getClipData(); + if (clipData != null) { + List< String > pathList = new ArrayList<>(); + for (int i = 0; i < clipData.getItemCount(); i++) { + ClipData.Item item = clipData.getItemAt(i); + Uri uri = item.getUri(); + //TODO 对获得的uri做解析 + String path = uri.getPath(); + path = path.replace("/document/primary:","/storage/emulated/0/"); + String str1 = path; + str1 = str1.substring(str1.lastIndexOf("/")+1,str1.length()); + final String s1 = path; + final String s2 = modDir+"/"+str1; + new Thread(() -> { + copyFile(s1,s2); + han.sendEmptyMessage(0); + }).start(); + pathList.add(path); + //pathList.add(uri.toString()); + } + //TODO 对转换得到的真实路径path做相关处理 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < pathList.size(); i++) { + if (i == pathList.size() - 1) { + sb.append(pathList.get(i)); + } else { + sb.append(pathList.get(i)); + sb.append(separator); + } + } + //dirresult.setText(sb.toString()); + System.out.println(pathList); + } + } + } + initMods(); + } + + class ModsRecyclerAdapter extends RecyclerView.Adapter< ModsActivity.ModsRecyclerAdapter.MyModViewHolder>{ + private List datas; + private LayoutInflater inflater; + public ModsRecyclerAdapter(Context context, List datas){ + inflater=LayoutInflater.from(context); + this.datas=datas; + } + //创建每一行的View 用RecyclerView.ViewHolder包装 + @Override + public ModsActivity.ModsRecyclerAdapter.MyModViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView=inflater.inflate(R.layout.mod_local_item,null); + return new MyModViewHolder(itemView); + } + //给每一行View填充数据 + @SuppressLint("UseCompatLoadingForDrawables") + @Override + public void onBindViewHolder(ModsActivity.ModsRecyclerAdapter.MyModViewHolder holder, @SuppressLint("RecyclerView") int position) { + holder.textview.setText(datas.get(position)); + if (!datas.get(position).endsWith(".jar")&&!datas.get(position).endsWith(".jar.disabled")){ + holder.icon.setImageDrawable(getResources().getDrawable(R.drawable.xicon_red)); + holder.rl.setEnabled(false); + } + if(datas.get(position).endsWith(".jar")) { + holder.tog.setChecked(true); + String s = datas.get(position); + s = s.substring(0, s.length() - 4); + holder.textview.setText(s); + } else if (datas.get(position).endsWith(".jar.disabled")){ + holder.tog.setChecked(false); + String s = datas.get(position); + s = s.substring(0, s.length() - 13); + holder.textview.setText(s); + } else { + holder.tog.setVisibility(View.GONE); + } + + holder.tog.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (holder.tog.isChecked()){ + String s = datas.get(position); + s = s.substring(0, s.length() - 9); + final String a = s; + renameFile(modDir+"/"+datas.get(position),modDir+"/"+a); + //new Handler().postDelayed(() -> initMods(), 400); + if (mModRecyclerView.isComputingLayout()) { + mModRecyclerView.post(new Runnable() { + @Override + public void run() { + datas.set(position,a); + mModAdapter.notifyItemChanged(position); + notifyItemChanged(holder.getAdapterPosition()); + } + }); + } + + } else { + String s = datas.get(position); + renameFile(modDir+"/"+s,modDir+"/"+s+".disabled"); + //new Handler().postDelayed(() -> initMods(), 400); + final String a = s + ".disabled"; + if (mModRecyclerView.isComputingLayout()) { + mModRecyclerView.post(new Runnable() { + @Override + public void run() { + datas.set(position,a); + mModAdapter.notifyItemChanged(position); + notifyItemChanged(holder.getAdapterPosition()); + } + }); + } + } + + }); + + holder.rl.setOnClickListener(v->{ + if (holder.tog.isChecked()){ + holder.tog.setChecked(false); + } else { + holder.tog.setChecked(true); + } + }); + holder.btn.setOnClickListener(v->{ + AlertDialog alertDialog1 = new AlertDialog.Builder(ModsActivity.this) + .setTitle(getResources().getString(R.string.action))//标题 + .setIcon(R.drawable.ic_boat)//图标 + .setMessage(R.string.ver_if_del) + .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @SuppressLint("UseCompatLoadingForDrawables") + @Override + public void onClick(DialogInterface dialogInterface, int i) { + String publicDir = modDir+"/"+datas.get(position); + File f = new File(publicDir); + holder.icon.setImageDrawable(getResources().getDrawable(R.drawable.xicon_red)); + holder.tog.setVisibility(View.GONE); + holder.btn.setVisibility(View.INVISIBLE); + holder.textview.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); + holder.rl.setEnabled(false); + //TODO + new Thread(() -> { + //String file2= "/data/data/com.koishi.launcher.h2o2/app_runtime"; + if (f.isDirectory()){ + deleteDirWihtFile(f); + }else { + deleteFile(publicDir); + } + han.sendEmptyMessage(2); + }).start(); + + } + }) + .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + } + }) + .create(); + + alertDialog1.show(); + }); + } + //数据源的数量 + @Override + public int getItemCount() { + return datas.size(); + } + class MyModViewHolder extends RecyclerView.ViewHolder{ + private TextView textview; + private MaterialButton btn; + private LinearLayout rl; + private ImageView icon; + private SwitchMaterial tog; + + public MyModViewHolder(View itemView) { + super(itemView); + textview = itemView.findViewById(R.id.ver_name); + btn = itemView.findViewById(R.id.ver_remove); + rl = itemView.findViewById(R.id.ver_item); + icon = itemView.findViewById(R.id.mod_icon); + tog = itemView.findViewById(R.id.mod_toggle); + } + } + + public void deleteDirWihtFile(File dir) { + if (dir == null || !dir.exists() || !dir.isDirectory()) + return; + for (File file : dir.listFiles()) { + if (file.isFile()) + file.delete(); // 删除所有文件 + else if (file.isDirectory()) + deleteDirWihtFile(file); // 递规的方式删除文件夹 + } + dir.delete();// 删除目录本身 + } + + public boolean deleteFile(String filePath) { + File file = new File(filePath); + if (file.isFile() && file.exists()) { + return file.delete(); + } + return false; + } + + public void renameFile(String oldPath, String newPath) { + File oleFile = new File(oldPath); + File newFile = new File(newPath); + //执行重命名 + oleFile.renameTo(newFile); + } + } + + @SuppressLint("HandlerLeak") + Handler han = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + initMods(); + } + if (msg.what == 2) { + //mModRecyclerView.setAdapter(null); + //initMods(); + //Snackbar.make(page, getResources().getString(R.string.ver_add_done), Snackbar.LENGTH_LONG) + //.setAction("Action", null).show(); + } + + } + }; + + public void initMods(){ + File modList = new File(modDir); + if (modList.isDirectory() && modList.exists()) { + Comparator cp = Collator.getInstance(Locale.CHINA); + String[] getMods = modList.list(); + List< String > mList = Arrays.asList(getMods); //此集合无法操作添加元素 + Collections.sort(mList, cp); + mModRecyclerView = findViewById(R.id.mod_list); + mModRecyclerView.setLayoutManager(new LinearLayoutManager(this));//设置布局管理器 + mModRecyclerView.setAdapter(mModAdapter = new ModsActivity.ModsRecyclerAdapter(this, mList)); + } else { + mModRecyclerView = findViewById(R.id.mVerRecyclerView); + } + } + + @Override + protected void onResume() { + super.onResume(); + Intent intent = getIntent(); + //获取传递的值 + modDir = intent.getStringExtra("mod")+"/mods"; + initMods(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_add_files, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_add: + start(); + break; + default: + break; + + } + return super.onOptionsItemSelected(item); + } + + public boolean copyFile(String oldPath$Name, String newPath$Name) { + try { + File oldFile = new File(oldPath$Name); + if (!oldFile.exists()) { + Log.e("--Method--", "copyFile: oldFile not exist."); + return false; + } else if (!oldFile.isFile()) { + Log.e("--Method--", "copyFile: oldFile not file."); + return false; + } else if (!oldFile.canRead()) { + Log.e("--Method--", "copyFile: oldFile cannot read."); + return false; + } + + FileInputStream fileInputStream = new FileInputStream(oldPath$Name); + FileOutputStream fileOutputStream = new FileOutputStream(newPath$Name); + byte[] buffer = new byte[1024]; + int byteRead; + while (-1 != (byteRead = fileInputStream.read(buffer))) { + fileOutputStream.write(buffer, 0, byteRead); + } + fileInputStream.close(); + fileOutputStream.flush(); + fileOutputStream.close(); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/SettingsActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/SettingsActivity.java new file mode 100644 index 00000000..9f50a16f --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/SettingsActivity.java @@ -0,0 +1,91 @@ +package org.koishi.launcher.h2o2pro; + +import android.content.SharedPreferences; +import android.graphics.Typeface; +import android.os.Bundle; +import android.widget.TextView; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.ui.custom.SettingsFragment; + +import java.util.Objects; + +public class SettingsActivity extends AppCompatActivity { + + public SharedPreferences sp; + public Toolbar toolbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + toolbar = findViewById(R.id.terminal_toolbar); + setSupportActionBar(toolbar); + toolbar.setTitle(R.string.menu_terminal); + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(v -> { + finish(); + //startActivity(new Intent(SettingsActivity.this,HomeActivity.class)); + }); + Typeface tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + TextView bigTitle= (TextView) toolbar.getChildAt(0); + bigTitle.setTypeface(tf); + bigTitle.setText(getResources().getString(R.string.settings)); + sp = getSharedPreferences("org.koishi.launcher.h2o2pro_preferences", MODE_PRIVATE); + if (savedInstanceState == null) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.settings, new SettingsFragment()) + .commit(); + } + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + + } + @Override + public void onBackPressed() { + finish(); + //startActivity(new Intent(SettingsActivity.this,HomeActivity.class)); + } + + @Override + public void onPause() { + super.onPause(); + new Thread(() -> { + String set_id = sp.getString("set_id","player"); + String set_control = sp.getString("set_control","None"); + String set_jvm = sp.getString("set_jvm","-client -Xmx750M"); + String set_mcf = sp.getString("set_mcf",""); + String set_gl = sp.getString("set_gl","libGL112.so.1"); + String set_source = sp.getString("set_source","https://download.mcbbs.net"); + boolean set_click_b = sp.getBoolean("set_click",false); + boolean set_pause_b = sp.getBoolean("set_pause",false); + boolean set_single_b = sp.getBoolean("set_single",false); + boolean set_check_b = sp.getBoolean("set_check_file",false); + String set_click = String.valueOf(set_click_b); + String set_pause = String.valueOf(set_pause_b); + String set_single = String.valueOf(set_single_b); + String set_check = String.valueOf(set_check_b); + + GetGameJson.setBoatJson("auth_player_name",set_id); + GetGameJson.setAppJson("jumpToLeft",set_control); + GetGameJson.setBoatJson("extraJavaFlags",set_jvm); + GetGameJson.setBoatJson("extraMinecraftFlags",set_mcf); + GetGameJson.setAppJson("openGL",set_gl); + GetGameJson.setAppJson("sourceLink",set_source); + GetGameJson.setAppJson("backToRightClick",set_click); + GetGameJson.setAppJson("dontEsc",set_pause); + GetGameJson.setAppJson("allVerLoad",set_single); + GetGameJson.setAppJson("checkFile",set_check); + }).start(); + + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/SplashActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/SplashActivity.java new file mode 100644 index 00000000..b195dff2 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/SplashActivity.java @@ -0,0 +1,207 @@ +package org.koishi.launcher.h2o2pro; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Handler; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.android.material.snackbar.Snackbar; + +import org.koishi.launcher.h2o2pro.tool.AssetsUtils; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.tool.file.AppExecute; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class SplashActivity extends AppCompatActivity { + + public LinearLayout splash; + public TextView splashCheck; + + boolean existMcConfig = FileExists("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + boolean existH2oConfig = FileExists("/storage/emulated/0/games/com.koishi.launcher/h2o2/h2ocfg.json"); + //boolean existH2oMd = FileExists("/storage/emulated/0/games/com.koishi.launcher/h2o2/info.md"); + boolean existRuntime = FileExists("/data/data/org.koishi.launcher.h2o2pro/app_runtime/libopenal.so.1"); + boolean existGame = FileExists(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir")); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //setTheme(R.style.Theme_Boat_H2O2_Custom_GREEN); + setContentView(R.layout.activity_splah); + splash = findViewById(R.id.splash_view); + splashCheck = findViewById(R.id.splash_check); + start(); + } + + public void start() { + new Handler().postDelayed(() -> startApp(), 1000); + } + + public void updateMarkDown() { + File md = new File("/storage/emulated/0/games/com.koishi.launcher/h2o2/markdown"); + if (md.exists()&&md.isDirectory()){ + } else { + md.mkdir(); + } + copyData(); + /* + AssetsUtils.getInstance(SplashActivity.this).copyAssetsToSD("markdown", "games/com.koishi.launcher/h2o2/markdown").setFileOperateCallback(new AssetsUtils.FileOperateCallback() { + @Override + public void onSuccess() { + // TODO: 文件复制成功时,主线程回调 + } + + @Override + public void onFailed(String error) { + // TODO: 文件复制失败时,主线程回调 + } + }); + + */ + } + + public void copyData() + + { + InputStream in = null; + + FileOutputStream out = null; + + //String path = this.getApplicationContext().getFilesDir() + + //.getAbsolutePath() + "/mydb.db3"; // data/data目录 + String path = "/storage/emulated/0/games/com.koishi.launcher/h2o2/markdown/info.md"; + + File file = new File(path); + try + { + in = this.getAssets().open("markdown/info.md"); // 从assets目录下复制 + out = new FileOutputStream(file); + int length = -1; + byte[] buf = new byte[1024]; + while ((length = in.read(buf)) != -1) + { + out.write(buf, 0, length); + } + out.flush(); + } + catch (Exception e) + { + e.printStackTrace(); + } + + finally{ + if (in != null) + { + try { + in.close(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + if (out != null) + { + try { + out.close(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + + + public void updateAuthlib() { + AssetsUtils.getInstance(SplashActivity.this).copyAssetsToSD("authlib", "games/com.koishi.launcher/h2o2/authlib").setFileOperateCallback(new AssetsUtils.FileOperateCallback() { + @Override + public void onSuccess() { + // TODO: 文件复制成功时,主线程回调 + } + + @Override + public void onFailed(String error) { + // TODO: 文件复制失败时,主线程回调 + } + }); + } + + public void startApp() { + updateMarkDown(); + updateAuthlib(); + if (existRuntime) { + if (existGame && existMcConfig && existH2oConfig) { + updateMarkDown(); + Intent i = new Intent(this, HomeActivity.class); + i.putExtra("fragment", getResources().getString(R.string.menu_home)); + startActivity(i); + this.finish(); + } else { + new Thread(() -> { + try { + AppExecute.output(SplashActivity.this, "h2o2.zip", "/storage/emulated/0/games/com.koishi.launcher/h2o2"); + } catch (IOException e) { + Snackbar.make(splash, e.toString(), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + }).start(); + splashCheck.setText(getResources().getString(R.string.launcher_initial_install_start)); + new Handler().postDelayed(() -> { + Intent i = new Intent(SplashActivity.this, HomeActivity.class); + i.putExtra("fragment", getResources().getString(R.string.menu_home)); + startActivity(i); + finish(); + }, 3000); + } + } else { + if (existGame && existMcConfig && existH2oConfig) { + startActivity(new Intent(SplashActivity.this, InitialActivity.class)); + this.finish(); + } else { + new Thread(() -> { + try { + AppExecute.output(SplashActivity.this, "h2o2.zip", "/storage/emulated/0/games/com.koishi.launcher/h2o2"); + } catch (IOException e) { + Snackbar.make(splash, e.toString(), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + }).start(); + updateMarkDown(); + splashCheck.setText(getResources().getString(R.string.launcher_initial_install_start)); + new Handler().postDelayed(() -> { + startActivity(new Intent(SplashActivity.this, InitialActivity.class)); + finish(); + }, 3000); + } + } + + } + + public static boolean FileExists(String strFile) { + try { + File f = new File(strFile); + if (!f.exists()) { + return false; + } + + } catch (Exception e) { + return false; + } + + return true; + } + +} + diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/TerminalActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/TerminalActivity.java new file mode 100644 index 00000000..99f24c60 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/TerminalActivity.java @@ -0,0 +1,288 @@ +package org.koishi.launcher.h2o2pro; + +import android.graphics.Typeface; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import android.app.ProgressDialog; +import android.os.AsyncTask; +import android.os.Bundle; +import android.text.Html; +import android.text.Spanned; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.TextView; + +import com.google.android.material.button.MaterialButton; +import com.google.android.material.card.MaterialCardView; +import com.google.android.material.checkbox.MaterialCheckBox; +import com.google.android.material.textfield.TextInputEditText; +import com.jrummyapps.android.shell.CommandResult; +import com.jrummyapps.android.shell.Shell; + +import java.util.Objects; + +import ren.qinc.edit.PerformEdit; + +public class TerminalActivity extends AppCompatActivity { + + public MaterialCardView card; + public EditText outputText,commandText; + public ProgressDialog dialog; + public ImageButton backText; + public MaterialButton clearText,exec; + public MaterialCheckBox cbRoot; + public PerformEdit mPerformEdit,mPerformEdit2; + public TextInputEditText inputText; + public Toolbar toolbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_terminal); + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + toolbar = findViewById(R.id.terminal_toolbar); + setSupportActionBar(toolbar); + toolbar.setTitle(R.string.menu_terminal); + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(v -> finish()); + Typeface tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + TextView bigTitle= (TextView) toolbar.getChildAt(0); + bigTitle.setTypeface(tf); + bigTitle.setText(getResources().getString(R.string.menu_terminal)); + inputText = findViewById(R.id.terminal_input); + backText = findViewById(R.id.terminal_backspace); + commandText = findViewById(R.id.terminal_command); + clearText = findViewById(R.id.terminal_clear); + card = findViewById(R.id.terminal_card); + outputText = findViewById(R.id.terminal_output); + + cbRoot = findViewById(R.id.root_check); + exec = findViewById(R.id.terminal_exec); + + commandText.setKeyListener(null); + outputText.setKeyListener(null); + outputText.addTextChangedListener(new TextWatcher(){ + @Override + public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { + } + + @Override + public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { + } + + @Override + public void afterTextChanged(Editable p1) { + if (outputText.getText().toString().equals("")){ + card.setVisibility(View.GONE); + } else { + card.setVisibility(View.VISIBLE); + } + } + }); + + mPerformEdit = new PerformEdit(outputText); + mPerformEdit2 = new PerformEdit(commandText); + mPerformEdit.setDefaultText(""); + + //outputText.setMovementMethod(new ScrollingMovementMethod()); + + backText.setOnClickListener(v->inputText.setText("")); + clearText.setOnClickListener(v-> { + outputText.setText(""); + commandText.setText(""); + mPerformEdit.clearHistory(); + mPerformEdit2.clearHistory(); + }); + + exec.setOnClickListener(v-> { + if (!inputText.getText().toString().equals("")) { + //exec(); + //InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + //imm.hideSoftInputFromWindow(inputText.getWindowToken(), 0); + String command = inputText.getText().toString(); + boolean asRoot = cbRoot.isChecked(); + new RunCommandTask(asRoot).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, command); + }else{ + + } + }); + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_terminal, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_undo: + mPerformEdit.undo(); + mPerformEdit2.undo(); + break; + case R.id.action_redo: + mPerformEdit.redo(); + mPerformEdit2.redo(); + break; + case R.id.action_del_all: + outputText.setText(""); + commandText.setText(""); + mPerformEdit.clearHistory(); + mPerformEdit2.clearHistory(); + break; + default: + break; + + } + return super.onOptionsItemSelected(item); + } + + @Override protected void onDestroy() { + super.onDestroy(); + if (isFinishing()) { + Shell.SU.closeConsole(); + } + } + + // Ignore the bad AsyncTask usage. + final class RunCommandTask extends AsyncTask { + + private final boolean asRoot; + + RunCommandTask(boolean asRoot) { + this.asRoot = asRoot; + } + + @Override protected void onPreExecute() { + dialog = ProgressDialog.show(TerminalActivity.this, getResources().getString(R.string.menu_terminal), "Please Wait..."); + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(true); + } + + @Override protected CommandResult doInBackground(String... commands) { + if (asRoot) { + return Shell.SU.run(commands); + } else { + return Shell.SH.run(commands); + } + } + + @Override protected void onPostExecute(CommandResult result) { + if (!isFinishing()) { + if (dialog.isShowing()){ + dialog.dismiss(); + card.setVisibility(View.VISIBLE); + outputText.append(resultToHtml(result)); + commandText.setText(inputText.getText().toString()); + inputText.setText(""); + } else { + } + } + } + + private Spanned resultToHtml(CommandResult result) { + StringBuilder html = new StringBuilder(); + // exit status + html.append("

"); + html.append("").append("Command: ").append(""); + html.append("").append(inputText.getText().toString()).append(""); + html.append("

"); + html.append("

Exit Code: "); + if (result.isSuccessful()) { + html.append("").append(result.exitCode).append(""); + } else { + html.append("").append(result.exitCode).append(""); + } + html.append("

"); + // stdout + if (result.stdout.size() > 0) { + html.append("

>STDOUT:

") + .append(result.getStdout().replaceAll("\n", "
")) + .append("

"); + } + // stderr + if (result.stderr.size() > 0) { + html.append("

STDERR:

") + .append(result.getStderr().replaceAll("\n", "
")) + .append("

"); + } + html.append("

"); + html.append("").append("\n-----Finished-----").append(""); + html.append("

"); + return Html.fromHtml(html.toString()); + } + + } + + @Override + public void onBackPressed() { + if (dialog != null){ + if (dialog.isShowing()){ + dialog.dismiss(); + //Shell.SU.closeConsole(); + } else { + finish(); + } + } else { + finish(); + } + } + + /* + + public String getShellResult() { + try { + String cmds = ""; + String[] arr = cmds.split("\n"); // 用,分割 + for (String cmd : arr) { + cmds += cmd + ";"; + } + String[] cmdA = {"/bin/sh", "-c", cmds}; + Process process = Runtime.getRuntime().exec(cmdA); + LineNumberReader br = new LineNumberReader(new InputStreamReader( + process.getInputStream())); + StringBuffer sb = new StringBuffer(); + String line; + while ((line = br.readLine()) != null) { + System.out.println(line); + sb.append(line).append("\n"); + return sb.toString(); + } + } catch (Exception e) { + e.printStackTrace(); + return e.toString(); + } + return null; + + } + + public void exec(){ + new Thread(() -> { + b = getShellResult(); + han.sendEmptyMessage(0); + }).start(); + } + + Handler han = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + outputText.append(b+"\n"); + } + } + }; + + */ +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/VersionsActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/VersionsActivity.java new file mode 100644 index 00000000..d0a94169 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/VersionsActivity.java @@ -0,0 +1,726 @@ +package org.koishi.launcher.h2o2pro; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.android.material.button.MaterialButton; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textfield.TextInputLayout; +import com.mistake.revision.VanillaActivity; + +import org.json.JSONObject; +import org.koishi.launcher.h2o2pro.adapters.BaseRecycleAdapter; +//import org.koishi.launcher.h2o2pro.adapters.SeachRecordAdapter; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.tool.data.DbDao; +import org.koishi.launcher.h2o2pro.tool.file.AppExecute; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.text.Collator; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +public class VersionsActivity extends AppCompatActivity { + + private Button mbtn_serarch; + private Dialog mDialog; + private EditText met_search; + private FloatingActionButton dir,ver; + private LinearLayout page; + //private TabItem rb1,rb2; + private TabLayout tab; + private RecyclerView mRecyclerView,mVerRecyclerView; + private TextView mtv_deleteAll; + private SearchDirAdapter mAdapter; + private VersionRecyclerAdapter mVerAdapter; + private String getBoatDir; + private String sd1 = "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"; + private String sd2 = "/sdcard/games/com.koishi.launcher/h2o2/gamedir"; + private String sd3 = "/mnt/sdcard/games/com.koishi.launcher/h2o2/gamedir"; + + private List verList; + + private DbDao mDbDao; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_versions); + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + page = findViewById(R.id.dir_layout); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(v -> { + finish(); + startActivity(new Intent(VersionsActivity.this,HomeActivity.class)); + }); + Typeface tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + TextView bigTitle= (TextView) toolbar.getChildAt(0); + bigTitle.setTypeface(tf); + bigTitle.setText(getResources().getString(R.string.menu_ver)); + + //rb1 = findViewById(R.id.ver_title_dir); + //rb2 = findViewById(R.id.ver_title_ver); + + initViews(); + initVers(); + + //rb1.setOnClickListener(v->{ + //mRecyclerView.setVisibility(View.VISIBLE); + //mVerRecyclerView.setVisibility(View.GONE); + //}); + //rb2.setOnClickListener(v->{ + // mRecyclerView.setVisibility(View.GONE); + //mVerRecyclerView.setVisibility(View.VISIBLE); + //}); + dir = findViewById(R.id.ver_new_dir); + ver = findViewById(R.id.ver_new_ver); + ver.hide(); + tab = findViewById(R.id.ver_tab); + tab.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + + // tab.getPosition() 返回数字,从0开始 + // tab.getText() 返回字符串类型,从0开始 + if (tab.getPosition()==0){ + mRecyclerView.setVisibility(View.VISIBLE); + mVerRecyclerView.setVisibility(View.GONE); + ver.hide(); + dir.show(); + } + if (tab.getPosition()==1){ + mRecyclerView.setVisibility(View.GONE); + mVerRecyclerView.setVisibility(View.VISIBLE); + dir.hide(); + ver.show(); + } + } + @Override + public void onTabUnselected(TabLayout.Tab tab) { + + } + @Override + public void onTabReselected(TabLayout.Tab tab) { + + } + }); + + } + + private void initViews() { + mDbDao =new DbDao(this); + //mbtn_serarch = findViewById(R.id.btn_serarch); + //met_search = findViewById(R.id.et_search); + //mtv_deleteAll = findViewById(R.id.tv_deleteAll); + //mtv_deleteAll.setOnClickListener(view -> { + //mDbDao.deleteData(); + //mAdapter.updata(mDbDao.queryData("")); + //}); + mRecyclerView = findViewById(R.id.mRecyclerView); + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + mAdapter = new SearchDirAdapter(mDbDao.queryData(""), this); + mAdapter.setRvItemOnclickListener(position -> { + mDbDao.delete(mDbDao.queryData("").get(position)); + mAdapter.updata(mDbDao.queryData("")); + }); + if (!mDbDao.hasData(sd1)){ + mDbDao.insertData(sd1); + mAdapter.updata(mDbDao.queryData("")); + } + mRecyclerView.setAdapter(mAdapter); + //事件监听 + /* + mbtn_serarch.setOnClickListener(view -> { + + if (met_search.getText().toString().trim().length() != 0){ + boolean hasData = mDbDao.hasData(met_search.getText().toString().trim()); + if (!hasData){ + mDbDao.insertData(met_search.getText().toString().trim()); + }else { + Toast.makeText(VersionsActivity.this, "该内容已在历史记录中", Toast.LENGTH_SHORT).show(); + } + + // + mAdapter.updata(mDbDao.queryData("")); + + }else { + Toast.makeText(VersionsActivity.this, "请输入内容", Toast.LENGTH_SHORT).show(); + } + + }); + */ + } + + public void initVers(){ + File versionlist = new File(GetGameJson.getBoatCfg("game_directory","null") + "/versions"); + if (versionlist.isDirectory() && versionlist.exists()) { + Comparator cp = Collator.getInstance(Locale.CHINA); + String[] getVer = versionlist.list(); + List< String > verList = Arrays.asList(getVer); //此集合无法操作添加元素 + Collections.sort(verList, cp); + mVerRecyclerView = findViewById(R.id.mVerRecyclerView); + mVerRecyclerView.setLayoutManager(new LinearLayoutManager(this));//设置布局管理器 + mVerRecyclerView.setAdapter(mVerAdapter = new VersionRecyclerAdapter(this, verList)); + } else { + mVerRecyclerView = findViewById(R.id.mVerRecyclerView); + mVerRecyclerView.setAdapter(null); + } + } + + public void newDir(View v){ + showDirDialog(); + } + + public void newVer(View v){ + finish(); + startActivity(new Intent(VersionsActivity.this, VanillaActivity.class)); + } + + public void showDirDialog() { + mDialog = new Dialog(VersionsActivity.this); + View dialogView = VersionsActivity.this.getLayoutInflater().inflate(R.layout.custom_dialog_directory, null); + mDialog.setContentView(dialogView); + //mDialog.getWindow().findViewById(R.id.design_bottom_sheet).setBackgroundColor(Color.TRANSPARENT); + MaterialButton cancel = dialogView.findViewById(R.id.custom_dir_cancel); + MaterialButton start = dialogView.findViewById(R.id.custom_dir_ok); + TextInputLayout lay = dialogView.findViewById(R.id.dialog_dir_lay); + lay.setError(getString(R.string.ver_input_hint)); + start.setEnabled(false); + TextInputEditText et = dialogView.findViewById(R.id.dialog_dir_name); + et.addTextChangedListener(new TextWatcher(){ + @Override + public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { + } + + @Override + public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { + } + + @Override + public void afterTextChanged(Editable p1) { + String value = et.getText().toString(); + if (value.matches("(/storage/emulated/0|/sdcard|/mnt/sdcard).*")){ + lay.setErrorEnabled(false); + start.setEnabled(true); + } else { + lay.setError(getString(R.string.ver_input_hint)); + start.setEnabled(false); + } + } + }); + + cancel.setOnClickListener(v-> mDialog.dismiss()); + start.setOnClickListener(v->{ + if (et.getText().toString().trim().length() != 0){ + boolean hasData = mDbDao.hasData(et.getText().toString().trim()); + if (!hasData){ + File f = new File(et.getText().toString().trim()); + if (f.exists()){ + if (f.isDirectory()){ + getBoatDir = et.getText().toString(); + newDir(); + } else { + Snackbar.make(page, getResources().getString(R.string.ver_not_dir), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + } else { + getBoatDir = et.getText().toString(); + newDir(); + } + }else { + Snackbar.make(page, getResources().getString(R.string.ver_already_exists), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + + // + mAdapter.updata(mDbDao.queryData("")); + + }else { + Snackbar.make(page, "Please input", Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = VersionsActivity.this.getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void newDir(){ + new Thread(() -> { + try { + AppExecute.output(VersionsActivity.this, "pack.zip", getBoatDir); + //Snackbar.make(getView(), getResources().getString(R.string.install_done), Snackbar.LENGTH_LONG) + //.setAction("Action", null).show(); + han.sendEmptyMessage(1); + } catch (IOException e) { + Snackbar.make(page, getResources().getString(R.string.ver_not_right_dir)+e.toString(), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + han.sendEmptyMessage(0); + } + }).start(); + } + + @SuppressLint("HandlerLeak") + Handler han = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + mDialog.dismiss(); + } + if (msg.what == 1) { + mDialog.dismiss(); + mDbDao.insertData(getBoatDir); + mAdapter.updata(mDbDao.queryData("")); + Snackbar.make(page, getResources().getString(R.string.ver_add_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + if (msg.what == 2) { + //mVerRecyclerView.setAdapter(null); + //initVers(); + Snackbar.make(page, getResources().getString(R.string.ver_add_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + + } + }; + + //public void refresh(){ + //finish(); + //startActivity(new Intent(VersionsActivity.this,VersionsActivity.class)); + //} + + class SearchDirAdapter extends BaseRecycleAdapter { + public SearchDirAdapter(List< String > datas, Context mContext) { + super(datas, mContext); + } + + @SuppressLint({"ResourceAsColor", "UseCompatLoadingForDrawables"}) + @Override + protected void bindData(BaseViewHolder holder, final int position) { + + TextView textView = (TextView) holder.getView(R.id.tv_record); + TextView textView1 = (TextView) holder.getView(R.id.tv_name); + LinearLayout lay = (LinearLayout) holder.getView(R.id.ver_item); + ImageView check = (ImageView) holder.getView(R.id.ver_check_icon); + MaterialButton del = (MaterialButton) holder.getView(R.id.tv_remove_dir); + MaterialButton delDir = (MaterialButton) holder.getView(R.id.tv_del_dir); + textView.setText(datas.get(position)); + if (datas.get(position).equals(GetGameJson.getBoatCfg("game_directory", "null"))) { + //lay.setSelected(true); + //check.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_check_file_blue_true)); + lay.setBackground(getResources().getDrawable(R.drawable.recycler_button_pressed)); + } else { + //lay.setSelected(false); + //check.setImageDrawable(getResources().getDrawable(R.drawable.cv_shape)); + lay.setBackground(getResources().getDrawable(R.drawable.recycler_button_normal)); + } + if (datas.get(position).equals(sd1) || datas.get(position).equals(sd2) || datas.get(position).equals(sd3)) { + del.setVisibility(View.GONE); + delDir.setVisibility(View.GONE); + } else { + del.setVisibility(View.VISIBLE); + delDir.setVisibility(View.VISIBLE); + } + + String str1 = textView.getText().toString(); + str1 = str1.substring(0, str1.lastIndexOf("/")); + int idx = str1.lastIndexOf("/"); + str1 = str1.substring(idx+1,str1.length()); + textView1.setText(str1); + + File f = new File(textView.getText().toString()); + if (f.isDirectory() && f.exists()){ + + } else { + check.setImageDrawable(getResources().getDrawable(R.drawable.xicon_red)); + delDir.setVisibility(View.VISIBLE); + } + /* + if (f.exists() && f.isDirectory()) { + mRvItemOnclickListener.RvItemOnclick(position); + mAdapter.updata(mDbDao.queryData("")); + } else { + if (null != mRvItemOnclickListener) { + mRvItemOnclickListener.RvItemOnclick(position); + mAdapter.updata(mDbDao.queryData("")); + } + } + */ + lay.setOnClickListener(v -> { + if (f.exists() && f.isDirectory()) { + setDir(textView.getText().toString()); + //finish(); + //startActivity(new Intent(VersionsActivity.this,VersionsActivity.class)); + mAdapter.updata(mDbDao.queryData("")); + mVerRecyclerView.setAdapter(null); + initVers(); + } else { + if (null != mRvItemOnclickListener) { + mRvItemOnclickListener.RvItemOnclick(position); + mAdapter.updata(mDbDao.queryData("")); + Snackbar.make(page, getResources().getString(R.string.ver_null_dir), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + mVerRecyclerView.setAdapter(null); + } + } + + }); + // + del.setOnClickListener(view -> { + //if (null != mRvItemOnclickListener) { + //if (datas.get(position).equals(GetGameJson.getBoatCfg("game_directory", "null"))) { + //setDir(sd1); + //} else { + + //} + // } + if (null!=mRvItemOnclickListener){ + mRvItemOnclickListener.RvItemOnclick(position); + } + }); + + delDir.setOnClickListener(view -> { + if (null != mRvItemOnclickListener) { + if (datas.get(position).equals(GetGameJson.getBoatCfg("game_directory", "null"))) { + setDir(sd1); + } else { + + } + AlertDialog alertDialog1 = new AlertDialog.Builder(VersionsActivity.this) + .setTitle(getResources().getString(R.string.action))//标题 + .setIcon(R.drawable.ic_boat)//图标 + .setMessage(R.string.ver_if_del) + .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + File f = new File(datas.get(position)); + //TODO + mRvItemOnclickListener.RvItemOnclick(position); + //finish(); + //startActivity(new Intent(VersionsActivity.this,VersionsActivity.class)); + mAdapter.updata(mDbDao.queryData("")); + new Thread(() -> { + //String file2= "/data/data/com.koishi.launcher.h2o2/app_runtime"; + deleteDirWihtFile(f); + /* + File file = new File(file2); + if(file.isDirectory()){ + deleteDirectory(file2); + } + if(file.isFile()){ + deleteFile(file2); + } + */ + }).start(); + + } + }) + .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + } + }) + .create(); + + alertDialog1.show(); + } + }); + } + + public void deleteDirWihtFile(File dir) { + if (dir == null || !dir.exists() || !dir.isDirectory()) + return; + for (File file : dir.listFiles()) { + if (file.isFile()) + file.delete(); // 删除所有文件 + else if (file.isDirectory()) + deleteDirWihtFile(file); // 递规的方式删除文件夹 + } + dir.delete();// 删除目录本身 + } + + @Override + public int getLayoutId() { + return R.layout.dir_item; + } + + public void setDir(String dir) { + try { + FileInputStream in = new FileInputStream("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + JSONObject json = new JSONObject(str); + json.remove("game_directory"); + json.remove("game_assets"); + json.remove("assets_root"); + json.remove("currentVersion"); + json.put("game_directory", dir); + json.put("game_assets", dir + "/assets/virtual/legacy"); + json.put("assets_root", dir + "/assets"); + json.put("currentVersion", dir + "/versions"); + FileWriter fr = new FileWriter(new File("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt")); + fr.write(json.toString()); + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + } + + class VersionRecyclerAdapter extends RecyclerView.Adapter{ + private List datas; + private LayoutInflater inflater; + public VersionRecyclerAdapter(Context context,List datas){ + inflater=LayoutInflater.from(context); + this.datas=datas; + } + //创建每一行的View 用RecyclerView.ViewHolder包装 + @Override + public VersionRecyclerAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView=inflater.inflate(R.layout.version_local_item,null); + return new MyViewHolder(itemView); + } + //给每一行View填充数据 + @Override + public void onBindViewHolder(VersionRecyclerAdapter.MyViewHolder holder, @SuppressLint("RecyclerView") int position) { + holder.textview.setText(datas.get(position)); + File f = new File(GetGameJson.getBoatCfg("game_directory","Null")+"/versions/"+datas.get(position)); + if (f.isDirectory()&&f.exists()){ + }else{ + holder.rl.setEnabled(false); + holder.ic.setImageDrawable(getResources().getDrawable(R.drawable.xicon_red)); + } + holder.rl.setOnClickListener(v->{ + holder.dirs = datas.get(position); + showExecDialog(holder.dirs); + }); + holder.btn.setOnClickListener(v->{ + AlertDialog alertDialog1 = new AlertDialog.Builder(VersionsActivity.this) + .setTitle(getResources().getString(R.string.action))//标题 + .setIcon(R.drawable.ic_boat)//图标 + .setMessage(R.string.ver_if_del) + .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + holder.ic.setImageDrawable(getResources().getDrawable(R.drawable.xicon_red)); + holder.btn.setVisibility(View.INVISIBLE); + holder.textview.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); + holder.rl.setEnabled(false); + File f = new File(GetGameJson.getBoatCfg("game_directory","Null")+"/versions/"+datas.get(position)); + //TODO + new Thread(() -> { + //String file2= "/data/data/com.koishi.launcher.h2o2/app_runtime"; + if (f.isDirectory()){ + deleteDirWihtFile(f); + }else{ + deleteFile(GetGameJson.getBoatCfg("game_directory","Null")+"/versions/"+datas.get(position)); + } + /* + File file = new File(file2); + if(file.isDirectory()){ + deleteDirectory(file2); + } + if(file.isFile()){ + deleteFile(file2); + } + */ + han.sendEmptyMessage(2); + }).start(); + + } + }) + .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + } + }) + .create(); + + alertDialog1.show(); + }); + } + + public void showExecDialog(String dir) { + mDialog = new Dialog(VersionsActivity.this); + View dialogView = VersionsActivity.this.getLayoutInflater().inflate(R.layout.custom_dialog_choose_exec, null); + mDialog.setContentView(dialogView); + String load = GetGameJson.getAppCfg("allVerLoad","false"); + String loadDir; + if (load.equals("true")){ + loadDir = GetGameJson.getBoatCfg("game_directory","Null")+"/versions/"+dir; + }else{ + loadDir = GetGameJson.getBoatCfg("game_directory","Null"); + } + LinearLayout lay = dialogView.findViewById(R.id.ver_exec_mod); + lay.setOnClickListener(v->{ + Intent i = new Intent(VersionsActivity.this, ModsActivity.class); + Bundle bundle=new Bundle(); + bundle.putString("mod", loadDir); + i.putExtras(bundle); + //i.putExtra("dat",c); + VersionsActivity.this.startActivity(i); + }); + //mDialog.getWindow().findViewById(R.id.design_bottom_sheet).setBackgroundColor(Color.TRANSPARENT); + + mDialog.setContentView(dialogView); + WindowManager windowManager = VersionsActivity.this.getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + //数据源的数量 + @Override + public int getItemCount() { + return datas.size(); + } + class MyViewHolder extends RecyclerView.ViewHolder{ + private TextView textview; + private MaterialButton btn; + private ImageView ic; + private LinearLayout rl; + private String dirs; + + public MyViewHolder(View itemView) { + super(itemView); + textview = itemView.findViewById(R.id.ver_name); + btn = itemView.findViewById(R.id.ver_remove); + rl = itemView.findViewById(R.id.ver_item); + ic = itemView.findViewById(R.id.ver_icon); + } + } + + public void deleteDirWihtFile(File dir) { + if (dir == null || !dir.exists() || !dir.isDirectory()) + return; + for (File file : dir.listFiles()) { + if (file.isFile()) + file.delete(); // 删除所有文件 + else if (file.isDirectory()) + deleteDirWihtFile(file); // 递规的方式删除文件夹 + } + dir.delete();// 删除目录本身 + } + + public boolean deleteFile(String filePath) { + File file = new File(filePath); + if (file.isFile() && file.exists()) { + return file.delete(); + } + return false; + } + } + + @Override + public void onBackPressed() { + finish(); + startActivity(new Intent(VersionsActivity.this,HomeActivity.class)); + } + + @Override + protected void onResume() { + super.onResume(); + //updateDirList(); + //initViews(); + //mRecyclerView.post(() -> updateDirList()); + + String currentDir = GetGameJson.getBoatCfg("game_directory","Null"); + File f = new File(currentDir); + //if (mRecyclerView.isComputingLayout()) { + //updateDirList(); + //if (f.exists()&&f.isDirectory()){ + //if (mDbDao.hasData(dir.trim())){ + //mDbDao.delete(dir); + //updateDirList(); + //}else{ +// + // } + //} + // } + if (f.exists()&&f.isDirectory()){ + initVers(); + } else { + setDir(sd1); + Snackbar.make(page, getResources().getString(R.string.ver_null_dir), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + mDbDao.delete(currentDir); + mAdapter.updata(mDbDao.queryData("")); + initVers(); + } + } + + public void setDir(String dir) { + try { + FileInputStream in = new FileInputStream("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + JSONObject json = new JSONObject(str); + json.remove("game_directory"); + json.remove("game_assets"); + json.remove("assets_root"); + json.remove("currentVersion"); + json.put("game_directory", dir); + json.put("game_assets", dir + "/assets/virtual/legacy"); + json.put("assets_root", dir + "/assets"); + json.put("currentVersion", dir + "/versions"); + FileWriter fr = new FileWriter(new File("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt")); + fr.write(json.toString()); + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/WelcomeActivity.java b/app/src/main/java/org/koishi/launcher/h2o2pro/WelcomeActivity.java new file mode 100644 index 00000000..ce9cdb56 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/WelcomeActivity.java @@ -0,0 +1,141 @@ +package org.koishi.launcher.h2o2pro; + +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AppCompatActivity; +import androidx.browser.customtabs.CustomTabsIntent; + +import android.Manifest; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.provider.Settings; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.TextView; +import android.widget.Toast; +import androidx.appcompat.widget.Toolbar; + +import com.google.android.material.snackbar.Snackbar; + +import org.koishi.launcher.h2o2pro.ui.custom.SettingsFragment; +import org.koishi.launcher.h2o2pro.ui.home.WelcomeFragment; + +public class WelcomeActivity extends AppCompatActivity implements View.OnClickListener { + + public Boolean isPermed; + public CheckBox skip; + public SharedPreferences sp; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_welcome); + Toolbar tb = findViewById(R.id.toolbar); + Typeface tf = Typeface.createFromAsset(this.getAssets(), + "Sans.ttf"); + TextView bigTitle= (TextView) tb.getChildAt(0); + bigTitle.setTypeface(tf); + bigTitle.setText(getResources().getString(R.string.app_name)); + getWindow().setStatusBarColor(getResources().getColor(R.color.material_card_background)); + + skip = findViewById(R.id.welcome_skip); + + sp = this.getSharedPreferences("isChecked", 0); + boolean result = sp.getBoolean("skip", false); // 这里就是开始取值了 false代表的就是如果没有得到对应数据我们默认显示为false + // 把得到的状态设置给CheckBox组件 + skip.setChecked(result); + skip.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (skip.isChecked()) { + sp = this.getSharedPreferences("isChecked", 0); + SharedPreferences.Editor edit = sp.edit(); + edit.putBoolean("skip", true); + edit.apply(); + } else { + sp = this.getSharedPreferences("isChecked", 0); + SharedPreferences.Editor edit = sp.edit(); + edit.putBoolean("skip", false); + edit.apply(); + } + }); + checkPermission(); + if (isPermed) { + + }else { + skip.setChecked(false); + } + //if (isTabletDevice(WelcomeActivity.this) == true){ + //skip.setChecked(false); + //finish(); + //Toast.makeText(WelcomeActivity.this,getResources().getString(R.string.stop_app),Toast.LENGTH_LONG).show(); + //} else{ + + //} + if (skip.isChecked()) { + startActivity(new Intent(this,SplashActivity.class)); + this.finish(); + } else { + } + } + + @Override + protected void onResume() { + super.onResume(); + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.perm, new WelcomeFragment()) + .commit(); + /* + if (!(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager())) { + //表明已经有这个权限了 + getPremissionBtn.setEnabled(false); + startBtn.setEnabled(true); + getPremissionBtn.setText(getResources().getString(R.string.welcome_perm_true)); + getPremissionBtn.setTextColor(getResources().getColor(R.color.green_light)); + } else { + getPremissionBtn.setEnabled(true); + startBtn.setEnabled(false); + getPremissionBtn.setText(getResources().getString(R.string.welcome_perm)); + getPremissionBtn.setTextColor(getResources().getColor(R.color.red_light)); + + } + */ + } + + @RequiresApi(api = Build.VERSION_CODES.M) + @Override + public void onClick(View v) { + + } + + public Boolean checkPermission() { + isPermed = true; + if (android.os.Build.VERSION.SDK_INT >= 23) { + if (this.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + isPermed = false; + } + if (this.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) !=PackageManager.PERMISSION_GRANTED) { + isPermed = false; + } + } + return isPermed; + } + + /* + private boolean isTabletDevice(Context context) { + if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= + Configuration.SCREENLAYOUT_SIZE_LARGE){ + return true; + } else { + return false; + } + } + */ +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/adapters/BaseRecycleAdapter.java b/app/src/main/java/org/koishi/launcher/h2o2pro/adapters/BaseRecycleAdapter.java new file mode 100644 index 00000000..2e63e616 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/adapters/BaseRecycleAdapter.java @@ -0,0 +1,286 @@ +package org.koishi.launcher.h2o2pro.adapters; + +import android.content.Context; + +import android.icu.text.Transliterator; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by yi.huangxing on 17/12/13.类描述: + */ + +public abstract class BaseRecycleAdapter extends RecyclerView.Adapter{ + + protected List datas; + protected Context mContext; + + public BaseRecycleAdapter(List datas,Context mContext) { + this.datas = datas; + this.mContext =mContext; + } + + // 头部控件 + private View mHeaderView; + + // 底部控件 + private View mFooterView; + + + // item 的三种类型 + public static final int ITEM_TYPE_NORMAL = 0X1111; // 正常的item类型 + public static final int ITEM_TYPE_HEADER = 0X1112; // header + public static final int ITEM_TYPE_FOOTER = 0X1113; // footer + + + private boolean isHasHeader = false; + + private boolean isHasFooter = false; + + @Override + public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + + if(viewType==ITEM_TYPE_FOOTER){ + // 如果是底部类型,返回底部视图 + return new BaseViewHolder(mFooterView); + } + + if(viewType==ITEM_TYPE_HEADER){ + return new BaseViewHolder(mHeaderView); + } + View view = LayoutInflater.from(parent.getContext()).inflate(getLayoutId(),parent,false); + return new BaseViewHolder(view); + } + + @Override + public void onBindViewHolder(BaseRecycleAdapter.BaseViewHolder holder, final int position) { + + if(isHasHeader&&isHasFooter){ + // 有头布局和底部时,向前便宜一个,且最后一个不能绑定数据 + if(position==0 ||position==datas.size()+1){ + return; + } + bindData(holder,position-1); + } + + if(position!=0&&isHasHeader&&!isHasFooter){ + // 有顶部,但没有底部 + bindData(holder,position-1); + } + + if(!isHasHeader&&isHasFooter){ + // 没有顶部,但有底部 + if(position==datas.size()){ + return; + } + bindData(holder,position); + } + + if(!isHasHeader&&!isHasFooter){ + // 没有顶部,没有底部 + bindData(holder,position); + } + + } + + /** + * 添加头部视图 + * @param header + */ + public void setHeaderView(View header){ + this.mHeaderView = header; + isHasHeader = true; + notifyDataSetChanged(); + } + + /** + * 添加底部视图 + * @param footer + */ + public void setFooterView(View footer){ + this.mFooterView = footer; + isHasFooter = true; + notifyDataSetChanged(); + } + + + + @Override + public int getItemViewType(int position) { + + // 根据索引获取当前View的类型,以达到复用的目的 + + // 根据位置的索引,获取当前position的类型 + if(isHasHeader&&position==0){ + return ITEM_TYPE_HEADER; + } + if(isHasHeader&&isHasFooter&&position==datas.size()+1){ + // 有头部和底部时,最后底部的应该等于size+! + return ITEM_TYPE_FOOTER; + }else if(!isHasHeader&&isHasFooter&&position==datas.size()){ + // 没有头部,有底部,底部索引为size + return ITEM_TYPE_FOOTER; + } + return ITEM_TYPE_NORMAL; + } + + /** + * 刷新数据 + * @param datas + */ + public void refresh(List datas){ + this.datas.clear(); + this.datas.addAll(datas); + notifyDataSetChanged(); + } + + /** + * 刷新数据 + * @param data + */ + public void updata(List data){ + this.datas=data; + notifyDataSetChanged(); + } + + /** + * 添加数据 + * @param datas + */ + public void addData(List datas){ + this.datas.addAll(datas); + notifyDataSetChanged(); + } + /** + * 移除数据 + * + * @param position + */ + public void remove(int position) { + if (position >= 0 && position < datas.size()) { + datas.remove(position); + notifyDataSetChanged(); + } + } + + + /** + * 绑定数据 + * @param holder 具体的viewHolder + * @param position 对应的索引 + */ + protected abstract void bindData(BaseViewHolder holder, int position); + + + + @Override + public int getItemCount() { + int size = datas.size(); + if(isHasFooter) + size ++; + if(isHasHeader) + size++; + return size; + } + + + + + /** + * 封装ViewHolder ,子类可以直接使用 + */ + public class BaseViewHolder extends RecyclerView.ViewHolder{ + + + private Map mViewMap; + + public BaseViewHolder(View itemView) { + super(itemView); + mViewMap = new HashMap<>(); + } + + /** + * 获取设置的view + * @param id + * @return + */ + public View getView(int id) { + View view = mViewMap.get(id); + if (view == null) { + view = itemView.findViewById(id); + mViewMap.put(id, view); + } + return view; + } + } + + /** + * 获取子item + * @return + */ + public abstract int getLayoutId(); + + + + /** + * 设置文本属性 + * @param view + * @param text + */ + public void setItemText(View view,String text){ + if(view instanceof TextView){ + ((TextView) view).setText(text); + } + } + + + public RvItemOnclickListener getRvItemOnclickListener() { + return mRvItemOnclickListener; + } + + public void setRvItemOnclickListener(RvItemOnclickListener rvItemOnclickListener) { + mRvItemOnclickListener = rvItemOnclickListener; + } + + protected RvItemOnclickListener mRvItemOnclickListener; + + + public interface RvItemOnclickListener{ + + void RvItemOnclick(int position); + } + + + + /** + * 这个方法很重要的 + * @param holder + */ +// +// @Override +// public void onAttachedToRecyclerView(RecyclerView recyclerView) { +// super.onAttachedToRecyclerView(recyclerView); +// +// RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); +// if(manager instanceof GridLayoutManager) { +// final GridLayoutManager gridManager = ((GridLayoutManager) manager); +// gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { +// @Override +// public int getSpanSize(int position) { +// return getItemViewType(position) == TYPE_HEADER +// ? gridManager.getSpanCount() : 1; +// } +// }); +// } +// } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/AssetsUtils.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/AssetsUtils.java new file mode 100644 index 00000000..dc4fee27 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/AssetsUtils.java @@ -0,0 +1,107 @@ +package org.koishi.launcher.h2o2pro.tool; + +import android.content.Context; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; + +/** + * Created by shenhua on 1/17/2017. + * Email shenhuanet@126.com + */ +public class AssetsUtils { + + private static AssetsUtils instance; + private static final int SUCCESS = 1; + private static final int FAILED = 0; + private Context context; + private FileOperateCallback callback; + private volatile boolean isSuccess; + private String errorStr; + + public static AssetsUtils getInstance(Context context) { + if (instance == null) + instance = new AssetsUtils(context); + return instance; + } + + private AssetsUtils (Context context) { + this.context = context; + } + + private Handler handler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (callback != null) { + if (msg.what == SUCCESS) { + callback.onSuccess(); + } + if (msg.what == FAILED) { + callback.onFailed(msg.obj.toString()); + } + } + } + }; + + public AssetsUtils copyAssetsToSD(final String srcPath, final String sdPath) { + new Thread(() -> { + copyAssetsToDst(context, srcPath, sdPath); + if (isSuccess) + handler.obtainMessage(SUCCESS).sendToTarget(); + else + handler.obtainMessage(FAILED, errorStr).sendToTarget(); + }).start(); + return this; + } + + public void setFileOperateCallback(FileOperateCallback callback) { + this.callback = callback; + } + + private void copyAssetsToDst(Context context, String srcPath, String dstPath) { + try { + String fileNames[] = context.getAssets().list(srcPath); + if (fileNames.length > 0) { + File file = new File(Environment.getExternalStorageDirectory(), dstPath); + if (!file.exists()) file.mkdirs(); + for (String fileName : fileNames) { + if (!srcPath.equals("")) { // assets 文件夹下的目录 + copyAssetsToDst(context, srcPath + File.separator + fileName, dstPath + File.separator + fileName); + } else { // assets 文件夹 + copyAssetsToDst(context, fileName, dstPath + File.separator + fileName); + } + } + } else { + File outFile = new File(Environment.getExternalStorageDirectory(), dstPath); + InputStream is = context.getAssets().open(srcPath); + FileOutputStream fos = new FileOutputStream(outFile); + byte[] buffer = new byte[1024]; + int byteCount; + while ((byteCount = is.read(buffer)) != -1) { + fos.write(buffer, 0, byteCount); + } + fos.flush(); + is.close(); + fos.close(); + } + isSuccess = true; + } catch (Exception e) { + e.printStackTrace(); + errorStr = e.getMessage(); + isSuccess = false; + } + } + + public interface FileOperateCallback { + void onSuccess(); + + void onFailed(String error); + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/GetGameJson.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/GetGameJson.java new file mode 100644 index 00000000..e53e717f --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/GetGameJson.java @@ -0,0 +1,115 @@ +package org.koishi.launcher.h2o2pro.tool; + +import org.json.JSONObject; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; + +public class GetGameJson { + + public static String boatCfg = "/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"; + public static String h2oCfg = "/storage/emulated/0/games/com.koishi.launcher/h2o2/h2ocfg.json"; + + public static void setBoatJson(String name, String value) { + try { + FileInputStream in = new FileInputStream(boatCfg); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + JSONObject json = new JSONObject(str); + json.remove(name); + json.put(name, value); + FileWriter fr = new FileWriter(new File(boatCfg)); + fr.write(json.toString()); + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + + public static void setAppJson(String name, String value) { + try { + FileInputStream in = new FileInputStream(h2oCfg); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + JSONObject json = new JSONObject(str); + json.remove(name); + json.put(name, value); + FileWriter fr = new FileWriter(new File(h2oCfg)); + fr.write(json.toString()); + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + + public static void setExtraJson(String name, String value, String dir) { + try { + FileInputStream in = new FileInputStream(dir); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + JSONObject json = new JSONObject(str); + json.remove(name); + json.put(name, value); + FileWriter fr = new FileWriter(new File(dir)); + fr.write(json.toString()); + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + + //---------------------获取json的值--------------------- + + //h2ocfg + public static String getBoatCfg(String name, String defaultValue) { + try { + FileInputStream in=new FileInputStream(boatCfg); + byte[] b=new byte[in.available()]; + in.read(b); + in.close(); + String str=new String(b); + JSONObject json=new JSONObject(str); + return json.getString(name); + } catch (Exception e) { + System.out.println(e); + } + return defaultValue; + } + + public static String getAppCfg(String name, String defaultValue) { + try { + FileInputStream in=new FileInputStream(h2oCfg); + byte[] b=new byte[in.available()]; + in.read(b); + in.close(); + String str=new String(b); + JSONObject json=new JSONObject(str); + return json.getString(name); + } catch (Exception e) { + System.out.println(e); + } + return defaultValue; + } + + public static String getExtraCfg(String value, String defaultValue, String dir) { + try { + FileInputStream in=new FileInputStream(dir); + byte[] b=new byte[in.available()]; + in.read(b); + in.close(); + String str=new String(b); + JSONObject json=new JSONObject(str); + return json.getString(value); + } catch (Exception e) { + System.out.println(e); + } + return defaultValue; + } +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/StatusBarUtil.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/StatusBarUtil.java new file mode 100644 index 00000000..0b194b33 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/StatusBarUtil.java @@ -0,0 +1,57 @@ +package org.koishi.launcher.h2o2pro.tool; + +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +public class StatusBarUtil { + public static boolean hasNavigationBarShow(Activity activity) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + return false; + } + WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + DisplayMetrics outMetrics = new DisplayMetrics(); + //获取整个屏幕的高度 + display.getRealMetrics(outMetrics); + int heightPixels = outMetrics.heightPixels; + int widthPixels = outMetrics.widthPixels; + //获取内容展示部分的高度 + outMetrics = new DisplayMetrics(); + display.getMetrics(outMetrics); + int heightPixelsContent = outMetrics.heightPixels; + int widthPixelsContent = outMetrics.widthPixels; + int h = heightPixels - heightPixelsContent; + int w = widthPixels - widthPixelsContent; + return w > 0 || h > 0; //竖屏和横屏两种情况 + } + + /** + * 获取导航栏高度 + * + * @param context + * @return + */ + public static int getNavigationBarHeight(Context context) { + return getSystemComponentDimen(context, "navigation_bar_height"); + } + + public static int getSystemComponentDimen(Context context, String dimenName) { + // 反射手机运行的类:android.R.dimen.status_bar_height. + int statusHeight = -1; + try { + Class clazz = Class.forName("com.android.internal.R$dimen"); + Object object = clazz.newInstance(); + String heightStr = clazz.getField(dimenName).get(object).toString(); + int height = Integer.parseInt(heightStr); + //dp->px + statusHeight = context.getResources().getDimensionPixelSize(height); + } catch (Exception e) { + e.printStackTrace(); + } + return statusHeight; + } +} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/tools/Consant.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/Consant.java similarity index 80% rename from app/src/main/java/com/koishi/launcher/h2o2/tools/Consant.java rename to app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/Consant.java index ca31e235..415aab33 100644 --- a/app/src/main/java/com/koishi/launcher/h2o2/tools/Consant.java +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/Consant.java @@ -1,4 +1,4 @@ -package com.koishi.launcher.h2o2.tools; +package org.koishi.launcher.h2o2pro.tool.data; /** * 作者:Leon diff --git a/app/src/main/java/com/koishi/launcher/h2o2/tools/DBHelper.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DBHelper.java similarity index 79% rename from app/src/main/java/com/koishi/launcher/h2o2/tools/DBHelper.java rename to app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DBHelper.java index 432de2da..78d5c82e 100644 --- a/app/src/main/java/com/koishi/launcher/h2o2/tools/DBHelper.java +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DBHelper.java @@ -1,12 +1,13 @@ -package com.koishi.launcher.h2o2.tools; +package org.koishi.launcher.h2o2pro.tool.data; +import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import com.koishi.launcher.h2o2.tools.DBUser.User; +import org.koishi.launcher.h2o2pro.tool.data.DBUser.User; /** * 操作数据库辅助类 @@ -17,7 +18,7 @@ public class DBHelper { public static final int DB_VERSION = 1; public static final String DB_NAME = "example.db"; public static final String USER_TABLE_NAME = "user_table"; - public static final String[] USER_COLS = { User.USERNAME, User.PASSWORD, + public static final String[] USER_COLS = { User.USERNAME, User.PASSWORD, User.API, User.ISSAVED }; private SQLiteDatabase db; @@ -46,7 +47,7 @@ private void establishDb() { * 表名 * @return 插入记录的id -1表示插入不成功 */ - public long insertOrUpdate(String userName, String password, int isSaved) { + public long insertOrUpdate(String userName, String password, String api, int isSaved) { boolean isUpdate = false; String[] usernames = queryAllUserName(); for (int i = 0; i < usernames.length; i++) { @@ -57,12 +58,13 @@ public long insertOrUpdate(String userName, String password, int isSaved) { } long id = -1; if (isUpdate) { - id = update(userName, password, isSaved); + id = update(userName, password, api, isSaved); } else { if (db != null) { ContentValues values = new ContentValues(); values.put(User.USERNAME, userName); values.put(User.PASSWORD, password); + values.put(User.API, api); values.put(User.ISSAVED, isSaved); id = db.insert(USER_TABLE_NAME, null, values); } @@ -94,10 +96,11 @@ public long delete(String userName) { * 表名 * @return 更新过后记录的id -1表示更新不成功 */ - public long update(String username, String password, int isSaved) { + public long update(String username, String password, String api, int isSaved) { ContentValues values = new ContentValues(); values.put(User.USERNAME, username); values.put(User.PASSWORD, password); + values.put(User.API, api); values.put(User.ISSAVED, isSaved); long id = db.update(USER_TABLE_NAME, values, User.USERNAME + " = '" + username + "'", null); @@ -106,7 +109,7 @@ public long update(String username, String password, int isSaved) { /** * 根据用户名查询密码 - * + * * @param username * 用户名 * @param tableName @@ -126,12 +129,36 @@ public String queryPasswordByName(String username) { return password; } + /** + * 根据用户名查询密码 + * + * @param username + * 用户名 + * @param tableName + * 表名 + * @return Hashmap 查询的记录 + */ + + public String queryApiByName(String username) { + String sql = "select * from " + USER_TABLE_NAME + " where " + + User.USERNAME + " = '" + username + "'"; + Cursor cursor5 = db.rawQuery(sql, null); + String api = ""; + if (cursor5.getCount() > 0) { + cursor5.moveToFirst(); + api = cursor5.getString(cursor5.getColumnIndex(User.API)); + } + + return api; + } + /** * 记住密码选项框是否被选中 * * @param username * @return */ + @SuppressLint("Range") public int queryIsSavedByName(String username) { String sql = "select * from " + USER_TABLE_NAME + " where " + User.USERNAME + " = '" + username + "'"; @@ -151,6 +178,7 @@ public int queryIsSavedByName(String username) { * 表名 * @return 所有记录的list集合 */ + @SuppressLint("Range") public String[] queryAllUserName() { if (db != null) { Cursor cursor = db.query(USER_TABLE_NAME, null, null, null, null, @@ -194,8 +222,8 @@ public DBOpenHelper(Context context) { @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table " + USER_TABLE_NAME + " (" + User._ID - + " integer primary key," + User.USERNAME + " text, " - + User.PASSWORD + " text, " + User.ISSAVED + " INTEGER)"); + + " integer primary key, " + User.USERNAME + " text, " + + User.PASSWORD + " text, " + User.API + " text, " + User.ISSAVED + " INTEGER)"); } @Override diff --git a/app/src/main/java/com/koishi/launcher/h2o2/tools/DBUser.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DBUser.java similarity index 77% rename from app/src/main/java/com/koishi/launcher/h2o2/tools/DBUser.java rename to app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DBUser.java index 4c6aa783..ecfe3814 100644 --- a/app/src/main/java/com/koishi/launcher/h2o2/tools/DBUser.java +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DBUser.java @@ -1,4 +1,4 @@ -package com.koishi.launcher.h2o2.tools; +package org.koishi.launcher.h2o2pro.tool.data; import android.provider.BaseColumns; @@ -11,6 +11,7 @@ public final class DBUser { public static final class User implements BaseColumns { public static final String USERNAME = "username"; public static final String PASSWORD = "password"; + public static final String API = "api"; public static final String ISSAVED = "issaved"; } diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DbDao.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DbDao.java new file mode 100644 index 00000000..ccae7426 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/DbDao.java @@ -0,0 +1,99 @@ +package org.koishi.launcher.h2o2pro.tool.data; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by yi.huangxing on 17/12/13.类描述: 数据库的增删改查 + */ + +public class DbDao { + + private Context context; + private RecordSQLiteOpenHelper helper; + private SQLiteDatabase db; + + public DbDao(Context context) { + this.context = context; + init(); + } + + private void init() { + + //实例化数据库SQLiteOpenHelper子类对象 + helper = new RecordSQLiteOpenHelper(context); + // 第一次进入时查询所有的历史记录 + queryData(""); + } + + public List queryData(String tempName) { + List data = new ArrayList<>(); + //模糊搜索 + Cursor cursor = helper.getReadableDatabase().rawQuery( + "select id as _id,name from records where name like '%" + tempName + "%' order by id desc ", null); + + while (cursor.moveToNext()) { + //注意这里的name跟建表的name统一 + String name = cursor.getString(cursor.getColumnIndex("name")); + data.add(name); + } + cursor.close(); + return data; + + } + + /** + * 检查数据库中是否已经有该条记录 + * + * @param tempName + * @return + */ + public boolean hasData(String tempName) { + //从Record这个表里找到name=tempName的id + Cursor cursor = helper.getReadableDatabase().rawQuery( + "select id as _id,name from records where name =?", new String[]{tempName}); + //判断是否有下一个 + return cursor.moveToNext(); + } + + /** + * 插入数据 + * + * @param tempName + */ + public void insertData(String tempName) { + db = helper.getWritableDatabase(); + db.execSQL("insert into records(name) values('" + tempName + "')"); + db.close(); + } + + /** + * 插入数据 + * + * @param name + * @return + */ + + public int delete(String name) { + // 获取数据 + SQLiteDatabase db = helper.getWritableDatabase(); + // 执行SQL + int delete = db.delete("records", " name=?", new String[]{name}); + // 关闭数据库连接 + db.close(); + return delete; + } + + /** + * 清空数据 + */ + public void deleteData() { + db = helper.getWritableDatabase(); + db.execSQL("delete from records"); + db.close(); + } +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/RecordSQLiteOpenHelper.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/RecordSQLiteOpenHelper.java new file mode 100644 index 00000000..b382ecb5 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/data/RecordSQLiteOpenHelper.java @@ -0,0 +1,31 @@ +package org.koishi.launcher.h2o2pro.tool.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +/** + * Created by yi.huangxing on 17/12/13.类描述: + */ + +public class RecordSQLiteOpenHelper extends SQLiteOpenHelper{ + private static String name = "record.db"; + private static Integer version = 1; + + + public RecordSQLiteOpenHelper(Context context) { + super(context, name, null, version); + } + + @Override + public void onCreate(SQLiteDatabase db) { + //打开数据库,建立了一个叫records的表,里面只有一列name来存储历史记录: + db.execSQL("create table records(id integer primary key autoincrement,name varchar(200))"); + + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { + + } +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/file/AppExecute.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/file/AppExecute.java new file mode 100644 index 00000000..a9ca6e4e --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/file/AppExecute.java @@ -0,0 +1,56 @@ +package org.koishi.launcher.h2o2pro.tool.file; + +import android.content.Context; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class AppExecute { + public static void output(Context context, String assetName, String outputDirectory) throws IOException { + File file = new File(outputDirectory); + if (!file.exists()) { + file.mkdirs(); + } + + InputStream inputStream = null; + inputStream = context.getAssets().open(assetName); + ZipInputStream zipInputStream = new ZipInputStream(inputStream); + ZipEntry zipEntry = zipInputStream.getNextEntry(); + byte[] buffer = new byte[1024 * 1024]; + int count = 0; + while (zipEntry != null) { + //如果是一个目录 + if (zipEntry.isDirectory()) { + //String name = zipEntry.getName(); + //name = name.substring(0, name.length() - 1); + file = new File(outputDirectory + File.separator + zipEntry.getName()); + file.mkdir(); + } else { + //如果是文件 + file = new File(outputDirectory + File.separator + + zipEntry.getName()); + //创建该文件 + file.createNewFile(); + FileOutputStream fileOutputStream = new FileOutputStream(file); + while ((count = zipInputStream.read(buffer)) > 0) { + fileOutputStream.write(buffer, 0, count); + } + + fileOutputStream.close(); + } + //定位到下一个文件入口 + zipEntry = zipInputStream.getNextEntry(); + + } + zipInputStream.close(); + + } + + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/Json.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/Json.java new file mode 100644 index 00000000..4b1ebf20 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/Json.java @@ -0,0 +1,166 @@ +package org.koishi.launcher.h2o2pro.tool.json; + +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonHandler; +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.List; + +/** + * The type Json. + */ +public class Json { + + private final JsonGenerator jsonGenerator = new JsonGenerator(); + private final JsonParser jsonParser = new JsonParser(); + + /** + * Parse {@link String} to {@link JsonValue}. + * + * @param json the json used to parse + * @return the json value is the raw return type + */ + public JsonValue fromJsonString(String json) { + return jsonParser.parse(json); + } + + /** + * Parse {@link String} to {@link JsonValue} and cast it to {@link Class} + * + * @param the type parameter determines the type of {@link JsonValue} + * @param json the input stream is used to parse + * @param clazz the clazz is used to cast {@link T} + * @return the value {@link T} + */ + public T fromJsonString(String json, Class clazz) { + return jsonParser.parse(json, clazz); + } + + + /** + * Parse {@link File} to {@link JsonValue} and cast it to {@link Class} + * + * @param the type parameter determines the type of {@link JsonValue} + * @param file the file is used to parse + * @param clazz the clazz is used to cast {@link T} + * @return the value {@link T} + * @throws FileNotFoundException the file not found exception + */ + public T fromFile(File file, Class clazz) throws FileNotFoundException { + return clazz.cast(jsonParser.parse(file)); + } + + /** + * Parse {@link File} to {@link JsonValue}. + * + * @param file the file used to parse + * @return the json value raw return type + * @throws FileNotFoundException the file not found exception + */ + public JsonValue fromFile(File file) throws FileNotFoundException { + return jsonParser.parse(new FileInputStream(file)); + } + + + /** + * Parse {@link InputStream} to {@link JsonValue} and cast it to {@link Class} + * + * @param the type parameter determines the type of {@link JsonValue} + * @param inputStream the input stream is used to parse + * @param clazz the clazz is used to cast {@link T} + * @return the value {@link T} + */ + public T parse(InputStream inputStream, Class clazz) { + return jsonParser.parse(inputStream, clazz); + } + + /** + * Parse json value with {@link InputStream} + * + * @param inputStream the input stream is used to parse + * @return the json value is the raw return type + */ + public JsonValue parse(InputStream inputStream) { + return jsonParser.parse(inputStream); + } + + /** + * To json value. + * Parse object of type {@link T} to {@link JsonValue} + * + * @param the type parameter used to determine value + * @param value the value used to parse + * @return the json value returns raw type of {@link JsonValue} + */ + public JsonValue toJson(T value) { + return jsonGenerator.toJson(value); + } + + + /** + * From json to list. + * Convert {@link JsonValue} to {@link T} and cast with {@link Class} + * + * @param the type parameter determines object type + * @param the type parameter is the class that is used t ocast + * @param jsonValue the json value is used to convert + * @param listClazz the list clazz is used to cast {@link T} + * @param clazz the clazz is used to determine object in {@link List} + * @return T is a list with cast {@link Class} + */ + public , K> T fromJson(JsonValue jsonValue, Class listClazz, Class clazz) { + return jsonGenerator.fromJson(jsonValue, listClazz, clazz); + } + + /** + * From json with cast. + * Convert {@link JsonValue} to {@link T} + * + * @param the type parameter determines type of return object + * @param jsonValue the json value is used to convert to {@link T} + * @param clazz the clazz is used to cast {@link T} + * @return {@link T} cast with {@link Class} + */ + public T fromJsonCast(JsonValue jsonValue, Class clazz) { + return jsonGenerator.fromJsonCast(jsonValue, clazz); + } + + /** + * From json. + * Convert {@link JsonValue} to raw object + * + * @param the type parameter determines type of return object + * @param jsonValue the json value is used to convert to {@link Object} + * @param clazz the clazz is used create object + * @return the object + */ + public Object fromJson(JsonValue jsonValue, Class clazz) { + return jsonGenerator.fromJson(jsonValue, clazz); + } + + + /** + * Register handler. + * Register a {@link JsonHandler } by {@link Class} + * + * @param clazz the clazz used to put {@link Class} and {@link JsonHandler} in {@link #jsonGenerator} + * @param jsonHandler the json handler is used to insert + */ + public void registerHandler(Class clazz, JsonHandler jsonHandler) { + jsonGenerator.registerHandler(clazz, jsonHandler); + } + + /** + * Unregister handler. + * Unregister a {@link JsonHandler} by {@link Class} + * + * @param clazz the clazz used to remove {@link JsonHandler} from {@link #jsonGenerator} + */ + public void unregisterHandler(Class clazz) { + jsonGenerator.unregisterHandler(clazz); + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/JsonGenerator.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/JsonGenerator.java new file mode 100644 index 00000000..146bfb83 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/JsonGenerator.java @@ -0,0 +1,299 @@ +package org.koishi.launcher.h2o2pro.tool.json; + +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonArray; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonBoolean; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonNull; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonNumber; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonObject; +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonHandler; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonString; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The class Json generator is used to parse json to a class or object to json. + */ +public class JsonGenerator { + + /** + * The Handlers is {@link Map} with key {@link Class} and {@link JsonHandler} + */ + protected final HashMap, JsonHandler> handlers = new HashMap<>(); + + /** + * To json value. + * Parse object of type {@link T} to {@link JsonValue} + * + * @param the type parameter used to determine value + * @param value the value used to parse + * @return the json value returns raw type of {@link JsonValue} + */ + public JsonValue toJson(T value) { + JsonValue jsonValue; + if (value == null) { + jsonValue = new JsonNull(); + return jsonValue; + } + + JsonHandler jsonHandler = getHandler(value.getClass()); + + if (jsonHandler != null) { + return jsonHandler.deserialize(value); + } + + Class clazz = value.getClass(); + + if (String.class.isAssignableFrom(clazz)) { + jsonValue = new JsonString(); + ((JsonString) jsonValue).setValue((String) value); + return jsonValue; + } else if (Enum.class.isAssignableFrom(clazz)) { + jsonValue = new JsonString(); + ((JsonString) jsonValue).setValue(((Enum) value).name()); + return jsonValue; + } else if (Number.class.isAssignableFrom(clazz)) { + jsonValue = new JsonNumber(); + ((JsonNumber) jsonValue).setValue(value.toString()); + return jsonValue; + } else if (Boolean.class.isAssignableFrom(clazz)) { + jsonValue = new JsonBoolean(); + ((JsonBoolean) jsonValue).setValue((Boolean) value); + return jsonValue; + } else if (List.class.isAssignableFrom(clazz)) { + JsonArray jsonArray = new JsonArray(); + List list = (List) value; + for (Object listValue : list) { + jsonArray.add(toJson(listValue)); + } + return jsonArray; + } else if (Map.class.isAssignableFrom(clazz)) { + JsonObject jsonObject = new JsonObject(); + Map map = (Map) value; + + for (Map.Entry entry : map.entrySet()) { + Object key = entry.getKey(); + Object mapValue = entry.getValue(); + if (key == null) { + jsonObject.add("null", toJson(mapValue)); + continue; + } + + Class keyClazz = key.getClass(); + if (String.class.isAssignableFrom(keyClazz) + || Number.class.isAssignableFrom(keyClazz) + || Boolean.class.isAssignableFrom(keyClazz)) { + jsonObject.add(String.valueOf(key), toJson(mapValue)); + } else if (Enum.class.isAssignableFrom(keyClazz)) { + jsonObject.add(((Enum) key).name(), toJson(mapValue)); + } + + } + return jsonObject; + } else { + JsonObject jsonObject = new JsonObject(); + + if (hasSuperclass(clazz)) { + for (Field declaredField : clazz.getSuperclass().getDeclaredFields()) { + declaredField.setAccessible(true); + try { + JsonValue transformedValue = toJson(declaredField.get(value)); + transformedValue.setKey(declaredField.getName()); + + jsonObject.add(transformedValue); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + for (Field declaredField : clazz.getDeclaredFields()) { + declaredField.setAccessible(true); + try { + JsonValue transformedValue = toJson(declaredField.get(value)); + transformedValue.setKey(declaredField.getName()); + + jsonObject.add(transformedValue); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + jsonValue = jsonObject; + } + + + return jsonValue; + } + + /** + * From json to list. + * Convert {@link JsonValue} to {@link T} and cast with {@link Class} + * + * @param the type parameter determines object type + * @param the type parameter is the class that is used t ocast + * @param jsonValue the json value is used to convert + * @param listClazz the list clazz is used to cast {@link T} + * @param clazz the clazz is used to determine object in {@link List} + * @return T is a list with cast {@link Class} + */ + public , K> T fromJson(JsonValue jsonValue, Class listClazz, Class clazz) { + return listClazz.cast(fromJson(null, jsonValue, clazz)); + } + + /** + * From json with cast. + * Convert {@link JsonValue} to {@link T} + * + * @param the type parameter determines type of return object + * @param jsonValue the json value is used to convert to {@link T} + * @param clazz the clazz is used to cast {@link T} + * @return {@link T} cast with {@link Class} + */ + public T fromJsonCast(JsonValue jsonValue, Class clazz) { + return clazz.cast(fromJson(null, jsonValue, clazz)); + } + + /** + * From json. + * Convert {@link JsonValue} to raw object + * + * @param the type parameter determines type of return object + * @param jsonValue the json value is used to convert to {@link Object} + * @param clazz the clazz is used create object + * @return the object + */ + public Object fromJson(JsonValue jsonValue, Class clazz) { + return fromJson(null, jsonValue, clazz); + } + + /** + * From json. + * Convert {@link JsonValue} to raw object + * + * @param the type parameter determines type of return object + * @param key the key is used to get a value out of {@link JsonObject} + * @param jsonValue the json value is used to convert to {@link Object} + * @param clazz the clazz is used create object + * @return the object + */ + public Object fromJson(String key, JsonValue jsonValue, Class clazz) { + if (jsonValue instanceof JsonString) { + return clazz.cast(((JsonString) jsonValue).getValue()); + } else if (jsonValue instanceof JsonNumber) { + return ((JsonNumber) jsonValue).getNumber(clazz); + } else if (jsonValue instanceof JsonBoolean) { + return clazz.cast(((JsonBoolean) jsonValue).isValue()); + } else if (jsonValue instanceof JsonNull) { + return null; + } else if (jsonValue instanceof JsonObject) { + if (key != null) { + return fromJson(((JsonObject) jsonValue).get(key), clazz); + } else { + try { + T object = clazz.newInstance(); + + JsonHandler jsonHandler = getHandler(clazz); + + if (jsonHandler != null) { + return jsonHandler.serialize(jsonValue); + } + + Class objectClazz = object.getClass(); + + if (hasSuperclass(objectClazz)) { + for (Field declaredField : objectClazz.getSuperclass().getDeclaredFields()) { + declaredField.setAccessible(true); + declaredField.set(object, fromJson(declaredField.getName(), jsonValue, declaredField.getType())); + } + } + + for (Field declaredField : objectClazz.getDeclaredFields()) { + declaredField.setAccessible(true); + declaredField.set(object, fromJson(declaredField.getName(), jsonValue, declaredField.getType())); + } + + return object; + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + + } + + } else if (jsonValue instanceof JsonArray) { + List list = new ArrayList(); + ((JsonArray) jsonValue).loop((integer, listValue) -> { + list.add(fromJson(listValue, clazz)); + }); + return list; + } + + + return null; + } + + /** + * Has superclass boolean. + * Checks if given class has a superclass + * + * @param the type parameter determines type of class used in class + * @param clazz the clazz is used to check + * @return the boolean true or false + */ + public boolean hasSuperclass(Class clazz) { + return clazz.getSuperclass() != null; + } + + /** + * Register handler. + * Register a {@link JsonHandler} by {@link Class} + * + * @param clazz the clazz used to put {@link Class} and {@link JsonHandler} in {@link #handlers} + * @param jsonHandler the json handler is used to insert + */ + public void registerHandler(Class clazz, JsonHandler jsonHandler) { + if (!isRegistered(clazz)) { + handlers.put(clazz, jsonHandler); + } + } + + /** + * Unregister handler. + * Unregister a {@link JsonHandler} by {@link Class} + * + * @param clazz the clazz used to remove {@link JsonHandler} from {@link #handlers} + */ + public void unregisterHandler(Class clazz) { + if (isRegistered(clazz)) { + handlers.remove(clazz); + } + } + + /** + * Gets handler from {@link #handlers}. + * + * @param clazz the clazz used to get {@link JsonHandler} from {@link #handlers} + * @return the handler null or {@link JsonHandler} + */ + public JsonHandler getHandler(Class clazz) { + if (!isRegistered(clazz)) return null; + + return handlers.get(clazz); + } + + /** + * Is registered boolean. + * Check if {@link JsonHandler} is registered in {@link #handlers} + * + * @param clazz the clazz used to get {@link JsonHandler} + * @return the boolean true or false + */ + public boolean isRegistered(Class clazz) { + return handlers.containsKey(clazz); + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/JsonParser.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/JsonParser.java new file mode 100644 index 00000000..314873b6 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/JsonParser.java @@ -0,0 +1,536 @@ +package org.koishi.launcher.h2o2pro.tool.json; + +import org.koishi.launcher.h2o2pro.tool.json.model.JsonArray; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonBoolean; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonNull; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonNumber; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonObject; +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonString; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +/** + * The class Json parser is used to parse a {@link String} or a {@link File} to {@link JsonValue} + */ +public class JsonParser { + + private char[] jsonBuffer; + private int jsonBufferPosition = 0; + + /** + * Parse {@link InputStream} to {@link JsonValue} and cast it to {@link Class} + * + * @param the type parameter determines the type of {@link JsonValue} + * @param inputStream the input stream is used to parse + * @param clazz the clazz is used to cast {@link T} + * @return the value {@link T} + */ + public T parse(InputStream inputStream, Class clazz) { + return clazz.cast(parse(inputStream)); + } + + /** + * Parse json value with {@link InputStream} + * + * @param inputStream the input stream is used to parse + * @return the json value is the raw return type + */ + public JsonValue parse(InputStream inputStream) { + try { + prepareParser(inputStream); + } catch (IOException exception) { + exception.printStackTrace(); + } + + skipWhiteSpace(); + switch (peekChar()) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + case 'E': + case 'e': + case '+': + case '-': { + return parseJsonNumber(); + } + case 'f': + case 't': { + return parseJsonBoolean(); + } + case 'n': { + return parseJsonNull(); + } + case '"': { + return parseJsonString(); + } + case '{': { + JsonObject jsonObject = parseJsonObject(); + jsonBuffer = null; + jsonBufferPosition = 0; + return jsonObject; + } + case '[': { + JsonArray jsonArray = parseJsonArray(); + jsonBuffer = null; + jsonBufferPosition = 0; + return jsonArray; + } + default: { + throw new RuntimeException("Could not parse file to Json!"); + } + } + } + + + /** + * Parse {@link String} to {@link JsonValue} and cast it to {@link Class} + * + * @param the type parameter determines the type of {@link JsonValue} + * @param json the input stream is used to parse + * @param clazz the clazz is used to cast {@link T} + * @return the value {@link T} + */ + public T parse(String json, Class clazz) { + return clazz.cast(parse(json)); + } + + /** + * Parse {@link String} to {@link JsonValue}. + * + * @param json the json used to parse + * @return the json value is the raw return type + */ + public JsonValue parse(String json) { + return parse(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8))); + } + + + /** + * Parse {@link File} to {@link JsonValue} and cast it to {@link Class} + * + * @param the type parameter determines the type of {@link JsonValue} + * @param file the file is used to parse + * @param clazz the clazz is used to cast {@link T} + * @return the value {@link T} + * @throws FileNotFoundException the file not found exception + */ + public T parse(File file, Class clazz) throws FileNotFoundException { + return clazz.cast(parse(file)); + } + + /** + * Parse {@link File} to {@link JsonValue}. + * + * @param file the file used to parse + * @return the json value raw return type + * @throws FileNotFoundException the file not found exception + */ + public JsonValue parse(File file) throws FileNotFoundException { + return parse(new FileInputStream(file)); + } + + + /** + * Prepare parser to parse given input to {@link JsonValue}. + * + * @param inputStream the input stream is used to parse + * @throws IOException the io exception + */ + public void prepareParser(InputStream inputStream) throws IOException { + StringBuilder stringBuilder = new StringBuilder(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\n"); + } + + jsonBuffer = stringBuilder.toString().toCharArray(); + bufferedReader.close(); + } + + /** + * Parse char from {@link #jsonBuffer} and increase {@link #jsonBufferPosition} + * + * @return the char + */ + public char parseChar() { + try { + return jsonBuffer[jsonBufferPosition++]; + } catch (IndexOutOfBoundsException exception) { + return (char) -1; + } + } + + /** + * Peek char with {@link #parseChar()} and revoke {@link #jsonBufferPosition} + * + * @return the char + */ + public char peekChar() { + char currentChar = parseChar(); + jsonBufferPosition--; + return currentChar; + } + + /** + * Skip white space. + */ + public void skipWhiteSpace() { + while (isWhiteSpace()) { + parseChar(); + } + } + + + /** + * Parse json object json object. + * Iterates through chars and construct json object. + * + * @return the json object + */ + public JsonObject parseJsonObject() { + JsonObject jsonObject = new JsonObject(); + + skipWhiteSpace(); + // Skip '{' + parseChar(); + + char currentChar = peekChar(); + while (currentChar != '}') { + skipWhiteSpace(); + + // Check the next char and handle it! + switch (peekChar()) { + case '"': { + + String key = parseJsonString().getValue(); + + skipWhiteSpace(); + // Skip ':' + currentChar = parseChar(); + skipWhiteSpace(); + + switch (peekChar()) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + case 'E': + case 'e': + case '+': + case '-': { + JsonNumber jsonNumber = parseJsonNumber(); + jsonNumber.setKey(key); + jsonObject.add(jsonNumber); + break; + } + case 'f': + case 't': { + JsonBoolean jsonBoolean = parseJsonBoolean(); + jsonBoolean.setKey(key); + jsonObject.add(jsonBoolean); + break; + } + case 'n': { + JsonNull jsonNull = parseJsonNull(); + jsonNull.setKey(key); + jsonObject.add(jsonNull); + break; + } + case '"': { + JsonString jsonString = parseJsonString(); + jsonString.setKey(key); + jsonObject.add(jsonString); + break; + } + case '{': { + JsonObject object = parseJsonObject(); + object.setKey(key); + jsonObject.add(object); + break; + } + case '[': { + JsonArray jsonArray = parseJsonArray(); + jsonArray.setKey(key); + jsonObject.add(jsonArray); + break; + } + } + + break; + } + case '}': + case ',': { + currentChar = parseChar(); + break; + } + default: { + throw new RuntimeException(String.format("Could not parse JsonObject stuck at Index: %s as Char: %s", jsonBufferPosition, jsonBuffer[jsonBufferPosition])); + } + + } + } + return jsonObject; + } + + /** + * Parse json array json array. + * Iterates through chars and construct json array. + * + * @return the json array + */ + public JsonArray parseJsonArray() { + JsonArray jsonArray = new JsonArray(); + + skipWhiteSpace(); + // Skip '[' + parseChar(); + + char currentChar = peekChar(); + + + while (currentChar != ']') { + skipWhiteSpace(); + + // Check the next char and handle it! + switch (peekChar()) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + case 'E': + case 'e': + case '+': + case '-': { + jsonArray.add(parseJsonNumber()); + break; + } + case '"': { + jsonArray.add(parseJsonString()); + break; + } + case 'f': + case 't': { + jsonArray.add(parseJsonBoolean()); + break; + } + case 'n': { + jsonArray.add(parseJsonNull()); + break; + } + case '{': { + jsonArray.add(parseJsonObject()); + break; + } + case '[': { + jsonArray.add(parseJsonArray()); + break; + } + case ']': + case ',': { + currentChar = parseChar(); + break; + } + default: { + throw new RuntimeException(String.format("Could not parse JsonArray stuck at Index: %s as Char: %s", jsonBufferPosition, jsonBuffer[jsonBufferPosition])); + } + } + } + + return jsonArray; + } + + /** + * Parse json string. + * Iterates through chars and construct json string. + * + * @return the json string + */ + public JsonString parseJsonString() { + JsonString jsonString = new JsonString(); + + StringBuilder stringBuilder = new StringBuilder(); + + skipWhiteSpace(); + + + // Take the first '"' + parseChar(); + + char currentChar = parseChar(); + + while (currentChar != '"') { + // Check if in a string is an escape char + if (currentChar == '\\') { + stringBuilder.append(currentChar); + currentChar = parseChar(); + } + + stringBuilder.append(currentChar); + currentChar = parseChar(); + } + + skipWhiteSpace(); + + jsonString.setValue(stringBuilder.toString()); + + return jsonString; + } + + /** + * Parse json null. + * Iterates through chars and check if json null is given. + * + * @return the json null + */ + public JsonNull parseJsonNull() { + char currentChar = parseChar(); + if (currentChar == 'n' && isNextChar('u', 0) && isNextChar('l', 1) && isNextChar('l', 2)) { + for (int i = 0; i < 3; i++) { + jsonBufferPosition++; + } + return new JsonNull(); + } + return null; + } + + /** + * Parse json boolean. + * Iterates through chars and check if json boolean is given. + * + * @return the json boolean + */ + public JsonBoolean parseJsonBoolean() { + char currentChar = parseChar(); + JsonBoolean jsonBoolean = null; + if (currentChar == 't' && isNextChar('r', 0) && isNextChar('u', 1) && isNextChar('e', 2)) { + for (int i = 0; i < 3; i++) { + jsonBufferPosition++; + } + jsonBoolean = new JsonBoolean(); + jsonBoolean.setValue(true); + } else if (currentChar == 'f' && isNextChar('a', 0) && isNextChar('l', 1) && isNextChar('s', 2) && isNextChar('e', 3)) { + for (int i = 0; i < 4; i++) { + jsonBufferPosition++; + } + jsonBoolean = new JsonBoolean(); + jsonBoolean.setValue(false); + } + return jsonBoolean; + } + + /** + * Parse json number. + * Iterates through chars and check if json number is given. + * + * @return the json number + */ + public JsonNumber parseJsonNumber() { + StringBuilder stringBuilder = new StringBuilder(); + + char currentChar = parseChar(); + + while (isNumber(currentChar)) { + stringBuilder.append(currentChar); + + currentChar = parseChar(); + } + + jsonBufferPosition--; + + JsonNumber jsonNumber = new JsonNumber(); + jsonNumber.setValue(stringBuilder.toString()); + + return jsonNumber; + } + + /** + * Is white space boolean. + * Check if current char in {@link #jsonBuffer} is a whitespace + * + * @return the boolean true or false + */ + public boolean isWhiteSpace() { + char currentChar = jsonBuffer[jsonBufferPosition]; + return currentChar == ' ' || currentChar == '\t' || currentChar == '\r' || currentChar == '\n'; + } + + /** + * Is next char boolean. + * Check if next char is given char by position + * + * @param currentChar the current char is the char that is going to be checked + * @param position the position used to get char at position from {@link #jsonBuffer} + * @return the boolean true or false + */ + public boolean isNextChar(char currentChar, int position) { + for (int i = 0; i < position; i++) { + parseChar(); + } + char nextChar = peekChar(); + for (int i = 0; i < position; i++) { + jsonBufferPosition--; + } + return nextChar == currentChar; + } + + /** + * Is number boolean. + * Check if current char is a number + * @param currentChar the current char is used to check + * @return the boolean true or false + */ + public boolean isNumber(char currentChar) { + char[] numberElements = new char[]{ + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '.', + 'E', + 'e', + '+', + '-' + }; + + for (char listChar : numberElements) { + if (listChar == currentChar) { + return true; + } + } + return false; + } + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/abstracts/JsonHandler.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/abstracts/JsonHandler.java new file mode 100644 index 00000000..08bdeebf --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/abstracts/JsonHandler.java @@ -0,0 +1,29 @@ +package org.koishi.launcher.h2o2pro.tool.json.abstracts; + +import org.koishi.launcher.h2o2pro.tool.json.model.JsonArray; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonObject; + +/** + * The abstract class {@link JsonHandler} with generic type {@link T} is used to serialize and deserialize an object + * + * @param the type parameter type of object which is going to be serialized or deserialized. + */ +public abstract class JsonHandler { + + /** + * Serialize {@link JsonValue} to object of type {@link T} + * + * @param jsonValue the json value can be a value like something {@link JsonObject} or {@link JsonArray} + * @return the t + */ + public abstract T serialize(JsonValue jsonValue); + + /** + * Deserialize {@link T} to {@link JsonValue} + * + * @param value the value is an object of {@link T} + * @return the json value is the deserialized value of {@link T} + */ + public abstract JsonValue deserialize(T value); + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/abstracts/JsonValue.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/abstracts/JsonValue.java new file mode 100644 index 00000000..e35ee90b --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/abstracts/JsonValue.java @@ -0,0 +1,82 @@ +package org.koishi.launcher.h2o2pro.tool.json.abstracts; + +import org.koishi.launcher.h2o2pro.tool.json.model.JsonObject; + +/** + * The class {@link JsonValue} is a upper class for Json values like {@link JsonObject} + */ +public abstract class JsonValue { + + private int intend = 0; + private String key; + + /** + * Instantiates a new Json value. + */ + public JsonValue() { + } + + /** + * Instantiates a new Json value. + * + * @param key the key is used to find a document in {@link JsonObject} + */ + public JsonValue(String key) { + this.key = key; + } + + /** + * Create space string. + * Used to generate the spaces when a object of type {@link JsonValue} is used with {@link #toString()} + * + * @return the string + */ + public String createSpace() { + StringBuilder spaceBuilder = new StringBuilder(); + for (int i = 0; i < intend; i++) { + spaceBuilder.append(" "); + } + return spaceBuilder.toString(); + } + + @Override + public abstract String toString(); + + /** + * Gets key. + * + * @return key the key is used to find a document in {@link JsonObject} + */ + public String getKey() { + return key; + } + + /** + * Sets key. + * + * @param key the key is used to find a document in {@link JsonObject} + */ + public void setKey(String key) { + this.key = key; + } + + + /** + * Gets intend. + * + * @return the intend used to calculate free space in method {@link #createSpace()} + */ + public int getIntend() { + return intend; + } + + /** + * Sets intend. + * + * @param intend the intend used to calculate ree space in method {@link #createSpace()} + */ + public void setIntend(int intend) { + this.intend = intend; + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/interfaces/IListable.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/interfaces/IListable.java new file mode 100644 index 00000000..1c1b5eaa --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/interfaces/IListable.java @@ -0,0 +1,70 @@ +package org.koishi.launcher.h2o2pro.tool.json.interfaces; + +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * The interface Listable. + * Used to implement functions like {@link #loop(Consumer)} or {@link #get(int)} + * + * @param the type parameter determines generic type of value that can be get or added from a list + */ +public interface IListable { + + /** + * Size int. + * + * @return the int determines the size of given list + */ + int size(); + + /** + * Add value to something. + * + * @param value the value is going to be add to a list or something else + */ + void add(T value); + + /** + * Add value to something where a index is needed. + * + * @param index the index is the position identifier of the object + * @param value the value is going to be add to a list or something else + */ + void add(int index, T value); + + /** + * Get a value of type {@link T} by its index and cast it with {@link Class}. + * + * @param index the index is the position of the object + * @param clazz the clazz is the type of object + * @return object of type {@link T} + */ + T get(int index, Class clazz); + + /** + * Get a value of type {@link T} by its index. + * + * @param index the index is the position of the object + * @return object of type {@link T} + */ + T get(int index); + + /** + * Loop is used to iterate through a {@link java.util.List} or an {@link java.util.Iterator} + * + * @param consumer the consumer accepts values from {@link java.util.List} + */ + void loop(Consumer consumer); + + /** + * Loop is used to iterate through a {@link java.util.List} or an {@link java.util.Iterator} + * + * @param consumer the consumer the consumer accepts values and indexes from {@link java.util.List} + */ + void loop(BiConsumer consumer); + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonArray.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonArray.java new file mode 100644 index 00000000..d9d1f900 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonArray.java @@ -0,0 +1,107 @@ +package org.koishi.launcher.h2o2pro.tool.json.model; + +import org.koishi.launcher.h2o2pro.tool.json.interfaces.IListable; +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * The class Json array is used to store objects of type {@link JsonValue} in {@link #values} + */ +public class JsonArray extends JsonValue implements IListable { + + + /** + * The Values is a list which is used by the {@link IListable} + */ + protected final List values = new ArrayList<>(); + + /** + * Instantiates a new Json array. + */ + public JsonArray() { + } + + /** + * Instantiates a new Json array. + * + * @param key the key is the identifier of {@link JsonValue} + */ + public JsonArray(String key) { + super(key); + } + + + + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + + String space = createSpace(); + + stringBuilder.append(space); + if (getKey() != null && !getKey().isEmpty()) { + stringBuilder.append("\"").append(getKey()).append("\"").append(" : "); + } + + stringBuilder.append("["); + loop((integer, jsonValue) -> { + jsonValue.setIntend(getIntend() + 2); + stringBuilder.append("\n"); + if(!(integer == size() - 1)) { + stringBuilder.append(jsonValue).append(","); + } else { + stringBuilder.append(jsonValue); + } + }); + stringBuilder.append("\n").append(space).append("]"); + + return stringBuilder.toString(); + } + + + @Override + public int size() { + return values.size(); + } + + @Override + public void add(JsonValue value) { + values.add(value); + } + + @Override + public void add(int index, JsonValue value) { + values.set(index, value); + } + + @Override + public JsonValue get(int index, Class clazz) { + return clazz.cast(get(index)); + } + + @Override + public JsonValue get(int index) { + return values.get(index); + } + + @Override + public void loop(Consumer consumer) { + for (JsonValue value : values) { + consumer.accept(value); + } + } + + @Override + public void loop(BiConsumer consumer) { + for (int index = 0; index < values.size(); index++) { + JsonValue jsonValue = values.get(index); + consumer.accept(index, jsonValue); + } + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonBoolean.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonBoolean.java new file mode 100644 index 00000000..fb5772bb --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonBoolean.java @@ -0,0 +1,77 @@ +package org.koishi.launcher.h2o2pro.tool.json.model; + +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +/** + * The class Json boolean stores a boolean. + */ +public class JsonBoolean extends JsonValue { + + /** + * The Value is the given boolean + */ + public boolean value; + + /** + * Instantiates a new Json boolean. + */ + public JsonBoolean() { + } + + /** + * Instantiates a new Json boolean. + * + * @param value the value is the given boolean that is set to {@link #value} + */ + public JsonBoolean(boolean value) { + this.value = value; + } + + /** + * Instantiates a new Json boolean. + * + * @param key the key is the identifier of {@link JsonValue} + * @param value the value is the given boolean that is set to {@link #value} + */ + public JsonBoolean(String key, boolean value) { + super(key); + this.value = value; + } + + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + String space = createSpace(); + + stringBuilder.append(space); + if (getKey() != null && !getKey().isEmpty()) { + stringBuilder.append("\"").append(getKey()).append("\"").append(" : "); + } + stringBuilder.append(isValue()); + + return stringBuilder.toString(); + } + + + /** + * Is value boolean. + * + * @return the boolean value is the stored at {@link #value} + */ + public boolean isValue() { + return value; + } + + /** + * Sets value. + * + * @param value the value is the value {@link #value} + */ + public void setValue(boolean value) { + this.value = value; + } + + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonNull.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonNull.java new file mode 100644 index 00000000..f4a971e5 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonNull.java @@ -0,0 +1,53 @@ +package org.koishi.launcher.h2o2pro.tool.json.model; + +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +/** + * The class Json null store a null value. + */ +public class JsonNull extends JsonValue { + + /** + * The Value is a final value because null is null! + */ + protected final String value = "null"; + + /** + * Instantiates a new Json null. + */ + public JsonNull() { + } + + /** + * Instantiates a new Json null. + * + * @param key the key is the identifier of {@link JsonValue} + */ + public JsonNull(String key) { + super(key); + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + String space = createSpace(); + + + stringBuilder.append(space); + if (getKey() != null && !getKey().isEmpty()) { + stringBuilder.append("\"").append(getKey()).append("\"").append(" : "); + } + stringBuilder.append("null"); + + return stringBuilder.toString(); + } + + /** + * Gets value. + * + * @return the value is the stored at {@link #value} + */ + public String getValue() { + return value; + } +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonNumber.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonNumber.java new file mode 100644 index 00000000..be80f6e1 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonNumber.java @@ -0,0 +1,264 @@ +package org.koishi.launcher.h2o2pro.tool.json.model; + +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +import java.math.BigDecimal; + +/** + * The class Json number stores a string that can be cast to a number. + */ +public class JsonNumber extends JsonValue { + + /** + * The Value is a string that can be cast to a number. + */ + protected String value; + + /** + * Instantiates a new Json number. + */ + public JsonNumber() { + } + + /** + * Instantiates a new Json number. + * + * @param key the key is the identifier of {@link JsonValue} + */ + public JsonNumber(String key) { + super(key); + } + + /** + * Instantiates a new Json number. + * + * @param key the key is the identifier of {@link JsonValue} + * @param value the value is the given string that is set to {@link #value} + */ + public JsonNumber(String key, String value) { + super(key); + this.value = value; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + + String space = createSpace(); + + stringBuilder.append(space); + if (getKey() != null && !getKey().isEmpty()) { + stringBuilder.append("\"").append(getKey()).append("\"").append(" : "); + } + stringBuilder.append(getValue()); + + return stringBuilder.toString(); + } + + + /** + * Gets value. + * + * @return the value the value is the given string that is set to {@link #value} + */ + public String getValue() { + return value; + } + + /** + * Sets value. + * + * @param value the value is set to {@link #value} + */ + public void setValue(String value) { + this.value = value; + } + + /** + * Byte value byte. + * Convert {@link #value} to {@link Byte} + * @return the byte converted value + */ + public byte byteValue() { + return getBigDecimal().byteValue(); + } + + /** + * Int value int. + * Convert {@link #value} to {@link Integer} + * @return the int converted value + */ + public int intValue() { + return getBigDecimal().intValue(); + } + + /** + * Short value short. + * Convert {@link #value} to {@link Short} + * @return the short converted value + */ + public short shortValue() { + return getBigDecimal().shortValue(); + } + + /** + * Double value double. + * Convert {@link #value} to {@link Double} + * @return the double converted value + */ + public double doubleValue() { + return getBigDecimal().doubleValue(); + } + + /** + * Float value float. + * Convert {@link #value} to {@link Float} + * @return the float converted value + */ + public float floatValue() { + return getBigDecimal().floatValue(); + } + + /** + * Long value long. + * Convert {@link #value} to {@link Long} + * @return the long converted value + */ + public long longValue() { + return getBigDecimal().longValue(); + } + + /** + * Gets number determined by given class {@link Class} + * + * @param the type parameter determines the given number + * @param clazz the clazz used to use correct number. + * @return the number object of type {@link Number} + */ + public Object getNumber(Class clazz) { + + if (clazz.equals(Byte.class) || clazz.equals(byte.class)) { + return byteValue(); + } else if (clazz.equals(Integer.class) || clazz.equals(int.class)) { + return intValue(); + } else if (clazz.equals(Short.class) || clazz.equals(short.class)) { + return shortValue(); + } else if (clazz.equals(Double.class) || clazz.equals(double.class)) { + return doubleValue(); + } else if (clazz.equals(Float.class) || clazz.equals(float.class)) { + return floatValue(); + } else if (clazz.equals(Long.class) || clazz.equals(long.class)) { + return longValue(); + } + + return null; + } + + /** + * Gets big decimal. + * + * @return the big decimal created by {@link #value} + */ + public BigDecimal getBigDecimal() { + return new BigDecimal(getValue()); + } + + + /** + * Is numeric boolean. + * Check if given string is a number + * @param value the value is used to check + * @return the boolean true or false + */ + public boolean isNumeric(String value) { + + if (value == null) { + return false; + } + boolean isNumber = value.matches("[+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?)"); + + if (isNumber) { + String testValue; + + if (isInteger(value)) { + int integerValue = intValue(); + + testValue = String.valueOf(integerValue); + } else if (isDouble(value)) { + double doubleValue = doubleValue(); + + + if (doubleValue > Double.MAX_VALUE || doubleValue < Double.MIN_EXPONENT) { + return false; + } + + testValue = String.valueOf(Math.round(doubleValue)); + } else if (isFloat(value)) { + float floatValue = floatValue(); + + if (floatValue > Float.MAX_VALUE || floatValue < Float.MIN_EXPONENT) { + return false; + } + + testValue = String.valueOf(Math.round(floatValue)); + } else { + testValue = value; + } + + try { + Long.parseLong(testValue); + } catch (Exception exception) { + return false; + } + + } + + return isNumber; + } + + /** + * Is float boolean. + * Check if given string is a float + * @param value the value is used to check + * @return the boolean true or false + */ + public boolean isFloat(String value) { + try { + Float.parseFloat(value); + return true; + } catch (Exception exception) { + return false; + } + } + + /** + * Is integer boolean. + * Check if given string is a integer + * @param value the value is used to check + * @return the boolean true or false + */ + public boolean isInteger(String value) { + try { + Integer.parseInt(value); + return true; + } catch (Exception exception) { + return false; + } + } + + /** + * Is double boolean. + * Check if given string is a double + * @param value the value is used to check + * @return the boolean true or false + */ + public boolean isDouble(String value) { + try { + Double.parseDouble(value); + return true; + } catch (Exception exception) { + return false; + } + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonObject.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonObject.java new file mode 100644 index 00000000..7d8a5971 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonObject.java @@ -0,0 +1,172 @@ +package org.koishi.launcher.h2o2pro.tool.json.model; + +import org.koishi.launcher.h2o2pro.tool.json.interfaces.IListable; +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * The class Json object is used to store objects of type {@link JsonValue} in {@link #values} + */ +public class JsonObject extends JsonValue implements IListable { + + /** + * The Values is a list which is used by the {@link IListable} + */ + protected final List values = new ArrayList<>(); + + /** + * Instantiates a new Json object. + */ + public JsonObject() { + } + + /** + * Instantiates a new Json object. + * + * @param key the key is the identifier of {@link JsonValue} + */ + public JsonObject(String key) { + super(key); + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + String space = createSpace(); + + stringBuilder.append(space); + + if (getKey() != null && !getKey().isEmpty()) { + stringBuilder.append("\"").append(getKey()).append("\"").append(" : "); + } + + stringBuilder.append("{"); + loop((integer, jsonValue) -> { + jsonValue.setIntend(getIntend() + 2); + stringBuilder.append("\n"); + if(!(integer == size() - 1)) { + stringBuilder.append(jsonValue).append(","); + } else { + stringBuilder.append(jsonValue); + } + }); + stringBuilder.append("\n").append(space).append("}"); + + return stringBuilder.toString(); + } + + + /** + * Get json value by key. + * + * @param key the key is the identifier of {@link JsonValue} + * @return the json value is null or the Json value that is found in {@link #values} + */ + public JsonValue get(String key) { + if(!has(key)) return null; + + return values.stream().filter(jsonValue -> jsonValue.getKey().equalsIgnoreCase(key)).findFirst().get(); + } + + /** + * Get {@link T} by key and cast it to {@link Class} + * + * @param the type parameter is used to determine what type of object is needed + * @param key the key is the identifier of {@link JsonValue} + * @param clazz the clazz is used to cast the {@link T} + * @return the {@link T} object + */ + public T get(String key, Class clazz) { + return clazz.cast(get(key)); + } + + /** + * Has is used to find a {@link JsonValue} by its key in {@link #values} + * + * @param key the key is the identifier of {@link JsonValue} + * @return the boolean true or false + */ + public boolean has(String key) { + return values.stream().anyMatch(jsonValue -> jsonValue.getKey() != null && jsonValue.getKey().equalsIgnoreCase(key)); + } + + /** + * Gets index. + * Used to get the index of an key if it is found in {@link #values} + * @param key the key is the identifier of {@link JsonValue} + * @return the index by key + */ + public int getIndex(String key) { + if(!has(key)) return -1; + + for (int index = 0; index < values.size(); index++) { + JsonValue jsonValue = values.get(index); + if(jsonValue.getKey().equalsIgnoreCase(key)) { + return index; + } + } + return -1; + } + + /** + * Add an object to {@link #values} by its key. + * + * @param key the key is the identifier of {@link JsonValue} + * @param jsonValue the json value is the {@link JsonValue} that is going to be added to {@link #values} + */ + public void add(String key, JsonValue jsonValue) { + jsonValue.setKey(key); + add(jsonValue); + } + + @Override + public int size() { + return values.size(); + } + + @Override + public void add(JsonValue value) { + if(has(value.getKey())) { + int index = getIndex(value.getKey()); + add(index, value); + } else { + values.add(value); + } + } + + @Override + public void add(int index, JsonValue value) { + values.set(index, value); + } + + @Override + public JsonValue get(int index, Class clazz) { + return clazz.cast(get(index)); + } + + @Override + public JsonValue get(int index) { + return values.get(index); + } + + @Override + public void loop(Consumer consumer) { + for (JsonValue value : values) { + consumer.accept(value); + } + } + + @Override + public void loop(BiConsumer consumer) { + for (int index = 0; index < values.size(); index++) { + JsonValue jsonValue = values.get(index); + consumer.accept(index, jsonValue); + } + } + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonString.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonString.java new file mode 100644 index 00000000..6bf2cfda --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/json/model/JsonString.java @@ -0,0 +1,73 @@ +package org.koishi.launcher.h2o2pro.tool.json.model; + +import org.koishi.launcher.h2o2pro.tool.json.abstracts.JsonValue; + +/** + * The class Json string is used to store a string. + */ +public class JsonString extends JsonValue { + + private String value; + + /** + * Instantiates a new Json string. + */ + public JsonString() { + } + + /** + * Instantiates a new Json string. + * + * @param key the key is the identifier of {@link JsonValue} + * @param value the value is the given string that is set to {@link #value} + */ + public JsonString(String key, String value) { + super(key); + this.value = value; + } + + /** + * Instantiates a new Json string. + * + * @param value the value is the given string that is set to {@link #value} + */ + public JsonString(String value) { + this.value = value; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + String space = createSpace(); + + stringBuilder.append(space); + if (getKey() != null && !getKey().isEmpty()) { + stringBuilder.append("\"").append(getKey()).append("\"") + .append(" : ").append("\"").append(getValue()).append("\""); + } else { + stringBuilder.append("\"").append(value).append("\""); + } + + return stringBuilder.toString(); + } + + + /** + * Gets value. + * + * @return the value is the stored at {@link #value} + */ + public String getValue() { + return value; + } + + /** + * Sets value. + * + * @param value the value is set to {@link #value} + */ + public void setValue(String value) { + this.value = value; + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/AuthenticationToken.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/AuthenticationToken.java new file mode 100644 index 00000000..4049ceea --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/AuthenticationToken.java @@ -0,0 +1,7 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts; + +/** + * The class Authentication token. + */ +public abstract class AuthenticationToken { +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/Authenticator.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/Authenticator.java new file mode 100644 index 00000000..28ded943 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/Authenticator.java @@ -0,0 +1,23 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts; + +import org.koishi.launcher.h2o2pro.tool.json.Json; + +/** + * The class Authenticator is used to log in to mojang or microsoft + */ +public abstract class Authenticator { + + protected final Json json = new Json(); + + /** + * Login string. + * + * @param email the email + * @param password the password + * @return the string + */ + public abstract T login(String email, String password); + + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/TextureVariable.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/TextureVariable.java new file mode 100644 index 00000000..670fc4c5 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/TextureVariable.java @@ -0,0 +1,81 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts; + +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile.MinecraftProfile; + +/** + * The type Texture variable stores data from {@link MinecraftProfile} + */ +public abstract class TextureVariable { + + private String id; + private String state; + private String url; + private String alias; + + /** + * Instantiates a new Texture variable. + */ + public TextureVariable() { + } + + /** + * Instantiates a new Texture variable. + * + * @param id the id + * @param state the state + * @param url the url + * @param alias the alias + */ + public TextureVariable(String id, String state, String url, String alias) { + this.id = id; + this.state = state; + this.url = url; + this.alias = alias; + } + + /** + * Gets id. + * + * @return the id + */ + public String getId() { + return id; + } + + /** + * Gets state. + * + * @return the state + */ + public String getState() { + return state; + } + + /** + * Gets url. + * + * @return the url + */ + public String getUrl() { + return url; + } + + /** + * Gets alias. + * + * @return the alias + */ + public String getAlias() { + return alias; + } + + @Override + public String toString() { + return "TextureVariable{" + + "id='" + id + '\'' + + ", state='" + state + '\'' + + ", url='" + url + '\'' + + ", alias='" + alias + '\'' + + '}'; + } +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/exception/AuthenticationException.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/exception/AuthenticationException.java new file mode 100644 index 00000000..5c023211 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/abstracts/exception/AuthenticationException.java @@ -0,0 +1,17 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.exception; + +/** + * The class Authentication exception is thrown when something went wrong during authentication + */ +public class AuthenticationException extends RuntimeException { + + /** + * Instantiates a new Authentication exception. + * + * @param message the message + */ + public AuthenticationException(String message) { + super(message); + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/MicrosoftAuthenticator.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/MicrosoftAuthenticator.java new file mode 100644 index 00000000..ada2596f --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/MicrosoftAuthenticator.java @@ -0,0 +1,332 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.microsoft; + +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.MinecraftToken; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.Authenticator; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.exception.AuthenticationException; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonArray; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonObject; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonString; + +import java.io.*; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * The class Microsoft authenticator is used to log in into microsoft account and generate mojang JWT token + */ +public class MicrosoftAuthenticator extends Authenticator { + + protected final String clientId = "00000000402b5328"; + protected final String scopeUrl = "service::user.auth.xboxlive.com::MBI_SSL"; + + protected String loginUrl; + protected String loginCookie; + protected String loginPPFT; + + @Override + public XboxToken login(String email, String password) { + MicrosoftToken microsoftToken = generateTokenPair(generateLoginCode(email, password)); + XboxLiveToken xboxLiveToken = generateXboxTokenPair(microsoftToken); + return generateXboxTokenPair(xboxLiveToken); + } + + /** + * Generate start login code from email and password + * + * @param email microsoft email + * @param password microsoft password + * @return login code + */ + private String generateLoginCode(String email, String password) { + try { + URL url = new URL("https://login.live.com/oauth20_authorize.srf?redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=" + scopeUrl + "&display=touch&response_type=code&locale=en&client_id=" + clientId); + HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); + InputStream inputStream = httpURLConnection.getResponseCode() == 200 ? httpURLConnection.getInputStream() : httpURLConnection.getErrorStream(); + + loginCookie = httpURLConnection.getHeaderField("set-cookie"); + + String responseData = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining()); + Matcher bodyMatcher = Pattern.compile("sFTTag:[ ]?'.*value=\"(.*)\"/>'").matcher(responseData); + if (bodyMatcher.find()) { + loginPPFT = bodyMatcher.group(1); + } else { + throw new AuthenticationException("Authentication error. Could not find 'LOGIN-PFTT' tag from response!"); + } + + bodyMatcher = Pattern.compile("urlPost:[ ]?'(.+?(?='))").matcher(responseData); + if (bodyMatcher.find()) { + loginUrl = bodyMatcher.group(1); + } else { + throw new AuthenticationException("Authentication error. Could not find 'LOGIN-URL' tag from response!"); + } + + if (loginCookie == null || loginPPFT == null || loginUrl == null) + throw new AuthenticationException("Authentication error. Error in authentication process!"); + + } catch (IOException exception) { + throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage())); + } + + return sendCodeData(email, password); + } + + /** + * Send code data from email and password + * + * @param email microsoft email + * @param password microsoft password + * @return login code + */ + private String sendCodeData(String email, String password) { + String authToken; + + Map requestData = new HashMap<>(); + + requestData.put("login", email); + requestData.put("loginfmt", email); + requestData.put("passwd", password); + requestData.put("PPFT", loginPPFT); + + String postData = encodeURL(requestData); + + try { + byte[] data = postData.getBytes(StandardCharsets.UTF_8); + + HttpURLConnection connection = (HttpURLConnection) new URL(loginUrl).openConnection(); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); + connection.setRequestProperty("Content-Length", String.valueOf(data.length)); + connection.setRequestProperty("Cookie", loginCookie); + + connection.setDoInput(true); + connection.setDoOutput(true); + + try (OutputStream outputStream = connection.getOutputStream()) { + outputStream.write(data); + } + + if (connection.getResponseCode() != 200 || connection.getURL().toString().equals(loginUrl)) { + throw new AuthenticationException("Authentication error. Username or password is not valid."); + } + + Pattern pattern = Pattern.compile("[?|&]code=([\\w.-]+)"); + + Matcher tokenMatcher = pattern.matcher(URLDecoder.decode(connection.getURL().toString(), StandardCharsets.UTF_8.name())); + if (tokenMatcher.find()) { + authToken = tokenMatcher.group(1); + } else { + throw new AuthenticationException("Authentication error. Could not handle data from response."); + } + } catch (IOException exception) { + throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage())); + } + + this.loginUrl = null; + this.loginCookie = null; + this.loginPPFT = null; + + return authToken; + } + + + /** + * Send xbox auth request + */ + private void sendXboxRequest(HttpURLConnection httpURLConnection, JsonObject request, JsonObject properties) throws IOException { + request.add("Properties", properties); + + String requestBody = request.toString(); + + httpURLConnection.setFixedLengthStreamingMode(requestBody.length()); + httpURLConnection.setRequestProperty("Content-Type", "application/json"); + httpURLConnection.setRequestProperty("Accept", "application/json"); + httpURLConnection.connect(); + try (OutputStream outputStream = httpURLConnection.getOutputStream()) { + outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII)); + } + } + + /** + * Generate {@link MinecraftToken} + * + * @param authToken from {@link #generateLoginCode(String, String)} + * @return {@link MinecraftToken} + */ + private MicrosoftToken generateTokenPair(String authToken) { + try { + Map arguments = new HashMap<>(); + arguments.put("client_id", clientId); + arguments.put("code", authToken); + arguments.put("grant_type", "authorization_code"); + arguments.put("redirect_uri", "https://login.live.com/oauth20_desktop.srf"); + arguments.put("scope", scopeUrl); + + StringJoiner argumentBuilder = new StringJoiner("&"); + for (Map.Entry entry : arguments.entrySet()) { + argumentBuilder.add(encodeURL(entry.getKey()) + "=" + encodeURL(entry.getValue())); + } + + byte[] data = argumentBuilder.toString().getBytes(StandardCharsets.UTF_8); + + URL url = new URL("https://login.live.com/oauth20_token.srf"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + httpURLConnection.setFixedLengthStreamingMode(data.length); + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpURLConnection.connect(); + + try (OutputStream outputStream = httpURLConnection.getOutputStream()) { + outputStream.write(data); + } + + JsonObject jsonObject = parseResponseData(httpURLConnection); + + return new MicrosoftToken(jsonObject.get("access_token", JsonString.class).getValue(), jsonObject.get("refresh_token", JsonString.class).getValue()); + + } catch (IOException exception) { + throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage())); + } + } + + /** + * Generate {@link XboxLiveToken} from {@link MicrosoftToken} + * + * @param microsoftToken the microsoft token + * @return the xbox live token + */ + public XboxLiveToken generateXboxTokenPair(MicrosoftToken microsoftToken) { + try { + URL url = new URL("https://user.auth.xboxlive.com/user/authenticate"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + httpURLConnection.setDoOutput(true); + + JsonObject request = new JsonObject(); + request.add("RelyingParty", new JsonString("http://auth.xboxlive.com")); + request.add("TokenType", new JsonString("JWT")); + + JsonObject properties = new JsonObject(); + properties.add("AuthMethod", new JsonString("RPS")); + properties.add("SiteName", new JsonString("user.auth.xboxlive.com")); + properties.add("RpsTicket", new JsonString(microsoftToken.getToken())); + + sendXboxRequest(httpURLConnection, request, properties); + + JsonObject jsonObject = parseResponseData(httpURLConnection); + + String uhs = ((JsonObject) (jsonObject.get("DisplayClaims", JsonObject.class)).get("xui", JsonArray.class).get(0)).get("uhs", JsonString.class).getValue(); + return new XboxLiveToken(jsonObject.get("Token", JsonString.class).getValue(), uhs); + } catch (IOException exception) { + throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage())); + } + } + + + /** + * Generate {@link XboxToken} from {@link XboxLiveToken} + * + * @param xboxLiveToken the xbox live token + * @return the xbox token + */ + public XboxToken generateXboxTokenPair(XboxLiveToken xboxLiveToken) { + try { + URL url = new URL("https://xsts.auth.xboxlive.com/xsts/authorize"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + + JsonObject request = new JsonObject(); + request.add("RelyingParty", new JsonString("rp://api.minecraftservices.com/")); + request.add("TokenType", new JsonString("JWT")); + + JsonObject properties = new JsonObject(); + properties.add("SandboxId", new JsonString("RETAIL")); + JsonArray userTokens = new JsonArray(); + userTokens.add(new JsonString(xboxLiveToken.getToken())); + properties.add("UserTokens", userTokens); + + sendXboxRequest(httpURLConnection, request, properties); + + if (httpURLConnection.getResponseCode() == 401) { + throw new AuthenticationException("No xbox account was found!"); + } + + JsonObject jsonObject = parseResponseData(httpURLConnection); + + String uhs = ((JsonObject) (jsonObject.get("DisplayClaims", JsonObject.class)).get("xui", JsonArray.class).get(0)).get("uhs", JsonString.class).getValue(); + return new XboxToken(jsonObject.get("Token", JsonString.class).getValue(), uhs); + } catch (IOException exception) { + throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage())); + } + } + + /** + * Parse response data to {@link JsonObject} + * + * @param httpURLConnection the http url connection + * @return the json object + * @throws IOException the io exception + */ + public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException { + BufferedReader bufferedReader; + + if (httpURLConnection.getResponseCode() != 200) { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream())); + } else { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); + } + String lines = bufferedReader.lines().collect(Collectors.joining()); + + JsonObject jsonObject = json.fromJsonString(lines, JsonObject.class); + if (jsonObject.has("error")) { + throw new AuthenticationException(jsonObject.get("error") + ": " + jsonObject.get("error_description")); + } + return jsonObject; + } + + + /** + * Encode url string. + * + * @param url the url + * @return the string + */ + private String encodeURL(String url) { + try { + return URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException exception) { + throw new UnsupportedOperationException(exception); + } + } + + + /** + * Encode url string. + * + * @param map the map + * @return the string + */ + private String encodeURL(Map map) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : map.entrySet()) { + if (sb.length() > 0) { + sb.append("&"); + } + sb.append(String.format("%s=%s", + encodeURL(entry.getKey().toString()), + encodeURL(entry.getValue().toString()) + )); + } + return sb.toString(); + } + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/MicrosoftToken.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/MicrosoftToken.java new file mode 100644 index 00000000..eae5b6f0 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/MicrosoftToken.java @@ -0,0 +1,48 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.microsoft; + +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.AuthenticationToken; + +/** + * The class Microsoft token stores token and refreshToken + */ +public class MicrosoftToken extends AuthenticationToken { + + protected String token; + protected String refreshToken; + + /** + * Instantiates a new Microsoft token. + */ + public MicrosoftToken() { + } + + /** + * Instantiates a new Microsoft token. + * + * @param token the token + * @param refreshToken the refresh token + */ + public MicrosoftToken(String token, String refreshToken) { + this.token = token; + this.refreshToken = refreshToken; + } + + /** + * Gets token. + * + * @return the token + */ + public String getToken() { + return token; + } + + /** + * Gets refresh token. + * + * @return the refresh token + */ + public String getRefreshToken() { + return refreshToken; + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/XboxLiveToken.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/XboxLiveToken.java new file mode 100644 index 00000000..9885d638 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/XboxLiveToken.java @@ -0,0 +1,49 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.microsoft; + +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.AuthenticationToken; + +/** + * The class Xbox live token stores token and uhs + */ +public class XboxLiveToken extends AuthenticationToken { + + protected String token; + protected String uhs; + + /** + * Instantiates a new Xbox live token. + */ + public XboxLiveToken() { + } + + /** + * Instantiates a new Xbox live token. + * + * @param token the token + * @param uhs the uhs + */ + public XboxLiveToken(String token, String uhs) { + this.token = token; + this.uhs = uhs; + } + + /** + * Gets token. + * + * @return the token + */ + public String getToken() { + return token; + } + + /** + * Gets uhs. + * + * @return the uhs + */ + public String getUhs() { + return uhs; + } + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/XboxToken.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/XboxToken.java new file mode 100644 index 00000000..7cd0fa81 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/microsoft/XboxToken.java @@ -0,0 +1,24 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.microsoft; + +/** + * The class xbox token has the same functions as {@link XboxLiveToken} + */ +public class XboxToken extends XboxLiveToken { + + /** + * Instantiates a new Xbox token. + */ + public XboxToken() { + } + + /** + * Instantiates a new Xbox token. + * + * @param token the token + * @param uhs the uhs + */ + public XboxToken(String token, String uhs) { + super(token, uhs); + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/MinecraftAuthenticator.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/MinecraftAuthenticator.java new file mode 100644 index 00000000..d52b88e1 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/MinecraftAuthenticator.java @@ -0,0 +1,155 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang; + +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.Authenticator; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.exception.AuthenticationException; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.microsoft.MicrosoftAuthenticator; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.microsoft.XboxToken; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile.MinecraftCape; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile.MinecraftProfile; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile.MinecraftSkin; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonArray; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonObject; +import org.koishi.launcher.h2o2pro.tool.json.model.JsonString; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * The class Minecraft authenticator is used to log in with normal minecraft details or with microsoft + */ +public class MinecraftAuthenticator extends Authenticator { + + /** + * The Microsoft authenticator is used for {@link #loginWithXbox(String, String)} + */ + protected final MicrosoftAuthenticator microsoftAuthenticator = new MicrosoftAuthenticator(); + + @Override + public MinecraftToken login(String email, String password) { + throw new RuntimeException("Not implemented yet."); + } + + /** + * Login with microsoft email and microsoft password + * + * @param email the email + * @param password the password + * @return the minecraft token + */ + public MinecraftToken loginWithXbox(String email, String password) { + XboxToken xboxToken = microsoftAuthenticator.login(email, password); + + try { + URL url = new URL("https://api.minecraftservices.com/authentication/login_with_xbox"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + + JsonObject request = new JsonObject(); + request.add("identityToken", new JsonString("XBL3.0 x=" + xboxToken.getUhs() + ";" + xboxToken.getToken())); + + String requestBody = request.toString(); + + httpURLConnection.setFixedLengthStreamingMode(requestBody.length()); + httpURLConnection.setRequestProperty("Content-Type", "application/json"); + httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com"); + httpURLConnection.connect(); + + try (OutputStream outputStream = httpURLConnection.getOutputStream()) { + outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII)); + } + + JsonObject jsonObject = microsoftAuthenticator.parseResponseData(httpURLConnection); + return new MinecraftToken(jsonObject.get("access_token", JsonString.class).getValue(), jsonObject.get("username", JsonString.class).getValue()); + } catch (IOException exception) { + throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage())); + } + } + + /** + * Check ownership from {@link MinecraftToken} and generate {@link MinecraftProfile} + * + * @param minecraftToken the minecraft token + * @return the minecraft profile + */ + public MinecraftProfile checkOwnership(MinecraftToken minecraftToken) { + try { + URL url = new URL("https://api.minecraftservices.com/minecraft/profile"); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + httpURLConnection.setRequestMethod("GET"); + + httpURLConnection.setRequestProperty("Authorization", "Bearer " + minecraftToken.getAccessToken()); + httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com"); + httpURLConnection.connect(); + + JsonObject jsonObject = parseResponseData(httpURLConnection); + + UUID uuid = generateUUID(jsonObject.get("id", JsonString.class).getValue()); + String name = jsonObject.get("name", JsonString.class).getValue(); + List minecraftSkins = json.fromJson(jsonObject.get("skins", JsonArray.class), List.class, MinecraftSkin.class); + List minecraftCapes = json.fromJson(jsonObject.get("skins", JsonArray.class), List.class, MinecraftCape.class); + + return new MinecraftProfile(uuid, name, minecraftSkins, minecraftCapes); + } catch (IOException exception) { + throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage())); + } + } + + /** + * Parse response data to {@link JsonObject} + * + * @param httpURLConnection the http url connection + * @return the json object + * @throws IOException the io exception + */ + public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException { + BufferedReader bufferedReader; + + if (httpURLConnection.getResponseCode() != 200) { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream())); + } else { + bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); + } + String lines = bufferedReader.lines().collect(Collectors.joining()); + + JsonObject jsonObject = json.fromJsonString(lines, JsonObject.class); + if (jsonObject.has("error")) { + throw new AuthenticationException(String.format("Could not find profile!. Error: '%s'", jsonObject.get("errorMessage", JsonString.class).getValue())); + } + return jsonObject; + } + + + /** + * Generate uuid from trimmedUUID + * + * @param trimmedUUID the trimmed uuid + * @return the uuid + * @throws IllegalArgumentException the illegal argument exception + */ + public UUID generateUUID(String trimmedUUID) throws IllegalArgumentException { + if (trimmedUUID == null) throw new IllegalArgumentException(); + StringBuilder builder = new StringBuilder(trimmedUUID.trim()); + try { + builder.insert(20, "-"); + builder.insert(16, "-"); + builder.insert(12, "-"); + builder.insert(8, "-"); + return UUID.fromString(builder.toString()); + } catch (StringIndexOutOfBoundsException e) { + return null; + } + } + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/MinecraftToken.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/MinecraftToken.java new file mode 100644 index 00000000..6ba01832 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/MinecraftToken.java @@ -0,0 +1,53 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang; + +/** + * The class Minecraft token stores minecraft accessToken and username + */ +public class MinecraftToken { + + private String accessToken; + private String username; + + /** + * Instantiates a new Minecraft token. + */ + public MinecraftToken() { + } + + /** + * Instantiates a new Minecraft token. + * + * @param accessToken the access token + * @param username the username + */ + public MinecraftToken(String accessToken, String username) { + this.accessToken = accessToken; + this.username = username; + } + + /** + * Gets access token. + * + * @return the access token + */ + public String getAccessToken() { + return accessToken; + } + + /** + * Gets username. + * + * @return the username + */ + public String getUsername() { + return username; + } + + @Override + public String toString() { + return "MinecraftToken{" + + "accessToken='" + accessToken + '\'' + + ", username='" + username + '\'' + + '}'; + } +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftCape.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftCape.java new file mode 100644 index 00000000..81839ae0 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftCape.java @@ -0,0 +1,31 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile; + +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.TextureVariable; + +/** + * The class Minecraft cape stores cape data from {@link MinecraftProfile} + */ +public class MinecraftCape extends TextureVariable { + + /** + * Instantiates a new Minecraft cape. + */ + public MinecraftCape() { + } + + /** + * Instantiates a new Minecraft cape. + * + * @param id the id + * @param state the state + * @param url the url + * @param alias the alias + */ + public MinecraftCape(String id, String state, String url, String alias) { + super(id, state, url, alias); + } + + + + +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftProfile.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftProfile.java new file mode 100644 index 00000000..1259b29d --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftProfile.java @@ -0,0 +1,82 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile; + +import java.util.List; +import java.util.UUID; + +/** + * The class Minecraft profile stores uuid, username, skins and capes + */ +public class MinecraftProfile { + + private UUID uuid; + private String username; + private List skins; + private List capes; + + /** + * Instantiates a new Minecraft profile. + */ + public MinecraftProfile() { + } + + /** + * Instantiates a new Minecraft profile. + * + * @param uuid the uuid + * @param username the username + * @param skins the skins + * @param capes the capes + */ + public MinecraftProfile(UUID uuid, String username, List skins, List capes) { + this.uuid = uuid; + this.username = username; + this.skins = skins; + this.capes = capes; + } + + /** + * Gets uuid. + * + * @return the uuid + */ + public UUID getUuid() { + return uuid; + } + + /** + * Gets username. + * + * @return the username + */ + public String getUsername() { + return username; + } + + /** + * Gets skins. + * + * @return the skins + */ + public List getSkins() { + return skins; + } + + /** + * Gets capes. + * + * @return the capes + */ + public List getCapes() { + return capes; + } + + @Override + public String toString() { + return "MinecraftProfile{" + + "uuid=" + uuid + + ", username='" + username + '\'' + + ", skins=" + skins + + ", capes=" + capes + + '}'; + } +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftSkin.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftSkin.java new file mode 100644 index 00000000..586a32b5 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/NewLoginTask/auth/model/mojang/profile/MinecraftSkin.java @@ -0,0 +1,61 @@ +package org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile; + +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.TextureVariable; + +/** + * The class Minecraft skin stores cape data from {@link MinecraftProfile} + */ +public class MinecraftSkin extends TextureVariable { + + private String variant; + + /** + * Instantiates a new Minecraft skin. + */ + public MinecraftSkin() { + } + + /** + * Instantiates a new Minecraft skin. + * + * @param variant the variant + */ + public MinecraftSkin(String variant) { + this.variant = variant; + } + + /** + * Instantiates a new Minecraft skin. + * + * @param id the id + * @param state the state + * @param url the url + * @param alias the alias + * @param variant the variant + */ + public MinecraftSkin(String id, String state, String url, String alias, String variant) { + super(id, state, url, alias); + this.variant = variant; + } + + /** + * Gets variant. + * + * @return the variant + */ + public String getVariant() { + return variant; + } + + + @Override + public String toString() { + return "MinecraftSkin{" + + "id='" + getId() + '\'' + + ", state='" + getState() + '\'' + + ", url='" + getUrl() + '\'' + + ", alias='" + getAlias() + '\'' + + "variant='" + variant + '\'' + + '}'; + } +} diff --git a/app/src/main/java/com/koishi/launcher/h2o2/tools/LoginTask.java b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/OldLoginTask/LoginTask.java similarity index 90% rename from app/src/main/java/com/koishi/launcher/h2o2/tools/LoginTask.java rename to app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/OldLoginTask/LoginTask.java index 750af391..05021f26 100644 --- a/app/src/main/java/com/koishi/launcher/h2o2/tools/LoginTask.java +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/tool/login/OldLoginTask/LoginTask.java @@ -1,4 +1,4 @@ -package com.koishi.launcher.h2o2.tools; +package org.koishi.launcher.h2o2pro.tool.login.OldLoginTask; import java.io.BufferedReader; import java.io.DataOutputStream; @@ -10,6 +10,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; +import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; @@ -18,24 +19,30 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; + import org.json.JSONException; import org.json.JSONObject; + import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; public class LoginTask { - public static String[] login(String username,String password){ + public static String str; + public static String[] login(String username,String password, String api){ try { + JSONObject json=new JSONObject(); json.put("username",username); json.put("password",password); json.put("agent",new JSONObject().put("name","Minecraft").put("version",1)); json.put("requestUser",true); - json.put("clientToken","mio_launcher"); - String str=getJsonData(json,"https://authserver.mojang.com/authenticate",false); + json.put("clientToken","h2o_launcher"); + str=getJsonData(json, api, false); + JSONObject data=new JSONObject(str); String[] msg=new String[4]; //token @@ -43,10 +50,10 @@ public static String[] login(String username,String password){ //id msg[1]=data.getJSONObject("selectedProfile").getString("name"); //uuid - msg[2]=getUUID(msg[1]); + msg[2]=data.getJSONObject("selectedProfile").getString("id"); //true id // msg[3]=data.getJSONObject("selectedProfile").getString("id"); - + return msg; } catch (Exception e) @@ -56,26 +63,28 @@ public static String[] login(String username,String password){ return s; } } - public static boolean checkif(String at){ + public static boolean checkif(String at, String api){ try { JSONObject json=new JSONObject(); json.put("accessToken",at); json.put("clientToken","boat_launcher"); - if(getJsonData(json,"https://authserver.mojang.com/validate",true).equals("204")){ - return true; - }else{ - return false; - } + if(getJsonData(json,api,true).equals("204")){ + return true; + }else{ + return false; + } + } catch (JSONException e) { - + } return false; } + private static String getJsonData(JSONObject jsonParam,String urls,boolean nodata) { StringBuffer sb=new StringBuffer(); try { @@ -108,7 +117,7 @@ private static String getJsonData(JSONObject jsonParam,String urls,boolean nodat // 设置文件类型: conn.setRequestProperty("Content-Type", "application/json"); // 开始连接请求 - conn.connect(); + conn.connect(); OutputStream out = new DataOutputStream(conn.getOutputStream()) ; // 写入请求的字符串 out.write(data); @@ -122,7 +131,7 @@ private static String getJsonData(JSONObject jsonParam,String urls,boolean nodat } // 请求返回的状态 if (HttpsURLConnection.HTTP_OK == conn.getResponseCode()){ - System.out.println("连接成功"); + System.out.println("Success"); // 请求返回的数据 InputStream in1 = conn.getInputStream(); try { @@ -139,7 +148,7 @@ private static String getJsonData(JSONObject jsonParam,String urls,boolean nodat } } else { System.out.println("error++"); - + } } catch (Exception e) { @@ -162,7 +171,7 @@ public static String getUUID(String playerID) } } - + public static void set(String key,String value) { try { diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/CustomFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/CustomFragment.java new file mode 100644 index 00000000..3c8388ba --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/CustomFragment.java @@ -0,0 +1,295 @@ +package org.koishi.launcher.h2o2pro.ui.custom; + +import android.app.Dialog; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.method.LinkMovementMethod; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.fragment.app.Fragment; + +import com.google.android.material.button.MaterialButton; + +import org.koishi.launcher.h2o2pro.R; +import org.koishi.launcher.h2o2pro.SettingsActivity; +import org.koishi.launcher.h2o2pro.TerminalActivity; + +public class CustomFragment extends Fragment { + + /**************** + * 此页面不再使用 + * 改为SettingsFragment + ******************/ + + public LinearLayout pg1,pg2,pg3; + + public AppCompatImageButton vx,afd,ptr,qq,dis,git; + public ImageButton libBoat,libMio,libCrash,libLogin,libXz,libCommon,libJsoup,libGson,libShell,libMd,libHttp,libFast,thkBoat,thkMio,thkLogin,thkFire,thkFish,thkShulker; + public LinearLayout cSet,cTer,cDonate,cApp,cLib,cThk; + public TextView ab; + + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.fragment_custom, container, false); + + cSet = root.findViewById(R.id.open_set); + cTer = root.findViewById(R.id.open_ter); + cDonate = root.findViewById(R.id.open_donate); + cApp = root.findViewById(R.id.open_about); + cLib = root.findViewById(R.id.open_lib); + cThk = root.findViewById(R.id.open_thk); + + cSet.setOnClickListener(v->{ + startActivity(new Intent(requireActivity(), SettingsActivity.class)); + }); + cTer.setOnClickListener(v->{ + startActivity(new Intent(requireActivity(), TerminalActivity.class)); + }); + cDonate.setOnClickListener(v->openDonate()); + cApp.setOnClickListener(v->showAboutDialog()); + cLib.setOnClickListener(v->openLibDialog()); + cThk.setOnClickListener(v->openThkDialog()); + + return root; + } + + private void crash() { + throw new RuntimeException("Crash test from CustomFragment."); + } + + /**************** + * + * 发起添加群流程。群号:Boat_H2O2 && 高 考 冲 刺 (572291176) 的 key 为: -c3oG3cfXX-v6W8MbEl9_Fl2JjuuvpC6 + * 调用 joinQQGroup(-c3oG3cfXX-v6W8MbEl9_Fl2JjuuvpC6) 即可发起手Q客户端申请加群 Boat_H2O2 && 高 考 冲 刺 (572291176) + * + * @param key 由官网生成的key + * @return 返回true表示呼起手Q成功,返回false表示呼起失败 + ******************/ + public boolean joinQQGroup(String key) { + Intent intent = new Intent(); + intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3D" + key)); + // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + try { + startActivity(intent); + return true; + } catch (Exception e) { + // 未安装手Q或安装的版本不支持 + return false; + } + } + + //----------Menu点击---------- + + public void openDonate() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_donate_layout, null); + mDialog.setContentView(dialogView); + + vx = dialogView.findViewById(R.id.donate_wc); + afd = dialogView.findViewById(R.id.donate_afd); + ptr = dialogView.findViewById(R.id.donate_ptr); + + vx.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://gitee.com/NaCln4c1/naclfile/raw/master/Documents/ic_donate_wx.png")); + }); + afd.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://afdian.net/@boat-h2o")); + }); + ptr.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://www.patreon.com/boatapp_h2o")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void showDonateDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_dialog_donate, null); + mDialog.setContentView(dialogView); + MaterialButton cancel = dialogView.findViewById(R.id.custom_donate_cancel); + MaterialButton start = dialogView.findViewById(R.id.custom_donate_ok); + cancel.setOnClickListener(v -> mDialog.dismiss()); + start.setOnClickListener(v -> { + joinQQGroup("-c3oG3cfXX-v6W8MbEl9_Fl2JjuuvpC6"); + }); + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void showAboutDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_about_layout, null); + mDialog.setContentView(dialogView); + + ab = dialogView.findViewById(R.id.ab); + ab.setMovementMethod(LinkMovementMethod.getInstance()); + + qq = dialogView.findViewById(R.id.about_qq); + dis = dialogView.findViewById(R.id.about_dis); + git = dialogView.findViewById(R.id.about_git); + + qq.setOnClickListener(v->{ + showDonateDialog(); + mDialog.dismiss(); + }); + dis.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://discord.gg/Ktw9sYx879\n")); + }); + git.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/NaCln4c1")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void openLibDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_lib_layout, null); + mDialog.setContentView(dialogView); + + libBoat = dialogView.findViewById(R.id.lib_boat); + libMio = dialogView.findViewById(R.id.lib_mio); + libCrash = dialogView.findViewById(R.id.lib_cat); + libLogin = dialogView.findViewById(R.id.lib_login); + libXz = dialogView.findViewById(R.id.lib_xz); + libCommon = dialogView.findViewById(R.id.lib_common); + libJsoup = dialogView.findViewById(R.id.lib_jsoup); + libGson = dialogView.findViewById(R.id.lib_gson); + libShell = dialogView.findViewById(R.id.lib_shell); + libMd = dialogView.findViewById(R.id.lib_md); + libHttp = dialogView.findViewById(R.id.lib_okhttp); + libFast = dialogView.findViewById(R.id.lib_fastjson); + + libBoat.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/AOF-Dev/BoatApp\n")); + }); + libMio.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ShirosakiMio/BoatApp\n")); + }); + libCrash.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/Ereza/CustomActivityOnCrash\n")); + }); + libLogin.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/Ratsiiel/minecraft-auth-library\n")); + }); + libXz.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://tukaani.org/xz/java.html\n")); + }); + libCommon.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/apache/commons-compress\n")); + }); + libJsoup.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/jhy/jsoup\n")); + }); + libGson.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/google/gson\n")); + }); + libShell.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/jackpal/Android-Terminal-Emulator\n")); + }); + libMd.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://gitee.com/wateryuan/MarkDownTest\n")); + }); + libHttp.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ejlchina/okhttps\n")); + }); + libFast.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/alibaba/fastjson\n")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void openThkDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_thank_layout, null); + mDialog.setContentView(dialogView); + + thkBoat = dialogView.findViewById(R.id.thk_boat); + thkMio = dialogView.findViewById(R.id.thk_mio); + thkLogin = dialogView.findViewById(R.id.thk_ratsiiel); + thkFire = dialogView.findViewById(R.id.thk_fire); + thkFish = dialogView.findViewById(R.id.thk_fish); + thkShulker = dialogView.findViewById(R.id.thk_shulker); + + thkBoat.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/CosineMath\n")); + }); + thkMio.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ShirosakiMio\n")); + }); + thkLogin.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/Ratsiiel\n")); + }); + thkFire.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/MCfire-miracle\n")); + }); + thkFish.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/TSaltedfishKing\n")); + }); + thkShulker.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ShulkerSakura\n")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/CustomViewModel.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/CustomViewModel.java new file mode 100644 index 00000000..9c8d4b26 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/CustomViewModel.java @@ -0,0 +1,19 @@ +package org.koishi.launcher.h2o2pro.ui.custom; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class CustomViewModel extends ViewModel { + + private MutableLiveData mText; + + public CustomViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is slideshow fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/FuncFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/FuncFragment.java new file mode 100644 index 00000000..85c159e2 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/FuncFragment.java @@ -0,0 +1,304 @@ +package org.koishi.launcher.h2o2pro.ui.custom; + +import android.app.Dialog; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.method.LinkMovementMethod; +import android.view.Display; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import com.google.android.material.button.MaterialButton; + +import org.koishi.launcher.h2o2pro.R; +import org.koishi.launcher.h2o2pro.SettingsActivity; +import org.koishi.launcher.h2o2pro.TerminalActivity; + +public class FuncFragment extends PreferenceFragmentCompat { + + public AppCompatImageButton vx,afd,ptr,qq,dis,git; + public ImageButton libBoat,libMio,libCrash,libLogin,libXz,libCommon,libJsoup,libGson,libShell,libMd,libHttp,libFast,thkBoat,thkMio,thkLogin,thkFire,thkFish,thkShulker; + public Preference cSet,cTer,cDonate,cApp,cLib,cThk; + public TextView ab; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.func_preferences, rootKey); + + cSet = findPreference("c_set"); + cTer = findPreference("c_ter"); + cDonate = findPreference("c_donate"); + cApp = findPreference("c_about"); + cLib = findPreference("c_lib"); + cThk = findPreference("c_thk"); + + if (cSet != null){ + cSet.setOnPreferenceClickListener(preference -> { + startActivity(new Intent(requireActivity(), SettingsActivity.class)); + //requireActivity().finish(); + return true; + }); + } + + if (cTer != null){ + cTer.setOnPreferenceClickListener(preference -> { + startActivity(new Intent(requireActivity(), TerminalActivity.class)); + return true; + }); + } + + if (cDonate != null){ + cDonate.setOnPreferenceClickListener(preference -> { + openDonate(); + return true; + }); + } + + if (cApp != null){ + cApp.setOnPreferenceClickListener(preference -> { + showAboutDialog(); + return true; + }); + } + + if (cLib != null){ + cLib.setOnPreferenceClickListener(preference -> { + openLibDialog(); + return true; + }); + } + + if (cThk != null){ + cThk.setOnPreferenceClickListener(preference -> { + openThkDialog(); + return true; + }); + } + } + + public boolean joinQQGroup(String key) { + Intent intent = new Intent(); + intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3D" + key)); + // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + try { + startActivity(intent); + return true; + } catch (Exception e) { + // 未安装手Q或安装的版本不支持 + return false; + } + } + + //----------Menu点击---------- + + public void openDonate() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_donate_layout, null); + mDialog.setContentView(dialogView); + + vx = dialogView.findViewById(R.id.donate_wc); + afd = dialogView.findViewById(R.id.donate_afd); + ptr = dialogView.findViewById(R.id.donate_ptr); + + vx.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://gitee.com/NaCln4c1/naclfile/raw/master/Documents/ic_donate_wx.png")); + }); + afd.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://afdian.net/@boat-h2o")); + }); + ptr.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://www.patreon.com/boatapp_h2o")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void showDonateDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_dialog_donate, null); + mDialog.setContentView(dialogView); + MaterialButton cancel = dialogView.findViewById(R.id.custom_donate_cancel); + MaterialButton start = dialogView.findViewById(R.id.custom_donate_ok); + cancel.setOnClickListener(v -> mDialog.dismiss()); + start.setOnClickListener(v -> { + joinQQGroup("-c3oG3cfXX-v6W8MbEl9_Fl2JjuuvpC6"); + }); + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void showAboutDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_about_layout, null); + mDialog.setContentView(dialogView); + + ab = dialogView.findViewById(R.id.ab); + ab.setMovementMethod(LinkMovementMethod.getInstance()); + + qq = dialogView.findViewById(R.id.about_qq); + dis = dialogView.findViewById(R.id.about_dis); + git = dialogView.findViewById(R.id.about_git); + + qq.setOnClickListener(v->{ + showDonateDialog(); + mDialog.dismiss(); + }); + dis.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://discord.gg/Ktw9sYx879\n")); + }); + git.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/NaCln4c1")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void openLibDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_lib_layout, null); + mDialog.setContentView(dialogView); + + libBoat = dialogView.findViewById(R.id.lib_boat); + libMio = dialogView.findViewById(R.id.lib_mio); + libCrash = dialogView.findViewById(R.id.lib_cat); + libLogin = dialogView.findViewById(R.id.lib_login); + libXz = dialogView.findViewById(R.id.lib_xz); + libCommon = dialogView.findViewById(R.id.lib_common); + libJsoup = dialogView.findViewById(R.id.lib_jsoup); + libGson = dialogView.findViewById(R.id.lib_gson); + libShell = dialogView.findViewById(R.id.lib_shell); + libMd = dialogView.findViewById(R.id.lib_md); + libHttp = dialogView.findViewById(R.id.lib_okhttp); + libFast = dialogView.findViewById(R.id.lib_fastjson); + + libBoat.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/AOF-Dev/BoatApp\n")); + }); + libMio.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ShirosakiMio/BoatApp\n")); + }); + libCrash.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/Ereza/CustomActivityOnCrash\n")); + }); + libLogin.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/Ratsiiel/minecraft-auth-library\n")); + }); + libXz.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://tukaani.org/xz/java.html\n")); + }); + libCommon.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/apache/commons-compress\n")); + }); + libJsoup.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/jhy/jsoup\n")); + }); + libGson.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/google/gson\n")); + }); + libShell.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/jackpal/Android-Terminal-Emulator\n")); + }); + libMd.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://gitee.com/wateryuan/MarkDownTest\n")); + }); + libHttp.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ejlchina/okhttps\n")); + }); + libFast.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/alibaba/fastjson\n")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + public void openThkDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.custom_thank_layout, null); + mDialog.setContentView(dialogView); + + thkBoat = dialogView.findViewById(R.id.thk_boat); + thkMio = dialogView.findViewById(R.id.thk_mio); + thkLogin = dialogView.findViewById(R.id.thk_ratsiiel); + thkFire = dialogView.findViewById(R.id.thk_fire); + thkFish = dialogView.findViewById(R.id.thk_fish); + thkShulker = dialogView.findViewById(R.id.thk_shulker); + + thkBoat.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/CosineMath\n")); + }); + thkMio.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ShirosakiMio\n")); + }); + thkLogin.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/Ratsiiel\n")); + }); + thkFire.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/MCfire-miracle\n")); + }); + thkFish.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/TSaltedfishKing\n")); + }); + thkShulker.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://github.com/ShulkerSakura\n")); + }); + + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/SettingsFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/SettingsFragment.java new file mode 100644 index 00000000..9fa1d240 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/custom/SettingsFragment.java @@ -0,0 +1,226 @@ +package org.koishi.launcher.h2o2pro.ui.custom; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.widget.Toast; + +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.preference.CheckBoxPreference; +import androidx.preference.EditTextPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreference; +import androidx.preference.SwitchPreferenceCompat; + +import org.koishi.launcher.h2o2pro.LogcatActivity; +import org.koishi.launcher.h2o2pro.MainActivity; +import org.koishi.launcher.h2o2pro.R; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.tool.file.AppExecute; + +import java.io.File; +import java.io.IOException; + +public class SettingsFragment extends PreferenceFragmentCompat { + + public Preference delRun,delCfg,crash,logView,langTr; + public EditTextPreference etId,editJvm,editMcf; + public SwitchPreferenceCompat appTheme; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.settings_preferences, rootKey); + etId = (EditTextPreference) findPreference("set_id"); + editJvm = (EditTextPreference) findPreference("set_jvm"); + editMcf= (EditTextPreference) findPreference("set_mcf"); + + assert etId != null; + etId.setText(GetGameJson.getBoatCfg("auth_player_name","player")); + + assert editJvm != null; + editJvm.setText(GetGameJson.getBoatCfg("extraJavaFlags","-client -Xmx750M")); + + assert editMcf != null; + editMcf.setText(GetGameJson.getBoatCfg("extraMinecraftFlags","")); + + delRun = findPreference("set_reset_cfg"); + if (delRun != null) { + delRun.setOnPreferenceClickListener(preference -> { + del(); + return true; + }); + } + delCfg = findPreference("set_reset_run"); + if (delCfg != null) { + delCfg.setOnPreferenceClickListener(preference -> { + reset(); + return true; + }); + } + + appTheme = findPreference("set_theme"); + assert appTheme != null; + if (Build.VERSION.SDK_INT >= 31) { + appTheme.setChecked(true); + } else { + appTheme.setChecked(false); + } + + langTr = findPreference("set_lang_tr"); + if (langTr != null){ + langTr.setOnPreferenceClickListener(preference -> { + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://wwa.lanzoui.com/iGyPkvlgqdc\n")); + return true; + }); + } + logView = findPreference("set_log"); + if (logView != null) { + logView.setOnPreferenceClickListener(preference -> { + Intent i = (new Intent(requireActivity(), LogcatActivity.class)); + startActivity(i); + return true; + }); + } + crash = findPreference("set_crash"); + if (crash != null) { + crash.setOnPreferenceClickListener(preference -> { + crash(); + return true; + }); + } + } + + public void reset() { + AlertDialog alertDialog1 = new AlertDialog.Builder(getActivity()) + .setTitle(getResources().getString(R.string.action))//标题 + .setIcon(R.drawable.ic_boat)//图标 + .setMessage(getResources().getString(R.string.resetwarn)) + .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + deleteFile("/storage/emulated/0/games/com.koishi.launcher/h2o2/h2ocfg.json"); + try { + /* + FileWriter fr = new FileWriter("/storage/emulated/0/games/com.koishi.launcher/h2o2/h2ocfg.json"); + fr.write("{\"mouseMode\":\"false\",\"backToRightClick\":\"false\",\"jumpToLeft\":\"None\",\"email\":\"\",\"password\":\"\",\"dontEsc\":\"false\",\"pack\":\"Default\",\"allVerLoad\":\"true\",\"openGL\":\"libGL112.so.1\"}"); + fr.close(); + Intent intent = new Intent(getActivity(), MainActivity.class); + startActivity(intent);// TODO: Implement this method + System.out.println("success"); + getActivity().finish(); + */ AppExecute.output(getActivity(),"h2o2.zip", Environment.getExternalStorageDirectory() + "/games/com.koishi.launcher/h2o2"); + Intent i2 = new Intent(getActivity(), MainActivity.class); + i2.putExtra("fragment", getResources().getString(R.string.menu_home)); + startActivity(i2); + getActivity().finish(); + } catch (IOException e) { + System.out.println(e); + Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_SHORT).show(); + } + } + }) + .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + } + }) + .create(); + + alertDialog1.show(); + } + + public void del() { + AlertDialog alertDialog1 = new AlertDialog.Builder(getActivity()) + .setTitle(getResources().getString(R.string.action))//标题 + .setIcon(R.drawable.ic_boat)//图标 + .setMessage(getResources().getString(R.string.resetwarn)) + .setPositiveButton("Yes Yes Yes", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + delRun.setEnabled(false); + delCfg.setEnabled(false); + //TODO + new Thread(() -> { + //String file2= "/data/data/com.koishi.launcher.h2o2/app_runtime"; + killlist(); + /* + File file = new File(file2); + if(file.isDirectory()){ + deleteDirectory(file2); + } + if(file.isFile()){ + deleteFile(file2); + } + */ + han.sendEmptyMessage(0); + }).start(); + + } + }) + .setNegativeButton("No No No", new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + } + }) + .create(); + + alertDialog1.show(); + } + + private void killlist() { + File file2 = new File("/data/data/org.koishi.launcher.h2o2pro/app_runtime/"); + deleteDirWihtFile(file2); + } + + public boolean deleteFile(String filePath) { + File file = new File(filePath); + if (file.isFile() && file.exists()) { + return file.delete(); + } + return false; + } + + private void deleteDirWihtFile(File file2) { + if (file2 == null || !file2.exists() || !file2.isDirectory()) + return; + for (File file : file2.listFiles()) { + if (file.isFile()) + file.delete(); + else if (file.isDirectory()) + deleteDirWihtFile(file); + + } + file2.delete(); + } + + private void crash() { + throw new RuntimeException("Crash test from SettingsActivity. 这是从设置里点进来的崩溃,给我发这个是没用的!!请在log.txt或者client_output.txt中找原因。路径是/sdcard/games/com.koishi.launcher/h2o2。"); + } + + @SuppressLint("HandlerLeak") + Handler han = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + Intent intent1 = new Intent(getActivity(), MainActivity.class); + intent1.putExtra("fragment", getResources().getString(R.string.menu_home)); + startActivity(intent1); + Toast.makeText(getActivity(), getResources().getString(R.string.delete), Toast.LENGTH_SHORT).show(); + getActivity().finish(); + } + } + }; +} diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/HomeFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/HomeFragment.java new file mode 100644 index 00000000..37ef20c7 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/HomeFragment.java @@ -0,0 +1,1531 @@ +package org.koishi.launcher.h2o2pro.ui.home; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.PopupWindow; +import android.widget.RadioButton; +import android.widget.ScrollView; +import android.widget.SimpleAdapter; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatSpinner; +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.core.widget.NestedScrollView; +import androidx.fragment.app.Fragment; + +import com.bumptech.glide.Glide; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.navigation.NavigationView; +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.switchmaterial.SwitchMaterial; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textfield.TextInputLayout; +import com.google.android.material.textview.MaterialTextView; +import com.mistake.revision.Download.DownloadFragment; +import com.mistake.revision.VanillaActivity; + +import org.json.JSONObject; +import org.koishi.launcher.h2o2pro.InstructionActivity; +import org.koishi.launcher.h2o2pro.R; +import org.koishi.launcher.h2o2pro.VersionsActivity; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; +import org.koishi.launcher.h2o2pro.tool.data.DBHelper; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.abstracts.exception.AuthenticationException; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.MinecraftAuthenticator; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.MinecraftToken; +import org.koishi.launcher.h2o2pro.tool.login.NewLoginTask.auth.model.mojang.profile.MinecraftProfile; +import org.koishi.launcher.h2o2pro.tool.login.OldLoginTask.LoginTask; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; + +import cosine.boat.LauncherActivity; +import cosine.boat.LauncherActivityMk; + +public class HomeFragment extends Fragment implements View.OnClickListener, NavigationView.OnNavigationItemSelectedListener { + + private final Handler handler = new Handler(); + + public AppCompatSpinner list; + public Button newacc; + public NestedScrollView layout1,layout2; + public CheckBox mCheckBox, info, xbox; + public DBHelper dbHelper; + public EditText mUserName, mPassword, mOffline, mAPI; + //public EditText msg1, msg2, msg0; + public Handler getNotice; + public ImageView img1, skin; + public ImageButton mDropDown; + public LinearLayout mainCheck, mainInfo, mainHelp, mainFix, mLoginButton, showAcc,saveAcc, openBc; + public MaterialButton homeReg,homeNew,homeMan,homeQQ; + public MyAdapter dropDownAdapter; + //private PopupMenu popupMenu; + //public MaterialCardView userinfo, inputcv; + public MinecraftProfile pf; + public MinecraftToken tk; + public NavigationView nav; + public PopupWindow popView; + public ProgressDialog pb; + public TextView logt, userInfo, userStatus; + public TextInputLayout userNameLayout, passwordLayout, offlineLayout, apiLayout; + public SharedPreferences sp; + public SharedPreferences.Editor editorName, editorPass, editorApi; + public ScrollView onlineLayout; + public SwitchMaterial swOnline; + public String message; + + public boolean flag = true; + + private String f; + private boolean run = false; + private final Runnable task = new Runnable() { + @Override + public void run() { + // TODO Auto-generated method stub + if (run) { + handler.postDelayed(this, 1000); + } + } + }; + + public static boolean FileExists(String strFile) { + try { + File f = new File(strFile); + if (!f.exists()) { + return false; + } + + } catch (Exception e) { + return false; + } + + return true; + } + + @SuppressLint({"SetTextI18n", "UseCompatLoadingForDrawables"}) + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + + View root = inflater.inflate(R.layout.fragment_home, container, false); + + /**-----------------主页面--------------------*/ + + layout1 = root.findViewById(R.id.home_layout_1); + layout2 = root.findViewById(R.id.home_layout_2); + + layout1.setVisibility(View.VISIBLE); + layout2.setVisibility(View.GONE); + + /**-----------------获取公告--------------------*/ + + new Thread(() -> { + try { + HttpURLConnection con = (HttpURLConnection) new URL("https://gitee.com/NaCln4c1/naclfile/raw/master/Documents/Notification.txt").openConnection(); + //HttpURLConnection con=(HttpURLConnection)new URL("http://49.234.85.55/Mio/tips.txt").openConnection(); + con.setConnectTimeout(5000); + InputStream in = con.getInputStream(); + BufferedReader bfr = new BufferedReader(new InputStreamReader(in)); + String temp = null; + String str = ""; + while ((temp = bfr.readLine()) != null) { + str += temp + "\n"; + } + bfr.close(); + in.close(); + con.disconnect(); + Message msg = new Message(); + message = "" + str; + } catch (IOException e) { + Message msg = new Message(); + message = "拉取公告失败: " + e; + } + }).start(); + + run = true; + handler.postDelayed(task, 1000); + + /**-----------------文件检查--------------------*/ + boolean existMcConfig = FileExists("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + //boolean existRuntime = FileExists("/data/data/"+getActivity().getPackageName()+"/libopenal.so.1"); + boolean existGame = FileExists(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir")); + File file = new File(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir") + "/versions"); + f = GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"); + + list = root.findViewById(R.id.ver_list); + + /**-----------------版本列表--------------------*/ + if (existMcConfig && existGame) { + if (file.exists() && file.isDirectory()) { + File versionlist = new File(f + "/versions"); + Comparator cp = Collator.getInstance(Locale.CHINA); + String[] getVer = versionlist.list(); + List verList = Arrays.asList(getVer); //此集合无法操作添加元素 + Collections.sort(verList,cp); + getVer = verList.toArray(new String[verList.size()]); + ArrayAdapter< String > adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, getVer); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + list.setAdapter(adapter); + list.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView< ? > p1, View p2, int p3, long p4) { + if (!p1.getItemAtPosition(p3).equals("Null")) { + setVersion((String) p1.getItemAtPosition(p3)); + } + + } + + @Override + public void onNothingSelected(AdapterView< ? > p1) { + } + }); + list.setSelection(adapter.getPosition(getVer())); + } else { + String s = "Error, "; + final String[] getVer = s.split(","); + ArrayAdapter< String > adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, getVer); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + list.setAdapter(adapter); + list.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView< ? > p1, View p2, int p3, long p4) { + if (!((String) p1.getItemAtPosition(p3)).equals("Null")) { + + } + + } + + @Override + public void onNothingSelected(AdapterView< ? > p1) { + } + }); + list.setSelection(adapter.getPosition(getVer())); + } + } else { + String s = "Error, "; + final String[] getVer = s.split(","); + ArrayAdapter< String > adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, getVer); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + list.setAdapter(adapter); + list.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView< ? > p1, View p2, int p3, long p4) { + if (!((String) p1.getItemAtPosition(p3)).equals("Null")) { + } + } + @Override + public void onNothingSelected(AdapterView< ? > p1) { + } + }); + list.setSelection(adapter.getPosition(getVer())); + } + //content://com.android.externalstorage.documents/document/primary%3Agames%2Fcom.koishi.launcher%2Fh2o2%2Fgamedir + + /**-----------------登录状态UI--------------------*/ + userInfo = root.findViewById(R.id.user_info); + userInfo.setText(getResources().getString(R.string.account_before) + " " + GetGameJson.getBoatCfg("auth_player_name", "Null")); + mOffline = root.findViewById(R.id.home_offline_id); + mOffline.setText(GetGameJson.getBoatCfg("auth_player_name", "Null")); + offlineLayout = root.findViewById(R.id.offline_lay); + onlineLayout = root.findViewById(R.id.home_online_layout); + skin = root.findViewById(R.id.home_skin); + swOnline = root.findViewById(R.id.home_sw_online); + userStatus = root.findViewById(R.id.user_status); + showAcc = root.findViewById(R.id.show_login); + sp = getActivity().getSharedPreferences("isChecked", 0); + boolean result = sp.getBoolean("choose", true); // 这里就是开始取值了 false代表的就是如果没有得到对应数据我们默认显示为false + // 把得到的状态设置给CheckBox组件 + swOnline.setChecked(result); + //inputcv = root.findViewById(R.id.inputcv); + showAcc.setOnClickListener(v -> { + if (layout1.getVisibility() == View.GONE) { + layout1.setVisibility(View.VISIBLE); + layout2.setVisibility(View.GONE); + } else { + layout1.setVisibility(View.GONE); + layout2.setVisibility(View.VISIBLE); + } + }); + + if (swOnline.isChecked()) { + onlineLayout.setVisibility(View.VISIBLE); + mOffline.setVisibility(View.GONE); + offlineLayout.setVisibility(View.GONE); + userStatus.setText(getResources().getString(R.string.nav_header_account_mode)); + } else { + onlineLayout.setVisibility(View.GONE); + mOffline.setVisibility(View.VISIBLE); + offlineLayout.setVisibility(View.VISIBLE); + userStatus.setText(getResources().getString(R.string.login_offline)); + } + + swOnline.setOnCheckedChangeListener((buttonView, isChecked) -> { + // 判断CheckBox是否被勾选了 + if (swOnline.isChecked()) {// CheckBox被勾选了 我们就把你的状态保存起来 + onlineLayout.setVisibility(View.VISIBLE); + mOffline.setVisibility(View.GONE); + offlineLayout.setVisibility(View.GONE); + userStatus.setText(getResources().getString(R.string.nav_header_account_mode)); + showAcc.setBackgroundColor(getResources().getColor(R.color.app_green_normal)); + // 我们先来个吐司 + sp = getActivity().getSharedPreferences("isChecked", 0); + // 使用编辑器来进行操作 + SharedPreferences.Editor edit = sp.edit(); + // 将勾选的状态保存起来 + edit.putBoolean("choose", true); // 这里的choose就是一个key 通过这个key我们就可以得到对应的值 + // 最好我们别忘记提交一下 + edit.apply(); + } else { + onlineLayout.setVisibility(View.GONE); + mOffline.setVisibility(View.VISIBLE); + offlineLayout.setVisibility(View.VISIBLE); + userStatus.setText(getResources().getString(R.string.login_offline)); + showAcc.setBackgroundColor(getResources().getColor(R.color.app_blue_normal)); + sp = getActivity().getSharedPreferences("isChecked", 0); + SharedPreferences.Editor edit = sp.edit(); + edit.putBoolean("choose", false); + edit.apply(); + } + + }); + pb = ProgressDialog.show(requireActivity(), getResources().getString(R.string.login), getResources().getString(R.string.login_ing)); + pb.setCanceledOnTouchOutside(false); + pb.setCancelable(false); + pb.hide(); + + /**-----------------功能UI--------------------*/ + mainCheck = root.findViewById(R.id.main_check); + mainInfo = root.findViewById(R.id.main_info); + mainHelp = root.findViewById(R.id.main_help); + mainFix = root.findViewById(R.id.main_fix); + saveAcc = root.findViewById(R.id.main_save_acc); + openBc = root.findViewById(R.id.bc_open); + openBc.setOnClickListener(v->showBC()); + mainCheck.setOnClickListener(v -> { + }); + mainInfo.setOnClickListener(v -> showInfoDialog()); + mainHelp.setOnClickListener(v -> { + //CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + //intent.launchUrl(getActivity(), Uri.parse("https://b23.tv/ea3HRj\n")); + startActivity(new Intent(getActivity(), InstructionActivity.class)); + }); + mainFix.setOnClickListener(v -> launchFragment()); + + /**-----------------登录界面UI--------------------*/ + logt = root.findViewById(R.id.login_text); + img1 = root.findViewById(R.id.img1); + userNameLayout = root.findViewById(R.id.name_lay); + passwordLayout = root.findViewById(R.id.pass_lay); + apiLayout = root.findViewById(R.id.api_lay); + mUserName = root.findViewById(R.id.username); + mPassword = root.findViewById(R.id.password); + mLoginButton = root.findViewById(R.id.login); + mAPI = root.findViewById(R.id.login_api); + mDropDown = root.findViewById(R.id.dropdown_button); + mCheckBox = root.findViewById(R.id.remember); + newacc = root.findViewById(R.id.newacc); + info = root.findViewById(R.id.infocb); + xbox = root.findViewById(R.id.xboxcb); + mLoginButton.setOnClickListener(this); + mDropDown.setOnClickListener(this); + mAPI.setKeyListener(null); + mAPI.setOnClickListener(v -> showAPIDialog()); + dbHelper = new DBHelper(getActivity()); + if (dbHelper.queryAllUserName().length <= 0) { + //offline.setText("Demo"); + } + + SharedPreferences nameSp = getActivity().getSharedPreferences("name", getContext().MODE_PRIVATE); + SharedPreferences passSp = getActivity().getSharedPreferences("pass", getContext().MODE_PRIVATE); + SharedPreferences apiSp = getActivity().getSharedPreferences("api", getContext().MODE_PRIVATE); + + editorName = getActivity().getSharedPreferences("name", getContext().MODE_PRIVATE).edit(); + editorPass = getActivity().getSharedPreferences("pass", getContext().MODE_PRIVATE).edit(); + editorApi = getActivity().getSharedPreferences("api", getContext().MODE_PRIVATE).edit(); + + //offline = root.findViewById(R.id.offline); + newacc.setOnClickListener(v -> { + newacc.getBackground().setAlpha(90); + newacc.setVisibility(View.GONE); + skin.setImageResource(R.drawable.ic_home_user_normal); + GetGameJson.setBoatJson("auth_uuid", ""); + GetGameJson.setBoatJson("auth_access_token", ""); + mPassword.setText(""); + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", ""); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(mUserName.getText().toString(), "", mAPI.getText().toString(), 0); + newacc.setEnabled(false); + userNameLayout.setVisibility(View.VISIBLE); + passwordLayout.setVisibility(View.VISIBLE); + apiLayout.setVisibility(View.VISIBLE); + mUserName.setVisibility(View.VISIBLE); + mPassword.setVisibility(View.VISIBLE); + mAPI.setVisibility(View.VISIBLE); + mCheckBox.setVisibility(View.VISIBLE); + mDropDown.setVisibility(View.VISIBLE); + //info.setVisibility(View.VISIBLE); + img1.setVisibility(View.GONE); + logt.setVisibility(View.GONE); + mLoginButton.setVisibility(View.VISIBLE); + }); + + info.setChecked(false); + info.setEnabled(false); + + final String id = (GetGameJson.getBoatCfg("auth_player_name", "Null")); + if (!id.equals("")) { + } else { + GetGameJson.setBoatJson("acth_player_name", "Player"); + } + logt.setText(getResources().getString(R.string.login_welcome) + "\n" + GetGameJson.getBoatCfg("auth_player_name", "Null")); + + initLoginUserName(); + + if (dbHelper.queryAllUserName().length > 0) { + mUserName.setText(nameSp.getString("name", "")); + mPassword.setText(passSp.getString("pass", "")); + mAPI.setText(apiSp.getString("api", "Microsoft")); + } else { + mUserName.setText(""); + mPassword.setText(""); + mAPI.setText("Microsoft"); + } + + final String password = mPassword.getText().toString(); + if (!password.equals("")) { + //mLoginButton.setVisibility(View.VISIBLE); + userNameLayout.setVisibility(View.GONE); + passwordLayout.setVisibility(View.GONE); + apiLayout.setVisibility(View.GONE); + mUserName.setVisibility(View.GONE); + mPassword.setVisibility(View.GONE); + mAPI.setVisibility(View.GONE); + mCheckBox.setVisibility(View.GONE); + mDropDown.setVisibility(View.GONE); + //info.setVisibility(View.GONE); + img1.setVisibility(View.VISIBLE); + logt.setVisibility(View.VISIBLE); + newacc.setVisibility(View.VISIBLE); + } else { + newacc.setEnabled(false); + //mLoginButton.setVisibility(View.GONE); + userNameLayout.setVisibility(View.VISIBLE); + passwordLayout.setVisibility(View.VISIBLE); + apiLayout.setVisibility(View.VISIBLE); + mUserName.setVisibility(View.VISIBLE); + mPassword.setVisibility(View.VISIBLE); + mAPI.setVisibility(View.VISIBLE); + mCheckBox.setVisibility(View.VISIBLE); + mDropDown.setVisibility(View.VISIBLE); + //info.setVisibility(View.VISIBLE); + img1.setVisibility(View.GONE); + logt.setVisibility(View.GONE); + newacc.setVisibility(View.GONE); + } + + sp = getActivity().getSharedPreferences("isXbox", 0); + boolean xb = sp.getBoolean("msAcc", true); // 这里就是开始取值了 false代表的就是如果没有得到对应数据我们默认显示为false + // 把得到的状态设置给CheckBox组件 + xbox.setChecked(xb); + + xbox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (xbox.isChecked()) { + sp = getActivity().getSharedPreferences("isXbox", 0); + SharedPreferences.Editor edit = sp.edit(); + edit.putBoolean("msAcc", true); + edit.apply(); + } else { + sp = getActivity().getSharedPreferences("isXbox", 0); + SharedPreferences.Editor edit = sp.edit(); + edit.putBoolean("msAcc", false); + edit.apply(); + } + + }); + + if (!swOnline.isChecked()){ + if (mOffline.getText().toString().equals("")){ + //inputcv.setVisibility(View.VISIBLE); + layout2.setVisibility(View.VISIBLE); + layout1.setVisibility(View.GONE); + } else { + //inputcv.setVisibility(View.GONE); + layout2.setVisibility(View.GONE); + layout1.setVisibility(View.VISIBLE); + } + } else { + if(mPassword.getText().toString().equals("")){ + //inputcv.setVisibility(View.VISIBLE); + layout2.setVisibility(View.VISIBLE); + layout1.setVisibility(View.GONE); + } else { + //inputcv.setVisibility(View.GONE); + layout2.setVisibility(View.GONE); + layout1.setVisibility(View.VISIBLE); + } + } + + if (swOnline.isChecked()) { + showAcc.setBackgroundColor(getResources().getColor(R.color.app_green_normal)); + loadSkin(); + } else { + showAcc.setBackgroundColor(getResources().getColor(R.color.app_blue_normal)); + skin.setImageResource(R.drawable.ic_home_user_normal); + } + + /**-----------------卡片UI--------------------*/ + homeReg = root.findViewById(R.id.home_reg); + homeNew = root.findViewById(R.id.home_new); + homeMan = root.findViewById(R.id.home_manager); + homeQQ = root.findViewById(R.id.home_qq); + + homeReg.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://www.minecraft.net/store/minecraft-java-edition/buy\n")); + }); + homeNew.setOnClickListener(v->{ + startActivity(new Intent(requireActivity(), VanillaActivity.class)); + requireActivity().finish(); + }); + homeMan.setOnClickListener(v->{ + startActivity(new Intent(requireActivity(), VersionsActivity.class)); + requireActivity().finish(); + }); + homeQQ.setOnClickListener(v->{ + joinQQGroup("-c3oG3cfXX-v6W8MbEl9_Fl2JjuuvpC6"); + }); + + nav = root.findViewById(R.id.nav_view); + nav.setNavigationItemSelectedListener(this); + Menu m = nav.getMenu(); + if (GetGameJson.getAppCfg("checkFile","false").equals("false")){ + //mainFix.setVisibility(View.VISIBLE); + m.findItem(R.id.home_open_fix).setVisible(true); + } else { + //mainFix.setVisibility(View.GONE); + m.findItem(R.id.home_open_fix).setVisible(false); + } + + return root; + } + + @SuppressLint("NonConstantResourceId") + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.home_open_info: + showInfoDialog(); + break; + case R.id.home_open_fix: + launchFragment(); + break; + case R.id.home_open_help: + startActivity(new Intent(getActivity(), InstructionActivity.class)); + break; + default: + break; + } + return true; + } + + public boolean joinQQGroup(String key) { + Intent intent = new Intent(); + intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3D" + key)); + // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + try { + startActivity(intent); + return true; + } catch (Exception e) { + // 未安装手Q或安装的版本不支持 + return false; + } + } + + /**-----------------初始化账号下拉框UI--------------------*/ + private void initLoginUserName() { + String[] usernames = dbHelper.queryAllUserName(); + if (usernames.length > 0) { + String tempName = usernames[usernames.length - 1]; + mUserName.setText(tempName); + mUserName.setSelection(tempName.length()); + String tempPwd = dbHelper.queryPasswordByName(tempName); + String tempApi = dbHelper.queryApiByName(tempName); + int checkFlag = dbHelper.queryIsSavedByName(tempName); + if (checkFlag == 0) { + mCheckBox.setChecked(false); + } else if (checkFlag == 1) { + mCheckBox.setChecked(true); + } + mPassword.setText(tempPwd); + mAPI.setText(tempApi); + + } + mUserName.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + mPassword.setText(""); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + + } + + @Override + public void afterTextChanged(Editable s) { + + } + }); + + saveAcc.setOnClickListener(v->{ + if (swOnline.isChecked()){ + if (mUserName.getText().toString().equals("") || mPassword.getText().toString().equals("")){ + Snackbar.make(layout2, getResources().getString(R.string.home_no_account), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } else { + layout1.setVisibility(View.VISIBLE); + layout2.setVisibility(View.GONE); + } + } else { + if (mOffline.getText().toString().equals("")){ + Snackbar.make(layout2, getResources().getString(R.string.home_no_account), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } else { + layout1.setVisibility(View.VISIBLE); + layout2.setVisibility(View.GONE); + } + } + + }); + } + + /**-----------------点击--------------------*/ + @Override + public void onClick(View v) { + File file = new File(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir") + "/versions"); + boolean existGame = FileExists(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir")); + if (v == mLoginButton) { + if (swOnline.isChecked()) { + if (existGame && file.list().length != 0 && file.isDirectory()) { + doLogin(); + } else { + Snackbar.make(getView(), getResources().getString(R.string.no_ver), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + } else { + if (mOffline.equals("")){ + Snackbar.make(getView(), getResources().getString(R.string.home_no_username), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } else { + if (existGame && file.list().length != 0 && file.isDirectory()) { + GetGameJson.setBoatJson("auth_player_name", mOffline.getText().toString()); + userInfo.setText(getResources().getString(R.string.account_before) + " " + mOffline.getText().toString()); + chooseMode(); + } else { + Snackbar.make(getView(), getResources().getString(R.string.no_ver), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + } + } + } + if (v == mDropDown) { + if (popView != null) { + if (!popView.isShowing()) { + popView.showAsDropDown(mUserName); + } else { + popView.dismiss(); + } + } else { + if (dbHelper.queryAllUserName().length > 0) { + initPopView(dbHelper.queryAllUserName()); + if (!popView.isShowing()) { + popView.showAsDropDown(mUserName); + } else { + popView.dismiss(); + } + } else { + Snackbar.make(getView(), getResources().getString(R.string.home_no_account), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + + } + } + + } + + /**-----------------登录--------------------*/ + public void doLogin() { + final String userName = mUserName.getText().toString(); + final String password = mPassword.getText().toString(); + final String api = mAPI.getText().toString(); + if (!userName.equals("") && !password.equals("") && !api.equals("")) { + //Toast.makeText(getActivity(), getResources().getString(R.string.home_login_start_toast), Toast.LENGTH_SHORT).show(); + Snackbar.make(getView(), getResources().getString(R.string.home_login_start_toast), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + mLoginButton.setEnabled(false); + mLoginButton.getBackground().setAlpha(80); + pb.show(); + //登录操作为耗时操作,必须放到线程中执行 + if (api.equals("Mojang")) { + new Thread(() -> { + if (!LoginTask.checkif(LoginTask.get("auth_access_token"), "https://authserver.mojang.com/validate")) { + //token不可用 + //调用LoginTask + UserMsg = LoginTask.login(userName, password, "https://authserver.mojang.com/authenticate"); + CheckMsg.sendEmptyMessage(0); + } else { + //token可用,无需调用登录 + CheckMsg.sendEmptyMessage(1); + } + }).start(); + } else if (api.equals("Microsoft")) { + new Thread(() -> { + try { + MinecraftAuthenticator minecraftAuthenticator = new MinecraftAuthenticator(); + tk = minecraftAuthenticator.loginWithXbox(mUserName.getText().toString(), mPassword.getText().toString()); + pf = minecraftAuthenticator.checkOwnership(tk); + xboxHandler.sendEmptyMessage(1); + } catch (AuthenticationException e) { + Snackbar.make(getView(), e.toString(), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + xboxHandler.sendEmptyMessage(0); + } + }).start(); + } else { + new Thread(() -> { + if (!LoginTask.checkif(LoginTask.get("auth_access_token"), api + "/authserver/validate")) { + //token不可用 + //调用LoginTask + UserMsg = LoginTask.login(userName, password, api + "/authserver/authenticate"); + CheckMsg.sendEmptyMessage(0); + } else { + //token可用,无需调用登录 + CheckMsg.sendEmptyMessage(1); + } + }).start(); + } + } else { + //Toast.makeText(getActivity(), getResources().getString(R.string.home_no_account), Toast.LENGTH_SHORT).show(); + Snackbar.make(getView(), getResources().getString(R.string.home_no_account), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + + } + + /**-----------------登录线程--------------------*/ + @SuppressLint("HandlerLeak") + Handler xboxHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 1) { + //Intent intent2 = new Intent(LoginActivity.this, SplashActivity.class); + //startActivity(intent2);// TODO: Implement this method + //Toast.makeText(getApplicationContext(), getResources().getString(R.string.delete), Toast.LENGTH_SHORT).show(); + //finish(); + final String resultAc = mUserName.getText().toString(); + final String resultPw = mPassword.getText().toString(); + final String resultApi = mAPI.getText().toString(); + + GetGameJson.setBoatJson("auth_player_name", pf.getUsername()); + GetGameJson.setBoatJson("auth_uuid", pf.getUuid().toString()); + GetGameJson.setBoatJson("auth_access_token", tk.getAccessToken()); + if (mCheckBox.isChecked()) { + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", mPassword.getText().toString()); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(resultAc, resultPw, resultApi, 1); + } else { + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", ""); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(resultAc, "", resultApi, 0); + } + pb.hide(); + //Toast.makeText(getActivity(), getResources().getString(R.string.login_done), Toast.LENGTH_SHORT).show(); + Snackbar.make(getView(), getResources().getString(R.string.login_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + mLoginButton.setEnabled(true); + mLoginButton.getBackground().setAlpha(255); + userInfo.setText(getResources().getString(R.string.account_before) + " " + pf.getUsername()); + mOffline.setText(GetGameJson.getBoatCfg("auth_player_name", "Null")); + //mLoginButton.setVisibility(View.VISIBLE); + newacc.setEnabled(true); + userNameLayout.setVisibility(View.GONE); + passwordLayout.setVisibility(View.GONE); + apiLayout.setVisibility(View.GONE); + mUserName.setVisibility(View.GONE); + mPassword.setVisibility(View.GONE); + mAPI.setVisibility(View.GONE); + mCheckBox.setVisibility(View.GONE); + mDropDown.setVisibility(View.GONE); + //info.setVisibility(View.GONE); + img1.setVisibility(View.VISIBLE); + logt.setVisibility(View.VISIBLE); + newacc.setVisibility(View.VISIBLE); + logt.setText(getResources().getString(R.string.login_welcome) + "\n" + pf.getUsername()); + chooseMode(); + } else { + mCheckBox.setChecked(false); + mLoginButton.setEnabled(true); + pb.hide(); + mLoginButton.getBackground().setAlpha(255); + logt.setText(":("); + mPassword.setText(""); + newacc.getBackground().setAlpha(90); + newacc.setVisibility(View.GONE); + skin.setImageResource(R.drawable.ic_home_user_normal); + GetGameJson.setBoatJson("auth_uuid", ""); + GetGameJson.setBoatJson("auth_access_token", ""); + mPassword.setText(""); + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", ""); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(mUserName.getText().toString(), "", mAPI.getText().toString(), 0); + newacc.setEnabled(false); + userNameLayout.setVisibility(View.VISIBLE); + passwordLayout.setVisibility(View.VISIBLE); + apiLayout.setVisibility(View.VISIBLE); + mUserName.setVisibility(View.VISIBLE); + mPassword.setVisibility(View.VISIBLE); + mAPI.setVisibility(View.VISIBLE); + mCheckBox.setVisibility(View.VISIBLE); + mDropDown.setVisibility(View.VISIBLE); + //info.setVisibility(View.VISIBLE); + img1.setVisibility(View.GONE); + logt.setVisibility(View.GONE); + layout1.setVisibility(View.GONE); + layout2.setVisibility(View.VISIBLE); + } + + } + }; + + String[] UserMsg; + @SuppressLint("HandlerLeak") + Handler han = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + //Intent intent2 = new Intent(LoginActivity.this, SplashActivity.class); + //startActivity(intent2);// TODO: Implement this method + //Toast.makeText(getApplicationContext(), getResources().getString(R.string.delete), Toast.LENGTH_SHORT).show(); + //finish(); + } + } + }; + + @SuppressLint("HandlerLeak") + Handler CheckMsg = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + if (UserMsg == null) { + //Toast.makeText(getActivity(), UserMsg[0], Toast.LENGTH_SHORT).show(); + Snackbar.make(getView(), UserMsg[0], Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + mCheckBox.setChecked(false); + mLoginButton.setEnabled(true); + pb.hide(); + mLoginButton.getBackground().setAlpha(255); + logt.setText(":("); + mPassword.setText(""); + newacc.getBackground().setAlpha(90); + newacc.setVisibility(View.GONE); + skin.setImageResource(R.drawable.ic_home_user_normal); + GetGameJson.setBoatJson("auth_uuid", ""); + GetGameJson.setBoatJson("auth_access_token", ""); + mPassword.setText(""); + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", ""); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(mUserName.getText().toString(), "", mAPI.getText().toString(), 0); + newacc.setEnabled(false); + userNameLayout.setVisibility(View.VISIBLE); + passwordLayout.setVisibility(View.VISIBLE); + apiLayout.setVisibility(View.VISIBLE); + mUserName.setVisibility(View.VISIBLE); + mPassword.setVisibility(View.VISIBLE); + mAPI.setVisibility(View.VISIBLE); + mCheckBox.setVisibility(View.VISIBLE); + mDropDown.setVisibility(View.VISIBLE); + //info.setVisibility(View.VISIBLE); + img1.setVisibility(View.GONE); + logt.setVisibility(View.GONE); + layout1.setVisibility(View.GONE); + layout2.setVisibility(View.VISIBLE); + } else if (UserMsg.length == 1) { + //UserMsg长度为1时说明出现了错误,使用toast输出错误信息 + //Toast.makeText(getActivity(), getResources().getString(R.string.login_fail), Toast.LENGTH_SHORT).show(); + Snackbar.make(getView(), getResources().getString(R.string.login_fail), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + mCheckBox.setChecked(false); + mLoginButton.setEnabled(true); + pb.hide(); + mLoginButton.getBackground().setAlpha(255); + logt.setText(":("); + mPassword.setText(""); + newacc.getBackground().setAlpha(90); + newacc.setVisibility(View.GONE); + skin.setImageResource(R.drawable.ic_home_user_normal); + GetGameJson.setBoatJson("auth_uuid", ""); + GetGameJson.setBoatJson("auth_access_token", ""); + mPassword.setText(""); + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", ""); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(mUserName.getText().toString(), "", mAPI.getText().toString(), 0); + newacc.setEnabled(false); + userNameLayout.setVisibility(View.VISIBLE); + passwordLayout.setVisibility(View.VISIBLE); + apiLayout.setVisibility(View.VISIBLE); + mUserName.setVisibility(View.VISIBLE); + mPassword.setVisibility(View.VISIBLE); + mAPI.setVisibility(View.VISIBLE); + mCheckBox.setVisibility(View.VISIBLE); + mDropDown.setVisibility(View.VISIBLE); + //info.setVisibility(View.VISIBLE); + img1.setVisibility(View.GONE); + logt.setVisibility(View.GONE); + layout1.setVisibility(View.GONE); + layout2.setVisibility(View.VISIBLE); + } else { + final String resultAc = mUserName.getText().toString(); + final String resultPw = mPassword.getText().toString(); + final String resultApi = mAPI.getText().toString(); + + //以下三行用于将获取的登录信息写入config.txt + //需要添加文件操作权限 +// LoginTask.set("auth_access_token", userCon[0]); +// LoginTask.set("auth_player_name", userCon[1]); +// LoginTask.set("auth_uuid", userCon[2]); + + //将获取到的token等显示出来 + GetGameJson.setBoatJson("auth_player_name", UserMsg[1]); + GetGameJson.setBoatJson("auth_uuid", UserMsg[2]); + GetGameJson.setBoatJson("auth_access_token", UserMsg[0]); + + if (mCheckBox.isChecked()) { + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", mPassword.getText().toString()); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(resultAc, resultPw, resultApi, 1); + } else { + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", ""); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(resultAc, "", resultApi, 0); + } + + Snackbar.make(getView(), getResources().getString(R.string.login_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + + pb.hide(); + //Toast.makeText(getActivity(), getResources().getString(R.string.login_done), Toast.LENGTH_SHORT).show(); + mLoginButton.setEnabled(true); + mLoginButton.getBackground().setAlpha(255); + userInfo.setText(getResources().getString(R.string.account_before) + " " + UserMsg[1]); + mOffline.setText(UserMsg[1]); + //Intent intent = new Intent(LoginActivity.this, MainActivity.class); + //intent.putExtra("mode", getResources().getString(R.string.nav_header_account_mode)); + //startActivity(intent);// TODO: Implement this method + //finish(); + newacc.setEnabled(true); + //mLoginButton.setVisibility(View.VISIBLE); + userNameLayout.setVisibility(View.GONE); + passwordLayout.setVisibility(View.GONE); + apiLayout.setVisibility(View.GONE); + mUserName.setVisibility(View.GONE); + mPassword.setVisibility(View.GONE); + mAPI.setVisibility(View.GONE); + mCheckBox.setVisibility(View.GONE); + mDropDown.setVisibility(View.GONE); + //info.setVisibility(View.GONE); + img1.setVisibility(View.VISIBLE); + logt.setVisibility(View.VISIBLE); + newacc.setVisibility(View.VISIBLE); + logt.setText(getResources().getString(R.string.login_welcome) + "\n" + GetGameJson.getBoatCfg("auth_player_name", "Null")); + chooseMode(); + } + } else if (msg.what == 1) { + //token可用就显示登录成功 + final String resultAc = mUserName.getText().toString(); + final String resultPw = mPassword.getText().toString(); + final String resultApi = mAPI.getText().toString(); + pb.hide(); + newacc.setEnabled(true); + if (mCheckBox.isChecked()) { + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", mPassword.getText().toString()); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(resultAc, resultPw, resultApi, 1); + } else { + editorName.putString("name", mUserName.getText().toString()); + editorPass.putString("pass", ""); + editorApi.putString("api", mAPI.getText().toString()); + editorName.commit(); + editorPass.commit(); + editorApi.commit(); + dbHelper.insertOrUpdate(resultAc, "", resultApi, 0); + } + Snackbar.make(getView(), getResources().getString(R.string.login_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + mLoginButton.setEnabled(true); + mLoginButton.getBackground().setAlpha(255); + userInfo.setText(getResources().getString(R.string.account_before) + " " + GetGameJson.getBoatCfg("auth_player_name", "Null")); + mOffline.setText(GetGameJson.getBoatCfg("auth_player_name", "Null")); + //Intent intent2 = new Intent(LoginActivity.this, MainActivity.class); + //intent2.putExtra("mode", getResources().getString(R.string.nav_header_account_mode)); + //startActivity(intent2);// TODO: Implement this method + //mLoginButton.setVisibility(View.VISIBLE); + userNameLayout.setVisibility(View.GONE); + passwordLayout.setVisibility(View.GONE); + apiLayout.setVisibility(View.GONE); + mUserName.setVisibility(View.GONE); + mPassword.setVisibility(View.GONE); + mAPI.setVisibility(View.GONE); + mCheckBox.setVisibility(View.GONE); + mDropDown.setVisibility(View.GONE); + //info.setVisibility(View.GONE); + img1.setVisibility(View.VISIBLE); + logt.setVisibility(View.VISIBLE); + newacc.setVisibility(View.VISIBLE); + logt.setText(getResources().getString(R.string.login_welcome) + "\n" + GetGameJson.getBoatCfg("auth_player_name", "Null")); + chooseMode(); + + } + + } + }; + + + /**-----------------启动--------------------*/ + public void chooseMode() { + loadSkin(); + AlertDialog alertDialog1 = new AlertDialog.Builder(getActivity()) + .setTitle(getResources().getString(R.string.action))//标题 + .setIcon(R.drawable.ic_boat)//图标 + .setMessage(getResources().getString(R.string.choose_mode)) + .setPositiveButton(getResources().getString(R.string.choose_mode_touch), new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + launchBoat(); + + } + }) + .setNegativeButton(getResources().getString(R.string.choose_mode_mouse), new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + launchBoatMk(); + } + }) + .setNeutralButton(getResources().getString(R.string.choose_mode_cancel), new DialogInterface.OnClickListener() {//添加"Yes"按钮 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //TODO + } + }) + .create(); + + alertDialog1.show(); + } + + public void launchBoat() { + File file = new File(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir") + "/versions"); + boolean existGame = FileExists(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir")); + if (existGame && file.list().length != 0 && file.isDirectory()) { + startActivity(new Intent(getActivity(), LauncherActivity.class)); + } else { + Snackbar.make(getView(), getResources().getString(R.string.no_ver), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + } + + public void launchBoatMk() { + File file = new File(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir") + "/versions"); + boolean existGame = FileExists(GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir")); + if (existGame && file.list().length != 0 && file.isDirectory()) { + startActivity(new Intent(getActivity(), LauncherActivityMk.class)); + } else { + Snackbar.make(getView(), getResources().getString(R.string.no_ver), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + } + + /**-----------------适配器--------------------*/ + + class MyAdapter extends SimpleAdapter { + + private List< HashMap< String, Object > > data; + + public MyAdapter(Context context, List< HashMap< String, Object > > data, + int resource, String[] from, int[] to) { + super(context, data, resource, from, to); + this.data = data; + } + + @Override + public int getCount() { + return data.size(); + } + + @Override + public Object getItem(int position) { + return position; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(final int position, View convertView, + ViewGroup parent) { + System.out.println(position); + ViewHolder holder; + if (convertView == null) { + holder = new ViewHolder(); + convertView = LayoutInflater.from(getActivity()).inflate( + R.layout.dropdown_item, null); + holder.btn = convertView + .findViewById(R.id.delete); + holder.tv = convertView.findViewById(R.id.textview); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + holder.tv.setText(data.get(position).get("name").toString()); + holder.tv.setOnClickListener(v -> { + String[] usernames = dbHelper.queryAllUserName(); + mUserName.setText(usernames[position]); + mPassword.setText(dbHelper + .queryPasswordByName(usernames[position])); + mAPI.setText(dbHelper + .queryApiByName(usernames[position])); + popView.dismiss(); + }); + holder.btn.setOnClickListener(v -> { + String[] usernames = dbHelper.queryAllUserName(); + if (usernames.length > 1) { + dbHelper.delete(usernames[position]); + popView.dismiss(); + } else if (usernames.length == 1) { + dbHelper.delete(usernames[position]); + popView.dismiss(); + mUserName.setText(""); + mPassword.setText(""); + mAPI.setText(""); + } + String[] newusernames = dbHelper.queryAllUserName(); + if (newusernames.length > 0) { + initPopView(newusernames); + popView.showAsDropDown(mUserName); + } else { + popView.dismiss(); + popView = null; + } + }); + return convertView; + } + } + + private void initPopView(String[] usernames) { + List< HashMap< String, Object > > list = new ArrayList< HashMap< String, Object > >(); + for (int i = 0; i < usernames.length; i++) { + HashMap< String, Object > map = new HashMap< String, Object >(); + map.put("name", usernames[i]); + map.put("drawable", R.drawable.xicon); + list.add(map); + } + dropDownAdapter = new MyAdapter(getActivity(), list, R.layout.dropdown_item, + new String[]{"name", "drawable"}, new int[]{R.id.textview, + R.id.delete}); + ListView listView = new ListView(getActivity()); + listView.setAdapter(dropDownAdapter); + + popView = new PopupWindow(listView, mUserName.getWidth(), + ViewGroup.LayoutParams.WRAP_CONTENT, true); + popView.setFocusable(true); + popView.setOutsideTouchable(true); + popView.setBackgroundDrawable(getResources().getDrawable(R.drawable.pwbg)); + // popView.showAsDropDown(mUserName); + } + + class ViewHolder { + private TextView tv; + private ImageButton btn; + } + + /**-----------------补全UI--------------------*/ + public void launchFragment() { + String dir = GetGameJson.getBoatCfg("game_directory", "/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"); + String link = GetGameJson.getBoatCfg("sourceLink", "https://download.mcbbs.net"); + File f = new File(dir); + File fv = new File(dir + "/versions"); + if (f.exists() && fv.isDirectory() && fv.list().length != 0) { + DownloadFragment showDialog = new DownloadFragment(); + Bundle bundle = new Bundle(); + bundle.putString("version", list.getSelectedItem().toString()); + bundle.putString("game", dir); + bundle.putString("address", link); + showDialog.setArguments(bundle); + showDialog.show(getActivity().getSupportFragmentManager(), "show"); + } else { + Snackbar.make(getView(), getResources().getString(R.string.no_ver), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + + } + + /**-----------------设备信息--------------------*/ + public void showInfoDialog() { + Dialog dialog = new Dialog(getContext()); + View dialogView = getActivity().getLayoutInflater().inflate(R.layout.dialog_info, null); + String cpu, cpuInfo; + //Initial + TextView tv1 = dialogView.findViewById(R.id.info_android_ver); + TextView tv2 = dialogView.findViewById(R.id.info_dev); + TextView tv3 = dialogView.findViewById(R.id.info_cpu); + TextView tv4 = dialogView.findViewById(R.id.info_root); + + tv1.setText("Android" + Build.VERSION.RELEASE + " (API" + Build.VERSION.SDK_INT + ") "); + tv2.setText("" + Build.BRAND + " " + Build.MODEL + " (" + Build.BOARD + ") "); + + try { + cpu = "" + readCpuHardware(); + } catch (IOException e) { + cpu = "" + e.toString(); + } + + cpuInfo = cpu; + cpuInfo = cpuInfo.trim(); + + tv3.setText(cpuInfo); + + if (CheckRootPathSU() == false) { + tv4.setText(getResources().getString(R.string.info_root_false)); + } else { + tv4.setText(getResources().getString(R.string.info_root_true)); + } + + dialog.setContentView(dialogView); + WindowManager windowManager = getActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + Window window = dialog.getWindow(); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.width = (int) (display.getWidth() * 0.9); + dialog.show(); + //onClick + } + + private boolean CheckRootPathSU() { + File f = null; + final String kSuSearchPaths[] = {"/system/bin/", "/system/xbin/", "/system/sbin/", "/sbin/", "/vendor/bin/"}; + try { + for (int i = 0; i < kSuSearchPaths.length; i++) { + f = new File(kSuSearchPaths[i] + "su"); + if (f != null && f.exists()) { + return true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + public static String readCpuHardware() throws IOException { + File file = new File("proc/cpuinfo"); + FileReader in = new FileReader(file); + LineNumberReader reader = new LineNumberReader(in); + String s = reader.readLine(); + String str = null; + while (s != null) { + if (s.contains("Hardware")) { + str = s.replaceAll("Hardware", ""); + reader.close(); + in.close(); + return str.replaceAll(":", ""); + + } + s = reader.readLine(); + } + reader.close(); + in.close(); + return ""; + } + + /**-----------------版本字符读取和更改--------------------*/ + public void setVersion(String version) { + try { + FileInputStream in = new FileInputStream("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + JSONObject json = new JSONObject(str); + json.remove("currentVersion"); + json.put("currentVersion", f + "/versions/" + version.trim()); + FileWriter fr = new FileWriter(new File("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt")); + fr.write(json.toString()); + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + + public String getVer() { + try { + FileInputStream in = new FileInputStream("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + if (str.equals("")) { + return "null"; + } + JSONObject json = new JSONObject(str); + String cnt = json.getString("currentVersion"); + return cnt.substring(cnt.indexOf("versions") + 9); + } catch (Exception e) { + return e.toString(); + } + } + + /**-----------------加载皮肤头像--------------------*/ + public void loadSkin() { + if (mAPI.getText().toString().equals("Mojang") || mAPI.getText().toString().equals("Microsoft")) { + String uuid = GetGameJson.getBoatCfg("auth_uuid", "0"); + String skinUrl = "https://crafatar.com/avatars/" + uuid + "?overlay=true"; + Glide.with(this).load(skinUrl).placeholder(R.drawable.ic_home_user_normal).error(R.drawable.xicon_red).into(skin); + } else { + skin.setImageResource(R.drawable.ic_home_user_normal); + } + } + + /**-----------------选择登录API--------------------*/ + public void showAPIDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.home_dialog_api, null); + mDialog.setContentView(dialogView); + MaterialButton cancel = dialogView.findViewById(R.id.custom_api_cancel); + MaterialButton ok = dialogView.findViewById(R.id.custom_api_ok); + MaterialButton web = dialogView.findViewById(R.id.custom_api_web_open_dialog); + MaterialButton mojang = dialogView.findViewById(R.id.custom_api_web_open_mojang); + MaterialButton reg = dialogView.findViewById(R.id.custom_api_web_open_register); + RadioButton apiMojang = dialogView.findViewById(R.id.api_mojang); + RadioButton apiMs = dialogView.findViewById(R.id.api_microsoft); + RadioButton api3rd = dialogView.findViewById(R.id.api_3rd); + TextInputLayout lay = dialogView.findViewById(R.id.api_lay); + TextInputEditText url = dialogView.findViewById(R.id.custom_api_url); + + if (mAPI.getText().toString().equals("Mojang")) { + apiMojang.setChecked(true); + lay.setVisibility(View.GONE); + } else if (mAPI.getText().toString().equals("Microsoft")) { + apiMs.setChecked(true); + lay.setVisibility(View.GONE); + } else { + api3rd.setChecked(true); + lay.setVisibility(View.VISIBLE); + } + url.setText(GetGameJson.getAppCfg("LoginApiValue", "")); + + apiMojang.setOnClickListener(v -> lay.setVisibility(View.GONE)); + apiMs.setOnClickListener(v -> lay.setVisibility(View.GONE)); + api3rd.setOnClickListener(v -> lay.setVisibility(View.VISIBLE)); + web.setOnClickListener(v->{ + mDialog.dismiss(); + showAPIWebDialog(); + }); + mojang.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://help.minecraft.net/hc/en-us/articles/360050865492-JAVA-Account-Migration-FAQ\n")); + }); + reg.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://www.minecraft.net/store/minecraft-java-edition/buy\n")); + }); + + cancel.setOnClickListener(v -> mDialog.dismiss()); + ok.setOnClickListener(v -> { + if (apiMojang.isChecked()) { + mAPI.setText("Mojang"); + GetGameJson.setAppJson("LoginApi", "Mojang"); + } else if (apiMs.isChecked()) { + mAPI.setText("Microsoft"); + GetGameJson.setAppJson("LoginApi", "Microsoft"); + } else if (api3rd.isChecked()) { + //showCustomApiDialog(); + mAPI.setText(url.getText().toString()); + GetGameJson.setAppJson("LoginApi", url.getText().toString()); + GetGameJson.setAppJson("LoginApiValue", url.getText().toString()); + } + mDialog.dismiss(); + }); + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int) (display.getWidth() * 0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + /**-----------------前往你的API所属网站修改账号信息--------------------*/ + public void showAPIWebDialog() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.home_dialog_apiweb, null); + mDialog.setContentView(dialogView); + MaterialButton cancel = dialogView.findViewById(R.id.custom_web_cancel); + MaterialButton start = dialogView.findViewById(R.id.custom_web_ok); + TextInputLayout apiLay = dialogView.findViewById(R.id.api_web_lay); + TextInputEditText et = dialogView.findViewById(R.id.dialog_edit_web); + + et.addTextChangedListener(new TextWatcher(){ + @Override + public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) { + } + + @Override + public void onTextChanged(CharSequence p1, int p2, int p3, int p4) { + } + + @Override + public void afterTextChanged(Editable p1) { + String value = et.getText().toString(); + if (value.matches("(http://|https://).*")){ + apiLay.setErrorEnabled(false); + start.setEnabled(true); + } else { + apiLay.setError(getString(R.string.http_hint)); + start.setEnabled(false); + } + } + }); + + et.setText(GetGameJson.getAppCfg("apiWeb","")); + cancel.setOnClickListener(v->{ + mDialog.dismiss(); + showAPIDialog(); + }); + start.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse(et.getText().toString()+"\n")); + GetGameJson.setAppJson("apiWeb",et.getText().toString()); + }); + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + + /**-----------------公告--------------------*/ + @SuppressLint("HandlerLeak") + public void showBC() { + Dialog mDialog = new Dialog(requireActivity()); + View dialogView = requireActivity().getLayoutInflater().inflate(R.layout.home_dialog_notice, null); + mDialog.setContentView(dialogView); + MaterialButton cancel = dialogView.findViewById(R.id.bc_cancel); + MaterialTextView text = dialogView.findViewById(R.id.bc_text); + + text.setText(message); + cancel.setOnClickListener(v->{ + mDialog.dismiss(); + }); + mDialog.setContentView(dialogView); + WindowManager windowManager = requireActivity().getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); + lp.width = (int)(display.getWidth()*0.9); //设置宽度 dialog.getWindow().setAttributes(lp); + mDialog.show(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/HomeViewModel.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/HomeViewModel.java new file mode 100644 index 00000000..a6ac6bed --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/HomeViewModel.java @@ -0,0 +1,19 @@ +package org.koishi.launcher.h2o2pro.ui.home; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class HomeViewModel extends ViewModel { + + private MutableLiveData mText; + + public HomeViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is home fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/WelcomeFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/WelcomeFragment.java new file mode 100644 index 00000000..259379b5 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/home/WelcomeFragment.java @@ -0,0 +1,108 @@ +package org.koishi.launcher.h2o2pro.ui.home; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.view.View; + +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import org.koishi.launcher.h2o2pro.R; +import org.koishi.launcher.h2o2pro.SettingsActivity; +import org.koishi.launcher.h2o2pro.SplashActivity; +import org.koishi.launcher.h2o2pro.WelcomeActivity; + +public class WelcomeFragment extends PreferenceFragmentCompat { + + public Boolean isPermed; + public Preference wStart,wPerm,wGive,wHelp; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.welcome_preferences, rootKey); + + wStart = findPreference("welcome_start"); + wPerm = findPreference("welcome_perm"); + wGive = findPreference("welcome_give"); + wHelp = findPreference("welcome_help"); + + if (wStart != null){ + wStart.setOnPreferenceClickListener(preference -> { + startActivity(new Intent(requireActivity(), SplashActivity.class)); + requireActivity().finish(); + //requireActivity().finish(); + return true; + }); + } + + if (wPerm != null){ + wPerm.setOnPreferenceClickListener(preference -> { + requireActivity().requestPermissions( + new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission + .ACCESS_FINE_LOCATION, + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE}, + 102); + return true; + }); + } + + if (wGive != null){ + wGive.setOnPreferenceClickListener(preference -> { + goSetting(); + return true; + }); + } + if (wHelp != null){ + wHelp.setOnPreferenceClickListener(preference -> { + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(requireActivity(), Uri.parse("https://b23.tv/ea3HRj\n")); + return true; + }); + } + + checkPermission(); + if (isPermed){ + wPerm.setEnabled(false); + wStart.setEnabled(true); + wPerm.setTitle(getResources().getString(R.string.welcome_perm_true)); + } else { + wStart.setEnabled(false); + wPerm.setEnabled(true); + wPerm.setTitle(getResources().getString(R.string.welcome_perm)); + } + + } + + public Boolean checkPermission() { + isPermed = true; + if (android.os.Build.VERSION.SDK_INT >= 23) { + if (requireActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + isPermed = false; + } + if (requireActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) !=PackageManager.PERMISSION_GRANTED) { + isPermed = false; + } + } + return isPermed; + } + + public void goSetting(){ + Intent mIntent = new Intent(); + mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (Build.VERSION.SDK_INT >= 9) { + mIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); + mIntent.setData(Uri.fromParts("package", requireActivity().getPackageName(), null)); + } else if (Build.VERSION.SDK_INT <= 8) { + mIntent.setAction(Intent.ACTION_VIEW); + mIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails"); + mIntent.putExtra("com.android.settings.ApplicationPkgName", requireActivity().getPackageName()); + } + requireActivity().startActivity(mIntent); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/install/InstallFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/install/InstallFragment.java new file mode 100644 index 00000000..c1323d63 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/install/InstallFragment.java @@ -0,0 +1,106 @@ +package org.koishi.launcher.h2o2pro.ui.install; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; + +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.fragment.app.Fragment; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.google.android.material.card.MaterialCardView; +import com.mistake.revision.VanillaActivity; + +import org.koishi.launcher.h2o2pro.R; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link InstallFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class InstallFragment extends Fragment { + + // TODO: Rename parameter arguments, choose names that match + // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER + private static final String ARG_PARAM1 = "param1"; + private static final String ARG_PARAM2 = "param2"; + + // TODO: Rename and change types of parameters + private String mParam1; + private String mParam2; + + public MaterialCardView cardMc,cardForge,cardOpti,cardFab,cardLl,cardPack,cardMod,cardCf,cardMcmod; + + public InstallFragment() { + // Required empty public constructor + } + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @param param1 Parameter 1. + * @param param2 Parameter 2. + * @return A new instance of fragment InstallFragment. + */ + // TODO: Rename and change types and number of parameters + public static InstallFragment newInstance(String param1, String param2) { + InstallFragment fragment = new InstallFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PARAM1, param1); + args.putString(ARG_PARAM2, param2); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mParam1 = getArguments().getString(ARG_PARAM1); + mParam2 = getArguments().getString(ARG_PARAM2); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View root = inflater.inflate(R.layout.fragment_install, container, false); + cardMc = root.findViewById(R.id.install_mc); + //cardForge = root.findViewById(R.id.install_forge); + //cardOpti = root.findViewById(R.id.install_opt); + //cardFab = root.findViewById(R.id.install_fab); + //cardLl = root.findViewById(R.id.install_ll); + //cardPack = root.findViewById(R.id.install_h2o2pack); + //cardMod = root.findViewById(R.id.install_mods); + //cardCf = root.findViewById(R.id.install_opencf); + //cardMcmod = root.findViewById(R.id.install_openmcmod); + + cardMc.setOnClickListener(v->{ + startActivity(new Intent(getActivity(), VanillaActivity.class)); + requireActivity().finish(); + }); + /* + cardForge.setOnClickListener(v->{}); + cardOpti.setOnClickListener(v->{}); + cardFab.setOnClickListener(v->{}); + cardLl.setOnClickListener(v->{}); + cardPack.setOnClickListener(v->{}); + cardMod.setOnClickListener(v->{}); + cardCf.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(getActivity(), Uri.parse("https://www.curseforge.com/minecraft/\n")); + }); + cardMcmod.setOnClickListener(v->{ + CustomTabsIntent intent = new CustomTabsIntent.Builder().setToolbarColor(getResources().getColor(R.color.colorPrimary)).build(); + intent.launchUrl(getActivity(), Uri.parse("https://www.mcmod.cn/\n")); + }); + */ + + return root; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/manager/ManagerFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/manager/ManagerFragment.java new file mode 100644 index 00000000..1845fb16 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/manager/ManagerFragment.java @@ -0,0 +1,198 @@ +package org.koishi.launcher.h2o2pro.ui.manager; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.ProgressBar; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; + +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.textfield.TextInputEditText; + +import org.json.JSONObject; +import org.koishi.launcher.h2o2pro.R; +import org.koishi.launcher.h2o2pro.VersionsActivity; +import org.koishi.launcher.h2o2pro.tool.data.DbDao; +import org.koishi.launcher.h2o2pro.tool.file.AppExecute; +import org.koishi.launcher.h2o2pro.tool.GetGameJson; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Objects; + +public class ManagerFragment extends Fragment { + + public LinearLayout openVer; + public ManagerViewModel managerViewModel; + public TextInputEditText mDirectory,mOutput; + public Button mSetButton, mResetButton, mOutputButton; + public ProgressBar pbM; + public String d; + + public DbDao mDbDao; + + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + managerViewModel = + new ViewModelProvider(this).get(ManagerViewModel.class); + View root = inflater.inflate(R.layout.fragment_manager, container, false); + mDirectory = root.findViewById(R.id.manager_directory); + mSetButton = root.findViewById(R.id.manager_set_button); + mResetButton = root.findViewById(R.id.manager_reset_button); + mOutput = root.findViewById(R.id.manager_output_pack); + mOutputButton =root.findViewById(R.id.manager_output_button); + + pbM = root.findViewById(R.id.pb_m); + + openVer = root.findViewById(R.id.manager_open_ver); + openVer.setOnClickListener(v->{ + startActivity(new Intent(requireActivity(), VersionsActivity.class)); + requireActivity().finish(); + }); + + mSetButton.setOnClickListener(v -> setDirectory()); + mResetButton.setOnClickListener(v -> reset()); + mDirectory.setText(GetGameJson.getBoatCfg("game_directory","/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir")); + + mOutputButton.setOnClickListener(v -> setOutput()); + + return root; + } + + public void setDirectory() { + String file = mDirectory.getText().toString(); + File f = new File(file); + pbM.setVisibility(View.VISIBLE); + mDirectory.setEnabled(false); + mSetButton.setEnabled(false); + mResetButton.setEnabled(false); + mOutput.setEnabled(false); + mOutputButton.setEnabled(false); + if (!f.exists()) { + new Thread(() -> { + try { + AppExecute.output(getActivity(), "boat.zip", file); + //Snackbar.make(getView(), getResources().getString(R.string.install_done), Snackbar.LENGTH_LONG) + //.setAction("Action", null).show(); + han.sendEmptyMessage(0); + } catch (IOException e) { + Snackbar.make(getView(), e.toString(), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + han.sendEmptyMessage(-1); + } + }).start(); + + } else { + Snackbar.make(getView(), getResources().getString(R.string.install_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + setDir(file); + mDirectory.setText(file); + } + + } + + public void setOutput() { + String file = mOutput.getText().toString(); + pbM.setVisibility(View.VISIBLE); + mDirectory.setEnabled(false); + mSetButton.setEnabled(false); + mResetButton.setEnabled(false); + mOutput.setEnabled(false); + mOutputButton.setEnabled(false); + new Thread(() -> { + try { + AppExecute.output(getActivity(), "pack.zip", file); + //Snackbar.make(getView(), getResources().getString(R.string.install_done), Snackbar.LENGTH_LONG) + //.setAction("Action", null).show(); + han.sendEmptyMessage(1); + } catch (IOException e) { + Snackbar.make(getView(), e.toString(), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + han.sendEmptyMessage(-1); + } + }).start(); + + } + + @SuppressLint("HandlerLeak") + Handler han = new Handler() { + @SuppressLint("HandlerLeak") + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + Snackbar.make(getView(), getResources().getString(R.string.install_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + setDir(mDirectory.getText().toString()); + mDirectory.setText(mDirectory.getText().toString()); + } + if (msg.what == 1) { + Snackbar.make(getView(), getResources().getString(R.string.install_done), Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + boolean hasData = mDbDao.hasData(Objects.requireNonNull(mOutput.getText()).toString()); + if (!hasData){ + mDbDao.insertData(mOutput.getText().toString()); + } + //setDir(mOutput.getText().toString()); + //mDirectory.setText(mOutput.getText().toString()); + pbM.setVisibility(View.GONE); + mDirectory.setEnabled(true); + mSetButton.setEnabled(true); + mResetButton.setEnabled(true); + mOutput.setEnabled(true); + mOutputButton.setEnabled(true); + } + if (msg.what == -1) { + reset(); + } + } + }; + + public void reset() { + pbM.setVisibility(View.GONE); + mDirectory.setEnabled(true); + mSetButton.setEnabled(true); + mResetButton.setEnabled(true); + mOutput.setEnabled(true); + mOutputButton.setEnabled(true); + setDir("/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"); + mDirectory.setText("/storage/emulated/0/games/com.koishi.launcher/h2o2/gamedir"); + } + + public static void setDir(String dir) { + try { + FileInputStream in = new FileInputStream("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt"); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + String str = new String(b); + JSONObject json = new JSONObject(str); + json.remove("game_directory"); + json.remove("game_assets"); + json.remove("assets_root"); + json.remove("currentVersion"); + json.put("game_directory", dir); + json.put("game_assets", dir + "/assets/virtual/legacy"); + json.put("assets_root", dir + "/assets"); + json.put("currentVersion", dir + "/versions"); + FileWriter fr = new FileWriter(new File("/storage/emulated/0/games/com.koishi.launcher/h2o2/config.txt")); + fr.write(json.toString()); + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/manager/ManagerViewModel.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/manager/ManagerViewModel.java new file mode 100644 index 00000000..ce7c5483 --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/manager/ManagerViewModel.java @@ -0,0 +1,19 @@ +package org.koishi.launcher.h2o2pro.ui.manager; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class ManagerViewModel extends ViewModel { + + private MutableLiveData mText; + + public ManagerViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is gallery fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koishi/launcher/h2o2pro/ui/version/VersionFragment.java b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/version/VersionFragment.java new file mode 100644 index 00000000..51b79b2a --- /dev/null +++ b/app/src/main/java/org/koishi/launcher/h2o2pro/ui/version/VersionFragment.java @@ -0,0 +1,66 @@ +package org.koishi.launcher.h2o2pro.ui.version; + +import android.os.Bundle; + +import androidx.fragment.app.Fragment; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.koishi.launcher.h2o2pro.R; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link VersionFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class VersionFragment extends Fragment { + + // TODO: Rename parameter arguments, choose names that match + // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER + private static final String ARG_PARAM1 = "param1"; + private static final String ARG_PARAM2 = "param2"; + + // TODO: Rename and change types of parameters + private String mParam1; + private String mParam2; + + public VersionFragment() { + // Required empty public constructor + } + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @param param1 Parameter 1. + * @param param2 Parameter 2. + * @return A new instance of fragment VersionsFragment. + */ + // TODO: Rename and change types and number of parameters + public static VersionFragment newInstance(String param1, String param2) { + VersionFragment fragment = new VersionFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PARAM1, param1); + args.putString(ARG_PARAM2, param2); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mParam1 = getArguments().getString(ARG_PARAM1); + mParam2 = getArguments().getString(ARG_PARAM2); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_versions, container, false); + } +} \ No newline at end of file diff --git a/app/src/main/java/ren/qinc/edit/PerformEdit.java b/app/src/main/java/ren/qinc/edit/PerformEdit.java new file mode 100644 index 00000000..af6643f0 --- /dev/null +++ b/app/src/main/java/ren/qinc/edit/PerformEdit.java @@ -0,0 +1,250 @@ +/* + * Copyright 2016. SHENQINCI(沈钦赐)<946736079@qq.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ren.qinc.edit; + +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.widget.EditText; + +import androidx.annotation.NonNull; + +import java.util.Stack; + +/** + * 撤销和恢复撤销 + * Created by 沈钦赐 on 16/6/23. + */ +public class PerformEdit { + //操作序号(一次编辑可能对应多个操作,如替换文字,就是删除+插入) + int index; + //撤销栈 + Stack history = new Stack<>(); + //恢复栈 + Stack historyBack = new Stack<>(); + + private Editable editable; + private EditText editText; + //自动操作标志,防止重复回调,导致无限撤销 + private boolean flag = false; + + public PerformEdit(@NonNull EditText editText) { + CheckNull(editText, "EditText不能为空"); + this.editable = editText.getText(); + this.editText = editText; + editText.addTextChangedListener(new Watcher()); + } + + protected void onEditableChanged(Editable s) { + + } + + protected void onTextChanged(Editable s) { + + } + + + /** + * 清理记录 + * Clear history. + */ + public final void clearHistory() { + history.clear(); + historyBack.clear(); + } + + + /** + * 撤销 + * Undo. + */ + public final void undo() { + if (history.empty()) return; + //锁定操作 + flag = true; + Action action = history.pop(); + historyBack.push(action); + if (action.isAdd) { + //撤销添加 + editable.delete(action.startCursor, action.startCursor + action.actionTarget.length()); + editText.setSelection(action.startCursor, action.startCursor); + } else { + //插销删除 + editable.insert(action.startCursor, action.actionTarget); + if (action.endCursor == action.startCursor) { + editText.setSelection(action.startCursor + action.actionTarget.length()); + } else { + editText.setSelection(action.startCursor, action.endCursor); + } + } + //释放操作 + flag = false; + //判断是否是下一个动作是否和本动作是同一个操作,直到不同为止 + if (!history.empty() && history.peek().index == action.index) { + undo(); + } + } + + /** + * 恢复 + * Redo. + */ + public final void redo() { + if (historyBack.empty()) return; + flag = true; + Action action = historyBack.pop(); + history.push(action); + if (action.isAdd) { + //恢复添加 + editable.insert(action.startCursor, action.actionTarget); + if (action.endCursor == action.startCursor) { + editText.setSelection(action.startCursor + action.actionTarget.length()); + } else { + editText.setSelection(action.startCursor, action.endCursor); + } + } else { + //恢复删除 + editable.delete(action.startCursor, action.startCursor + action.actionTarget.length()); + editText.setSelection(action.startCursor, action.startCursor); + } + flag = false; + //判断是否是下一个动作是否和本动作是同一个操作 + if (!historyBack.empty() && historyBack.peek().index == action.index) + redo(); + } + + /** + * 首次设置文本 + * Set default text. + */ + public final void setDefaultText(CharSequence text) { + clearHistory(); + flag = true; + editable.replace(0, editable.length(), text); + flag = false; + } + + private class Watcher implements TextWatcher { + + /** + * Before text changed. + * + * @param s the s + * @param start the start 起始光标 + * @param count the endCursor 选择数量 + * @param after the after 替换增加的文字数 + */ + @Override + public final void beforeTextChanged(CharSequence s, int start, int count, int after) { + if (flag) return; + int end = start + count; + if (end > start && end <= s.length()) { + CharSequence charSequence = s.subSequence(start, end); + //删除了文字 + if (charSequence.length() > 0) { + Action action = new Action(charSequence, start, false); + if (count > 1) { + //如果一次超过一个字符,说名用户选择了,然后替换或者删除操作 + action.setSelectCount(count); + } else if (count == 1 && count == after) { + //一个字符替换 + action.setSelectCount(count); + } + //还有一种情况:选择一个字符,然后删除(暂时没有考虑这种情况) + + history.push(action); + historyBack.clear(); + action.setIndex(++index); + } + } + } + + /** + * On text changed. + * + * @param s the s + * @param start the start 起始光标 + * @param before the before 选择数量 + * @param count the endCursor 添加的数量 + */ + @Override + public final void onTextChanged(CharSequence s, int start, int before, int count) { + if (flag) return; + int end = start + count; + if (end > start) { + CharSequence charSequence = s.subSequence(start, end); + //添加文字 + if (charSequence.length() > 0) { + Action action = new Action(charSequence, start, true); + + history.push(action); + historyBack.clear(); + if (before > 0) { + //文字替换(先删除再增加),删除和增加是同一个操作,所以不需要增加序号 + action.setIndex(index); + } else { + action.setIndex(++index); + } + } + } + } + + @Override + public final void afterTextChanged(Editable s) { + if (flag) return; + if (s != editable) { + editable = s; + onEditableChanged(s); + } + PerformEdit.this.onTextChanged(s); + } + + } + + private class Action { + /** 改变字符. */ + CharSequence actionTarget; + /** 光标位置. */ + int startCursor; + int endCursor; + /** 标志增加操作. */ + boolean isAdd; + /** 操作序号. */ + int index; + + + public Action(CharSequence actionTag, int startCursor, boolean add) { + this.actionTarget = actionTag; + this.startCursor = startCursor; + this.endCursor = startCursor; + this.isAdd = add; + } + + public void setSelectCount(int count) { + this.endCursor = endCursor + count; + } + + public void setIndex(int index) { + this.index = index; + } + } + + + private static void CheckNull(Object o, String message) { + if (o == null) throw new IllegalStateException(message); + } +} diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml new file mode 100644 index 00000000..a28a2b51 --- /dev/null +++ b/app/src/main/res/anim/fade_in.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml new file mode 100644 index 00000000..a7cfc84d --- /dev/null +++ b/app/src/main/res/anim/fade_out.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_hide.xml b/app/src/main/res/anim/layout_hide.xml new file mode 100644 index 00000000..5625362d --- /dev/null +++ b/app/src/main/res/anim/layout_hide.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_in_from_left.xml b/app/src/main/res/anim/layout_in_from_left.xml new file mode 100644 index 00000000..a2bb4456 --- /dev/null +++ b/app/src/main/res/anim/layout_in_from_left.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_out_to_left.xml b/app/src/main/res/anim/layout_out_to_left.xml new file mode 100644 index 00000000..fe9ddac3 --- /dev/null +++ b/app/src/main/res/anim/layout_out_to_left.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/layout_show.xml b/app/src/main/res/anim/layout_show.xml new file mode 100644 index 00000000..ff991e19 --- /dev/null +++ b/app/src/main/res/anim/layout_show.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/ic_menu_camera.xml b/app/src/main/res/drawable-v21/ic_menu_camera.xml deleted file mode 100644 index 7d1c5833..00000000 --- a/app/src/main/res/drawable-v21/ic_menu_camera.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_gallery.xml b/app/src/main/res/drawable-v21/ic_menu_gallery.xml deleted file mode 100644 index 2f2ca2aa..00000000 --- a/app/src/main/res/drawable-v21/ic_menu_gallery.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_manage.xml b/app/src/main/res/drawable-v21/ic_menu_manage.xml deleted file mode 100644 index 065d9fa8..00000000 --- a/app/src/main/res/drawable-v21/ic_menu_manage.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/ic_menu_send.xml b/app/src/main/res/drawable-v21/ic_menu_send.xml deleted file mode 100644 index a5546577..00000000 --- a/app/src/main/res/drawable-v21/ic_menu_send.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_share.xml b/app/src/main/res/drawable-v21/ic_menu_share.xml deleted file mode 100644 index 8151b38e..00000000 --- a/app/src/main/res/drawable-v21/ic_menu_share.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_slideshow.xml b/app/src/main/res/drawable-v21/ic_menu_slideshow.xml deleted file mode 100644 index e7509918..00000000 --- a/app/src/main/res/drawable-v21/ic_menu_slideshow.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml index c7bd21db..2b068d11 100644 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -2,19 +2,15 @@ xmlns:aapt="http://schemas.android.com/aapt" android:width="108dp" android:height="108dp" - android:viewportHeight="108" - android:viewportWidth="108"> - + android:viewportWidth="108" + android:viewportHeight="108"> + - + android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + \ No newline at end of file diff --git a/app/src/main/res/drawable-v31/ic_btn_blue.xml b/app/src/main/res/drawable-v31/ic_btn_blue.xml new file mode 100644 index 00000000..537ba896 --- /dev/null +++ b/app/src/main/res/drawable-v31/ic_btn_blue.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v31/ic_btn_empty.xml b/app/src/main/res/drawable-v31/ic_btn_empty.xml new file mode 100644 index 00000000..9eb1da12 --- /dev/null +++ b/app/src/main/res/drawable-v31/ic_btn_empty.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v31/ic_btn_green.xml b/app/src/main/res/drawable-v31/ic_btn_green.xml new file mode 100644 index 00000000..4c646e35 --- /dev/null +++ b/app/src/main/res/drawable-v31/ic_btn_green.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v31/ic_home_user.xml b/app/src/main/res/drawable-v31/ic_home_user.xml new file mode 100644 index 00000000..3dcfd9d7 --- /dev/null +++ b/app/src/main/res/drawable-v31/ic_home_user.xml @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/add_blue.xml b/app/src/main/res/drawable/add_blue.xml index 9f2e0fa8..3439b9d2 100644 --- a/app/src/main/res/drawable/add_blue.xml +++ b/app/src/main/res/drawable/add_blue.xml @@ -3,9 +3,9 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorControlNormal"> + android:tint="@color/colorPrimary"> diff --git a/app/src/main/res/drawable/background_dark.xml b/app/src/main/res/drawable/background_dark.xml new file mode 100644 index 00000000..ccac9390 --- /dev/null +++ b/app/src/main/res/drawable/background_dark.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_light.xml b/app/src/main/res/drawable/background_light.xml new file mode 100644 index 00000000..cc5e8098 --- /dev/null +++ b/app/src/main/res/drawable/background_light.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_ripple_dark.xml b/app/src/main/res/drawable/background_ripple_dark.xml new file mode 100644 index 00000000..098e0b5b --- /dev/null +++ b/app/src/main/res/drawable/background_ripple_dark.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_ripple_light.xml b/app/src/main/res/drawable/background_ripple_light.xml new file mode 100644 index 00000000..97766794 --- /dev/null +++ b/app/src/main/res/drawable/background_ripple_light.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_yjx.png b/app/src/main/res/drawable/bg_yjx.png new file mode 100644 index 00000000..63417a47 Binary files /dev/null and b/app/src/main/res/drawable/bg_yjx.png differ diff --git a/app/src/main/res/drawable/bottom_nav_bg.xml b/app/src/main/res/drawable/bottom_nav_bg.xml new file mode 100644 index 00000000..7434ee2f --- /dev/null +++ b/app/src/main/res/drawable/bottom_nav_bg.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_green.xml b/app/src/main/res/drawable/btn_green.xml deleted file mode 100644 index 13a8ed1b..00000000 --- a/app/src/main/res/drawable/btn_green.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/button_ripple.xml b/app/src/main/res/drawable/button_ripple.xml new file mode 100644 index 00000000..56891d69 --- /dev/null +++ b/app/src/main/res/drawable/button_ripple.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/close.xml b/app/src/main/res/drawable/close.xml new file mode 100644 index 00000000..4daa8125 --- /dev/null +++ b/app/src/main/res/drawable/close.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/app/src/main/res/drawable/cv_shape.xml b/app/src/main/res/drawable/cv_shape.xml new file mode 100644 index 00000000..b3d3f5b6 --- /dev/null +++ b/app/src/main/res/drawable/cv_shape.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/drawable/toolbar_refresh.xml b/app/src/main/res/drawable/download_pause.xml similarity index 100% rename from app/src/main/res/drawable/toolbar_refresh.xml rename to app/src/main/res/drawable/download_pause.xml diff --git a/app/src/main/res/drawable/download_play.xml b/app/src/main/res/drawable/download_play.xml new file mode 100644 index 00000000..f2be45ba --- /dev/null +++ b/app/src/main/res/drawable/download_play.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/file_folder.xml b/app/src/main/res/drawable/file_folder.xml new file mode 100644 index 00000000..7d4ff25d --- /dev/null +++ b/app/src/main/res/drawable/file_folder.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/forge.png b/app/src/main/res/drawable/forge.png new file mode 100644 index 00000000..c79eec11 Binary files /dev/null and b/app/src/main/res/drawable/forge.png differ diff --git a/app/src/main/res/drawable/furnace.png b/app/src/main/res/drawable/furnace.png new file mode 100644 index 00000000..4fc95fc2 Binary files /dev/null and b/app/src/main/res/drawable/furnace.png differ diff --git a/app/src/main/res/drawable/grass.png b/app/src/main/res/drawable/grass.png new file mode 100644 index 00000000..2380963a Binary files /dev/null and b/app/src/main/res/drawable/grass.png differ diff --git a/app/src/main/res/drawable/hide.xml b/app/src/main/res/drawable/hide.xml new file mode 100644 index 00000000..796ed3fa --- /dev/null +++ b/app/src/main/res/drawable/hide.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/list_fwd.xml b/app/src/main/res/drawable/ic_arrow_right_black.xml similarity index 100% rename from app/src/main/res/drawable/list_fwd.xml rename to app/src/main/res/drawable/ic_arrow_right_black.xml diff --git a/app/src/main/res/drawable/tx.png b/app/src/main/res/drawable/ic_author.png similarity index 100% rename from app/src/main/res/drawable/tx.png rename to app/src/main/res/drawable/ic_author.png diff --git a/app/src/main/res/drawable/ic_baseline_toggle_off_24.xml b/app/src/main/res/drawable/ic_baseline_toggle_off_24.xml new file mode 100644 index 00000000..1af8c24e --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_toggle_off_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_toggle_on_24.xml b/app/src/main/res/drawable/ic_baseline_toggle_on_24.xml new file mode 100644 index 00000000..914671e1 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_toggle_on_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_boat_action.xml b/app/src/main/res/drawable/ic_boat_action.xml new file mode 100644 index 00000000..35f7f5f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_boat_action.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_btm_bg.xml b/app/src/main/res/drawable/ic_btm_bg.xml new file mode 100644 index 00000000..ccac9390 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_bg.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btm_custom.xml b/app/src/main/res/drawable/ic_btm_custom.xml new file mode 100644 index 00000000..39f59d94 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_custom.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btm_custom_check.xml b/app/src/main/res/drawable/ic_btm_custom_check.xml new file mode 100644 index 00000000..72a770f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_custom_check.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btm_custom_normal.xml b/app/src/main/res/drawable/ic_btm_custom_normal.xml new file mode 100644 index 00000000..c688e9a3 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_custom_normal.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_btm_custom_selected.xml b/app/src/main/res/drawable/ic_btm_custom_selected.xml new file mode 100644 index 00000000..2c26a4db --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_custom_selected.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btm_home.xml b/app/src/main/res/drawable/ic_btm_home.xml new file mode 100644 index 00000000..f91126ef --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_home.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/menu_b_home.xml b/app/src/main/res/drawable/ic_btm_home_check.xml similarity index 87% rename from app/src/main/res/drawable/menu_b_home.xml rename to app/src/main/res/drawable/ic_btm_home_check.xml index 3a4c7dac..26464223 100644 --- a/app/src/main/res/drawable/menu_b_home.xml +++ b/app/src/main/res/drawable/ic_btm_home_check.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorControlNormal"> + android:tint="@color/appTint"> diff --git a/app/src/main/res/drawable/ic_btm_home_normal.xml b/app/src/main/res/drawable/ic_btm_home_normal.xml new file mode 100644 index 00000000..fb571d64 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_home_normal.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_btm_home_selected.xml b/app/src/main/res/drawable/ic_btm_home_selected.xml new file mode 100644 index 00000000..7950a944 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_home_selected.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btm_install.xml b/app/src/main/res/drawable/ic_btm_install.xml new file mode 100644 index 00000000..97b2ccaa --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_install.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/arrow_right.xml b/app/src/main/res/drawable/ic_btm_install_check.xml similarity index 51% rename from app/src/main/res/drawable/arrow_right.xml rename to app/src/main/res/drawable/ic_btm_install_check.xml index 75bf9ed9..1e5999af 100644 --- a/app/src/main/res/drawable/arrow_right.xml +++ b/app/src/main/res/drawable/ic_btm_install_check.xml @@ -3,9 +3,8 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorControlNormal"> - + android:tint="@color/appTint"> + - diff --git a/app/src/main/res/drawable/ic_btm_install_normal.xml b/app/src/main/res/drawable/ic_btm_install_normal.xml new file mode 100644 index 00000000..3298202a --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_install_normal.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_btm_install_selected.xml b/app/src/main/res/drawable/ic_btm_install_selected.xml new file mode 100644 index 00000000..2da532bb --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_install_selected.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btm_manager.xml b/app/src/main/res/drawable/ic_btm_manager.xml new file mode 100644 index 00000000..38b71e6c --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_manager.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btm_manager_check.xml b/app/src/main/res/drawable/ic_btm_manager_check.xml new file mode 100644 index 00000000..6fb98fd9 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_manager_check.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_btm_manager_normal.xml b/app/src/main/res/drawable/ic_btm_manager_normal.xml new file mode 100644 index 00000000..de0440e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_manager_normal.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_btm_manager_selected.xml b/app/src/main/res/drawable/ic_btm_manager_selected.xml new file mode 100644 index 00000000..bba71304 --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_manager_selected.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/menu_l_about.xml b/app/src/main/res/drawable/ic_btm_more_check.xml similarity index 100% rename from app/src/main/res/drawable/menu_l_about.xml rename to app/src/main/res/drawable/ic_btm_more_check.xml diff --git a/app/src/main/res/drawable/ic_btm_selected_bg.xml b/app/src/main/res/drawable/ic_btm_selected_bg.xml new file mode 100644 index 00000000..4c283dfe --- /dev/null +++ b/app/src/main/res/drawable/ic_btm_selected_bg.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_blue.xml b/app/src/main/res/drawable/ic_btn_blue.xml new file mode 100644 index 00000000..881b8c7f --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_blue.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_cyan.xml b/app/src/main/res/drawable/ic_btn_cyan.xml new file mode 100644 index 00000000..44d76b24 --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_cyan.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_empty.xml b/app/src/main/res/drawable/ic_btn_empty.xml new file mode 100644 index 00000000..19965c29 --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_empty.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_green.xml b/app/src/main/res/drawable/ic_btn_green.xml new file mode 100644 index 00000000..05089c2d --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_green.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_orange.xml b/app/src/main/res/drawable/ic_btn_orange.xml new file mode 100644 index 00000000..2653d195 --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_orange.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_purple.xml b/app/src/main/res/drawable/ic_btn_purple.xml new file mode 100644 index 00000000..0e0e3e02 --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_purple.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_red.xml b/app/src/main/res/drawable/ic_btn_red.xml new file mode 100644 index 00000000..37f7f30d --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_red.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_btn_yellow.xml b/app/src/main/res/drawable/ic_btn_yellow.xml new file mode 100644 index 00000000..a6ec12f8 --- /dev/null +++ b/app/src/main/res/drawable/ic_btn_yellow.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_build.xml b/app/src/main/res/drawable/ic_build.xml new file mode 100644 index 00000000..d8dcc75e --- /dev/null +++ b/app/src/main/res/drawable/ic_build.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_cpu_outline.xml b/app/src/main/res/drawable/ic_cpu_outline.xml new file mode 100644 index 00000000..4b7c5dc2 --- /dev/null +++ b/app/src/main/res/drawable/ic_cpu_outline.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_crash.xml b/app/src/main/res/drawable/ic_crash.xml new file mode 100644 index 00000000..f9898d7f --- /dev/null +++ b/app/src/main/res/drawable/ic_crash.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_custom_back.xml b/app/src/main/res/drawable/ic_custom_back.xml new file mode 100644 index 00000000..b929a59f --- /dev/null +++ b/app/src/main/res/drawable/ic_custom_back.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_custom_gl.xml b/app/src/main/res/drawable/ic_custom_gl.xml new file mode 100644 index 00000000..863adc4a --- /dev/null +++ b/app/src/main/res/drawable/ic_custom_gl.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_custom_more.xml b/app/src/main/res/drawable/ic_custom_more.xml new file mode 100644 index 00000000..9f5c07ac --- /dev/null +++ b/app/src/main/res/drawable/ic_custom_more.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_custom_settings_black.xml b/app/src/main/res/drawable/ic_custom_settings_black.xml new file mode 100644 index 00000000..ada4e465 --- /dev/null +++ b/app/src/main/res/drawable/ic_custom_settings_black.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/file.xml b/app/src/main/res/drawable/ic_del_all.xml similarity index 66% rename from app/src/main/res/drawable/file.xml rename to app/src/main/res/drawable/ic_del_all.xml index f404fbf7..04aa8f2f 100644 --- a/app/src/main/res/drawable/file.xml +++ b/app/src/main/res/drawable/ic_del_all.xml @@ -6,5 +6,5 @@ android:tint="?attr/colorControlNormal"> + android:pathData="M16,9v10H8V9h8m-1.5,-6h-5l-1,1H5v2h14V4h-3.5l-1,-1zM18,7H6v12c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7z"/> diff --git a/app/src/main/res/drawable/ic_directory.xml b/app/src/main/res/drawable/ic_directory.xml new file mode 100644 index 00000000..1571b618 --- /dev/null +++ b/app/src/main/res/drawable/ic_directory.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/btn_afd.xml b/app/src/main/res/drawable/ic_donate_afd.xml similarity index 50% rename from app/src/main/res/drawable/btn_afd.xml rename to app/src/main/res/drawable/ic_donate_afd.xml index fd2bba30..7ec65925 100644 --- a/app/src/main/res/drawable/btn_afd.xml +++ b/app/src/main/res/drawable/ic_donate_afd.xml @@ -1,8 +1,8 @@ - + android:width="24dp" android:height="24dp" + android:viewportWidth="24" android:viewportHeight="24" android:tint="@color/orange_light_primary"> + diff --git a/app/src/main/res/drawable/btn_prt.xml b/app/src/main/res/drawable/ic_donate_patreon.xml similarity index 95% rename from app/src/main/res/drawable/btn_prt.xml rename to app/src/main/res/drawable/ic_donate_patreon.xml index e76bb81e..d05dfc10 100644 --- a/app/src/main/res/drawable/btn_prt.xml +++ b/app/src/main/res/drawable/ic_donate_patreon.xml @@ -1,6 +1,6 @@ + android:width="24dp" + android:height="24dp" + android:tint="@color/green_light" + android:viewportWidth="1024.0" + android:viewportHeight="1024.0"> + android:fillColor="@color/white" + android:pathData="M843.9,795.2l23.6,78.6 -85.7,-47.4c-31.2,7.9 -62.7,15.7 -93.7,15.7 -148.7,0 -265.8,-102.1 -265.8,-228.1 0,-125.7 117,-228.2 265.8,-228.2 140.4,0 265.5,102.4 265.5,228.2C953.4,685 906.7,747.8 843.9,795.2zM605.2,509.3c-18.7,0 -33.9,15.3 -33.9,34.1 0,18.9 15.2,34.1 33.9,34.1 18.7,0 33.9,-15.3 33.9,-34.1C639.1,524.6 623.9,509.3 605.2,509.3zM777.7,509.3c-18.7,0 -33.9,15.3 -33.9,34.1 0,18.9 15.2,34.1 33.9,34.1 18.7,0 33.9,-15.3 33.9,-34.1C811.7,524.6 796.5,509.3 777.7,509.3zM402.6,617.9c0,23 3.5,45 9.7,66 -9.7,0.6 -19.5,1.1 -29.3,1.1l0,0 -0,0c-39.1,0 -70.4,-7.9 -109.4,-15.7l-109.3,55.1 31.3,-94.5C117.3,574.7 70.5,503.9 70.5,417.5c0,-149.6 140.7,-267.4 312.6,-267.4 153.7,0 288.2,94.2 315.4,220.8 -10.1,-1.1 -20.1,-1.8 -30.2,-1.8C519.8,369.1 402.7,480.6 402.6,617.9zM278.1,280.3c-23.4,0 -42.4,19.1 -42.4,42.6 0,23.5 19,42.6 42.4,42.6 23.4,0 42.4,-19.1 42.4,-42.6C320.5,299.4 301.5,280.3 278.1,280.3zM498.7,279.9c-23.4,0 -42.4,19.1 -42.4,42.6 0,23.5 19,42.6 42.4,42.6 23.4,0 42.4,-19.1 42.4,-42.6C541.1,299 522.1,279.9 498.7,279.9z" /> diff --git a/app/src/main/res/drawable/qr.png b/app/src/main/res/drawable/ic_donate_wx.png similarity index 100% rename from app/src/main/res/drawable/qr.png rename to app/src/main/res/drawable/ic_donate_wx.png diff --git a/app/src/main/res/drawable/folder.png b/app/src/main/res/drawable/ic_file_folder.png similarity index 100% rename from app/src/main/res/drawable/folder.png rename to app/src/main/res/drawable/ic_file_folder.png diff --git a/app/src/main/res/drawable/jar.png b/app/src/main/res/drawable/ic_file_jar.png similarity index 100% rename from app/src/main/res/drawable/jar.png rename to app/src/main/res/drawable/ic_file_jar.png diff --git a/app/src/main/res/drawable/folder_125.xml b/app/src/main/res/drawable/ic_folder_outline.xml similarity index 64% rename from app/src/main/res/drawable/folder_125.xml rename to app/src/main/res/drawable/ic_folder_outline.xml index f58b501e..9cd7523e 100644 --- a/app/src/main/res/drawable/folder_125.xml +++ b/app/src/main/res/drawable/ic_folder_outline.xml @@ -6,5 +6,5 @@ android:tint="?attr/colorControlNormal"> + android:pathData="M9.17,6l2,2H20v10H4V6h5.17M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/> diff --git a/app/src/main/res/drawable/ic_gamelist_mc.png b/app/src/main/res/drawable/ic_gamelist_mc.png new file mode 100644 index 00000000..3ebab3b5 Binary files /dev/null and b/app/src/main/res/drawable/ic_gamelist_mc.png differ diff --git a/app/src/main/res/drawable/ic_h2o2.png b/app/src/main/res/drawable/ic_h2o2.png index 488cd28c..dbf875e2 100644 Binary files a/app/src/main/res/drawable/ic_h2o2.png and b/app/src/main/res/drawable/ic_h2o2.png differ diff --git a/app/src/main/res/drawable/ic_h2o2_bg.png b/app/src/main/res/drawable/ic_h2o2_bg.png new file mode 100644 index 00000000..f767c023 Binary files /dev/null and b/app/src/main/res/drawable/ic_h2o2_bg.png differ diff --git a/app/src/main/res/drawable/ic_h2o2_new.jpg b/app/src/main/res/drawable/ic_h2o2_default_px.jpg similarity index 100% rename from app/src/main/res/drawable/ic_h2o2_new.jpg rename to app/src/main/res/drawable/ic_h2o2_default_px.jpg diff --git a/app/src/main/res/drawable/ic_h2o2_home_play.xml b/app/src/main/res/drawable/ic_h2o2_home_play.xml new file mode 100644 index 00000000..93ec97bd --- /dev/null +++ b/app/src/main/res/drawable/ic_h2o2_home_play.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_h2o2_large.png b/app/src/main/res/drawable/ic_h2o2_large.png new file mode 100644 index 00000000..a86454d5 Binary files /dev/null and b/app/src/main/res/drawable/ic_h2o2_large.png differ diff --git a/app/src/main/res/drawable/ic_h2o2_lowpx.jpg b/app/src/main/res/drawable/ic_h2o2_low_px.jpg similarity index 100% rename from app/src/main/res/drawable/ic_h2o2_lowpx.jpg rename to app/src/main/res/drawable/ic_h2o2_low_px.jpg diff --git a/app/src/main/res/drawable/ic_h2o2_old.png b/app/src/main/res/drawable/ic_h2o2_old.png new file mode 100644 index 00000000..f21a601e Binary files /dev/null and b/app/src/main/res/drawable/ic_h2o2_old.png differ diff --git a/app/src/main/res/drawable/ic_h2o2_small.png b/app/src/main/res/drawable/ic_h2o2_small.png new file mode 100644 index 00000000..9e5694ba Binary files /dev/null and b/app/src/main/res/drawable/ic_h2o2_small.png differ diff --git a/app/src/main/res/drawable/menu_b_custom.xml b/app/src/main/res/drawable/ic_home_edit.xml similarity index 51% rename from app/src/main/res/drawable/menu_b_custom.xml rename to app/src/main/res/drawable/ic_home_edit.xml index 8adfae33..47ea705d 100644 --- a/app/src/main/res/drawable/menu_b_custom.xml +++ b/app/src/main/res/drawable/ic_home_edit.xml @@ -6,5 +6,5 @@ android:tint="?attr/colorControlNormal"> + android:pathData="M14.06,9.02l0.92,0.92L5.92,19L5,19v-0.92l9.06,-9.06M17.66,3c-0.25,0 -0.51,0.1 -0.7,0.29l-1.83,1.83 3.75,3.75 1.83,-1.83c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.2,-0.2 -0.45,-0.29 -0.71,-0.29zM14.06,6.19L3,17.25L3,21h3.75L17.81,9.94l-3.75,-3.75z"/> diff --git a/app/src/main/res/drawable/ic_home_logout.xml b/app/src/main/res/drawable/ic_home_logout.xml new file mode 100644 index 00000000..04cfa406 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_logout.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_msg.xml b/app/src/main/res/drawable/ic_home_msg.xml new file mode 100644 index 00000000..f8091d93 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_msg.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_notification.xml b/app/src/main/res/drawable/ic_home_notification.xml new file mode 100644 index 00000000..0a327617 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_notification.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_user.xml b/app/src/main/res/drawable/ic_home_user.xml new file mode 100644 index 00000000..636628dd --- /dev/null +++ b/app/src/main/res/drawable/ic_home_user.xml @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_home_user_normal.xml b/app/src/main/res/drawable/ic_home_user_normal.xml new file mode 100644 index 00000000..2275109c --- /dev/null +++ b/app/src/main/res/drawable/ic_home_user_normal.xml @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_info_android.xml b/app/src/main/res/drawable/ic_info_android.xml new file mode 100644 index 00000000..9a2e721d --- /dev/null +++ b/app/src/main/res/drawable/ic_info_android.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_info_cpu.xml b/app/src/main/res/drawable/ic_info_cpu.xml new file mode 100644 index 00000000..0d7a0a66 --- /dev/null +++ b/app/src/main/res/drawable/ic_info_cpu.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_info_discord.xml b/app/src/main/res/drawable/ic_info_discord.xml new file mode 100644 index 00000000..195d443d --- /dev/null +++ b/app/src/main/res/drawable/ic_info_discord.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_info_github.xml b/app/src/main/res/drawable/ic_info_github.xml new file mode 100644 index 00000000..08c191db --- /dev/null +++ b/app/src/main/res/drawable/ic_info_github.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_info_qq.xml b/app/src/main/res/drawable/ic_info_qq.xml new file mode 100644 index 00000000..007be90d --- /dev/null +++ b/app/src/main/res/drawable/ic_info_qq.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_info_root.xml b/app/src/main/res/drawable/ic_info_root.xml new file mode 100644 index 00000000..601a72bf --- /dev/null +++ b/app/src/main/res/drawable/ic_info_root.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_lang.xml b/app/src/main/res/drawable/ic_lang.xml new file mode 100644 index 00000000..4e7e3646 --- /dev/null +++ b/app/src/main/res/drawable/ic_lang.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/toolbar_add.xml b/app/src/main/res/drawable/ic_launcher_add.xml similarity index 100% rename from app/src/main/res/drawable/toolbar_add.xml rename to app/src/main/res/drawable/ic_launcher_add.xml diff --git a/app/src/main/res/drawable/ic_launcher_app_logo_round.png b/app/src/main/res/drawable/ic_launcher_app_logo_round.png new file mode 100644 index 00000000..23eed245 Binary files /dev/null and b/app/src/main/res/drawable/ic_launcher_app_logo_round.png differ diff --git a/app/src/main/res/drawable/ic_launcher_back_arrow.xml b/app/src/main/res/drawable/ic_launcher_back_arrow.xml new file mode 100644 index 00000000..bab545a7 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_back_arrow.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index d5fccc53..07d5da9c 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -2,169 +2,169 @@ + android:viewportWidth="108" + android:viewportHeight="108"> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> diff --git a/app/src/main/res/drawable/ic_launcher_boat_play_foreground.xml b/app/src/main/res/drawable/ic_launcher_boat_play_foreground.xml new file mode 100644 index 00000000..28b6b3e5 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_boat_play_foreground.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_boat_play_round.png b/app/src/main/res/drawable/ic_launcher_boat_play_round.png new file mode 100644 index 00000000..3c16ad75 Binary files /dev/null and b/app/src/main/res/drawable/ic_launcher_boat_play_round.png differ diff --git a/app/src/main/res/drawable/ic_launcher_cfg.xml b/app/src/main/res/drawable/ic_launcher_cfg.xml new file mode 100644 index 00000000..a2fbf43d --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_cfg.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_core.xml b/app/src/main/res/drawable/ic_launcher_check_core.xml new file mode 100644 index 00000000..f29d2247 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_core.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_file_blue_true.xml b/app/src/main/res/drawable/ic_launcher_check_file_blue_true.xml new file mode 100644 index 00000000..50382d4a --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_file_blue_true.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_file_false.xml b/app/src/main/res/drawable/ic_launcher_check_file_false.xml new file mode 100644 index 00000000..092c5e14 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_file_false.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_file_fill_green_true.xml b/app/src/main/res/drawable/ic_launcher_check_file_fill_green_true.xml new file mode 100644 index 00000000..a4af6a06 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_file_fill_green_true.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_file_fill_red_false.xml b/app/src/main/res/drawable/ic_launcher_check_file_fill_red_false.xml new file mode 100644 index 00000000..41960cd7 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_file_fill_red_false.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_file_red_false.xml b/app/src/main/res/drawable/ic_launcher_check_file_red_false.xml new file mode 100644 index 00000000..d41ae0ed --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_file_red_false.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_file_true.xml b/app/src/main/res/drawable/ic_launcher_check_file_true.xml new file mode 100644 index 00000000..e451d13d --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_file_true.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_check_game.xml b/app/src/main/res/drawable/ic_launcher_check_game.xml new file mode 100644 index 00000000..eb459842 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_check_game.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_close.xml b/app/src/main/res/drawable/ic_launcher_close.xml new file mode 100644 index 00000000..15501459 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_close.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_file_checker.xml b/app/src/main/res/drawable/ic_launcher_file_checker.xml new file mode 100644 index 00000000..560e399c --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_file_checker.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_game_play.xml b/app/src/main/res/drawable/ic_launcher_game_play.xml new file mode 100644 index 00000000..15a1c13d --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_game_play.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_gamedir_foreground.xml b/app/src/main/res/drawable/ic_launcher_gamedir_foreground.xml new file mode 100644 index 00000000..b793c655 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_gamedir_foreground.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_gamedir_round.png b/app/src/main/res/drawable/ic_launcher_gamedir_round.png new file mode 100644 index 00000000..5560255f Binary files /dev/null and b/app/src/main/res/drawable/ic_launcher_gamedir_round.png differ diff --git a/app/src/main/res/drawable/ic_launcher_install.xml b/app/src/main/res/drawable/ic_launcher_install.xml new file mode 100644 index 00000000..06a9632c --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_install.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/drawable/menu_mc_packs.xml b/app/src/main/res/drawable/ic_launcher_install_file.xml similarity index 64% rename from app/src/main/res/drawable/menu_mc_packs.xml rename to app/src/main/res/drawable/ic_launcher_install_file.xml index f58b501e..5c30d1cf 100644 --- a/app/src/main/res/drawable/menu_mc_packs.xml +++ b/app/src/main/res/drawable/ic_launcher_install_file.xml @@ -6,5 +6,5 @@ android:tint="?attr/colorControlNormal"> + android:pathData="M19,12v7L5,19v-7L3,12v7c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2zM13,12.67l2.59,-2.58L17,11.5l-5,5 -5,-5 1.41,-1.41L11,12.67L11,3h2z"/> diff --git a/app/src/main/res/drawable/ic_launcher_open.xml b/app/src/main/res/drawable/ic_launcher_open.xml new file mode 100644 index 00000000..adc215c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_open.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_refresh_file.xml b/app/src/main/res/drawable/ic_launcher_refresh_file.xml new file mode 100644 index 00000000..f2be45ba --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_refresh_file.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_runtime_foreground.xml b/app/src/main/res/drawable/ic_launcher_runtime_foreground.xml new file mode 100644 index 00000000..5b5cafa2 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_runtime_foreground.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_runtime_round.png b/app/src/main/res/drawable/ic_launcher_runtime_round.png new file mode 100644 index 00000000..e88dfd01 Binary files /dev/null and b/app/src/main/res/drawable/ic_launcher_runtime_round.png differ diff --git a/app/src/main/res/drawable/ic_launcher_title_game.xml b/app/src/main/res/drawable/ic_launcher_title_game.xml new file mode 100644 index 00000000..4b747bb9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_title_game.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_title_gamedir.xml b/app/src/main/res/drawable/ic_launcher_title_gamedir.xml new file mode 100644 index 00000000..1571b618 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_title_gamedir.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_title_how_to_use.xml b/app/src/main/res/drawable/ic_launcher_title_how_to_use.xml new file mode 100644 index 00000000..1f5cba54 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_title_how_to_use.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_title_runtime.xml b/app/src/main/res/drawable/ic_launcher_title_runtime.xml new file mode 100644 index 00000000..d485532e --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_title_runtime.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_layer_blue.xml b/app/src/main/res/drawable/ic_layer_blue.xml deleted file mode 100644 index 3fa86c68..00000000 --- a/app/src/main/res/drawable/ic_layer_blue.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_link_open.xml b/app/src/main/res/drawable/ic_link_open.xml new file mode 100644 index 00000000..455b503a --- /dev/null +++ b/app/src/main/res/drawable/ic_link_open.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_list_ver.xml b/app/src/main/res/drawable/ic_list_ver.xml new file mode 100644 index 00000000..9884aeb8 --- /dev/null +++ b/app/src/main/res/drawable/ic_list_ver.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_log_outline.xml b/app/src/main/res/drawable/ic_log_outline.xml new file mode 100644 index 00000000..d0e9d8dc --- /dev/null +++ b/app/src/main/res/drawable/ic_log_outline.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_log_send.xml b/app/src/main/res/drawable/ic_log_send.xml new file mode 100644 index 00000000..712adc00 --- /dev/null +++ b/app/src/main/res/drawable/ic_log_send.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable/drop.xml b/app/src/main/res/drawable/ic_login_drop.xml similarity index 85% rename from app/src/main/res/drawable/drop.xml rename to app/src/main/res/drawable/ic_login_drop.xml index ca571fb3..ce583469 100644 --- a/app/src/main/res/drawable/drop.xml +++ b/app/src/main/res/drawable/ic_login_drop.xml @@ -5,6 +5,6 @@ android:viewportHeight="24" android:tint="?attr/colorControlNormal"> diff --git a/app/src/main/res/drawable/ic_logout.xml b/app/src/main/res/drawable/ic_logout.xml new file mode 100644 index 00000000..83cdf05a --- /dev/null +++ b/app/src/main/res/drawable/ic_logout.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_device.xml b/app/src/main/res/drawable/ic_main_device.xml new file mode 100644 index 00000000..89abeb27 --- /dev/null +++ b/app/src/main/res/drawable/ic_main_device.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_go.xml b/app/src/main/res/drawable/ic_main_go.xml new file mode 100644 index 00000000..455b503a --- /dev/null +++ b/app/src/main/res/drawable/ic_main_go.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_help.xml b/app/src/main/res/drawable/ic_main_help.xml new file mode 100644 index 00000000..1f5cba54 --- /dev/null +++ b/app/src/main/res/drawable/ic_main_help.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_log.xml b/app/src/main/res/drawable/ic_main_log.xml new file mode 100644 index 00000000..d7fc3e30 --- /dev/null +++ b/app/src/main/res/drawable/ic_main_log.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_msg_app.xml b/app/src/main/res/drawable/ic_main_msg_app.xml new file mode 100644 index 00000000..c2e63f5b --- /dev/null +++ b/app/src/main/res/drawable/ic_main_msg_app.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_reg.xml b/app/src/main/res/drawable/ic_main_reg.xml new file mode 100644 index 00000000..1cd557e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_main_reg.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_share.xml b/app/src/main/res/drawable/ic_main_share.xml new file mode 100644 index 00000000..3a6a0598 --- /dev/null +++ b/app/src/main/res/drawable/ic_main_share.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_main_star.xml b/app/src/main/res/drawable/ic_main_star.xml new file mode 100644 index 00000000..b6d93cac --- /dev/null +++ b/app/src/main/res/drawable/ic_main_star.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_mc_fabric.png b/app/src/main/res/drawable/ic_mc_fabric.png new file mode 100644 index 00000000..1580e5cc Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_fabric.png differ diff --git a/app/src/main/res/drawable/ic_mc_forge.png b/app/src/main/res/drawable/ic_mc_forge.png new file mode 100644 index 00000000..9dfc6676 Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_forge.png differ diff --git a/app/src/main/res/drawable/ic_mc_liteloader.png b/app/src/main/res/drawable/ic_mc_liteloader.png new file mode 100644 index 00000000..4c842d35 Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_liteloader.png differ diff --git a/app/src/main/res/drawable/ic_mc_modcn.png b/app/src/main/res/drawable/ic_mc_modcn.png new file mode 100644 index 00000000..24a19729 Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_modcn.png differ diff --git a/app/src/main/res/drawable/ic_mc_mods.png b/app/src/main/res/drawable/ic_mc_mods.png new file mode 100644 index 00000000..df389cab Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_mods.png differ diff --git a/app/src/main/res/drawable/ic_mc_optifine.png b/app/src/main/res/drawable/ic_mc_optifine.png new file mode 100644 index 00000000..9b3a4824 Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_optifine.png differ diff --git a/app/src/main/res/drawable/ic_mc_packs.png b/app/src/main/res/drawable/ic_mc_packs.png new file mode 100644 index 00000000..a9aad6e6 Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_packs.png differ diff --git a/app/src/main/res/drawable/ic_mc_vanilla_old.png b/app/src/main/res/drawable/ic_mc_vanilla_old.png new file mode 100644 index 00000000..9dfc1bab Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_vanilla_old.png differ diff --git a/app/src/main/res/drawable/ic_mc_vanilla_release.png b/app/src/main/res/drawable/ic_mc_vanilla_release.png new file mode 100644 index 00000000..001f0bdb Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_vanilla_release.png differ diff --git a/app/src/main/res/drawable/ic_mc_vanilla_snapshot.png b/app/src/main/res/drawable/ic_mc_vanilla_snapshot.png new file mode 100644 index 00000000..2c38a09b Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_vanilla_snapshot.png differ diff --git a/app/src/main/res/drawable/ic_mc_version.png b/app/src/main/res/drawable/ic_mc_version.png new file mode 100644 index 00000000..2a277a4c Binary files /dev/null and b/app/src/main/res/drawable/ic_mc_version.png differ diff --git a/app/src/main/res/drawable/ic_menu_about.xml b/app/src/main/res/drawable/ic_menu_about.xml new file mode 100644 index 00000000..35f7f5f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_about.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_custom.xml b/app/src/main/res/drawable/ic_menu_custom.xml new file mode 100644 index 00000000..374e8f46 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_custom.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_donate.xml b/app/src/main/res/drawable/ic_menu_donate.xml new file mode 100644 index 00000000..f72bf394 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_donate.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_home.xml b/app/src/main/res/drawable/ic_menu_home.xml new file mode 100644 index 00000000..11b964ad --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_home.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_install.xml b/app/src/main/res/drawable/ic_menu_install.xml new file mode 100644 index 00000000..4f66da0f --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_install.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_manager.xml b/app/src/main/res/drawable/ic_menu_manager.xml new file mode 100644 index 00000000..d663aeb3 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_manager.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_settings.xml b/app/src/main/res/drawable/ic_menu_settings.xml new file mode 100644 index 00000000..0bd63eb7 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_settings.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_more_jvm.xml b/app/src/main/res/drawable/ic_more_jvm.xml new file mode 100644 index 00000000..85663cad --- /dev/null +++ b/app/src/main/res/drawable/ic_more_jvm.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_my_device.xml b/app/src/main/res/drawable/ic_my_device.xml new file mode 100644 index 00000000..14dcca15 --- /dev/null +++ b/app/src/main/res/drawable/ic_my_device.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_nav_color.xml b/app/src/main/res/drawable/ic_nav_color.xml new file mode 100644 index 00000000..819d46ba --- /dev/null +++ b/app/src/main/res/drawable/ic_nav_color.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/toolbar_download.xml b/app/src/main/res/drawable/ic_new_add.xml similarity index 80% rename from app/src/main/res/drawable/toolbar_download.xml rename to app/src/main/res/drawable/ic_new_add.xml index 27bb5a3b..eb232541 100644 --- a/app/src/main/res/drawable/toolbar_download.xml +++ b/app/src/main/res/drawable/ic_new_add.xml @@ -6,5 +6,5 @@ android:tint="?attr/colorControlNormal"> + android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> diff --git a/app/src/main/res/drawable/ic_play.xml b/app/src/main/res/drawable/ic_play.xml new file mode 100644 index 00000000..8f5ab9f8 --- /dev/null +++ b/app/src/main/res/drawable/ic_play.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_redo.xml b/app/src/main/res/drawable/ic_redo.xml new file mode 100644 index 00000000..702e70c5 --- /dev/null +++ b/app/src/main/res/drawable/ic_redo.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_refresh.xml b/app/src/main/res/drawable/ic_refresh.xml new file mode 100644 index 00000000..f2be45ba --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_bg_blue.xml b/app/src/main/res/drawable/ic_round_bg_blue.xml new file mode 100644 index 00000000..6b67b04b --- /dev/null +++ b/app/src/main/res/drawable/ic_round_bg_blue.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_round_bg_empty.xml b/app/src/main/res/drawable/ic_round_bg_empty.xml new file mode 100644 index 00000000..734b59d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_bg_empty.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_round_bg_green.xml b/app/src/main/res/drawable/ic_round_bg_green.xml new file mode 100644 index 00000000..fe08cadc --- /dev/null +++ b/app/src/main/res/drawable/ic_round_bg_green.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_round_bg_orange.xml b/app/src/main/res/drawable/ic_round_bg_orange.xml new file mode 100644 index 00000000..ae00bdb8 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_bg_orange.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_save_acc.xml b/app/src/main/res/drawable/ic_save_acc.xml new file mode 100644 index 00000000..1ce58432 --- /dev/null +++ b/app/src/main/res/drawable/ic_save_acc.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_control.xml b/app/src/main/res/drawable/ic_settings_control.xml new file mode 100644 index 00000000..9a4e4b70 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_control.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_control_outline.xml b/app/src/main/res/drawable/ic_settings_control_outline.xml new file mode 100644 index 00000000..6bc97439 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_control_outline.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_jvm_flag.xml b/app/src/main/res/drawable/ic_settings_jvm_flag.xml new file mode 100644 index 00000000..57db07db --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_jvm_flag.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_mouse_mode.xml b/app/src/main/res/drawable/ic_settings_mouse_mode.xml new file mode 100644 index 00000000..a3e754e5 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_mouse_mode.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_themes.xml b/app/src/main/res/drawable/ic_settings_themes.xml new file mode 100644 index 00000000..3cfe5861 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_themes.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_themes_outline.xml b/app/src/main/res/drawable/ic_settings_themes_outline.xml new file mode 100644 index 00000000..a528980b --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_themes_outline.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_settings_user_id.xml b/app/src/main/res/drawable/ic_settings_user_id.xml new file mode 100644 index 00000000..d01f8c8f --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_user_id.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/menu_b_execute.xml b/app/src/main/res/drawable/ic_terminal.xml similarity index 100% rename from app/src/main/res/drawable/menu_b_execute.xml rename to app/src/main/res/drawable/ic_terminal.xml diff --git a/app/src/main/res/drawable/ic_theme_custom.xml b/app/src/main/res/drawable/ic_theme_custom.xml new file mode 100644 index 00000000..78ddce5f --- /dev/null +++ b/app/src/main/res/drawable/ic_theme_custom.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_theme_point.xml b/app/src/main/res/drawable/ic_theme_point.xml new file mode 100644 index 00000000..29ae6f53 --- /dev/null +++ b/app/src/main/res/drawable/ic_theme_point.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_title_logo.xml b/app/src/main/res/drawable/ic_title_logo.xml new file mode 100644 index 00000000..f3a477de --- /dev/null +++ b/app/src/main/res/drawable/ic_title_logo.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_undo.xml b/app/src/main/res/drawable/ic_undo.xml new file mode 100644 index 00000000..bab545a7 --- /dev/null +++ b/app/src/main/res/drawable/ic_undo.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/item_select_bg.xml b/app/src/main/res/drawable/item_select_bg.xml new file mode 100644 index 00000000..1c3715bb --- /dev/null +++ b/app/src/main/res/drawable/item_select_bg.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/java.xml b/app/src/main/res/drawable/java.xml new file mode 100644 index 00000000..bce71118 --- /dev/null +++ b/app/src/main/res/drawable/java.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/launcher_bg.png b/app/src/main/res/drawable/launcher_bg.png new file mode 100644 index 00000000..1f811e7e Binary files /dev/null and b/app/src/main/res/drawable/launcher_bg.png differ diff --git a/app/src/main/res/drawable/list_delete.xml b/app/src/main/res/drawable/list_delete.xml deleted file mode 100644 index 6a0fa1e4..00000000 --- a/app/src/main/res/drawable/list_delete.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/list_disable.xml b/app/src/main/res/drawable/list_disable.xml deleted file mode 100644 index 082024c1..00000000 --- a/app/src/main/res/drawable/list_disable.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/list_edit.xml b/app/src/main/res/drawable/list_edit.xml deleted file mode 100644 index b12122fd..00000000 --- a/app/src/main/res/drawable/list_edit.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/material_design_3.png b/app/src/main/res/drawable/material_design_3.png new file mode 100644 index 00000000..f28612c4 Binary files /dev/null and b/app/src/main/res/drawable/material_design_3.png differ diff --git a/app/src/main/res/drawable/menu_b_execute_blue.xml b/app/src/main/res/drawable/menu_b_execute_blue.xml deleted file mode 100644 index f78b644f..00000000 --- a/app/src/main/res/drawable/menu_b_execute_blue.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/menu_b_keys.xml b/app/src/main/res/drawable/menu_b_keys.xml deleted file mode 100644 index 533fc156..00000000 --- a/app/src/main/res/drawable/menu_b_keys.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/menu_custom.xml b/app/src/main/res/drawable/menu_custom.xml new file mode 100644 index 00000000..374e8f46 --- /dev/null +++ b/app/src/main/res/drawable/menu_custom.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/menu_l_donate.xml b/app/src/main/res/drawable/menu_l_donate.xml deleted file mode 100644 index fecf0313..00000000 --- a/app/src/main/res/drawable/menu_l_donate.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/menu_mc_mods.xml b/app/src/main/res/drawable/menu_mc_mods.xml deleted file mode 100644 index 94055ba4..00000000 --- a/app/src/main/res/drawable/menu_mc_mods.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/menu_mc_textures.xml b/app/src/main/res/drawable/menu_mc_textures.xml deleted file mode 100644 index 4bf15508..00000000 --- a/app/src/main/res/drawable/menu_mc_textures.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/menu_mc_worlds.xml b/app/src/main/res/drawable/menu_mc_worlds.xml deleted file mode 100644 index 0ac168a2..00000000 --- a/app/src/main/res/drawable/menu_mc_worlds.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/nav_bg.xml b/app/src/main/res/drawable/nav_bg.xml new file mode 100644 index 00000000..3dde455a --- /dev/null +++ b/app/src/main/res/drawable/nav_bg.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/nav_select_bg.xml b/app/src/main/res/drawable/nav_select_bg.xml new file mode 100644 index 00000000..8a9faae5 --- /dev/null +++ b/app/src/main/res/drawable/nav_select_bg.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/notice.xml b/app/src/main/res/drawable/notice.xml new file mode 100644 index 00000000..27ebb6f6 --- /dev/null +++ b/app/src/main/res/drawable/notice.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/offline.xml b/app/src/main/res/drawable/offline.xml deleted file mode 100644 index ced48bdb..00000000 --- a/app/src/main/res/drawable/offline.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/offline_blue.xml b/app/src/main/res/drawable/offline_blue.xml index db539489..9536e2d0 100644 --- a/app/src/main/res/drawable/offline_blue.xml +++ b/app/src/main/res/drawable/offline_blue.xml @@ -3,9 +3,9 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorControlNormal"> + android:tint="@color/colorPrimary"> diff --git a/app/src/main/res/drawable/progress.xml b/app/src/main/res/drawable/progress.xml new file mode 100644 index 00000000..5d82b7ae --- /dev/null +++ b/app/src/main/res/drawable/progress.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/pwbg.xml b/app/src/main/res/drawable/pwbg.xml index 831849c5..143ea526 100644 --- a/app/src/main/res/drawable/pwbg.xml +++ b/app/src/main/res/drawable/pwbg.xml @@ -1,8 +1,8 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/radio_bg.xml b/app/src/main/res/drawable/radio_bg.xml new file mode 100644 index 00000000..92e3d569 --- /dev/null +++ b/app/src/main/res/drawable/radio_bg.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/recycler_button.xml b/app/src/main/res/drawable/recycler_button.xml new file mode 100644 index 00000000..c8c53c59 --- /dev/null +++ b/app/src/main/res/drawable/recycler_button.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/recycler_button_normal.xml b/app/src/main/res/drawable/recycler_button_normal.xml new file mode 100644 index 00000000..6072b47a --- /dev/null +++ b/app/src/main/res/drawable/recycler_button_normal.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/drawable/recycler_button_pressed.xml b/app/src/main/res/drawable/recycler_button_pressed.xml new file mode 100644 index 00000000..10d5024e --- /dev/null +++ b/app/src/main/res/drawable/recycler_button_pressed.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/refresh.xml b/app/src/main/res/drawable/refresh.xml new file mode 100644 index 00000000..f2be45ba --- /dev/null +++ b/app/src/main/res/drawable/refresh.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/replay.xml b/app/src/main/res/drawable/replay.xml new file mode 100644 index 00000000..58b063e0 --- /dev/null +++ b/app/src/main/res/drawable/replay.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector.xml b/app/src/main/res/drawable/selector.xml deleted file mode 100644 index c208cf46..00000000 --- a/app/src/main/res/drawable/selector.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml index c1dff26b..6d81870b 100644 --- a/app/src/main/res/drawable/side_nav_bar.xml +++ b/app/src/main/res/drawable/side_nav_bar.xml @@ -1,9 +1,9 @@ + android:shape="rectangle"> + android:centerColor="#009688" + android:endColor="#00695C" + android:startColor="#4DB6AC" + android:type="linear" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/sign_in_background.png b/app/src/main/res/drawable/sign_in_background.png new file mode 100644 index 00000000..e9d0988f Binary files /dev/null and b/app/src/main/res/drawable/sign_in_background.png differ diff --git a/app/src/main/res/drawable/tab_layout_bg.xml b/app/src/main/res/drawable/tab_layout_bg.xml new file mode 100644 index 00000000..f1de94be --- /dev/null +++ b/app/src/main/res/drawable/tab_layout_bg.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_selector.xml b/app/src/main/res/drawable/tab_selector.xml new file mode 100644 index 00000000..3ed05f62 --- /dev/null +++ b/app/src/main/res/drawable/tab_selector.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/timg.png b/app/src/main/res/drawable/timg.png deleted file mode 100644 index e4192aac..00000000 Binary files a/app/src/main/res/drawable/timg.png and /dev/null differ diff --git a/app/src/main/res/drawable/verrt.png b/app/src/main/res/drawable/verrt.png deleted file mode 100644 index cb986e68..00000000 Binary files a/app/src/main/res/drawable/verrt.png and /dev/null differ diff --git a/app/src/main/res/drawable/viihgv.png b/app/src/main/res/drawable/viihgv.png deleted file mode 100644 index 174f06d8..00000000 Binary files a/app/src/main/res/drawable/viihgv.png and /dev/null differ diff --git a/app/src/main/res/drawable/vmnvff.png b/app/src/main/res/drawable/vmnvff.png deleted file mode 100644 index 1443397e..00000000 Binary files a/app/src/main/res/drawable/vmnvff.png and /dev/null differ diff --git a/app/src/main/res/drawable/vnfdr.png b/app/src/main/res/drawable/vnfdr.png deleted file mode 100644 index d3ee62e8..00000000 Binary files a/app/src/main/res/drawable/vnfdr.png and /dev/null differ diff --git a/app/src/main/res/drawable/vpouy.png b/app/src/main/res/drawable/vpouy.png deleted file mode 100644 index 8e3699f5..00000000 Binary files a/app/src/main/res/drawable/vpouy.png and /dev/null differ diff --git a/app/src/main/res/drawable/vpver.png b/app/src/main/res/drawable/vpver.png deleted file mode 100644 index 56d3e250..00000000 Binary files a/app/src/main/res/drawable/vpver.png and /dev/null differ diff --git a/app/src/main/res/drawable/vqw.png b/app/src/main/res/drawable/vqw.png deleted file mode 100644 index 690362be..00000000 Binary files a/app/src/main/res/drawable/vqw.png and /dev/null differ diff --git a/app/src/main/res/drawable/vrty.png b/app/src/main/res/drawable/vrty.png deleted file mode 100644 index c29eda09..00000000 Binary files a/app/src/main/res/drawable/vrty.png and /dev/null differ diff --git a/app/src/main/res/drawable/vrtyj.png b/app/src/main/res/drawable/vrtyj.png deleted file mode 100644 index b7c0ed0d..00000000 Binary files a/app/src/main/res/drawable/vrtyj.png and /dev/null differ diff --git a/app/src/main/res/drawable/vzcgu.png b/app/src/main/res/drawable/vzcgu.png deleted file mode 100644 index 9802045d..00000000 Binary files a/app/src/main/res/drawable/vzcgu.png and /dev/null differ diff --git a/app/src/main/res/drawable/water_background.xml b/app/src/main/res/drawable/water_background.xml new file mode 100644 index 00000000..4f780745 --- /dev/null +++ b/app/src/main/res/drawable/water_background.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/wen.png b/app/src/main/res/drawable/wen.png deleted file mode 100644 index d331d2d4..00000000 Binary files a/app/src/main/res/drawable/wen.png and /dev/null differ diff --git a/app/src/main/res/drawable/white_filling.xml b/app/src/main/res/drawable/white_filling.xml new file mode 100644 index 00000000..2ed1e890 --- /dev/null +++ b/app/src/main/res/drawable/white_filling.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/app/src/main/res/drawable/xicon_red.xml b/app/src/main/res/drawable/xicon_red.xml new file mode 100644 index 00000000..9dca4d7b --- /dev/null +++ b/app/src/main/res/drawable/xicon_red.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/font-v26/google_sans.xml b/app/src/main/res/font-v26/google_sans.xml new file mode 100644 index 00000000..3bcd19c7 --- /dev/null +++ b/app/src/main/res/font-v26/google_sans.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/google_sans.xml b/app/src/main/res/font/google_sans.xml new file mode 100644 index 00000000..3bcd19c7 --- /dev/null +++ b/app/src/main/res/font/google_sans.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/sans.ttf b/app/src/main/res/font/sans.ttf new file mode 100644 index 00000000..54485787 Binary files /dev/null and b/app/src/main/res/font/sans.ttf differ diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml deleted file mode 100644 index 636caadb..00000000 --- a/app/src/main/res/layout/activity_about.xml +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -