Compare commits
73
Commits
b31ab340ab
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d65f30516 | ||
|
|
b17d4a0411 | ||
|
|
a297e76da0 | ||
|
|
eb51ed944a | ||
|
|
d00c97e7d7 | ||
|
|
2be0549b73 | ||
|
|
1169b159e8 | ||
|
|
4d8b9b728b | ||
|
|
10ac465aba | ||
|
|
3784f973ca | ||
|
|
ab2d0af594 | ||
|
|
33d0a930fd | ||
|
|
897992f914 | ||
|
|
98a1fc959e | ||
|
|
53a267424a | ||
|
|
caf5601a71 | ||
|
|
b81e12c61b | ||
|
|
8ba7005c53 | ||
|
|
d2dd6e8cd0 | ||
|
|
0a2cd56c93 | ||
|
|
4b51b9807a | ||
|
|
256a13b7df | ||
|
|
f2311bd7f9 | ||
|
|
ecb6122e7f | ||
|
|
0a77bd69d7 | ||
|
|
87ded0bda5 | ||
|
|
398ba8be0a | ||
|
|
f0cbf1c4fd | ||
|
|
aa9a0a7b24 | ||
|
|
36b18d63fb | ||
|
|
d6f550d4fe | ||
|
|
1b2c1f593b | ||
|
|
94000c4b67 | ||
|
|
edca12a137 | ||
|
|
3f2a92b880 | ||
|
|
8cd2ffc16d | ||
|
|
8fff21a6d8 | ||
|
|
0e72b9d3bc | ||
|
|
bad03a7116 | ||
|
|
440f136e50 | ||
|
|
ed1371c84e | ||
|
|
a7dfa35e10 | ||
|
|
74902ecb73 | ||
|
|
45552eacf8 | ||
|
|
a190454e00 | ||
|
|
8dd264dee0 | ||
|
|
d7f9c251a6 | ||
|
|
96b26b8c37 | ||
|
|
f53ac1b089 | ||
|
|
edf88cdc4f | ||
|
|
2599d6459e | ||
|
|
8c826272ae | ||
|
|
0ffc476b25 | ||
|
|
e75aa2eaa9 | ||
|
|
f914c7694f | ||
|
|
dd92a39f16 | ||
|
|
58b981f426 | ||
|
|
46e9865005 | ||
|
|
51d6a9b5b5 | ||
|
|
0eaeb0cb30 | ||
|
|
fe210b1f7d | ||
|
|
007be81744 | ||
|
|
6f3ac6d086 | ||
|
|
002c9a9e2d | ||
|
|
3561137c6b | ||
|
|
6e34a6cad6 | ||
|
|
e872fe4e8a | ||
|
|
9349d32c7c | ||
|
|
248e0ada31 | ||
|
|
798c6ce27f | ||
|
|
f3111e84f9 | ||
|
|
b298c6d86f | ||
|
|
809b2b4279 |
@@ -1,674 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
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.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
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
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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
|
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
<div align='center'>
|
|
||||||
<img src='fastlane/metadata/android/en-US/images/icon.png' alt='Lunar Launcher' width='100' height='100'>
|
|
||||||
<h2>Lunar Launcher</h2>
|
|
||||||
<p>
|
|
||||||
<img src='https://img.shields.io/badge/Android-3DDC84?style=flat-square&logo=android&logoColor=white'>
|
|
||||||
<img src='https://img.shields.io/badge/SDK-26-vibrant?style=flat-square'>
|
|
||||||
<a href='https://github.com/iamrasel/lunar-launcher/blob/main/LICENSE'><img src='https://img.shields.io/badge/License-GPL%20v3-blue?style=flat-square'></a>
|
|
||||||
<br>
|
|
||||||
<a href='https://hosted.weblate.org/engage/lunar-launcher/'><img src='https://img.shields.io/weblate/progress/lunar-launcher?style=flat-square&label=Translated&color=4DCCAA' alt='Oversettelsesstatus' /></a>
|
|
||||||
<a href='https://github.com/iamrasel/lunar-launcher/actions'><img src='https://img.shields.io/github/actions/workflow/status/iamrasel/lunar-launcher/ci_push.yml?branch=main&style=flat-square&label=Build'></a>
|
|
||||||
<a href='https://github.com/iamrasel/lunar-launcher/releases/latest'><img src='https://img.shields.io/github/downloads/iamrasel/lunar-launcher/total?style=flat-square&label=Downloads'></a>
|
|
||||||
</p>
|
|
||||||
<a href="https://www.buymeacoffee.com/iamrasel"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=iamrasel&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" /></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Features
|
|
||||||
<details><summary>Global</summary>
|
|
||||||
|
|
||||||
- [x] Appearances
|
|
||||||
- [x] Material Design 3
|
|
||||||
- [x] Material You
|
|
||||||
- [x] Day/night theme
|
|
||||||
- [x] Wallpaper with color filter support
|
|
||||||
- [x] Double tap: lock/sleep
|
|
||||||
- [x] Accessibility (SDK >= 28)
|
|
||||||
- [x] Device admin
|
|
||||||
- [x] Root
|
|
||||||
- [x] Swipe down: expand notification panel
|
|
||||||
- [ ] Yet to decide
|
|
||||||
|
|
||||||
</details>
|
|
||||||
<details><summary>Home</summary>
|
|
||||||
|
|
||||||
- [x] Battery status
|
|
||||||
- [x] Circular percentage indicator
|
|
||||||
- [x] Animation while charging
|
|
||||||
- [x] Time
|
|
||||||
- [x] 12/24 format
|
|
||||||
- [x] Date
|
|
||||||
- [x] Weather
|
|
||||||
- [x] Provider: OpenWeatherMap
|
|
||||||
- [x] Celsius/Fahrenheit
|
|
||||||
- [x] Todo
|
|
||||||
- [x] Add, delete, edit, copy
|
|
||||||
- [ ] Auto destructive todo with notify
|
|
||||||
- [x] 0–7 items in home screen
|
|
||||||
- [x] Access lock
|
|
||||||
|
|
||||||
</details>
|
|
||||||
<details><summary>App Drawer</summary>
|
|
||||||
|
|
||||||
- [x] Quick search
|
|
||||||
- [x] Launch from search
|
|
||||||
- [x] Launch in freeform mode
|
|
||||||
- [x] Total apps count
|
|
||||||
- [ ] Gesture search
|
|
||||||
- [ ] App grid with icon (alternative)
|
|
||||||
- [ ] App appearance
|
|
||||||
- [ ] App renaming
|
|
||||||
- [ ] App vault
|
|
||||||
- [x] Detailed app info
|
|
||||||
|
|
||||||
</details>
|
|
||||||
<details><summary>Feeds</summary>
|
|
||||||
|
|
||||||
- [x] Device stats
|
|
||||||
- [x] News feed
|
|
||||||
- [x] RSS
|
|
||||||
- [ ] Atom
|
|
||||||
- [x] Widget host
|
|
||||||
|
|
||||||
</details>
|
|
||||||
<details><summary>Quick Access</summary>
|
|
||||||
|
|
||||||
- [x] Favourite apps (<=6)
|
|
||||||
- [x] Favourite contacts and URLs (<=6)
|
|
||||||
- [x] Control system value
|
|
||||||
- [x] Brightness
|
|
||||||
- [x] Sound
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
As per version 14, click on any image to enlarge it. \
|
|
||||||
To know more, explore and see for yourself.
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/1.png' width='120'></td>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/2.png' width='120'></td>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/3.png' width='120'></td>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/4.png' width='120'></td>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/5.png' width='120'></td>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/6.png' width='120'></td>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/7.png' width='120'></td>
|
|
||||||
<td><img src='fastlane/metadata/android/en-US/images/phoneScreenshots/8.png' width='120'></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
To get updated with the latest build, head over to the [Actions](https://github.com/iamrasel/lunar-launcher/actions) tab and choose the latest workflow build from there.
|
|
||||||
<div align='center'>
|
|
||||||
|
|
||||||
<a href='https://github.com/iamrasel/lunar-launcher/releases/latest'><img src='https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white'></a>
|
|
||||||
<a href='https://f-droid.org/packages/rasel.lunar.launcher'><img src='https://img.shields.io/badge/F_Droid-1976d2?style=for-the-badge&logo=f-droid&logoColor=white'></a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
This app is also available on Google's Play Store, which is forked and published by [Vedansh Nigam](https://github.com/vednig). \
|
|
||||||
If you don't have any issue with installing apps from Play Store, you can go ahead.
|
|
||||||
<div align='center'>
|
|
||||||
|
|
||||||
<a href='https://play.google.com/store/apps/details?id=rasel.lunar.launcher'><img src='https://img.shields.io/badge/Play_Store-34A853?style=for-the-badge&logo=google-play&logoColor=white'></a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Permissions
|
|
||||||
- `android.permission.ACCESS_NETWORK_STATE` — Check for active network connections
|
|
||||||
- `android.permission.CALL_PHONE` — Place calls
|
|
||||||
- `android.permission.EXPAND_STATUS_BAR` — Expand the notification panel
|
|
||||||
- `android.permission.INTERNET` — Fetch weather and feed data
|
|
||||||
- `android.permission.READ_EXTERNAL_STORAGE` — Fetch images to set as wallpaper (SDK < 33)
|
|
||||||
- `android.permission.READ_MEDIA_IMAGES` — Fetch images to set as wallpaper (SDK 33+)
|
|
||||||
- `android.permission.REQUEST_DELETE_PACKAGES` — Uninstall APKs
|
|
||||||
- `android.permission.SET_WALLPAPER` — Set the wallpaper
|
|
||||||
- `android.permission.WRITE_SETTINGS` — Change system values like brightness
|
|
||||||
|
|
||||||
## Community
|
|
||||||
If you want to share your thoughts with me or other users, join the Lunar Launcher's users community.
|
|
||||||
<div align='center'>
|
|
||||||
|
|
||||||
<a href='https://github.com/iamrasel/lunar-launcher/discussions'><img src='https://img.shields.io/badge/Discussions-333333?style=for-the-badge&logo=github'></a>
|
|
||||||
<a href='https://t.me/LunarLauncher_chats'><img src='https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white'></a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Translations
|
|
||||||
Help [translate the app on Hosted Weblate](https://hosted.weblate.org/engage/lunar-launcher). \
|
|
||||||
<a href='https://hosted.weblate.org/engage/lunar-launcher/'>
|
|
||||||
<img src='https://hosted.weblate.org/widgets/lunar-launcher/-/multi-blue.svg' alt='Translation status' />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
- [https://github.com/cachapa/ExpandableLayout](https://github.com/cachapa/ExpandableLayout)
|
|
||||||
|
|
||||||
## Donation
|
|
||||||
Please support the development by donating. Lunar Launcher is gratis, copylefted libre app, \
|
|
||||||
it needs your support to keep it gratis and alive. \
|
|
||||||
Purchasing is not a requirement, donations are. 😊
|
|
||||||
|
|
||||||
<div align='center'>
|
|
||||||
|
|
||||||
|  | [iamrasel](https://www.buymeacoffee.com/iamrasel) |
|
|
||||||
|:---------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------:|
|
|
||||||
|  | `bc1qaps45fcd9uhqgr5w2k8cxphs07ht5a7ne9af7z` |
|
|
||||||
|  | `0x651Fc30Ad9293593aC571A0594Fb53417F76f896` |
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
There is also another way to support, just go through this [Amazon affiliate link](https://amzn.to/44krAw9) while shopping there. \
|
|
||||||
It doesn't cost you anything extra, which is a win-win for the both of us. 😉
|
|
||||||
+40
-10
@@ -1,4 +1,5 @@
|
|||||||
import org.jetbrains.kotlin.fir.scopes.debugCollectOverrides
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id ("com.android.application")
|
id ("com.android.application")
|
||||||
@@ -7,15 +8,16 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "rasel.lunar.launcher"
|
namespace = "bums.lunatic.launcher"
|
||||||
compileSdk = 34
|
compileSdk = 35
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "rasel.lunar.launcher"
|
applicationId = "bums.lunatic.launcher"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 38
|
versionCode = 38
|
||||||
versionName = "2.8.2"
|
versionName = "2.8.2"
|
||||||
|
multiDexEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -23,14 +25,16 @@ android {
|
|||||||
isMinifyEnabled = false
|
isMinifyEnabled = false
|
||||||
isShrinkResources = false
|
isShrinkResources = false
|
||||||
isDebuggable = true
|
isDebuggable = true
|
||||||
applicationIdSuffix = ".debug"
|
// applicationIdSuffix = ".debug"
|
||||||
versionNameSuffix = "-debug"
|
// versionNameSuffix = "-debug"
|
||||||
|
buildConfigField("Long","BuildDateTime", getDateTime().toString().plus("L"))
|
||||||
resValue ("string", "app_name", "Bums Launcher Debug")
|
resValue ("string", "app_name", "Bums Launcher Debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
getByName("release") {
|
getByName("release") {
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
isShrinkResources = true
|
isShrinkResources = true
|
||||||
|
buildConfigField("Long","BuildDateTime", getDateTime().toString().plus("L"))
|
||||||
proguardFiles (getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
proguardFiles (getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||||
resValue ("string", "app_name", "Bums Launcher")
|
resValue ("string", "app_name", "Bums Launcher")
|
||||||
}
|
}
|
||||||
@@ -60,12 +64,18 @@ android {
|
|||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
|
dataBinding = true
|
||||||
|
buildConfig = true
|
||||||
|
resValues = true
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
packagingOptions.resources.excludes.add("META-INF/*")
|
||||||
|
packagingOptions.resources.excludes.add("mozilla/*")
|
||||||
|
packagingOptions.resources.excludes.add("META-INF/*/*")
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
@@ -77,21 +87,41 @@ dependencies {
|
|||||||
implementation ("androidx.appcompat:appcompat:1.7.0")
|
implementation ("androidx.appcompat:appcompat:1.7.0")
|
||||||
implementation ("androidx.biometric:biometric-ktx:1.2.0-alpha05")
|
implementation ("androidx.biometric:biometric-ktx:1.2.0-alpha05")
|
||||||
implementation ("androidx.browser:browser:1.8.0")
|
implementation ("androidx.browser:browser:1.8.0")
|
||||||
implementation ("androidx.core:core-ktx:1.13.1")
|
implementation ("androidx.core:core-ktx:1.15.0")
|
||||||
implementation ("androidx.core:core-splashscreen:1.0.1")
|
implementation ("androidx.core:core-splashscreen:1.0.1")
|
||||||
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
|
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
|
||||||
implementation ("com.google.android.material:material:1.12.0")
|
implementation ("com.google.android.material:material:1.12.0")
|
||||||
|
implementation ("com.ibm.icu:icu4j:68.1")
|
||||||
implementation (kotlin("stdlib", version = kotlinVersion))
|
implementation (kotlin("stdlib", version = kotlinVersion))
|
||||||
implementation ("com.github.cachapa:ExpandableLayout:2.9.2")
|
implementation ("com.github.cachapa:ExpandableLayout:2.9.2")
|
||||||
implementation ("com.squareup.picasso:picasso:2.71828")
|
implementation ("com.squareup.picasso:picasso:2.71828")
|
||||||
implementation ("androidx.work:work-runtime:2.9.1")
|
implementation ("androidx.work:work-runtime:2.10.0")
|
||||||
implementation ("com.google.code.gson:gson:2.11.0")
|
implementation ("com.google.code.gson:gson:2.11.0")
|
||||||
implementation ("io.realm.kotlin:library-base:2.1.0")
|
implementation ("io.realm.kotlin:library-base:2.1.0")
|
||||||
implementation ("org.jsoup:jsoup:1.18.1")
|
implementation ("org.jsoup:jsoup:1.18.1")
|
||||||
implementation ("org.apache.commons:commons-text:1.12.0")
|
implementation ("org.apache.commons:commons-text:1.12.0")
|
||||||
implementation("com.squareup.okhttp:okhttp:2.7.5")
|
implementation("com.squareup.okhttp:okhttp:2.7.5")
|
||||||
implementation("com.google.android.gms:play-services-location:21.0.1")
|
implementation("com.google.android.gms:play-services-location:21.3.0")
|
||||||
implementation("com.google.android.gms:play-services-tasks:18.2.0")
|
implementation("com.google.android.gms:play-services-tasks:18.2.0")
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
|
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||||
|
implementation("com.squareup.retrofit2:converter-scalars:2.6.4")
|
||||||
|
implementation("androidx.viewpager2:viewpager2:1.1.0")
|
||||||
|
implementation("com.squareup.picasso:picasso:2.71828")
|
||||||
|
implementation("com.github.delight-im:Android-AdvancedWebView:v3.2.1")
|
||||||
|
implementation(project(":library"))
|
||||||
|
implementation(project(":utils"))
|
||||||
|
// implementation ("org.apache.tika:tika-parsers:1.12")
|
||||||
|
|
||||||
|
|
||||||
|
// implementation("org.opencv:opencv-android:4.11.0")
|
||||||
|
|
||||||
|
|
||||||
|
implementation ("androidx.media:media:1.7.0")
|
||||||
|
// implementation(project(":sdk"))
|
||||||
|
// implementation ("me.everything:providers-android:1.0.1")
|
||||||
|
// implementation ("me.everything:providers-core:1.0.1")
|
||||||
// implementation ("androidx.window:window:1.0.0")
|
// implementation ("androidx.window:window:1.0.0")
|
||||||
// implementation("io.github.vaneproject:hanguleditor:1.0.0")
|
// implementation("io.github.vaneproject:hanguleditor:1.0.0")
|
||||||
}
|
}
|
||||||
|
fun getDateTime() = SimpleDateFormat("yyyyMMddHHmm").format(Date()).toLong()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||||
<uses-permission android:name="android.permission.CALL_PHONE" />
|
<uses-permission android:name="android.permission.CALL_PHONE" />
|
||||||
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
|
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
@@ -24,12 +25,15 @@
|
|||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_MMS" />
|
<uses-permission android:name="android.permission.RECEIVE_MMS" />
|
||||||
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
||||||
<!-- Always include this permission -->
|
<!-- Always include this permission -->
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
<!-- Include only if your app benefits from precise location access. -->
|
<!-- Include only if your app benefits from precise location access. -->
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
|
||||||
@@ -48,7 +52,8 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||||
tools:ignore="ScopedStorage" />
|
tools:ignore="ScopedStorage" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@@ -56,9 +61,9 @@
|
|||||||
</queries>
|
</queries>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".LunarLauncher"
|
android:name=".LunaticLauncher"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher"
|
android:roundIcon="@drawable/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.LunarLauncher"
|
android:theme="@style/Theme.LunarLauncher"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
@@ -82,6 +87,11 @@
|
|||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="*/*"/>
|
||||||
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
@@ -89,7 +99,31 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".apps.AppDrawer"
|
||||||
|
android:label="@string/lunar_settings"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<!-- <activity-->
|
||||||
|
<!-- android:name=".PhotoFilter"-->
|
||||||
|
<!-- android:label="@string/lunar_settings"-->
|
||||||
|
<!-- android:exported="true">-->
|
||||||
|
<!-- </activity>-->
|
||||||
|
<activity
|
||||||
|
android:name=".feeds.Feeds"
|
||||||
|
android:label="@string/lunar_settings"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".settings.SettingsActivity"
|
android:name=".settings.SettingsActivity"
|
||||||
android:label="@string/lunar_settings"
|
android:label="@string/lunar_settings"
|
||||||
@@ -100,6 +134,33 @@
|
|||||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".behavior.Behavior"
|
||||||
|
android:label="@string/lunar_settings"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<receiver android:name=".helpers.HeadsetActionButtonReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true" >
|
||||||
|
<intent-filter
|
||||||
|
android:priority="2147483647">
|
||||||
|
<action android:name="android.intent.action.MEDIA_BUTTON"/>
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<!-- <service android:name=".MediaButtonService"-->
|
||||||
|
<!-- android:exported="true">-->
|
||||||
|
<!-- <intent-filter>-->
|
||||||
|
<!-- <action android:name="android.intent.action.MEDIA_BUTTON" />-->
|
||||||
|
<!-- <action android:name="android.media.browse.MediaBrowserService" />-->
|
||||||
|
<!-- </intent-filter>-->
|
||||||
|
<!-- </service>-->
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".feeds.rss.RssService"
|
android:name=".feeds.rss.RssService"
|
||||||
@@ -132,9 +193,30 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".home.RssViewerActivity"
|
||||||
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:exported="true"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:theme="@style/FinestWebViewTheme.Fullscreen" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:scheme="file"/>
|
||||||
|
<data android:scheme="content"/>
|
||||||
|
<data android:mimeType="text/html"/>
|
||||||
|
<data android:mimeType="text/plain"/>
|
||||||
|
<data android:mimeType="text/xml"/>
|
||||||
|
<data android:mimeType="application/xhtml+xml"/>
|
||||||
|
<data android:mimeType="application/vnd.wap.xhtml+xml"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="bums.lunatic.launcher.fileprovider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
@@ -151,6 +233,8 @@
|
|||||||
<action android:name="android.service.notification.NotificationListenerService" />
|
<action android:name="android.service.notification.NotificationListenerService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
<service android:name="bums.lunatic.launcher.workers.LocationUpdateService" />
|
||||||
|
|
||||||
<receiver android:name=".LauncherActivity$EndCallReceiver"
|
<receiver android:name=".LauncherActivity$EndCallReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|||||||
@@ -1,168 +1,168 @@
|
|||||||
package android.print;
|
//package android.print;
|
||||||
|
//
|
||||||
import android.app.Activity;
|
//import android.app.Activity;
|
||||||
import android.content.Context;
|
//import android.content.Context;
|
||||||
import android.os.Bundle;
|
//import android.os.Bundle;
|
||||||
import android.os.CancellationSignal;
|
//import android.os.CancellationSignal;
|
||||||
import android.os.ParcelFileDescriptor;
|
//import android.os.ParcelFileDescriptor;
|
||||||
import android.webkit.WebView;
|
//import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
//import android.webkit.WebViewClient;
|
||||||
|
//
|
||||||
import java.io.File;
|
//import java.io.File;
|
||||||
import java.io.FileInputStream;
|
//import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
//import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
//import java.io.IOException;
|
||||||
import java.io.InputStream;
|
//import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
//import java.io.OutputStream;
|
||||||
|
//
|
||||||
public class PDFPrint {
|
//public class PDFPrint {
|
||||||
|
//
|
||||||
public static void generatePDFFromHTML(final Context context, final File file, final String htmlString, final OnPDFPrintListener onPDFPrintListener) {
|
// public static void generatePDFFromHTML(final Context context, final File file, final String htmlString, final OnPDFPrintListener onPDFPrintListener) {
|
||||||
final WebView mWebView = new WebView(context);
|
// final WebView mWebView = new WebView(context);
|
||||||
mWebView.setWebViewClient(new WebViewClient() {
|
// mWebView.setWebViewClient(new WebViewClient() {
|
||||||
@Override
|
// @Override
|
||||||
public void onPageFinished(WebView view, String url) {
|
// public void onPageFinished(WebView view, String url) {
|
||||||
PrintAttributes printAttributes = new PrintAttributes.Builder()
|
// PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||||
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
// .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||||
.setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
// .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||||
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
// .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||||
.build();
|
// .build();
|
||||||
|
//
|
||||||
final PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(file.getName());
|
// final PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(file.getName());
|
||||||
documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
// documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||||
@Override
|
// @Override
|
||||||
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
// public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||||
documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
// documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onWriteCancelled() {
|
// public void onWriteCancelled() {
|
||||||
super.onWriteCancelled();
|
// super.onWriteCancelled();
|
||||||
onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
// onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onWriteFailed(CharSequence error) {
|
// public void onWriteFailed(CharSequence error) {
|
||||||
super.onWriteFailed(error);
|
// super.onWriteFailed(error);
|
||||||
onPDFPrintListener.onError(new Exception(error.toString()));
|
// onPDFPrintListener.onError(new Exception(error.toString()));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onWriteFinished(PageRange[] pages) {
|
// public void onWriteFinished(PageRange[] pages) {
|
||||||
super.onWriteFinished(pages);
|
// super.onWriteFinished(pages);
|
||||||
onPDFPrintListener.onSuccess(file);
|
// onPDFPrintListener.onSuccess(file);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}, null);
|
// }, null);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
mWebView.loadData(htmlString.replaceAll("#", "%23"), "text/HTML", "UTF-8");
|
// mWebView.loadData(htmlString.replaceAll("#", "%23"), "text/HTML", "UTF-8");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
|
// public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
|
||||||
PrintAttributes printAttributes = new PrintAttributes.Builder()
|
// PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||||
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
// .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||||
.setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
// .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||||
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
// .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||||
.build();
|
// .build();
|
||||||
|
//
|
||||||
final PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter(file.getName());
|
// final PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter(file.getName());
|
||||||
documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
// documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||||
@Override
|
// @Override
|
||||||
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
// public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||||
documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
// documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onWriteCancelled() {
|
// public void onWriteCancelled() {
|
||||||
super.onWriteCancelled();
|
// super.onWriteCancelled();
|
||||||
onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
// onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onWriteFailed(CharSequence error) {
|
// public void onWriteFailed(CharSequence error) {
|
||||||
super.onWriteFailed(error);
|
// super.onWriteFailed(error);
|
||||||
try {
|
// try {
|
||||||
if (error != null && error.toString().length() > 0) {
|
// if (error != null && error.toString().length() > 0) {
|
||||||
onPDFPrintListener.onError(new Exception(error.toString()));
|
// onPDFPrintListener.onError(new Exception(error.toString()));
|
||||||
} else {
|
// } else {
|
||||||
onPDFPrintListener.onError(new Exception("Empty Page"));
|
// onPDFPrintListener.onError(new Exception("Empty Page"));
|
||||||
}
|
// }
|
||||||
}catch (Exception e) {e.printStackTrace();}
|
// }catch (Exception e) {e.printStackTrace();}
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onWriteFinished(PageRange[] pages) {
|
// public void onWriteFinished(PageRange[] pages) {
|
||||||
super.onWriteFinished(pages);
|
// super.onWriteFinished(pages);
|
||||||
onPDFPrintListener.onSuccess(file);
|
// onPDFPrintListener.onSuccess(file);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}, null);
|
// }, null);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static ParcelFileDescriptor getOutputFile(File file) {
|
// private static ParcelFileDescriptor getOutputFile(File file) {
|
||||||
try {
|
// try {
|
||||||
if (!file.exists()) {
|
// if (!file.exists()) {
|
||||||
file.createNewFile();
|
// file.createNewFile();
|
||||||
}
|
// }
|
||||||
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
|
// return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
e.printStackTrace();
|
// e.printStackTrace();
|
||||||
}
|
// }
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static PrintJob printPDF(final Activity activity, final File pdfFileToPrint, final PrintAttributes printAttributes) {
|
// public static PrintJob printPDF(final Activity activity, final File pdfFileToPrint, final PrintAttributes printAttributes) {
|
||||||
PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
|
// PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
|
||||||
String jobName = Long.valueOf(System.currentTimeMillis()).toString();
|
// String jobName = Long.valueOf(System.currentTimeMillis()).toString();
|
||||||
return printManager.print(jobName, new PrintDocumentAdapter() {
|
// return printManager.print(jobName, new PrintDocumentAdapter() {
|
||||||
@Override
|
// @Override
|
||||||
public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
// public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
||||||
InputStream input = null;
|
// InputStream input = null;
|
||||||
OutputStream output = null;
|
// OutputStream output = null;
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
|
//
|
||||||
input = new FileInputStream(pdfFileToPrint);
|
// input = new FileInputStream(pdfFileToPrint);
|
||||||
output = new FileOutputStream(destination.getFileDescriptor());
|
// output = new FileOutputStream(destination.getFileDescriptor());
|
||||||
|
//
|
||||||
byte[] buf = new byte[1024];
|
// byte[] buf = new byte[1024];
|
||||||
int bytesRead;
|
// int bytesRead;
|
||||||
|
//
|
||||||
while ((bytesRead = input.read(buf)) > 0) {
|
// while ((bytesRead = input.read(buf)) > 0) {
|
||||||
output.write(buf, 0, bytesRead);
|
// output.write(buf, 0, bytesRead);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
|
// callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
|
||||||
|
//
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
e.printStackTrace();
|
// e.printStackTrace();
|
||||||
} finally {
|
// } finally {
|
||||||
try {
|
// try {
|
||||||
input.close();
|
// input.close();
|
||||||
output.close();
|
// output.close();
|
||||||
} catch (IOException e) {
|
// } catch (IOException e) {
|
||||||
e.printStackTrace();
|
// e.printStackTrace();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
|
// public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
|
||||||
if (cancellationSignal.isCanceled()) {
|
// if (cancellationSignal.isCanceled()) {
|
||||||
callback.onLayoutCancelled();
|
// callback.onLayoutCancelled();
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(pdfFileToPrint.getName()).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
|
// PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(pdfFileToPrint.getName()).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
|
||||||
callback.onLayoutFinished(pdi, true);
|
// callback.onLayoutFinished(pdi, true);
|
||||||
}
|
// }
|
||||||
}, printAttributes);
|
// }, printAttributes);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public interface OnPDFPrintListener {
|
// public interface OnPDFPrintListener {
|
||||||
void onSuccess(File file);
|
// void onSuccess(File file);
|
||||||
|
//
|
||||||
void onError(Exception exception);
|
// void onError(Exception exception);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
File diff suppressed because it is too large
Load Diff
+13
-4
@@ -16,17 +16,26 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher
|
package bums.lunatic.launcher
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.ComponentCallbacks2
|
import android.content.ComponentCallbacks2
|
||||||
|
import android.content.Context
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
|
import kr.lunaticbum.Base
|
||||||
|
|
||||||
|
|
||||||
internal class LunarLauncher : Application() {
|
internal class LunaticLauncher : Application() {
|
||||||
|
companion object {
|
||||||
|
var appContext : Context? = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
// Picasso.get().setIndicatorsEnabled(true)
|
appContext = this
|
||||||
|
Base.initialize(this)
|
||||||
|
PrefHelper.initialize(this)
|
||||||
}
|
}
|
||||||
override fun onTrimMemory(level: Int) {
|
override fun onTrimMemory(level: Int) {
|
||||||
super.onTrimMemory(level)
|
super.onTrimMemory(level)
|
||||||
@@ -34,4 +43,4 @@ internal class LunarLauncher : Application() {
|
|||||||
if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) SQLiteDatabase.releaseMemory()
|
if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) SQLiteDatabase.releaseMemory()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
//package bums.lunatic.launcher
|
||||||
|
//
|
||||||
|
//import bums.lunatic.launcher.common.CommonActivity
|
||||||
|
//import android.Manifest
|
||||||
|
//import android.app.Activity
|
||||||
|
//import android.content.Intent
|
||||||
|
//import android.content.pm.PackageManager
|
||||||
|
//import android.graphics.Bitmap
|
||||||
|
//import android.net.Uri
|
||||||
|
//import android.os.Build
|
||||||
|
//import android.os.Bundle
|
||||||
|
//import android.provider.MediaStore
|
||||||
|
//import android.widget.Button
|
||||||
|
//import android.widget.ImageView
|
||||||
|
//import androidx.activity.result.ActivityResultLauncher
|
||||||
|
//import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
//import androidx.annotation.RequiresApi
|
||||||
|
//import androidx.appcompat.app.AppCompatActivity
|
||||||
|
//import androidx.core.app.ActivityCompat
|
||||||
|
//import androidx.core.content.ContextCompat
|
||||||
|
//import bums.lunatic.launcher.utils.Blog
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//class PhotoFilter : CommonActivity() {
|
||||||
|
//// private lateinit var originalImageView: ImageView
|
||||||
|
//// private lateinit var filteredImageView: ImageView
|
||||||
|
//// private lateinit var selectImageButton: Button
|
||||||
|
//// private val PICK_IMAGE_REQUEST = 1
|
||||||
|
//// private val PERMISSION_REQUEST_CODE = 200
|
||||||
|
////
|
||||||
|
//// init {
|
||||||
|
////
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
//// super.onCreate(savedInstanceState)
|
||||||
|
//// setContentView(R.layout.photo_filter)
|
||||||
|
////
|
||||||
|
//// originalImageView = findViewById(R.id.originalImageView)
|
||||||
|
//// filteredImageView = findViewById(R.id.filteredImageView)
|
||||||
|
//// selectImageButton = findViewById(R.id.selectImageButton)
|
||||||
|
////
|
||||||
|
//// selectImageButton.setOnClickListener {
|
||||||
|
//// Blog.LOGE("imagePickerLauncher checkPermission() ${checkPermission()}")
|
||||||
|
//// if (checkPermission()) {
|
||||||
|
//// openGallery()
|
||||||
|
//// } else {
|
||||||
|
//// requestPermission()
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// imagePickerLauncher = registerForActivityResult(
|
||||||
|
//// ActivityResultContracts.GetContent(),
|
||||||
|
//// {result ->
|
||||||
|
//// Blog.LOGE("imagePickerLauncher result ${result}")
|
||||||
|
//// if (result != null) {
|
||||||
|
//// // Handle the selected image
|
||||||
|
//// FilePathUri = result;
|
||||||
|
//// try {
|
||||||
|
//// var bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), FilePathUri)
|
||||||
|
//// Blog.LOGE("imagePickerLauncher result ${result} 2")
|
||||||
|
//// originalImageView.setImageBitmap(bitmap)
|
||||||
|
//// Blog.LOGE("imagePickerLauncher result ${result} 3")
|
||||||
|
//// val filteredBitmap = applyCartoonFilter(bitmap)
|
||||||
|
//// Blog.LOGE("imagePickerLauncher result ${result} 4")
|
||||||
|
//// filteredImageView.setImageBitmap(filteredBitmap)
|
||||||
|
//// } catch (e : Exception ) {
|
||||||
|
//// e.printStackTrace();
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// );
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// var FilePathUri : Uri? = null
|
||||||
|
////
|
||||||
|
//// private var imagePickerLauncher : ActivityResultLauncher<String>? = null
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// private fun openGallery() {
|
||||||
|
////// val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
|
||||||
|
////// startActivityForResult(intent, PICK_IMAGE_REQUEST)
|
||||||
|
////
|
||||||
|
//// imagePickerLauncher?.launch("image/*");
|
||||||
|
//// Blog.LOGE("imagePickerLauncher ")
|
||||||
|
////
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// @RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
//// private fun checkPermission(): Boolean {
|
||||||
|
//// return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// @RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
//// private fun requestPermission() {
|
||||||
|
//// ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_MEDIA_IMAGES), PERMISSION_REQUEST_CODE)
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
|
//// super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
//// if (requestCode == PERMISSION_REQUEST_CODE) {
|
||||||
|
//// if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
//// openGallery()
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//}
|
||||||
@@ -0,0 +1,507 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import bums.lunatic.launcher.BuildConfig
|
||||||
|
import bums.lunatic.launcher.LauncherActivity
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.common.CommonActivity
|
||||||
|
import bums.lunatic.launcher.common.letTrue
|
||||||
|
import bums.lunatic.launcher.databinding.AppDrawerBinding
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_APPS_COUNT
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_APPS_LAYOUT
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_APP_NAMES
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefLong
|
||||||
|
import bums.lunatic.launcher.helpers.PrefString
|
||||||
|
import bums.lunatic.launcher.model.AppInfo
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
import io.realm.kotlin.query.RealmResults
|
||||||
|
import io.realm.kotlin.query.Sort
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.text.Normalizer
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
|
||||||
|
internal class AppDrawer : CommonActivity() {
|
||||||
|
|
||||||
|
private lateinit var binding: AppDrawerBinding
|
||||||
|
private var layoutType: Int = 0
|
||||||
|
// private var isSearchShown: Boolean = false
|
||||||
|
private var isKeyboardShowing: Boolean = false
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private var appsAdapter: AppsAdapter? = null
|
||||||
|
private var contactAdapter : ContactAdapter? = null
|
||||||
|
private var packageList = mutableListOf<AppInfo>()
|
||||||
|
@JvmStatic var settingsPrefs: SharedPreferences? = null
|
||||||
|
@JvmStatic var appNamesPrefs: SharedPreferences? = null
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
fun getInputText() = binding.searchInput.text.toString()
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
// setStyle(STYLE_NO_TITLE, R.style.FilterFullScreenDialog)
|
||||||
|
// packageManager
|
||||||
|
// }
|
||||||
|
|
||||||
|
// override fun onAttach(context: Context) {
|
||||||
|
// super.onAttach(context)
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
|
||||||
|
binding = AppDrawerBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
settingsPrefs = this.getSharedPreferences(PREFS_SETTINGS, 0)
|
||||||
|
appNamesPrefs = this.getSharedPreferences(PREFS_APP_NAMES, 0)
|
||||||
|
layoutType = settingsPrefs!!.getInt(KEY_APPS_LAYOUT, 0)
|
||||||
|
|
||||||
|
appsAdapter = AppsAdapter(packageManager!!, supportFragmentManager, binding.appsCount)
|
||||||
|
contactAdapter = ContactAdapter(packageManager!!, supportFragmentManager)
|
||||||
|
|
||||||
|
binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE
|
||||||
|
binding.searchNmap.setOnClickListener {
|
||||||
|
openSearchApps("nmap://search?query=${getInputText()}&appname=${BuildConfig.APPLICATION_ID}","com.nhn.android.nmap")
|
||||||
|
}
|
||||||
|
binding.searchYoutube.setOnClickListener {
|
||||||
|
openSearchApps("https://www.youtube.com/results?search_query=${getInputText()}","com.google.android.youtube")
|
||||||
|
}
|
||||||
|
binding.searchGoogleMap.setOnClickListener {
|
||||||
|
openSearchApps("geo:0,0?q=${getInputText()}","com.google.android.apps.maps")
|
||||||
|
}
|
||||||
|
binding.searchGoogle.setOnClickListener {
|
||||||
|
openSearchApps("https://www.google.com/search?q=${getInputText()}","com.android.chrome")
|
||||||
|
}
|
||||||
|
binding.searchTmap.setOnClickListener {
|
||||||
|
openSearchApps("tmap://search?name=${getInputText()}","com.skt.tmap.ku")
|
||||||
|
|
||||||
|
}
|
||||||
|
binding.searchNaver.setOnClickListener {
|
||||||
|
openSearchApps("https://search.naver.com/search.naver?where=nexearch&query=${getInputText()}", "com.nhn.android.search")
|
||||||
|
}
|
||||||
|
binding.searchDuckduckgo.setOnClickListener {
|
||||||
|
openSearchApps("https://duckduckgo.com/?t=h_&q=${getInputText()}","com.duckduckgo.mobile.android")
|
||||||
|
}
|
||||||
|
binding.searchNamuwiki.setOnClickListener {
|
||||||
|
openSearchApps("https://namu.wiki/Search?q=${getInputText()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.searchTranslate.setOnClickListener {
|
||||||
|
openSearchApps("https://translate.google.com/?hl=ko&sl=ko&tl=en&text=${getInputText()}&op=translate","com.android.chrome")
|
||||||
|
}
|
||||||
|
binding.searchStore.setOnClickListener {
|
||||||
|
openSearchApps("market://search?q=${getInputText()}")
|
||||||
|
}
|
||||||
|
binding.runSend.setOnClickListener {
|
||||||
|
sendMsg()
|
||||||
|
}
|
||||||
|
binding.runTelegram.setOnClickListener {
|
||||||
|
sendMsg("tg://msg?text=${getInputText()}&to=${PrefString.telegramSendTarget.get()}","org.telegram.messenger")
|
||||||
|
}
|
||||||
|
binding.runKatalk.setOnClickListener {
|
||||||
|
sendMsg(pkg = "com.kakao.talk")
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.runKatalkT.setOnClickListener{
|
||||||
|
openSearchApps("kakaot://taxi?dest_lat=${URLEncoder.encode("37.467696")}&dest_lng=${URLEncoder.encode("127.101063")}","com.kakao.taxi")
|
||||||
|
// openSearchApps("kakaot://taxi?${URLEncoder.encode("세곡동 557")}","com.kakao.taxi")
|
||||||
|
// openSearchApps("kakaot://taxi?dest_addr=${URLEncoder.encode("세곡동 557")}","com.kakao.taxi")
|
||||||
|
}
|
||||||
|
setLayout()
|
||||||
|
binding.searchInput.setOnKeyListener { v, keyCode, event ->
|
||||||
|
//contactList.size < 1 && packageList.size < 1 &&
|
||||||
|
if(PrefBoolean.useQuickLaunch.get(false) && keyCode == 66 && event.action == KeyEvent.ACTION_UP) {
|
||||||
|
checkResult(binding.searchInput.text.toString())
|
||||||
|
true
|
||||||
|
}else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var packageManager = lActivity?.packageManager
|
||||||
|
|
||||||
|
binding.searchInput.setOnLongClickListener {
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
var newQ = query<AppInfo>()
|
||||||
|
appQuery = newQ.sort(Pair("clickCount", Sort.DESCENDING),Pair("lastUseDate",Sort.DESCENDING)).find()
|
||||||
|
appQuery?.let {
|
||||||
|
if(it.size > 0) {
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
packageList.clear()
|
||||||
|
writeBlocking {
|
||||||
|
it.filter {
|
||||||
|
var installed = isPackageInstalled(it.pkgName ?: "fffffffail", packageManager!!)
|
||||||
|
// it.isInstalled = installed
|
||||||
|
installed
|
||||||
|
}.let { result ->
|
||||||
|
packageList.addAll(copyFromRealm(result))
|
||||||
|
binding.appsList.post { if (result.size > 0) {
|
||||||
|
appsAdapter?.updateData(packageList)
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
var newQ = query<SimpleContact>()
|
||||||
|
contactQuery = newQ.sort(Pair("touchCount", Sort.DESCENDING),Pair("lastedTouchDateTime",Sort.DESCENDING)).find()
|
||||||
|
contactQuery?.let {
|
||||||
|
if (it.size > 0) {
|
||||||
|
contactList.clear()
|
||||||
|
contactList.addAll(copyFromRealm(it).toList())
|
||||||
|
binding.contactList.post {
|
||||||
|
if (contactList.size > 0) {
|
||||||
|
contactAdapter?.updateData(contactList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
binding.searchInput.doOnTextChanged{ inputText, _, _, _ ->
|
||||||
|
binding.searchInput.text?.let { binding.searchInput.setSelection(it.length) }
|
||||||
|
filterAppsList(inputText.toString())
|
||||||
|
}
|
||||||
|
// return binding.root
|
||||||
|
}
|
||||||
|
fun isPackageInstalled( packageName : String, packageManager : PackageManager?) : Boolean{
|
||||||
|
try {
|
||||||
|
packageManager!!.getPackageInfo(packageName, 0)
|
||||||
|
return true;
|
||||||
|
} catch ( e : Exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMsg(scheme : String? = null , pkg : String? = null) {
|
||||||
|
var postIntent : Intent? = null
|
||||||
|
if (scheme != null && scheme.length > 1) {
|
||||||
|
postIntent = Intent(Intent.ACTION_VIEW,Uri.parse(scheme))
|
||||||
|
} else {
|
||||||
|
postIntent = Intent(Intent.ACTION_SEND)
|
||||||
|
postIntent.type = "text/plain"
|
||||||
|
postIntent.putExtra(Intent.EXTRA_TEXT, "${getInputText()}")
|
||||||
|
}
|
||||||
|
if (pkg != null && pkg.length > 1) {
|
||||||
|
postIntent?.setPackage(pkg)
|
||||||
|
startActivity(postIntent)
|
||||||
|
} else {
|
||||||
|
val chooserTitle = "바로 보냄"
|
||||||
|
startActivity(Intent.createChooser(postIntent, chooserTitle))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val appNames = hashSetOf<AppInfo>()
|
||||||
|
val contactList = arrayListOf<SimpleContact>()
|
||||||
|
|
||||||
|
fun openSearchApps(schemeString : String, pakage : String? = null) {
|
||||||
|
val gmmIntentUri = Uri.parse(schemeString)
|
||||||
|
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
||||||
|
pakage?.let {
|
||||||
|
mapIntent.setPackage(pakage)
|
||||||
|
WorkersDb.updateAppUse(pakage)
|
||||||
|
}
|
||||||
|
startActivity(mapIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun checkResult(keyword: String) {
|
||||||
|
openSearchMenus(keyword) {
|
||||||
|
registCancelSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun runonUi(invoke : () -> Unit) {
|
||||||
|
Handler(Looper.getMainLooper()).run {
|
||||||
|
try {
|
||||||
|
invoke.invoke()
|
||||||
|
}catch (e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
Blog.LOGE("onResume")
|
||||||
|
fetchApps()
|
||||||
|
|
||||||
|
binding.appsCount.visibility = if (PrefBoolean.showAppResultCount.get(false)) VISIBLE else GONE
|
||||||
|
|
||||||
|
PrefBoolean.openWithKayboard.get().letTrue { openSearch() }
|
||||||
|
registCancelSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
val chechHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
val cancelSearch = Runnable {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registCancelSearch() {
|
||||||
|
chechHandler.removeCallbacks(cancelSearch)
|
||||||
|
chechHandler.postDelayed(cancelSearch, 15000L)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearCancelSearch() {
|
||||||
|
chechHandler.removeCallbacks(cancelSearch)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
closeSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setLayout() {
|
||||||
|
binding.appsList.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.HORIZONTAL,false)
|
||||||
|
binding.contactList.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.HORIZONTAL,false)
|
||||||
|
/* initialize apps list adapter */
|
||||||
|
binding.appsList.adapter = appsAdapter
|
||||||
|
binding.contactList.adapter = contactAdapter
|
||||||
|
}
|
||||||
|
var appQuery : RealmResults<AppInfo>? = null
|
||||||
|
fun fetchApps(keyword : String? = null) {
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
var newQ = query<AppInfo>()
|
||||||
|
if (keyword != null && keyword.length > 0) {
|
||||||
|
if (JamoUtils.CHOSUNG.contains(keyword.split("")[0])) {
|
||||||
|
newQ = newQ.query("appName CONTAINS $0 OR appNameChosung CONTAINS $0 OR koreanName CONTAINS $0 OR alphaCho CONTAINS $0 OR category CONTAINS $0", keyword)
|
||||||
|
} else if(Pattern.matches("^[가-힣]*\$", keyword)){
|
||||||
|
newQ = newQ.query("appName CONTAINS $0 OR koreanName CONTAINS $0 OR category CONTAINS $0", keyword)
|
||||||
|
}else {
|
||||||
|
keyword.split("").forEach {
|
||||||
|
if (it.length > 0) {
|
||||||
|
newQ = newQ.query(
|
||||||
|
"appName CONTAINS $0 OR category CONTAINS $0 OR pkgName CONTAINS $0 OR appName CONTAINS $1 OR category CONTAINS $1 OR pkgName CONTAINS $1",
|
||||||
|
keyword.lowercase(),
|
||||||
|
keyword.uppercase()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appQuery = newQ.sort(Pair("clickCount", Sort.DESCENDING),Pair("lastUseDate",Sort.DESCENDING))
|
||||||
|
.limit(PrefLong.maxQueryCount.get(18L).toInt()).find()
|
||||||
|
appQuery?.let {
|
||||||
|
if(it.size > 0) {
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
packageList.clear()
|
||||||
|
writeBlocking {
|
||||||
|
it.filter {
|
||||||
|
var installed = isPackageInstalled(it.pkgName ?: "fffffffail", packageManager!!)
|
||||||
|
// it.isInstalled = installed
|
||||||
|
installed
|
||||||
|
}.let { result ->
|
||||||
|
packageList.addAll(copyFromRealm(result))
|
||||||
|
binding.appsList.post { if (result.size > 0) {
|
||||||
|
appsAdapter?.updateData(packageList)
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetcContact(keyword)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var contactQuery : RealmResults<SimpleContact>? = null
|
||||||
|
fun fetcContact(keyword : String? = null) {
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
var newQ = query<SimpleContact>()
|
||||||
|
if (keyword != null && keyword.length > 0) {
|
||||||
|
if(Pattern.matches("^[0-9]*\$", keyword)){
|
||||||
|
keyword.split("").forEach { if (it.length > 0) newQ = newQ.query("phoneNumber CONTAINS $0", keyword) }
|
||||||
|
} else {
|
||||||
|
newQ = newQ.query("name CONTAINS $0 OR chosung CONTAINS $0", keyword)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contactQuery = newQ.sort(Pair("touchCount", Sort.DESCENDING),Pair("lastedTouchDateTime",Sort.DESCENDING))
|
||||||
|
.limit(PrefLong.maxQueryCount.get(18L).toInt()).find()
|
||||||
|
contactQuery?.let {
|
||||||
|
if (it.size > 0)
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
contactList.clear()
|
||||||
|
contactList.addAll(copyFromRealm(it).toList())
|
||||||
|
binding.contactList.post { if (contactList.size > 0) {
|
||||||
|
contactAdapter?.updateData(contactList)
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getHangule() {
|
||||||
|
Blog.LOGE("on getHangule")
|
||||||
|
Executors.newSingleThreadScheduledExecutor().schedule({
|
||||||
|
if (appNames.size > 0) {
|
||||||
|
val info = appNames.first()
|
||||||
|
appNames.remove(info)
|
||||||
|
if (info.koreanName?.length ?: 0 > 0 || info.appNameChosung?.length ?: 0 > 0) {
|
||||||
|
getHangule()
|
||||||
|
} else {
|
||||||
|
Blog.LOGE("on getHangule ${info.appName}")
|
||||||
|
if (Pattern.matches("^[a-zA-Z]*$", info.appName)) {
|
||||||
|
// Jsoup.connect("https://translate.google.com/?hl=ko&sl=en&tl=ko&text=${info.appName}&op=translate").get().let { trans ->
|
||||||
|
// BLog.LOGE("on getHangule ${trans.title()}")
|
||||||
|
// trans.getElementsByTag("span").forEach {
|
||||||
|
// BLog.LOGE("on getHangule ${it.text()}")
|
||||||
|
// if(it.hasAttr("jsaction") &&
|
||||||
|
// it.attr("jsaction").contains("mouseout") &&
|
||||||
|
// it.attr("jsaction").contains("contextmenu") &&
|
||||||
|
// it.attr("jsaction").contains("mouseover")
|
||||||
|
// ) {
|
||||||
|
// BLog.LOGE("on getHangule $it")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }.apply {
|
||||||
|
// getHangule()
|
||||||
|
// }
|
||||||
|
// Handler(Looper.getMainLooper()).post {
|
||||||
|
// LauncherActivity.Companion.lActivity?.doWebParseStart(
|
||||||
|
// "https://translate.google.com/?hl=ko&sl=en&tl=ko&text=${info.appName}&op=translate",
|
||||||
|
// object : CommadCallabck {
|
||||||
|
// override fun onConsoleLog(log: String) {
|
||||||
|
// if (log.contains("result::")) {
|
||||||
|
// val appHangulName = log.split("result::")[1]
|
||||||
|
// if(appHangulName?.length ?: 0 > 0) {
|
||||||
|
// info.appNameChosung = JamoUtils.split(appHangulName).joinToString("")
|
||||||
|
// info.koreanName = appHangulName
|
||||||
|
//// BLog.LOGE("appHangulName >>> $appHangulName")
|
||||||
|
//// BLog.LOGE("appHangulName >>> ${info.appNameChosung}")
|
||||||
|
// WorkersDb.update(info)
|
||||||
|
// getHangule()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun collectComplete() {
|
||||||
|
// getHangule()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
info.appNameChosung = JamoUtils.split(info.appName).joinToString("")
|
||||||
|
info.koreanName = info.appName
|
||||||
|
WorkersDb.update(info)
|
||||||
|
getHangule()
|
||||||
|
Blog.LOGE("on getHangule to next")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},5,TimeUnit.SECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAlphabetItems() {
|
||||||
|
// settingsPrefs!!.getInt(KEY_SCROLLBAR_HEIGHT, DEFAULT_SCROLLBAR_HEIGHT).let { height: Int ->
|
||||||
|
// if (height == 0) { binding.alphabets.visibility = GONE }
|
||||||
|
// else {
|
||||||
|
// binding.alphabets.apply {
|
||||||
|
// if (visibility == GONE) visibility = VISIBLE
|
||||||
|
// updateLayoutParams { this.height = height }
|
||||||
|
// }
|
||||||
|
// alphabetList.clear()
|
||||||
|
// for (mPackage in packageList) {
|
||||||
|
// mPackage.appName.first().uppercase().let { firstLetter: String ->
|
||||||
|
// when {
|
||||||
|
// numberPattern.matcher(firstLetter).matches() -> alphabetList.add(0, "#")
|
||||||
|
// alphabetPattern.matcher(firstLetter).matches() -> alphabetList.add(firstLetter)
|
||||||
|
// !numberPattern.matcher(firstLetter).matches() &&
|
||||||
|
// !alphabetPattern.matcher(firstLetter).matches() -> alphabetList.add(alphabetList.size,"⠶")
|
||||||
|
// else -> {}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// binding.alphabets.invalidate()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun filterAppsList(searchString: String) {
|
||||||
|
fetchApps(searchString)
|
||||||
|
registCancelSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openSearch() {
|
||||||
|
try {
|
||||||
|
binding.searchInput.apply {
|
||||||
|
visibility = VISIBLE
|
||||||
|
requestFocus()
|
||||||
|
let {
|
||||||
|
(getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager)?.showSoftInput(
|
||||||
|
it,
|
||||||
|
InputMethodManager.SHOW_IMPLICIT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e : UninitializedPropertyAccessException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear search string, hide keyboard and search box */
|
||||||
|
private fun closeSearch() {
|
||||||
|
binding.searchInput.apply {
|
||||||
|
let {
|
||||||
|
text?.clear()
|
||||||
|
(getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager)?.hideSoftInputFromWindow(it.windowToken, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
+189
-175
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.apps
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.ActivityOptions
|
import android.app.ActivityOptions
|
||||||
@@ -26,7 +26,6 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.icu.text.SimpleDateFormat
|
import android.icu.text.SimpleDateFormat
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@@ -41,28 +40,25 @@ import android.view.inputmethod.InputMethodManager
|
|||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.apps.AppDrawer.Companion.appNamesPrefs
|
||||||
|
import bums.lunatic.launcher.databinding.ActivityBrowserDialogBinding
|
||||||
|
import bums.lunatic.launcher.databinding.AppInfoDialogBinding
|
||||||
|
import bums.lunatic.launcher.databinding.AppMenuBinding
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.copyToClipboard
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.screenHeight
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.screenWidth
|
||||||
|
import bums.lunatic.launcher.model.AppInfo
|
||||||
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.google.android.material.button.MaterialButton
|
|
||||||
import com.google.android.material.button.MaterialButtonToggleGroup
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.gson.Gson
|
import io.realm.kotlin.ext.query
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
|
||||||
import rasel.lunar.launcher.R
|
|
||||||
import rasel.lunar.launcher.apps.AppDrawer.Companion.appNamesPrefs
|
|
||||||
import rasel.lunar.launcher.databinding.ActivityBrowserDialogBinding
|
|
||||||
import rasel.lunar.launcher.databinding.AppInfoDialogBinding
|
|
||||||
import rasel.lunar.launcher.databinding.AppMenuBinding
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APP_NO_
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.MAX_FAVORITE_APPS
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_FAVORITE_APPS
|
|
||||||
import rasel.lunar.launcher.helpers.UniUtils.Companion.copyToClipboard
|
|
||||||
import rasel.lunar.launcher.helpers.UniUtils.Companion.screenHeight
|
|
||||||
import rasel.lunar.launcher.helpers.UniUtils.Companion.screenWidth
|
|
||||||
import rasel.lunar.launcher.utils.BLog
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
@@ -75,8 +71,8 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
private lateinit var binding: AppMenuBinding
|
private lateinit var binding: AppMenuBinding
|
||||||
private lateinit var packageName: String
|
private lateinit var packageName: String
|
||||||
private lateinit var packageManager: PackageManager
|
private lateinit var packageManager: PackageManager
|
||||||
private lateinit var appInfo: ApplicationInfo
|
|
||||||
private lateinit var defAppName: String
|
private lateinit var defAppName: String
|
||||||
|
var appInfo: ApplicationInfo? = null
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
binding = AppMenuBinding.inflate(inflater, container, false)
|
binding = AppMenuBinding.inflate(inflater, container, false)
|
||||||
@@ -87,16 +83,85 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
|
|
||||||
/* get application info */
|
/* get application info */
|
||||||
appInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
appInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
packageManager.getApplicationInfo(packageName,
|
try {
|
||||||
PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()))
|
packageManager.getApplicationInfo(packageName,
|
||||||
|
PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()))
|
||||||
|
}catch (e :Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
|
try {
|
||||||
|
packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
|
||||||
|
}catch (e :Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(appInfo == null){
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
defAppName = ""
|
||||||
|
var result = query<AppInfo>("pkgName == $0", packageName).find()
|
||||||
|
if (result.size > 0) {
|
||||||
|
val app = result.first()
|
||||||
|
app.currentInstalled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* get default app name */
|
||||||
|
defAppName = packageManager.resolveActivity(
|
||||||
|
Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
.setPackage(packageName), 0
|
||||||
|
)?.loadLabel(packageManager).toString()
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
var result = query<AppInfo>("pkgName == $0", packageName).find()
|
||||||
|
if (result.size > 0) {
|
||||||
|
val app = result.first()
|
||||||
|
binding.totalTouch.text = "총 실행 횟수 : ".plus(app.clickCount.toString())
|
||||||
|
binding.lastTouchDate.text =
|
||||||
|
"최종 실행 일시 : ".plus(SimpleDateFormat("yyyy-MM-dd HH:mm").format(Date(app.lastUseDate)))
|
||||||
|
app.currentInstalled = true
|
||||||
|
binding.alterName.setText(app.koreanName)
|
||||||
|
// app.clickCount = app.clickCount + 15
|
||||||
|
|
||||||
|
// app.lastUseDate = Math.max(app.lastUseDate, System.currentTimeMillis())
|
||||||
|
// app.clickCount = app.clickCount + 15
|
||||||
|
// app.lastUseDate = Math.max(app.lastUseDate, System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get default app name */
|
fun update() {
|
||||||
defAppName = packageManager.resolveActivity(Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
|
WorkersDb.getRealm().apply {
|
||||||
.setPackage(packageName), 0)?.loadLabel(packageManager).toString()
|
writeBlocking {
|
||||||
|
var result = query<AppInfo>("pkgName == $0",packageName).find()
|
||||||
|
if(result.size > 0) {
|
||||||
|
val app = result.first()
|
||||||
|
app.clickCount = app.clickCount + 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.totalTouch.setOnClickListener { update() }
|
||||||
|
binding.lastTouchDate.setOnClickListener { update() }
|
||||||
|
|
||||||
|
binding.alterName.doOnTextChanged { text, start, before, count ->
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
var result = query<AppInfo>("pkgName == $0",packageName).find()
|
||||||
|
if(result.size > 0) {
|
||||||
|
val app = result.first()
|
||||||
|
app.koreanName = text.toString()
|
||||||
|
app.appNameChosung = JamoUtils.split(app.koreanName).joinToString("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* set application name and package name */
|
/* set application name and package name */
|
||||||
binding.appName.apply {
|
binding.appName.apply {
|
||||||
setText(appNamesPrefs?.getString(packageName, defAppName))
|
setText(appNamesPrefs?.getString(packageName, defAppName))
|
||||||
@@ -104,9 +169,6 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
binding.appPackage.text = packageName
|
binding.appPackage.text = packageName
|
||||||
/* favorite apps */
|
|
||||||
favoriteApps()
|
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,56 +191,7 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
binding.appUninstall.setOnClickListener { uninstall() }
|
binding.appUninstall.setOnClickListener { uninstall() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* manage initial preview and clicks for favorite apps */
|
|
||||||
@SuppressLint("PrivateResource")
|
|
||||||
private fun favoriteApps() {
|
|
||||||
val sharedPreferences = requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
|
|
||||||
val enabledStroke =
|
|
||||||
ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.material_on_surface_stroke))
|
|
||||||
val disabledStroke =
|
|
||||||
ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.m3_chip_stroke_color))
|
|
||||||
|
|
||||||
for (position in 1..MAX_FAVORITE_APPS) {
|
|
||||||
val button = outlinedButton
|
|
||||||
val savedPackageName = sharedPreferences.getString(KEY_APP_NO_ + position, "")
|
|
||||||
|
|
||||||
/* set previews */
|
|
||||||
if (packageName == savedPackageName) button.isChecked = true
|
|
||||||
if (savedPackageName?.isNotEmpty() == true) button.strokeColor = enabledStroke
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
|
||||||
packageManager.getPackageInfo(savedPackageName!!, PackageManager.PackageInfoFlags.of(0))
|
|
||||||
else
|
|
||||||
packageManager.getPackageInfo(savedPackageName!!, 0)
|
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
|
||||||
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
|
|
||||||
.edit().remove(KEY_APP_NO_ + position).apply()
|
|
||||||
button.strokeColor = disabledStroke
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
/* listen on clicks */
|
|
||||||
binding.favGroup.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?,
|
|
||||||
checkedId: Int, isChecked: Boolean ->
|
|
||||||
try {
|
|
||||||
if (checkedId == button.id) {
|
|
||||||
if (isChecked) {
|
|
||||||
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
|
|
||||||
.edit().putString(KEY_APP_NO_ + position, packageName).apply()
|
|
||||||
button.strokeColor = enabledStroke
|
|
||||||
} else {
|
|
||||||
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
|
|
||||||
.edit().remove(KEY_APP_NO_ + position).apply()
|
|
||||||
button.strokeColor = disabledStroke
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun appName() {
|
private fun appName() {
|
||||||
binding.appName.setOnFocusChangeListener { _, hasFocus ->
|
binding.appName.setOnFocusChangeListener { _, hasFocus ->
|
||||||
@@ -221,26 +234,28 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
.setPositiveButton(android.R.string.cancel, null)
|
.setPositiveButton(android.R.string.cancel, null)
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
/* show app name */
|
appInfo?.let { appInfo ->
|
||||||
dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo)
|
dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo)
|
||||||
|
|
||||||
/* get package info */
|
/* get package info */
|
||||||
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
|
packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
|
||||||
} else {
|
} else {
|
||||||
packageManager.getPackageInfo(packageName, 0)
|
packageManager.getPackageInfo(packageName, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* show infos */
|
||||||
|
dialogBinding.mixed.text =
|
||||||
|
"${resources.getString(R.string.version)}: ${packageInfo.versionName} (${PackageInfoCompat.getLongVersionCode(packageInfo).toInt()})\n" +
|
||||||
|
"${resources.getString(R.string.sdk)}: ${appInfo.minSdkVersion} ~ ${appInfo.targetSdkVersion}\n" +
|
||||||
|
"${resources.getString(R.string.uid)}: ${appInfo.uid}\n" +
|
||||||
|
"${resources.getString(R.string.first_install)}: ${dateTimeFormat(packageInfo.firstInstallTime)}\n" +
|
||||||
|
"${resources.getString(R.string.last_update)}: ${dateTimeFormat(packageInfo.lastUpdateTime)}"
|
||||||
|
|
||||||
|
/* show permissions */
|
||||||
|
dialogBinding.permissions.text = permissionsList
|
||||||
}
|
}
|
||||||
|
|
||||||
/* show infos */
|
|
||||||
dialogBinding.mixed.text =
|
|
||||||
"${resources.getString(R.string.version)}: ${packageInfo.versionName} (${PackageInfoCompat.getLongVersionCode(packageInfo).toInt()})\n" +
|
|
||||||
"${resources.getString(R.string.sdk)}: ${appInfo.minSdkVersion} ~ ${appInfo.targetSdkVersion}\n" +
|
|
||||||
"${resources.getString(R.string.uid)}: ${appInfo.uid}\n" +
|
|
||||||
"${resources.getString(R.string.first_install)}: ${dateTimeFormat(packageInfo.firstInstallTime)}\n" +
|
|
||||||
"${resources.getString(R.string.last_update)}: ${dateTimeFormat(packageInfo.lastUpdateTime)}"
|
|
||||||
|
|
||||||
/* show permissions */
|
|
||||||
dialogBinding.permissions.text = permissionsList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* activity browser dialog */
|
/* activity browser dialog */
|
||||||
@@ -251,51 +266,55 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
.setPositiveButton(android.R.string.cancel, null)
|
.setPositiveButton(android.R.string.cancel, null)
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
/* show app name */
|
appInfo?.let { appInfo ->
|
||||||
dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo)
|
|
||||||
|
|
||||||
/* get activity info */
|
|
||||||
val activityInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
/* show app name */
|
||||||
packageManager.getPackageInfo(
|
dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo)
|
||||||
packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_ACTIVITIES.toLong())
|
|
||||||
)
|
/* get activity info */
|
||||||
} else {
|
val activityInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES)
|
packageManager.getPackageInfo(
|
||||||
}
|
packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_ACTIVITIES.toLong())
|
||||||
BLog.LOGE("activity. >>>>> ${Gson().toJson(activityInfo)}")
|
|
||||||
/* show activity list */
|
|
||||||
val activityAdapter: ArrayAdapter<String> =
|
|
||||||
ArrayAdapter(requireContext(), R.layout.list_item, R.id.itemText, ArrayList())
|
|
||||||
if (activityInfo.activities.isNotEmpty()) {
|
|
||||||
for (activity in activityInfo.activities) {
|
|
||||||
if (packageName.contains("com.kakao") == true) {
|
|
||||||
BLog.LOGE("activity. >>>>> ${Gson().toJson(activity)}")
|
|
||||||
}
|
|
||||||
activityAdapter.add(
|
|
||||||
activity.toString().split(" ").toTypedArray()[1].replace("}", "")
|
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES)
|
||||||
}
|
}
|
||||||
dialogBinding.activityList.adapter = activityAdapter
|
// BLog.LOGE("activity. >>>>> ${Gson().toJson(activityInfo)}")
|
||||||
}
|
/* show activity list */
|
||||||
|
val activityAdapter: ArrayAdapter<String> =
|
||||||
/* listen item clicks */
|
ArrayAdapter(requireContext(), R.layout.list_item, R.id.itemText, ArrayList())
|
||||||
dialogBinding.activityList.onItemClickListener =
|
if (activityInfo.activities?.isNotEmpty() == true) {
|
||||||
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, i: Int, _: Long ->
|
for (activity in activityInfo.activities!!) {
|
||||||
try {
|
if (packageName.contains("com.kakao") == true) {
|
||||||
/* open activity */
|
// BLog.LOGE("activity. >>>>> ${Gson().toJson(activity)}")
|
||||||
val intent = Intent()
|
}
|
||||||
intent.component = ComponentName(packageName, activityAdapter.getItem(i).toString())
|
activityAdapter.add(
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
activity.toString().split(" ").toTypedArray()[1].replace("}", "")
|
||||||
requireContext().startActivity(intent)
|
)
|
||||||
} catch (exception: Exception) {
|
|
||||||
/* couldn't open activity */
|
|
||||||
exception.printStackTrace()
|
|
||||||
val exceptionShort = (exception.toString().split(": ").toTypedArray())[0]
|
|
||||||
Toast.makeText(requireContext(),
|
|
||||||
"${resources.getString(R.string.unable_to_launch)} -\n$exceptionShort", Toast.LENGTH_LONG).show()
|
|
||||||
}
|
}
|
||||||
dialogBuilder.dismiss()
|
dialogBinding.activityList.adapter = activityAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* listen item clicks */
|
||||||
|
dialogBinding.activityList.onItemClickListener =
|
||||||
|
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, i: Int, _: Long ->
|
||||||
|
try {
|
||||||
|
/* open activity */
|
||||||
|
val intent = Intent()
|
||||||
|
intent.component = ComponentName(packageName, activityAdapter.getItem(i).toString())
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
requireContext().startActivity(intent)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
/* couldn't open activity */
|
||||||
|
exception.printStackTrace()
|
||||||
|
val exceptionShort = (exception.toString().split(": ").toTypedArray())[0]
|
||||||
|
Toast.makeText(requireContext(),
|
||||||
|
"${resources.getString(R.string.unable_to_launch)} -\n$exceptionShort", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
dialogBuilder.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open app's page in app store/market */
|
/* open app's page in app store/market */
|
||||||
@@ -337,35 +356,42 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
|
|
||||||
private fun share() {
|
private fun share() {
|
||||||
try {
|
try {
|
||||||
// Create a temporary file to copy the APK
|
appInfo?.let { appInfo ->
|
||||||
val apkLabel = packageManager.getApplicationLabel(appInfo).toString().lowercase().replace(" ", "_")
|
// Create a temporary file to copy the APK
|
||||||
val tempApkFile = File(requireContext().externalCacheDir, "$apkLabel.apk")
|
val apkLabel = packageManager.getApplicationLabel(appInfo).toString().lowercase()
|
||||||
|
.replace(" ", "_")
|
||||||
|
val tempApkFile = File(requireContext().externalCacheDir, "$apkLabel.apk")
|
||||||
|
|
||||||
// Copy the APK file
|
// Copy the APK file
|
||||||
FileInputStream(File(appInfo.sourceDir)).use { `in` ->
|
FileInputStream(File(appInfo.sourceDir)).use { `in` ->
|
||||||
FileOutputStream(tempApkFile).use { out ->
|
FileOutputStream(tempApkFile).use { out ->
|
||||||
val buffer = ByteArray(1024)
|
val buffer = ByteArray(1024)
|
||||||
var length: Int
|
var length: Int
|
||||||
while (`in`.read(buffer).also { length = it } > 0) {
|
while (`in`.read(buffer).also { length = it } > 0) {
|
||||||
out.write(buffer, 0, length)
|
out.write(buffer, 0, length)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a content URI using FileProvider
|
// Generate a content URI using FileProvider
|
||||||
val contentUri =
|
val contentUri =
|
||||||
FileProvider.getUriForFile(requireContext(), "${requireContext().packageName}.fileprovider", tempApkFile)
|
FileProvider.getUriForFile(
|
||||||
|
requireContext(),
|
||||||
|
"${requireContext().packageName}.fileprovider",
|
||||||
|
tempApkFile
|
||||||
|
)
|
||||||
|
|
||||||
//requireContext().grantUriPermission(receivers.package.name, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
//requireContext().grantUriPermission(receivers.package.name, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
|
||||||
// Create a Share Intent
|
// Create a Share Intent
|
||||||
Intent(Intent.ACTION_SEND).apply {
|
Intent(Intent.ACTION_SEND).apply {
|
||||||
type = "application/vnd.android.package-archive"
|
type = "application/vnd.android.package-archive"
|
||||||
putExtra(Intent.EXTRA_STREAM, contentUri)
|
putExtra(Intent.EXTRA_STREAM, contentUri)
|
||||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
}.let {
|
}.let {
|
||||||
// Start the chooser activity
|
// Start the chooser activity
|
||||||
startActivity(Intent.createChooser(it, getString(R.string.share_apk_message)))
|
startActivity(Intent.createChooser(it, getString(R.string.share_apk_message)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() }
|
catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() }
|
||||||
@@ -382,18 +408,6 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
this.dismiss()
|
this.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create and add an outlined button to the toggle group */
|
|
||||||
private val outlinedButton: MaterialButton get() {
|
|
||||||
val style = com.google.android.material.R.attr.materialButtonOutlinedStyle
|
|
||||||
val button = MaterialButton(requireContext(), null, style)
|
|
||||||
button.layoutParams = LinearLayoutCompat.LayoutParams(
|
|
||||||
LinearLayoutCompat.LayoutParams.WRAP_CONTENT,
|
|
||||||
LinearLayoutCompat.LayoutParams.WRAP_CONTENT, 1F
|
|
||||||
)
|
|
||||||
binding.favGroup.addView(button)
|
|
||||||
return button
|
|
||||||
}
|
|
||||||
|
|
||||||
/* long value to local date-time format */
|
/* long value to local date-time format */
|
||||||
private fun dateTimeFormat(long: Long) : String = SimpleDateFormat.getDateTimeInstance().format(Date(long))
|
private fun dateTimeFormat(long: Long) : String = SimpleDateFormat.getDateTimeInstance().format(Date(long))
|
||||||
|
|
||||||
@@ -405,14 +419,14 @@ internal class AppMenu : BottomSheetDialogFragment() {
|
|||||||
packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
|
packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (packageInfo.requestedPermissions.isNotEmpty()) {
|
return if (packageInfo.requestedPermissions?.isNotEmpty() == true) {
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
packageInfo.requestedPermissions.indices.forEach { i: Int ->
|
packageInfo.requestedPermissions?.indices?.forEach { i: Int ->
|
||||||
if (i != packageInfo.requestedPermissions.size - 1)
|
if (i != packageInfo.requestedPermissions!!.size - 1)
|
||||||
stringBuilder.append("${packageInfo.requestedPermissions[i]}\n\n")
|
stringBuilder.append("${packageInfo.requestedPermissions!![i]}\n\n")
|
||||||
/* don't add any new line after the last entry */
|
/* don't add any new line after the last entry */
|
||||||
else
|
else
|
||||||
stringBuilder.append(packageInfo.requestedPermissions[i])
|
stringBuilder.append(packageInfo.requestedPermissions!![i])
|
||||||
}
|
}
|
||||||
stringBuilder.toString()
|
stringBuilder.toString()
|
||||||
} else {
|
} else {
|
||||||
+22
-10
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.apps
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
@@ -28,22 +28,22 @@ import android.widget.TextView
|
|||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.apps.IconPackManager.Companion.getDrawableIconForPackage
|
||||||
|
import bums.lunatic.launcher.databinding.AppsChildBinding
|
||||||
|
import bums.lunatic.launcher.model.AppInfo
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import io.realm.kotlin.ext.query
|
import io.realm.kotlin.ext.query
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
|
||||||
import rasel.lunar.launcher.R
|
|
||||||
import rasel.lunar.launcher.apps.IconPackManager.Companion.getDrawableIconForPackage
|
|
||||||
import rasel.lunar.launcher.databinding.AppsChildBinding
|
|
||||||
import rasel.lunar.launcher.model.AppInfo
|
|
||||||
import rasel.lunar.launcher.workers.WorkersDb
|
|
||||||
|
|
||||||
|
|
||||||
internal class AppsAdapter(
|
internal class AppsAdapter(
|
||||||
private val layoutType: Int,
|
|
||||||
private val packageManager: PackageManager,
|
private val packageManager: PackageManager,
|
||||||
private val fragmentManager: FragmentManager,
|
private val fragmentManager: FragmentManager,
|
||||||
private val appsCount: TextView) : RecyclerView.Adapter<AppsAdapter.AppsViewHolder>() {
|
private val appsCount: TextView?) : RecyclerView.Adapter<AppsAdapter.AppsViewHolder>() {
|
||||||
|
|
||||||
private var oldList = mutableListOf<AppInfo>()
|
private var oldList = mutableListOf<AppInfo>()
|
||||||
// private var appGravity: Int = Gravity.CENTER
|
// private var appGravity: Int = Gravity.CENTER
|
||||||
@@ -80,6 +80,8 @@ internal class AppsAdapter(
|
|||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
WorkersDb.getRealm().apply {
|
WorkersDb.getRealm().apply {
|
||||||
writeBlocking {
|
writeBlocking {
|
||||||
|
Blog.LOGE("item.pkgName >>>> ${item.pkgName
|
||||||
|
}")
|
||||||
var result = query<AppInfo>("pkgName == $0",item.pkgName).find()
|
var result = query<AppInfo>("pkgName == $0",item.pkgName).find()
|
||||||
if(result.size > 0) {
|
if(result.size > 0) {
|
||||||
val app = result.first()
|
val app = result.first()
|
||||||
@@ -93,6 +95,16 @@ internal class AppsAdapter(
|
|||||||
|
|
||||||
/* on long click - open app menu */
|
/* on long click - open app menu */
|
||||||
setOnLongClickListener {
|
setOnLongClickListener {
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
var result = query<AppInfo>("pkgName == $0",item.pkgName).find()
|
||||||
|
if(result.size > 0) {
|
||||||
|
val app = result.first()
|
||||||
|
app.clickCount = app.clickCount + 15
|
||||||
|
// app.lastUseDate = Math.max(app.lastUseDate, System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
AppMenu().apply {
|
AppMenu().apply {
|
||||||
}.show(fragmentManager, item.pkgName)
|
}.show(fragmentManager, item.pkgName)
|
||||||
true
|
true
|
||||||
@@ -112,7 +124,7 @@ internal class AppsAdapter(
|
|||||||
oldList.clear()
|
oldList.clear()
|
||||||
oldList.addAll(newList)
|
oldList.addAll(newList)
|
||||||
newList.size.let {
|
newList.size.let {
|
||||||
appsCount.text = it.toString()
|
appsCount?.text = it.toString()
|
||||||
appsSize = it
|
appsSize = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-6
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.apps
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
@@ -26,13 +26,10 @@ import android.view.ViewGroup
|
|||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.databinding.ContactItemBinding
|
||||||
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
import io.realm.kotlin.types.RealmObject
|
import io.realm.kotlin.types.RealmObject
|
||||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||||
import rasel.lunar.launcher.databinding.ContactItemBinding
|
|
||||||
import rasel.lunar.launcher.utils.BLog
|
|
||||||
import rasel.lunar.launcher.utils.JamoUtils
|
|
||||||
import rasel.lunar.launcher.workers.RecentCallGetter
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
|
|
||||||
internal class ContactAdapter (
|
internal class ContactAdapter (
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.ContactsContract
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.databinding.ContactMenuBinding
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
|
||||||
|
internal class ContactMenu : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: ContactMenuBinding
|
||||||
|
private lateinit var contactId: String
|
||||||
|
|
||||||
|
var contactName : String = ""
|
||||||
|
var contactPhoneNumber : String = ""
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = ContactMenuBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
/* get package name from fragment's tag */
|
||||||
|
contactId = tag.toString()
|
||||||
|
|
||||||
|
WorkersDb.getRealm().writeBlocking {
|
||||||
|
if (contactId != null && contactId.length ?: 0 > 0) {
|
||||||
|
val result = query<SimpleContact>().query("id == $0", contactId).find()
|
||||||
|
if(result.size > 0){
|
||||||
|
var contact = result.first()
|
||||||
|
binding.totalTouch.text = "총 연락 횟수 : ".plus(contact.touchCount.toString())
|
||||||
|
binding.lastTouchDate.text = "마지막 연락 시간 : ".plus(SimpleDateFormat("yyyy-MM-dd HH:mm").format(Date(contact.lastedTouchDateTime)))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
WorkersDb.getRealm().writeBlocking {
|
||||||
|
if (contactId != null && contactId.length ?: 0 > 0) {
|
||||||
|
val result = query<SimpleContact>().query("id == $0", contactId).find()
|
||||||
|
if(result.size > 0){
|
||||||
|
var contact = result.first()
|
||||||
|
contact.touchCount = contact.touchCount + 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.totalTouch.setOnClickListener { update() }
|
||||||
|
binding.lastTouchDate.setOnClickListener { update() }
|
||||||
|
|
||||||
|
val resolver = lActivity!!.contentResolver
|
||||||
|
val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
|
||||||
|
val projection = arrayOf(
|
||||||
|
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
|
||||||
|
ContactsContract.CommonDataKinds.Phone.NUMBER,
|
||||||
|
)
|
||||||
|
|
||||||
|
Blog.LOGE("GetContact", "packageName ${contactId}")
|
||||||
|
try {
|
||||||
|
val cursor = resolver.query(phoneUri, projection, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null , null)
|
||||||
|
if (cursor != null) {
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
val nameIndex = cursor.getColumnIndex(projection[0])
|
||||||
|
val numberIndex = cursor.getColumnIndex(projection[1])
|
||||||
|
contactName = cursor.getString(nameIndex)
|
||||||
|
var number = cursor.getString(numberIndex)
|
||||||
|
contactPhoneNumber = number.replace("-", "")
|
||||||
|
Blog.LOGE("GetContact", "이름 : $contactName 번호 : $contactPhoneNumber ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 데이터 계열은 반드시 닫아줘야 한다.
|
||||||
|
cursor!!.close()
|
||||||
|
} catch ( e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get application info */
|
||||||
|
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
|
||||||
|
/* copy package name */
|
||||||
|
// binding.appPackage.setOnClickListener {
|
||||||
|
// copyToClipboard(requireContext(), packageName)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
appName()
|
||||||
|
binding.detailedInfo.setOnClickListener { detailedInfo() }
|
||||||
|
binding.call.setOnClickListener { callPhone() }
|
||||||
|
binding.sms.setOnClickListener { sendSms() }
|
||||||
|
// binding.activityBrowser.setOnClickListener { activityBrowser() }
|
||||||
|
// binding.appStore.setOnClickListener { appStore() }
|
||||||
|
// binding.appFreeform.setOnClickListener { freeform() }
|
||||||
|
// binding.appInfo.setOnClickListener { appInfo() }
|
||||||
|
// binding.appShare.setOnClickListener { share() }
|
||||||
|
// binding.appUninstall.setOnClickListener { uninstall() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun appName() {
|
||||||
|
binding.appName.text = contactName
|
||||||
|
binding.phoneNumber.text = contactPhoneNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun detailedInfo() {
|
||||||
|
var intent = Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + contactId));
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendSms() {
|
||||||
|
var intent = Intent(Intent.ACTION_SEND);
|
||||||
|
intent.setData(Uri.parse("smsto:" + contactPhoneNumber));
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
private fun callPhone() {
|
||||||
|
var intent = Intent(Intent.ACTION_DIAL);
|
||||||
|
intent.setData(Uri.parse("tel:" + contactPhoneNumber));
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+14
-14
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.apps
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
@@ -26,18 +26,18 @@ import android.graphics.drawable.BitmapDrawable
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.collection.LruCache
|
import androidx.collection.LruCache
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.DEFAULT_ICON_PACK
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_ICON_PACK
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_PKGICS
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.utils.ImageUtils
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
import org.xmlpull.v1.XmlPullParserException
|
import org.xmlpull.v1.XmlPullParserException
|
||||||
import org.xmlpull.v1.XmlPullParserFactory
|
import org.xmlpull.v1.XmlPullParserFactory
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.DEFAULT_ICON_PACK
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_ICON_PACK
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_PKGICS
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
|
||||||
import rasel.lunar.launcher.utils.BLog
|
|
||||||
import rasel.lunar.launcher.utils.ImageUtils
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -69,17 +69,17 @@ internal class IconPackManager {
|
|||||||
val appFilterId = iconPackRes!!.getIdentifier("appfilter", "xml", packageName)
|
val appFilterId = iconPackRes!!.getIdentifier("appfilter", "xml", packageName)
|
||||||
if (appFilterId > 0) {
|
if (appFilterId > 0) {
|
||||||
xpp = iconPackRes!!.getXml(appFilterId)
|
xpp = iconPackRes!!.getXml(appFilterId)
|
||||||
BLog.LOGE("packageName >>> ${packageName}")
|
// BLog.LOGE("packageName >>> ${packageName}")
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
xpp = XmlPullParserFactory.newInstance().apply { isNamespaceAware = true }
|
xpp = XmlPullParserFactory.newInstance().apply { isNamespaceAware = true }
|
||||||
.newPullParser().apply {
|
.newPullParser().apply {
|
||||||
BLog.LOGE("packageName >>> ${packageName}")
|
// BLog.LOGE("packageName >>> ${packageName}")
|
||||||
setInput(iconPackRes!!.assets.open("appfilter.xml"), "utf-8")
|
setInput(iconPackRes!!.assets.open("appfilter.xml"), "utf-8")
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
BLog.w("", "Couldn't find the appfilter.xml file")
|
Blog.w("", "Couldn't find the appfilter.xml file")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xpp != null) {
|
if (xpp != null) {
|
||||||
@@ -118,9 +118,9 @@ internal class IconPackManager {
|
|||||||
}
|
}
|
||||||
loaded = true
|
loaded = true
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
BLog.w("", "Failed to load the icon pack")
|
Blog.w("", "Failed to load the icon pack")
|
||||||
} catch (e: XmlPullParserException) {
|
} catch (e: XmlPullParserException) {
|
||||||
BLog.w("", "Failed to parse the appfilter.xml file")
|
Blog.w("", "Failed to parse the appfilter.xml file")
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ internal class IconPackManager {
|
|||||||
var componentName: String? = null
|
var componentName: String? = null
|
||||||
componentName = packagesConponentNames.get(appPackageName!!)
|
componentName = packagesConponentNames.get(appPackageName!!)
|
||||||
if (componentName == null || componentName.length ?: 0 <= 0 ) {
|
if (componentName == null || componentName.length ?: 0 <= 0 ) {
|
||||||
BLog.LOGE("it's compo ${appPackageName}")
|
Blog.LOGE("it's compo ${appPackageName}")
|
||||||
var pkgIntent =
|
var pkgIntent =
|
||||||
lActivity!!.packageManager.getLaunchIntentForPackage(
|
lActivity!!.packageManager.getLaunchIntentForPackage(
|
||||||
appPackageName!!
|
appPackageName!!
|
||||||
+8
-7
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.apps
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@@ -28,11 +28,12 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import bums.lunatic.launcher.BuildConfig
|
||||||
|
import bums.lunatic.launcher.common.DismissCalback
|
||||||
|
import bums.lunatic.launcher.databinding.SearchMenuBinding
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import rasel.lunar.launcher.BuildConfig
|
|
||||||
import rasel.lunar.launcher.databinding.SearchMenuBinding
|
|
||||||
import rasel.lunar.launcher.utils.BLog
|
|
||||||
|
|
||||||
|
|
||||||
internal class SearchMenu : BottomSheetDialogFragment() {
|
internal class SearchMenu : BottomSheetDialogFragment() {
|
||||||
@@ -131,16 +132,16 @@ internal class SearchMenu : BottomSheetDialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun dismiss() {
|
override fun dismiss() {
|
||||||
BLog.LOGE("dismiss()")
|
Blog.LOGE("dismiss()")
|
||||||
mDismissCalback?.invoke()
|
mDismissCalback?.invoke()
|
||||||
super.dismiss()
|
super.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDismiss(dialog: DialogInterface) {
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
BLog.LOGE("onDismiss(dialog: DialogInterface)")
|
Blog.LOGE("onDismiss(dialog: DialogInterface)")
|
||||||
mDismissCalback?.invoke()
|
mDismissCalback?.invoke()
|
||||||
super.onDismiss(dialog)
|
super.onDismiss(dialog)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias DismissCalback = ()->Unit
|
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.apps
|
package bums.lunatic.launcher.apps
|
||||||
|
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
@@ -6,10 +6,10 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.databinding.ContactMenuBinding
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
|
||||||
import rasel.lunar.launcher.databinding.ContactMenuBinding
|
|
||||||
|
|
||||||
class SmmsMenu: BottomSheetDialogFragment() {
|
class SmmsMenu: BottomSheetDialogFragment() {
|
||||||
|
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package bums.lunatic.launcher.behavior
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarAdapter
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarBean
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarDateView
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarFactory.getMonthOfDayList
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarUtil
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarView
|
||||||
|
import bums.lunatic.launcher.databinding.ItemCalendarBinding
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import java.util.Date
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
class Behavior: AppCompatActivity() {
|
||||||
|
|
||||||
|
private val sampleAdapter by lazy { SampleAdapter() }
|
||||||
|
|
||||||
|
private val getYMax by lazy {
|
||||||
|
resources.getDimension(R.dimen.appbar_height) - resources.getDimension(
|
||||||
|
R.dimen.toolbar_height
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val fadeIn by lazy { AnimationUtils.loadAnimation(this, R.anim.fade_in) }
|
||||||
|
|
||||||
|
private val fadeOut by lazy { AnimationUtils.loadAnimation(this, R.anim.fade_out) }
|
||||||
|
val dateArr: IntArray = CalendarUtil.getYMD(Date())
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
setContentView(R.layout.behavior)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
initTopBarAnimation()
|
||||||
|
initRecyclerView()
|
||||||
|
loadSample()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initTopBarAnimation() {
|
||||||
|
val appBarLayout = findViewById<AppBarLayout>(R.id.app_bar_layout)
|
||||||
|
|
||||||
|
val back = findViewById<ImageView>(R.id.iv_back)
|
||||||
|
val del = findViewById<ImageView>(R.id.iv_del)
|
||||||
|
val share = findViewById<ImageView>(R.id.iv_share)
|
||||||
|
val cal = findViewById<RecyclerView>(R.id.calendarDateView)
|
||||||
|
appBarLayout.addOnOffsetChangedListener(
|
||||||
|
AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
|
||||||
|
if (abs(verticalOffset) >= getYMax / 2) {
|
||||||
|
if (back.visibility != View.GONE) {
|
||||||
|
back.startAnimation(fadeOut)
|
||||||
|
del.startAnimation(fadeOut)
|
||||||
|
share.startAnimation(fadeOut)
|
||||||
|
|
||||||
|
back.visibility = View.GONE
|
||||||
|
del.visibility = View.GONE
|
||||||
|
share.visibility = View.GONE
|
||||||
|
var lp = cal.layoutParams
|
||||||
|
lp.height = resources.getDimension(R.dimen.toolbar_height).toInt()
|
||||||
|
cal.layoutParams = lp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (back.visibility != View.VISIBLE) {
|
||||||
|
back.startAnimation(fadeIn)
|
||||||
|
del.startAnimation(fadeIn)
|
||||||
|
share.startAnimation(fadeIn)
|
||||||
|
|
||||||
|
back.visibility = View.VISIBLE
|
||||||
|
del.visibility = View.VISIBLE
|
||||||
|
share.visibility = View.VISIBLE
|
||||||
|
var lp = cal.layoutParams
|
||||||
|
lp.height = resources.getDimension(R.dimen.appbar_height).toInt()
|
||||||
|
cal.layoutParams = lp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initRecyclerView() {
|
||||||
|
with(findViewById<RecyclerView>(R.id.rv_main)) {
|
||||||
|
adapter = sampleAdapter
|
||||||
|
}
|
||||||
|
with(findViewById<RecyclerView>(R.id.calendarDateView)) {
|
||||||
|
adapter = CalAdapter().apply {
|
||||||
|
items.clear()
|
||||||
|
items.addAll(getMonthOfDayList(
|
||||||
|
dateArr[0],
|
||||||
|
dateArr[1]
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadSample() {
|
||||||
|
sampleAdapter.notifySample()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CalAdapter : RecyclerView.Adapter<CalAdapter.CalViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<CalendarBean>()
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = CalViewHolder(ItemCalendarBinding.inflate(LayoutInflater.from(parent.context)))
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: CalViewHolder, position: Int) {
|
||||||
|
holder.bind.day.apply {
|
||||||
|
val bean = items[position]
|
||||||
|
this.text = bean?.day.toString()
|
||||||
|
if (bean?.monthFlag != 0) {
|
||||||
|
this.setTextColor(Color.WHITE)
|
||||||
|
} else {
|
||||||
|
this.setTextColor(Color.BLACK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
// fun notifySample() {
|
||||||
|
// items.clear()
|
||||||
|
// (1..10).forEach {
|
||||||
|
// items.add(it)
|
||||||
|
// }
|
||||||
|
// notifyDataSetChanged()
|
||||||
|
// }
|
||||||
|
|
||||||
|
class CalViewHolder(val bind: ItemCalendarBinding) : RecyclerView.ViewHolder(bind.root)
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package bums.lunatic.launcher.behavior
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
|
||||||
|
class SampleAdapter : RecyclerView.Adapter<SampleAdapter.SampleViewHolder>() {
|
||||||
|
|
||||||
|
private val items = mutableListOf<Int>()
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = SampleViewHolder(parent)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: SampleViewHolder, position: Int) {
|
||||||
|
//..
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
fun notifySample() {
|
||||||
|
items.clear()
|
||||||
|
(1..10).forEach {
|
||||||
|
items.add(it)
|
||||||
|
}
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SampleViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder(
|
||||||
|
LayoutInflater.from(parent.context).inflate(R.layout.item_sample, parent, false),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.behaviorimpl
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
|
class BehaviorBlackJin(context: Context, attrs: AttributeSet?) :
|
||||||
|
CoordinatorLayout.Behavior<TextView>(context, attrs) {
|
||||||
|
private val mContext: Context = context
|
||||||
|
|
||||||
|
private val marginTop: Float
|
||||||
|
private val marginTopAfter: Float
|
||||||
|
|
||||||
|
private val getYMax: Float =
|
||||||
|
context.getResources().getDimension(R.dimen.appbar_height) - context.getResources()
|
||||||
|
.getDimension(R.dimen.toolbar_height)
|
||||||
|
|
||||||
|
init {
|
||||||
|
marginTop = dpToPx(getYMax / 4)
|
||||||
|
marginTopAfter = dpToPx(getYMax / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun layoutDependsOn(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: TextView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
return dependency is AppBarLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dependency 의 View 의 변화가 있을때 이벤트가 들어옵니다.
|
||||||
|
*/
|
||||||
|
override fun onDependentViewChanged(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: TextView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
child.alpha = getRatioValue(
|
||||||
|
1f, 0f,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
child.alpha = getRatioValue(
|
||||||
|
1f, 0f,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
child.x = (dependency.width / 2 - (child.width / 2)).toFloat()
|
||||||
|
|
||||||
|
child.y = getRatioValue(
|
||||||
|
marginTop, marginTopAfter,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dpToPx(dp: Float): Float {
|
||||||
|
val dm: DisplayMetrics = mContext.getResources().getDisplayMetrics()
|
||||||
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, dm).toInt()
|
||||||
|
.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRatioValue(
|
||||||
|
firstValue: Float,
|
||||||
|
lastValue: Float,
|
||||||
|
getY: Float,
|
||||||
|
getYMax: Float
|
||||||
|
): Float {
|
||||||
|
val temp = -(firstValue - lastValue) * getY / getYMax
|
||||||
|
return firstValue + temp
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.behaviorimpl
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
|
class BehaviorRecT(context: Context, attrs: AttributeSet?) :
|
||||||
|
CoordinatorLayout.Behavior<RecyclerView>(context, attrs) {
|
||||||
|
private val mContext: Context = context
|
||||||
|
|
||||||
|
private val marginTop: Float
|
||||||
|
private val marginTopAfter: Float
|
||||||
|
|
||||||
|
private val getYMax: Float =
|
||||||
|
context.getResources().getDimension(R.dimen.appbar_height) - context.getResources()
|
||||||
|
.getDimension(R.dimen.toolbar_height)
|
||||||
|
|
||||||
|
init {
|
||||||
|
marginTop = dpToPx(getYMax / 4)
|
||||||
|
marginTopAfter = dpToPx(getYMax / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun layoutDependsOn(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: RecyclerView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
return dependency is AppBarLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dependency 의 View 의 변화가 있을때 이벤트가 들어옵니다.
|
||||||
|
*/
|
||||||
|
override fun onDependentViewChanged(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: RecyclerView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
child.alpha = getRatioValue(
|
||||||
|
1f, 0f,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
child.alpha = getRatioValue(
|
||||||
|
1f, 0f,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
child.x = (dependency.width / 2 - (child.width / 2)).toFloat()
|
||||||
|
|
||||||
|
child.y = getRatioValue(
|
||||||
|
marginTop, marginTopAfter,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dpToPx(dp: Float): Float {
|
||||||
|
val dm: DisplayMetrics = mContext.getResources().getDisplayMetrics()
|
||||||
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, dm).toInt()
|
||||||
|
.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRatioValue(
|
||||||
|
firstValue: Float,
|
||||||
|
lastValue: Float,
|
||||||
|
getY: Float,
|
||||||
|
getYMax: Float
|
||||||
|
): Float {
|
||||||
|
val temp = -(firstValue - lastValue) * getY / getYMax
|
||||||
|
return firstValue + temp
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.behaviorimpl
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
|
class BehaviorTistory(context: Context, attrs: AttributeSet?) :
|
||||||
|
CoordinatorLayout.Behavior<TextView>(context, attrs) {
|
||||||
|
private val mContext: Context = context
|
||||||
|
|
||||||
|
private val marginLeft: Float
|
||||||
|
private val marginTop: Float
|
||||||
|
private val marginTopAfter: Float
|
||||||
|
|
||||||
|
private val getYMax: Float =
|
||||||
|
context.getResources().getDimension(R.dimen.appbar_height) - context.getResources()
|
||||||
|
.getDimension(R.dimen.toolbar_height)
|
||||||
|
|
||||||
|
init {
|
||||||
|
marginLeft = dpToPx(70f)
|
||||||
|
marginTop = dpToPx(70f)
|
||||||
|
marginTopAfter = dpToPx(53f)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun layoutDependsOn(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: TextView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
return dependency is AppBarLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dependency 의 View 의 변화가 있을때 이벤트가 들어옵니다.
|
||||||
|
*/
|
||||||
|
override fun onDependentViewChanged(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: TextView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
child.scaleX = getRatioValue(
|
||||||
|
1f, 0.8f,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
child.x = getRatioValue(
|
||||||
|
marginLeft, ((dependency.width - child.width) / 2).toFloat(),
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
child.y = getRatioValue(
|
||||||
|
marginTop, marginTopAfter,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dpToPx(dp: Float): Float {
|
||||||
|
val dm: DisplayMetrics = mContext.getResources().getDisplayMetrics()
|
||||||
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, dm).toInt()
|
||||||
|
.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRatioValue(
|
||||||
|
firstValue: Float,
|
||||||
|
lastValue: Float,
|
||||||
|
getY: Float,
|
||||||
|
getYMax: Float
|
||||||
|
): Float {
|
||||||
|
val temp = -(firstValue - lastValue) * getY / getYMax
|
||||||
|
return firstValue + temp
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.behaviorimpl
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
|
class BehaviorTopBall(context: Context, attrs: AttributeSet?) :
|
||||||
|
CoordinatorLayout.Behavior<ImageView>(context, attrs) {
|
||||||
|
private val mContext: Context = context
|
||||||
|
|
||||||
|
private val iconMarginLeft: Float
|
||||||
|
private val iconMarginTop: Float
|
||||||
|
private val iconMarginTopAfter: Float
|
||||||
|
|
||||||
|
private val getYMax: Float =
|
||||||
|
context.getResources().getDimension(R.dimen.appbar_height) - context.getResources()
|
||||||
|
.getDimension(R.dimen.toolbar_height)
|
||||||
|
|
||||||
|
init {
|
||||||
|
iconMarginLeft = dpToPx(30f)
|
||||||
|
iconMarginTop = dpToPx(72f)
|
||||||
|
iconMarginTopAfter = dpToPx(20f)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun layoutDependsOn(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: ImageView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
return dependency is AppBarLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dependency 의 View 의 변화가 있을때 이벤트가 들어옵니다.
|
||||||
|
*/
|
||||||
|
override fun onDependentViewChanged(
|
||||||
|
@NonNull parent: CoordinatorLayout,
|
||||||
|
@NonNull child: ImageView,
|
||||||
|
@NonNull dependency: View
|
||||||
|
): Boolean {
|
||||||
|
// child icon scale [1 , 0.8]
|
||||||
|
|
||||||
|
child.scaleX = getRatioValue(
|
||||||
|
1f, 0.8f,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
child.scaleY = getRatioValue(
|
||||||
|
1f, 0.8f,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
// child icon set x [iconMarginLeft , (dependency.getWidth() - child.getWidth())/2]
|
||||||
|
child.x = getRatioValue(
|
||||||
|
iconMarginLeft, ((dependency.width - child.width) / 2).toFloat(),
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
// child icon set y [iconMarginTop, iconMarginTopAfter]
|
||||||
|
child.y = getRatioValue(
|
||||||
|
iconMarginTop, iconMarginTopAfter,
|
||||||
|
abs(dependency.y.toDouble()).toFloat(), getYMax
|
||||||
|
)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dpToPx(dp: Float): Float {
|
||||||
|
val dm: DisplayMetrics = mContext.getResources().getDisplayMetrics()
|
||||||
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, dm).toInt()
|
||||||
|
.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRatioValue(
|
||||||
|
firstValue: Float,
|
||||||
|
lastValue: Float,
|
||||||
|
getY: Float,
|
||||||
|
getYMax: Float
|
||||||
|
): Float {
|
||||||
|
val temp = -(firstValue - lastValue) * getY / getYMax
|
||||||
|
return firstValue + temp
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.calendar
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
|
||||||
|
|
||||||
|
interface CalendarAdapter {
|
||||||
|
fun getView(convertView: View?, parentView: ViewGroup?, bean: CalendarBean?): View
|
||||||
|
// fun hasChildView() : Boolean
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//package bums.lunatic.launcher.behavior.calendar;
|
||||||
|
//
|
||||||
|
//public class CalendarBean {
|
||||||
|
// public int year;
|
||||||
|
// public int month;
|
||||||
|
// public int day;
|
||||||
|
// public int week;
|
||||||
|
//
|
||||||
|
// //-1,0,1
|
||||||
|
// public int monthFlag;
|
||||||
|
//
|
||||||
|
// //显示
|
||||||
|
//
|
||||||
|
// public CalendarBean(int year, int month, int day) {
|
||||||
|
// this.year = year;
|
||||||
|
// this.month = month;
|
||||||
|
// this.day = day;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public String getDisplayWeek(){
|
||||||
|
// String s="";
|
||||||
|
// switch(week){
|
||||||
|
// case 1:
|
||||||
|
// s="星期日";
|
||||||
|
// break;
|
||||||
|
// case 2:
|
||||||
|
// s="星期一";
|
||||||
|
// break;
|
||||||
|
// case 3:
|
||||||
|
// s="星期二";
|
||||||
|
// break;
|
||||||
|
// case 4:
|
||||||
|
// s="星期三";
|
||||||
|
// break;
|
||||||
|
// case 5:
|
||||||
|
// s="星期四";
|
||||||
|
// break;
|
||||||
|
// case 6:
|
||||||
|
// s="星期五";
|
||||||
|
// break;
|
||||||
|
// case 7:
|
||||||
|
// s="星期六";
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// return s ;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String toString() {
|
||||||
|
// String s=year+"/"+month+"/"+day;
|
||||||
|
// return s;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.calendar
|
||||||
|
|
||||||
|
class CalendarBean //显示
|
||||||
|
(var year: Int, var month: Int, var day: Int) {
|
||||||
|
var week: Int = 0
|
||||||
|
|
||||||
|
//-1,0,1
|
||||||
|
var monthFlag: Int = 0
|
||||||
|
|
||||||
|
val displayWeek: String
|
||||||
|
get() {
|
||||||
|
var s = ""
|
||||||
|
when (week) {
|
||||||
|
1 -> s = "星期日"
|
||||||
|
2 -> s = "星期一"
|
||||||
|
3 -> s = "星期二"
|
||||||
|
4 -> s = "星期三"
|
||||||
|
5 -> s = "星期四"
|
||||||
|
6 -> s = "星期五"
|
||||||
|
7 -> s = "星期六"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val s = "$year/$month/$day"
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.calendar
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.viewpager.widget.PagerAdapter
|
||||||
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarFactory.getMonthOfDayList
|
||||||
|
import com.example.accountbook.calendar.CalendarTopView
|
||||||
|
import com.example.accountbook.calendar.CalendarTopViewChangeListener
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.LinkedList
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarDateView(context: Context, attrs: AttributeSet?):
|
||||||
|
ViewPager(context, attrs), CalendarTopView {
|
||||||
|
var views = HashMap<Int, CalendarView>()
|
||||||
|
private var mCaledarLayoutChangeListener: CalendarTopViewChangeListener? = null
|
||||||
|
private var onItemClickListener: CalendarView.OnItemClickListener? = null
|
||||||
|
private val cache: LinkedList<CalendarView?> = LinkedList<CalendarView?>()
|
||||||
|
private val MAXCOUNT = 6
|
||||||
|
private var row = 6
|
||||||
|
|
||||||
|
fun setCalrow(row : Int) {
|
||||||
|
this.row = row
|
||||||
|
}
|
||||||
|
private var mAdapter: CalendarAdapter? = null
|
||||||
|
override var itemHeight = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
|
||||||
|
fun setAdapter(adapter: CalendarAdapter?) {
|
||||||
|
mAdapter = adapter
|
||||||
|
initialize()
|
||||||
|
initData()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun reload() {
|
||||||
|
Log.i(this@CalendarDateView.javaClass.simpleName , "reload()")
|
||||||
|
sss.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnItemClickListener(onItemClickListener: CalendarView.OnItemClickListener?) {
|
||||||
|
this.onItemClickListener = onItemClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val a = context.obtainStyledAttributes(attrs, R.styleable.CalendarDateView)
|
||||||
|
row = a.getInteger(R.styleable.CalendarDateView_cbd_calendar_row, 6)
|
||||||
|
a.recycle()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||||
|
// var calendarHeight = 0
|
||||||
|
if (adapter != null) {
|
||||||
|
(getChildAt(0) as CalendarView)?.let {
|
||||||
|
// calendarHeight = it.measuredHeight
|
||||||
|
itemHeight = it.itemHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setMeasuredDimension(
|
||||||
|
widthMeasureSpec,
|
||||||
|
MeasureSpec.makeMeasureSpec(heightMeasureSpec, MeasureSpec.EXACTLY)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val dateArr: IntArray = CalendarUtil.getYMD(Date())
|
||||||
|
var sss = object : PagerAdapter() {
|
||||||
|
override fun getCount(): Int {
|
||||||
|
// Log.i(this@CalendarDateView::class.java.simpleName, "container >>> setAdapter getCount")
|
||||||
|
return Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isViewFromObject(view: View, `object`: Any): Boolean {
|
||||||
|
return view === `object`
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun instantiateItem(container: ViewGroup, position: Int): Any {
|
||||||
|
|
||||||
|
Log.i(this@CalendarDateView::class.java.simpleName, "container >>> ${container} position >> ${position}")
|
||||||
|
val view: CalendarView = if (!cache.isEmpty()) {
|
||||||
|
cache.removeFirst()!!
|
||||||
|
} else {
|
||||||
|
CalendarView(container.context, row)
|
||||||
|
}
|
||||||
|
view.setOnItemClickListener(onItemClickListener)
|
||||||
|
view.setAdapter(mAdapter)
|
||||||
|
|
||||||
|
container.addView(view)
|
||||||
|
views[position] = view
|
||||||
|
view.apply {
|
||||||
|
setData(
|
||||||
|
getMonthOfDayList(
|
||||||
|
dateArr[0],
|
||||||
|
dateArr[1] + position - Int.MAX_VALUE / 2
|
||||||
|
), position == Int.MAX_VALUE / 2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
|
||||||
|
Log.i(this@CalendarDateView.javaClass.simpleName , "destroyItem >>> position ${position}")
|
||||||
|
container.removeView(`object` as View)
|
||||||
|
cache.addLast(`object` as CalendarView)
|
||||||
|
views.remove(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initialize() {
|
||||||
|
setAdapter(sss)
|
||||||
|
addOnPageChangeListener(object: SimpleOnPageChangeListener() {
|
||||||
|
override fun onPageSelected(position: Int) {
|
||||||
|
super.onPageSelected(position)
|
||||||
|
onItemClickListener?.let{
|
||||||
|
views[position]?.let {v ->
|
||||||
|
val obs: Array<Any> = v.select
|
||||||
|
it.onItemClick(
|
||||||
|
obs[0] as View,
|
||||||
|
obs[1] as Int,
|
||||||
|
obs[2] as CalendarBean
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCaledarLayoutChangeListener?.onLayoutChange(this@CalendarDateView)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initData() {
|
||||||
|
setCurrentItem(Int.MAX_VALUE / 2, false)
|
||||||
|
adapter!!.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val currentSelectPositon: IntArray
|
||||||
|
get() {
|
||||||
|
var view = views[currentItem]
|
||||||
|
if (view == null) {
|
||||||
|
view = getChildAt(0) as? CalendarView
|
||||||
|
}
|
||||||
|
return view?.getSelectPosition() ?: IntArray(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCalendarTopViewChangeListener(listener: CalendarTopViewChangeListener?) {
|
||||||
|
mCaledarLayoutChangeListener = listener
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.calendar
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarUtil.getDayOfWeek
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
|
||||||
|
object CalendarFactory {
|
||||||
|
private val cache = HashMap<String, List<CalendarBean>>()
|
||||||
|
|
||||||
|
fun getMonthOfDayList(y: Int, m: Int): List<CalendarBean> {
|
||||||
|
Log.e("TIME CHECK" , "fun getMonthOfDayList Start")
|
||||||
|
val key = y.toString() + "" + m
|
||||||
|
if (cache.containsKey(key)) {
|
||||||
|
val list = cache[key]
|
||||||
|
if (list == null) {
|
||||||
|
cache.remove(key)
|
||||||
|
} else {
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val list: MutableList<CalendarBean> = ArrayList()
|
||||||
|
cache[key] = list
|
||||||
|
|
||||||
|
val fweek: Int = getDayOfWeek(y, m, 1)
|
||||||
|
val total: Int = CalendarUtil.getDayOfMaonth(y, m)
|
||||||
|
|
||||||
|
for (i in fweek - 1 downTo 1) {
|
||||||
|
val bean = getCalendarBean(y, m, 1 - i)
|
||||||
|
bean.monthFlag = -1
|
||||||
|
list.add(bean)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0 until total) {
|
||||||
|
val bean = getCalendarBean(y, m, i + 1)
|
||||||
|
list.add(bean)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0 until 42 - (fweek - 1) - total) {
|
||||||
|
val bean = getCalendarBean(y, m, total + i + 1)
|
||||||
|
bean.monthFlag = 1
|
||||||
|
list.add(bean)
|
||||||
|
}
|
||||||
|
Log.e("TIME CHECK" , "fun getMonthOfDayList END")
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCalendarBean(year: Int, month: Int, day: Int): CalendarBean {
|
||||||
|
|
||||||
|
val calendar: Calendar = Calendar.getInstance()
|
||||||
|
.apply { this.set(year, month - 1, day) }
|
||||||
|
val year = calendar.get(Calendar.YEAR)
|
||||||
|
val month = calendar.get(Calendar.MONTH) + 1
|
||||||
|
val day = calendar.get(Calendar.DATE)
|
||||||
|
val bean = CalendarBean(year, month, day)
|
||||||
|
bean.week = CalendarUtil.getDayOfWeek(year, month, day)
|
||||||
|
// val chinaDate: Array<String> = ChinaDate.getChinaDate(year, month, day)
|
||||||
|
// bean.chinaMonth = chinaDate[0]
|
||||||
|
// bean.chinaDay = chinaDate[1]
|
||||||
|
return bean
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.example.accountbook.calendar
|
||||||
|
|
||||||
|
|
||||||
|
interface CalendarTopView {
|
||||||
|
val currentSelectPositon: IntArray?
|
||||||
|
val itemHeight: Int
|
||||||
|
|
||||||
|
fun setCalendarTopViewChangeListener(listener: CalendarTopViewChangeListener?)
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package com.example.accountbook.calendar
|
||||||
|
|
||||||
|
interface CalendarTopViewChangeListener {
|
||||||
|
fun onLayoutChange(topView: CalendarTopView) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.calendar
|
||||||
|
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
|
||||||
|
object CalendarUtil {
|
||||||
|
fun getDayOfWeek(y: Int, m: Int, day: Int): Int {
|
||||||
|
val calendar: Calendar = Calendar.getInstance()
|
||||||
|
calendar.set(y, m - 1, day)
|
||||||
|
return calendar.get(Calendar.DAY_OF_WEEK)
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取一月最大天数
|
||||||
|
fun getDayOfMaonth(y: Int, m: Int): Int {
|
||||||
|
val cal: Calendar = Calendar.getInstance()
|
||||||
|
cal.set(y, m - 1, 1)
|
||||||
|
return cal.getActualMaximum(Calendar.DATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMothOfMonth(y: Int, m: Int): Int {
|
||||||
|
val cal: Calendar = Calendar.getInstance()
|
||||||
|
cal.set(y, m - 1, 1)
|
||||||
|
val dateOfMonth: Int = cal.get(Calendar.MONTH)
|
||||||
|
return dateOfMonth + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getYMD(date: Date?): IntArray {
|
||||||
|
val cal: Calendar = Calendar.getInstance()
|
||||||
|
date?.let { cal.setTime(it) }
|
||||||
|
return intArrayOf(
|
||||||
|
cal.get(Calendar.YEAR),
|
||||||
|
cal.get(Calendar.MONTH) + 1,
|
||||||
|
cal.get(Calendar.DATE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
package bums.lunatic.launcher.behavior.calendar
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import bums.lunatic.launcher.behavior.calendar.CalendarUtil.getYMD
|
||||||
|
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarView : ViewGroup {
|
||||||
|
private var selectPosition = -1
|
||||||
|
private var adapter: CalendarAdapter? = null
|
||||||
|
private var data: List<CalendarBean>? = null
|
||||||
|
private var onItemClickListener: OnItemClickListener? = null
|
||||||
|
private var row = 6
|
||||||
|
private val column = 7
|
||||||
|
private var itemWidth = 0
|
||||||
|
var itemHeight = 0
|
||||||
|
private set
|
||||||
|
private var isToday = false
|
||||||
|
|
||||||
|
interface OnItemClickListener {
|
||||||
|
fun onItemClick(view: View?, position: Int, bean: CalendarBean?)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context?, row: Int) : super(context) {
|
||||||
|
this.row = row
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnItemClickListener(onItemClickListener: OnItemClickListener?) {
|
||||||
|
this.onItemClickListener = onItemClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
|
||||||
|
setWillNotDraw(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAdapter(adapter: CalendarAdapter?) {
|
||||||
|
this.adapter = adapter
|
||||||
|
}
|
||||||
|
fun setCalrow(row : Int) {
|
||||||
|
if (this.row != row) {
|
||||||
|
this.row = row
|
||||||
|
removeAllViews()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun setData(data: List<CalendarBean>?, isToday: Boolean) {
|
||||||
|
this.data = data
|
||||||
|
this.isToday = isToday
|
||||||
|
setItem()
|
||||||
|
requestLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setItem() {
|
||||||
|
selectPosition = -1
|
||||||
|
if (adapter == null) {
|
||||||
|
throw RuntimeException("adapter is null,please setadapter")
|
||||||
|
}
|
||||||
|
Log.i("data >>> ","data ${data}")
|
||||||
|
for (i in data!!.indices) {
|
||||||
|
val bean = data!![i]
|
||||||
|
val chidView: View? = adapter?.getView(
|
||||||
|
getChildAt(i).also { v -> Log.i("data >>> ", "view $v") },
|
||||||
|
this,
|
||||||
|
bean
|
||||||
|
).also { v -> Log.i("data >>> ", "chidView $v") }
|
||||||
|
if (chidView != null && chidView != getChildAt(i)) {
|
||||||
|
addViewInLayout(chidView, i, chidView.layoutParams, true)
|
||||||
|
}
|
||||||
|
if (isToday && selectPosition == -1) {
|
||||||
|
val date = getYMD(Date())
|
||||||
|
if (bean.year == date[0] && bean.month == date[1] && bean.day == date[2]) {
|
||||||
|
selectPosition = i
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (selectPosition == -1 && bean.day == 1) {
|
||||||
|
selectPosition = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chidView?.isSelected = selectPosition == i
|
||||||
|
setItemClick(chidView, i, bean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val select: Array<Any>
|
||||||
|
get() = arrayOf(
|
||||||
|
getChildAt(selectPosition), selectPosition,
|
||||||
|
data!![selectPosition]
|
||||||
|
)
|
||||||
|
|
||||||
|
fun setItemClick(view: View?, potsion: Int, bean: CalendarBean?) {
|
||||||
|
view?.setOnClickListener {
|
||||||
|
if (selectPosition != -1) {
|
||||||
|
getChildAt(selectPosition).isSelected = false
|
||||||
|
getChildAt(potsion).isSelected = true
|
||||||
|
}
|
||||||
|
selectPosition = potsion
|
||||||
|
if (onItemClickListener != null) {
|
||||||
|
onItemClickListener!!.onItemClick(view, potsion, bean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSelectPosition(): IntArray {
|
||||||
|
val rect = Rect()
|
||||||
|
try {
|
||||||
|
getChildAt(selectPosition).getHitRect(rect)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return intArrayOf(rect.left, rect.top, rect.right, rect.top)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var lastwidthMeasureSpec = 0
|
||||||
|
var lastheightMeasureSpec = 0
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||||
|
Log.e(this.javaClass::class.java.simpleName , "this count check ${this}")
|
||||||
|
if (widthMeasureSpec != lastwidthMeasureSpec || heightMeasureSpec != lastheightMeasureSpec) {
|
||||||
|
val parentWidth =
|
||||||
|
MeasureSpec.getSize(
|
||||||
|
MeasureSpec.makeMeasureSpec(
|
||||||
|
widthMeasureSpec,
|
||||||
|
MeasureSpec.EXACTLY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val parentH =
|
||||||
|
MeasureSpec.getSize(
|
||||||
|
MeasureSpec.makeMeasureSpec(
|
||||||
|
heightMeasureSpec,
|
||||||
|
MeasureSpec.EXACTLY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
itemWidth = parentWidth / column
|
||||||
|
itemHeight = parentH / row
|
||||||
|
// itemWidth
|
||||||
|
val view = getChildAt(0) ?: return
|
||||||
|
val params = view.layoutParams
|
||||||
|
if (params != null && params.height > 0) {
|
||||||
|
itemHeight = params.height
|
||||||
|
}
|
||||||
|
setMeasuredDimension(parentWidth, itemHeight * row)
|
||||||
|
if (childCount.equals(row*column))
|
||||||
|
for (i in 0 until childCount) {
|
||||||
|
val childView = getChildAt(i)
|
||||||
|
childView.measure(
|
||||||
|
MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY),
|
||||||
|
MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i(
|
||||||
|
TAG,
|
||||||
|
"onMeasure() called with: itemHeight = [$itemHeight], itemWidth = [$itemWidth]"
|
||||||
|
)
|
||||||
|
lastwidthMeasureSpec = widthMeasureSpec
|
||||||
|
lastheightMeasureSpec = heightMeasureSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
||||||
|
if (changed && childCount.equals(row*column))
|
||||||
|
for (i in 0 until childCount) {
|
||||||
|
layoutChild(getChildAt(i), i, l, t, r, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addViewInLayout(
|
||||||
|
child: View?,
|
||||||
|
index: Int,
|
||||||
|
params: LayoutParams?,
|
||||||
|
preventRequestLayout: Boolean
|
||||||
|
): Boolean {
|
||||||
|
Log.d("CalendarView, time","time")
|
||||||
|
return super.addViewInLayout(child, index, params, preventRequestLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun layoutChild(view: View, position: Int, l: Int, t: Int, r: Int, b: Int) {
|
||||||
|
var l = l
|
||||||
|
var t = t
|
||||||
|
var r = r
|
||||||
|
var b = b
|
||||||
|
val cc = position % column
|
||||||
|
val cr = position / column
|
||||||
|
val itemWidth = view.measuredWidth
|
||||||
|
val itemHeight = view.measuredHeight
|
||||||
|
l = cc * itemWidth
|
||||||
|
t = cr * itemHeight
|
||||||
|
r = l + itemWidth
|
||||||
|
b = t + itemHeight
|
||||||
|
view.layout(l, t, r, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "CalendarView"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package bums.lunatic.launcher.common
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Environment
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.app.ComponentActivity
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.apps.SearchMenu
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.LocationUpdateService
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.io.OutputStreamWriter
|
||||||
|
import java.util.Base64
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
|
abstract class CommonActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
fun openSearchMenus(keyword : String, dismissCalback: DismissCalback) {
|
||||||
|
SearchMenu().show(supportFragmentManager,keyword) {dismissCalback.invoke()}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateLocationService() {
|
||||||
|
PrefBoolean.location.get().letTrue {
|
||||||
|
startService(Intent(this, LocationUpdateService::class.java))
|
||||||
|
}
|
||||||
|
if (PrefBoolean.location.get() == false) {
|
||||||
|
stopService(Intent(this, LocationUpdateService::class.java))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun saveObjToJson(path : File, targetFileName : String, targetObj : Any) {
|
||||||
|
val fileName = "prefSettings.stng"
|
||||||
|
val path = File(Environment.getExternalStorageDirectory(),"bums")
|
||||||
|
if (path.exists() == false) {
|
||||||
|
path.mkdirs()
|
||||||
|
}
|
||||||
|
val file = File(path, targetFileName)
|
||||||
|
Blog.LOGE("saveObjToJson [${path.absolutePath}]targetFileName[${targetFileName}] data >>>> ${Gson().toJson(targetObj)}")
|
||||||
|
writeToFile(String(Base64.getEncoder().encode(Gson().toJson(targetObj).toByteArray())),file)
|
||||||
|
Blog.LOGE("saveObjToJson [${path.absolutePath}]targetFileName[${targetFileName}].length >>>> ${file.length()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun writeToFile(data: String, file : File) {
|
||||||
|
try {
|
||||||
|
val outputStreamWriter =
|
||||||
|
OutputStreamWriter(FileOutputStream(file))
|
||||||
|
outputStreamWriter.write(data)
|
||||||
|
outputStreamWriter.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Blog.LOGE("Exception", "File write failed: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun readMap(file : File) : HashMap<String, Any> {
|
||||||
|
var result = HashMap<String, Any>()
|
||||||
|
readFromFile(file).let { base64String ->
|
||||||
|
String(Base64.getMimeDecoder().decode(base64String.toByteArray()))?.let { jsonString ->
|
||||||
|
Blog.LOGE("jsonString >>>> ${jsonString }")
|
||||||
|
result = Gson().fromJson(
|
||||||
|
jsonString, object : TypeToken<HashMap<String?, Any?>?>() {}.type
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun decodeString(file : File) : String {
|
||||||
|
var result = ""
|
||||||
|
readFromFile(file).let { base64String ->
|
||||||
|
String(Base64.getMimeDecoder().decode(base64String.toByteArray()))?.let { jsonString ->
|
||||||
|
result = jsonString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun readFromFile(file : File): String {
|
||||||
|
var ret = ""
|
||||||
|
try {
|
||||||
|
val inputStream: InputStream? = FileInputStream(file)
|
||||||
|
if (inputStream != null) {
|
||||||
|
val inputStreamReader = InputStreamReader(inputStream)
|
||||||
|
val bufferedReader = BufferedReader(inputStreamReader)
|
||||||
|
var receiveString: String? = ""
|
||||||
|
val stringBuilder = StringBuilder()
|
||||||
|
while ((bufferedReader.readLine().also { receiveString = it }) != null) { stringBuilder.append("\n").append(receiveString) }
|
||||||
|
inputStream.close()
|
||||||
|
ret = stringBuilder.toString()
|
||||||
|
}
|
||||||
|
} catch (e: FileNotFoundException) {
|
||||||
|
Blog.LOGE("login activity", "File not found: $e")
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Blog.LOGE("login activity", "Can not read file: $e")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package bums.lunatic.launcher.common
|
||||||
|
|
||||||
|
|
||||||
|
typealias DismissCalback = ()->Unit
|
||||||
|
typealias BLOCK = ()->Unit
|
||||||
|
|
||||||
|
inline fun Boolean.letTrue(block: BLOCK) {
|
||||||
|
if (this) {
|
||||||
|
block.invoke()
|
||||||
|
} else {
|
||||||
|
// elseblock.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,776 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.feeds
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.speech.RecognitionListener
|
||||||
|
import android.speech.RecognizerIntent
|
||||||
|
import android.speech.SpeechRecognizer
|
||||||
|
import android.text.method.ScrollingMovementMethod
|
||||||
|
import android.view.ContextMenu
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.EditText
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import bums.lunatic.launcher.CommadCallabck
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.getCal
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.refreshDeviceData
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.refreshFeeds
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.common.CommonActivity
|
||||||
|
import bums.lunatic.launcher.databinding.FeedsBinding
|
||||||
|
import bums.lunatic.launcher.feeds.rss.RssAdapter
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_WIDGET_HEIGHTS
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_WIDGET_IDS
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_WIDGETS
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.SEPARATOR
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefString
|
||||||
|
import bums.lunatic.launcher.home.LauncherHome.Companion.home
|
||||||
|
import bums.lunatic.launcher.model.CiliMagnet
|
||||||
|
import bums.lunatic.launcher.model.RssData
|
||||||
|
import bums.lunatic.launcher.model.RssDataInterface
|
||||||
|
import bums.lunatic.launcher.model.RssDataType
|
||||||
|
import bums.lunatic.launcher.model.jGuruTag
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.utils.FeedParseManager
|
||||||
|
import bums.lunatic.launcher.utils.getJ
|
||||||
|
import bums.lunatic.launcher.workers.RecentCallGetter
|
||||||
|
import bums.lunatic.launcher.workers.RecentSmsGetter
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
import io.realm.kotlin.query.Sort
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.Base64
|
||||||
|
|
||||||
|
|
||||||
|
internal class Feeds : CommonActivity() , CommadCallabck {
|
||||||
|
|
||||||
|
private lateinit var binding: FeedsBinding
|
||||||
|
private val requestCodeString = "requestCode"
|
||||||
|
var mRssAdapter : RssAdapter<RssDataInterface>? = null
|
||||||
|
var mRssAdapter2 : RssAdapter<jGuruTag>? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = FeedsBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
mRssAdapter = RssAdapter(this)
|
||||||
|
mRssAdapter2 = RssAdapter(this)
|
||||||
|
binding.feedsRss.rss.adapter = mRssAdapter
|
||||||
|
binding.feedsRss.rss2.adapter = mRssAdapter2
|
||||||
|
binding.consoleLog.movementMethod = ScrollingMovementMethod();
|
||||||
|
// updateWidgets()
|
||||||
|
expandCollapse()
|
||||||
|
systemInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
registerForContextMenu(binding.widgetContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
unregisterForContextMenu(binding.widgetContainer)
|
||||||
|
if (binding.expandRss.isChecked)
|
||||||
|
binding.expandRss.isChecked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
|
||||||
|
super.onCreateContextMenu(menu, v, menuInfo)
|
||||||
|
menu.clearHeader()
|
||||||
|
menuInflater.inflate(R.menu.add_widget, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// override fun onContextItemSelected(item: MenuItem): Boolean {
|
||||||
|
// if (item.itemId == R.id.add_widget) selectWidget()
|
||||||
|
// return super.onContextItemSelected(item)
|
||||||
|
// }
|
||||||
|
|
||||||
|
/* control view's expand-collapse actions */
|
||||||
|
private fun expandCollapse() {
|
||||||
|
binding.expandableButtons.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean ->
|
||||||
|
if (isChecked) {
|
||||||
|
when (checkedId) {
|
||||||
|
binding.expandRss.id -> {
|
||||||
|
binding.feedsRss.rss.visibility = View.GONE
|
||||||
|
binding.feedsRss.rss2.visibility = View.GONE
|
||||||
|
binding.feedsSysInfos.expandableSystemInfo.collapse()
|
||||||
|
binding.feedsRss.expandableRss.expand()
|
||||||
|
startService()
|
||||||
|
}
|
||||||
|
binding.expandSystemInfo.id -> {
|
||||||
|
binding.feedsRss.expandableRss.collapse()
|
||||||
|
binding.feedsSysInfos.expandableSystemInfo.expand()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when (checkedId) {
|
||||||
|
binding.expandRss.id -> binding.feedsRss.expandableRss.collapse()
|
||||||
|
binding.expandSystemInfo.id -> binding.feedsSysInfos.expandableSystemInfo.collapse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun consoleLog(str : String) {
|
||||||
|
mMainHandler.removeCallbacks(hideConsole)
|
||||||
|
binding.consoleLog.post {
|
||||||
|
binding.consoleLog.visibility = View.VISIBLE
|
||||||
|
binding.consoleLog.text = binding.consoleLog.text.toString() + "\n" + str
|
||||||
|
}
|
||||||
|
mMainHandler.postDelayed(hideConsole,10000L)
|
||||||
|
Blog.LOGE("consoleLog >>>> ${str}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openOpera(schemeString : String) {
|
||||||
|
Blog.LOGE("openOpera ${schemeString}")
|
||||||
|
val gmmIntentUri = Uri.parse(schemeString)
|
||||||
|
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
||||||
|
mapIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
|
||||||
|
mapIntent.setPackage("com.opera.browser")
|
||||||
|
startActivity(mapIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConsoleLog(log: String) {
|
||||||
|
consoleLog(log)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val mMainHandler = Handler(Looper.getMainLooper())
|
||||||
|
val hideConsole = {
|
||||||
|
binding.consoleLog.visibility = View.GONE
|
||||||
|
binding.consoleLog.text = ""
|
||||||
|
}
|
||||||
|
override fun collectComplete() {
|
||||||
|
|
||||||
|
}
|
||||||
|
var speechRecognizer : SpeechRecognizer? = null
|
||||||
|
|
||||||
|
/* start rss service if network is active and rss url is not empty */
|
||||||
|
private fun startService() {
|
||||||
|
try {
|
||||||
|
System.gc()
|
||||||
|
}catch (e : Exception){e.printStackTrace()}
|
||||||
|
binding.feedsRss.rss.visibility = View.GONE
|
||||||
|
binding.feedsRss.rss2.visibility = View.GONE
|
||||||
|
binding.feedsRss.loading.visibility = View.VISIBLE
|
||||||
|
binding.feedsRss.refresh.visibility = View.VISIBLE
|
||||||
|
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
||||||
|
builder.setTitle("Command Line")
|
||||||
|
val viewInflated: View = LayoutInflater.from(this)
|
||||||
|
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
||||||
|
val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
||||||
|
builder.setView(viewInflated)
|
||||||
|
builder.setPositiveButton(android.R.string.ok,
|
||||||
|
DialogInterface.OnClickListener { dialog, which ->
|
||||||
|
dialog.dismiss()
|
||||||
|
consoleLog("input.text.toString() >>>> ${input.text.toString()}")
|
||||||
|
if (input.text.toString().trim().contains(" ")) {
|
||||||
|
val cmd = input.text.toString().trim().split(" ")
|
||||||
|
when(cmd[0]) {
|
||||||
|
"code"-> {
|
||||||
|
if (cmd[1].trim().length > 1) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
consoleLog("${cmd[0]} Start ${cmd[1]}")
|
||||||
|
String.format("https://glojav.us/search?q=",cmd[1]).getJ().let { doc -> FeedParseManager.parse(doc){consoleLog(it)} }
|
||||||
|
consoleLog("${cmd[0]} END ${cmd[1]}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"car" -> {
|
||||||
|
if (cmd[1].trim().length > 2) {
|
||||||
|
PrefString.carName.set(cmd[1].trim())
|
||||||
|
}
|
||||||
|
consoleLog(PrefString.carName.get())
|
||||||
|
}
|
||||||
|
"tt" -> {
|
||||||
|
if (cmd[1].trim().length > 5) {
|
||||||
|
PrefString.telegramSendTarget.set(cmd[1].trim())
|
||||||
|
}
|
||||||
|
consoleLog(PrefString.telegramSendTarget.get())
|
||||||
|
}
|
||||||
|
"so"-> {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
consoleLog("${cmd[0]} Start ${cmd[1]}")
|
||||||
|
String.format(String(Base64.getMimeDecoder().decode("aHR0cHM6Ly9rciVzLnNvZ2lybC5zby8=".toByteArray())),cmd[1]).getJ().let { doc -> FeedParseManager.parse(doc){consoleLog(it)} }
|
||||||
|
consoleLog("current j req() ${WorkersDb.getRealm().query<RssData>("category == $0", RssDataType.GURU.name).find().size}")
|
||||||
|
consoleLog("${cmd[0]} END ${cmd[1]}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"s" -> {
|
||||||
|
home?.queryInfos(keyword = cmd[1])
|
||||||
|
}
|
||||||
|
"jf" -> {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
consoleLog("${cmd[0]} Start ${cmd[1]}")
|
||||||
|
String(Base64.getMimeDecoder().decode("aHR0cHM6Ly9qYXZtb3N0LnRvL2xhdGVzdC11cGRhdGVzCg==".toByteArray())).getJ().let { doc -> FeedParseManager.parse(doc){consoleLog(it)} }
|
||||||
|
consoleLog("current j req() ${WorkersDb.getRealm().query<RssData>("category == $0", RssDataType.GURU.name).find().size}")
|
||||||
|
consoleLog("${cmd[0]} END ${cmd[1]}")
|
||||||
|
}
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
consoleLog("${cmd[0]} Start ${cmd[1]}")
|
||||||
|
String.format(String(Base64.getMimeDecoder().decode("aHR0cHM6Ly9qYXZtb3N0LnRvL3NlYXJjaC9tb3ZpZS8lcw==".toByteArray())),cmd[1]).getJ().let { doc -> FeedParseManager.parse(doc){consoleLog(it)} }
|
||||||
|
consoleLog("current j req() ${WorkersDb.getRealm().query<RssData>("category == $0", RssDataType.GURU.name).find().size}")
|
||||||
|
consoleLog("${cmd[0]} END ${cmd[1]}")
|
||||||
|
}
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
consoleLog("on Cmd JF with MOST")
|
||||||
|
consoleLog("${cmd[0]} Start ${cmd[1]}")
|
||||||
|
String.format(String(Base64.getMimeDecoder().decode("aHR0cHM6Ly9rcjcxLnNvZ2lybC5zby8/cz0lcw==".toByteArray())),cmd[1]).getJ().let { doc -> FeedParseManager.parse(doc){consoleLog(it)} }
|
||||||
|
consoleLog("current j req() ${WorkersDb.getRealm().query<RssData>("category == $0", RssDataType.MOST.name).find().size}")
|
||||||
|
consoleLog("${cmd[0]} END ${cmd[1]}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"mgn"-> {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
var temp = arrayListOf<CiliMagnet>()
|
||||||
|
consoleLog("this >>>> cili ${cmd[0]} -> ${cmd[1]}")
|
||||||
|
Jsoup.connect("https://cili.site/search?q=${URLEncoder.encode(cmd[1], Charset.defaultCharset().name())}").get().let { cili ->
|
||||||
|
consoleLog("this >>>> cili ${cili.title()}")
|
||||||
|
cili.getElementsByTag("tr").forEach { cili_tr ->
|
||||||
|
CiliMagnet().let { ciliMgn ->
|
||||||
|
ciliMgn.link = if(cili_tr.getElementsByTag("a").size > 0)cili_tr.getElementsByTag("a").get(0).attr("href") else ""
|
||||||
|
ciliMgn.title = if(cili_tr.getElementsByTag("p").size > 0)cili_tr.getElementsByTag("p").text() else ""
|
||||||
|
ciliMgn.size = if(cili_tr.getElementsByClass("td-size").size > 0)cili_tr.getElementsByClass("td-size").text() else ""
|
||||||
|
if(ciliMgn.isValid() && temp.size < 8 ) {
|
||||||
|
Jsoup.connect(ciliMgn.getMagnetPageLink()).get().let { mgn_Page ->
|
||||||
|
consoleLog("magnet_page >>> ${mgn_Page.title()}")
|
||||||
|
if (mgn_Page.getElementsByClass("input-group magnet-box").size > 0) {
|
||||||
|
mgn_Page.getElementsByClass("input-group magnet-box")
|
||||||
|
.get(0)?.let { magnet_box ->
|
||||||
|
magnet_box.getElementById(
|
||||||
|
"input-magnet"
|
||||||
|
)?.let { input_magnet ->
|
||||||
|
// BLog.LOGE("input_magnet >>> ${input_magnet}")
|
||||||
|
ciliMgn.magnetLink = input_magnet.attr("value").replace("&","&")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.apply {
|
||||||
|
temp.add(ciliMgn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}.apply {
|
||||||
|
temp.forEach {
|
||||||
|
consoleLog("ciliResult >>> ${Gson().toJson(it)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.expandRss.isChecked = false
|
||||||
|
} else {
|
||||||
|
when (input.text.toString()) {
|
||||||
|
"spe"->{
|
||||||
|
speechRecognizer?.stopListening()
|
||||||
|
speechRecognizer?.destroy()
|
||||||
|
speechRecognizer = null
|
||||||
|
}
|
||||||
|
"sps"->{
|
||||||
|
let { lActivity ->
|
||||||
|
if (lActivity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
lActivity.requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), 1)
|
||||||
|
} else {
|
||||||
|
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(lActivity)
|
||||||
|
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
|
||||||
|
intent.putExtra(
|
||||||
|
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
|
||||||
|
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
|
||||||
|
)
|
||||||
|
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
|
||||||
|
|
||||||
|
speechRecognizer?.setRecognitionListener(object : RecognitionListener {
|
||||||
|
override fun onReadyForSpeech(params: Bundle) {
|
||||||
|
consoleLog("onReadyForSpeech ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBeginningOfSpeech() {
|
||||||
|
consoleLog("onBeginningOfSpeech ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRmsChanged(rmsdB: Float) {}
|
||||||
|
|
||||||
|
override fun onBufferReceived(buffer: ByteArray) {}
|
||||||
|
|
||||||
|
override fun onEndOfSpeech() {
|
||||||
|
consoleLog("onEndOfSpeech ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(error: Int) {
|
||||||
|
consoleLog("onError ${error}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResults(results: Bundle) {
|
||||||
|
val matches =
|
||||||
|
results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
|
||||||
|
if (matches != null) {
|
||||||
|
val recognizedText = matches[0]
|
||||||
|
consoleLog("recognizedText ${recognizedText}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPartialResults(partialResults: Bundle) {
|
||||||
|
consoleLog("recognizedText ${partialResults}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEvent(eventType: Int, params: Bundle) {}
|
||||||
|
})
|
||||||
|
|
||||||
|
speechRecognizer?.startListening(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"citys" -> {
|
||||||
|
val baseUrl = "https://www.worldcitydb.com/"
|
||||||
|
var nations = arrayListOf<String>()
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
"https://www.worldcitydb.com/search-by-country?lang=ko".getJ().let { doc ->
|
||||||
|
Blog.LOGE("it.title() >> ${doc.title()}")
|
||||||
|
doc.getElementsByTag("tr").forEach { table ->
|
||||||
|
table.children().forEach {
|
||||||
|
it.getElementsByTag("td").forEach { td ->
|
||||||
|
td.children().forEach {
|
||||||
|
if (it.tag().name.equals("a")) {
|
||||||
|
Blog.LOGE("TD>>A ${it}")
|
||||||
|
it.text()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"loc_ck" -> {
|
||||||
|
FeedsResult().show(supportFragmentManager, "")
|
||||||
|
}
|
||||||
|
"loc_on" -> {
|
||||||
|
PrefBoolean.location.set(!PrefBoolean.location.get())
|
||||||
|
consoleLog("PrefHelper.isLocationOn() >>> ${PrefBoolean.location.get()}")
|
||||||
|
updateLocationService()
|
||||||
|
}
|
||||||
|
"cal" ->{
|
||||||
|
getCal()
|
||||||
|
}
|
||||||
|
"ojs" -> home?.queryInfos(arrayListOf<RssDataType>().apply {
|
||||||
|
addAll(RssDataType.values())
|
||||||
|
remove(RssDataType.GURU)
|
||||||
|
remove(RssDataType.MOST)
|
||||||
|
})
|
||||||
|
"all" -> home?.queryInfos(arrayListOf<RssDataType>().apply {
|
||||||
|
|
||||||
|
})
|
||||||
|
"onews" -> home?.queryInfos(arrayListOf<RssDataType>().apply {
|
||||||
|
addAll(RssDataType.values())
|
||||||
|
remove(RssDataType.NEWSFEED)
|
||||||
|
})
|
||||||
|
"ored" -> home?.queryInfos(arrayListOf<RssDataType>().apply {
|
||||||
|
addAll(RssDataType.values())
|
||||||
|
remove(RssDataType.REDDIT)
|
||||||
|
})
|
||||||
|
"req" -> {
|
||||||
|
refreshFeeds()
|
||||||
|
refreshDeviceData()
|
||||||
|
consoleLog("excute refreshFeeds()")
|
||||||
|
}
|
||||||
|
"reqmax" -> {
|
||||||
|
refreshFeeds()
|
||||||
|
RecentCallGetter.dayRange = 365
|
||||||
|
RecentSmsGetter.dayRange = 365
|
||||||
|
refreshDeviceData()
|
||||||
|
consoleLog("excute refreshFeeds()")
|
||||||
|
}
|
||||||
|
|
||||||
|
"taxi" -> {
|
||||||
|
consoleLog("before run State home?.binding?.alcholKatalkT?.isVisible >> ${home?.binding?.alcholKatalkT?.isVisible}")
|
||||||
|
home?.showAl()
|
||||||
|
consoleLog("after run State home?.binding?.alcholKatalkT?.isVisible >> ${home?.binding?.alcholKatalkT?.isVisible}")
|
||||||
|
}
|
||||||
|
|
||||||
|
"tax" -> {
|
||||||
|
consoleLog("before run State home?.binding?.alcholKatalkT?.isVisible >> ${home?.binding?.alcholKatalkT?.isVisible}")
|
||||||
|
home?.hideAl()
|
||||||
|
consoleLog("after run State home?.binding?.alcholKatalkT?.isVisible >> ${home?.binding?.alcholKatalkT?.isVisible}")
|
||||||
|
}
|
||||||
|
|
||||||
|
"jshow" -> {
|
||||||
|
binding.feedsRss.apply {
|
||||||
|
rss.adapter = mRssAdapter
|
||||||
|
loading.visibility = View.VISIBLE
|
||||||
|
mRssAdapter?.updateData(WorkersDb.getRealm()
|
||||||
|
.query<RssData>("category == $0 || category == $1", RssDataType.GURU.name, RssDataType.MOST.name)
|
||||||
|
.sort("pubDate", Sort.DESCENDING).find())
|
||||||
|
rss.visibility = View.VISIBLE
|
||||||
|
loading.visibility = View.GONE
|
||||||
|
refresh.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"jjp" -> {
|
||||||
|
// doWebParseStart("https://projectjav.com") {}
|
||||||
|
}
|
||||||
|
"jmnew" -> {
|
||||||
|
// doWebParseStart("https://missav.com/dm507/en/release") {}
|
||||||
|
}
|
||||||
|
"jmiss" -> {
|
||||||
|
// doWebParseStart("https://missav.com/dm16/en") {}
|
||||||
|
}
|
||||||
|
// "jreq" -> {
|
||||||
|
// consoleLog("current j req() ${WorkersDb.getRealm()
|
||||||
|
// .query<RssData>("category == $0", RssDataType.GURU.name).find().size}")
|
||||||
|
// CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
// var isOk = false
|
||||||
|
//// plist.forEach {
|
||||||
|
// if (!isOk) {
|
||||||
|
// try {
|
||||||
|
// Jsoup.connect(jGuruMain)
|
||||||
|
// .userAgent("Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.117 Mobile Safari/537.36")
|
||||||
|
// .referrer("http://www.google.com")
|
||||||
|
// .header("Accept-Language", "it-IT,en;q=0.8,en-US;q=0.6,de;q=0.4,it;q=0.2,es;q=0.2")
|
||||||
|
// .header("Connection", "keep-alive")
|
||||||
|
// .header("scheme", "https")
|
||||||
|
// .header("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
|
||||||
|
// .header("accept-encoding", "gzip, deflate, br")
|
||||||
|
// .header("cache-control", "no-cache")
|
||||||
|
// .header("pragma", "no-cache")
|
||||||
|
// .header("upgrade-insecure-requests", "1")
|
||||||
|
// .ignoreContentType(true)
|
||||||
|
// .timeout(30000).execute().let {
|
||||||
|
// BLog.LOGE("DOC -> ${it}")
|
||||||
|
// isOk = true
|
||||||
|
// }
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// e.printStackTrace()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//// }
|
||||||
|
// BLog.LOGE("last state ${isOk}")
|
||||||
|
// }
|
||||||
|
//// doWebParseStart(jGuruMain,callBack = object : CommadCallabck {
|
||||||
|
//// override fun onConsoleLog(log: String) {
|
||||||
|
//// this@Feeds.consoleLog(log)
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// override fun collectComplete() {
|
||||||
|
//// consoleLog("excuted j req() ${WorkersDb.getRealm()
|
||||||
|
//// .query<RssData>("category == $0", RssDataType.GURU.name).find().size}")
|
||||||
|
//// }
|
||||||
|
//// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// "jtag" -> {
|
||||||
|
//// doWebPare(TEST_PAG.plus("tags")) {
|
||||||
|
// binding.feedsRss.apply {
|
||||||
|
// rss2.adapter = mRssAdapter2
|
||||||
|
//
|
||||||
|
// loading.visibility = View.VISIBLE
|
||||||
|
// if (listTags.size > 0) {
|
||||||
|
// mRssAdapter2?.updateData(listTags)
|
||||||
|
// rss2.visibility = View.VISIBLE
|
||||||
|
// loading.visibility = View.GONE
|
||||||
|
// refresh.visibility = View.GONE
|
||||||
|
// } else {
|
||||||
|
// refresh.visibility = View.VISIBLE
|
||||||
|
// rss2.visibility = View.GONE
|
||||||
|
// refresh.setOnClickListener {
|
||||||
|
// doWebParseStart(jGuruMain.plus("tags"), callBack = object : CommadCallabck {
|
||||||
|
// override fun onConsoleLog(log: String) {
|
||||||
|
// this@Feeds.consoleLog(log)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun collectComplete() {
|
||||||
|
// if (listTags.size > 0) {
|
||||||
|
// rss2?.postDelayed({
|
||||||
|
// mRssAdapter2?.updateData(listTags)
|
||||||
|
// loading.visibility = View.GONE
|
||||||
|
// refresh.visibility = View.GONE
|
||||||
|
// rss2.visibility = View.VISIBLE
|
||||||
|
// }, 500L)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
binding.expandRss.isChecked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
builder.setNegativeButton(android.R.string.cancel,
|
||||||
|
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
|
||||||
|
|
||||||
|
builder.show()
|
||||||
|
// binding.feedsRss.apply {
|
||||||
|
// if(rss.adapter != null) {
|
||||||
|
// (rss.adapter as RssAdapter).items.clear()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// val rssUrl = lActivity!!.getSharedPreferences(PREFS_SETTINGS, 0)
|
||||||
|
// .getString(KEY_RSS_URL, "")
|
||||||
|
// when {
|
||||||
|
// isNetworkAvailable && !rssUrl.isNullOrEmpty() -> {
|
||||||
|
//// Intent(lActivity!!, RssService::class.java)
|
||||||
|
//// .putExtra(RSS_RECEIVER, resultReceiver).let {
|
||||||
|
//// enqueueWork(lActivity!!, RssService::class.java, rssJobId, it)
|
||||||
|
//// }
|
||||||
|
// }
|
||||||
|
// else -> resumeService()
|
||||||
|
// }
|
||||||
|
// val rssUrl2 = lActivity!!.getSharedPreferences(PREFS_SETTINGS, 0)
|
||||||
|
// .getString(KEY_RSS_URL2, "")
|
||||||
|
// when {
|
||||||
|
// isNetworkAvailable && !rssUrl2.isNullOrEmpty() -> {
|
||||||
|
// Intent(lActivity!!, RssService::class.java)
|
||||||
|
// .putExtra(RSS_RECEIVER, resultReceiver).let {
|
||||||
|
// enqueueWork(lActivity!!, RssService::class.java, rssJobId, it)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else -> resumeService()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* retry to start rss service */
|
||||||
|
private fun resumeService() {
|
||||||
|
binding.feedsRss.apply {
|
||||||
|
rss.visibility = View.GONE
|
||||||
|
loading.visibility = View.GONE
|
||||||
|
refresh.visibility = View.VISIBLE
|
||||||
|
refresh.setOnClickListener {
|
||||||
|
mRssAdapter?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun systemInfo() {
|
||||||
|
// viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
// repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
SystemStats().apply {
|
||||||
|
intStorage(binding.feedsSysInfos.intParent)
|
||||||
|
extStorage(binding.feedsSysInfos.extParent)
|
||||||
|
// while (isActive) {
|
||||||
|
ram(binding.feedsSysInfos.ramParent)
|
||||||
|
cpu(binding.feedsSysInfos.cpuParent)
|
||||||
|
misc(binding.feedsSysInfos.misc)
|
||||||
|
// delay(1000)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private fun selectWidget() {
|
||||||
|
// Intent(AppWidgetManager.ACTION_APPWIDGET_PICK).apply {
|
||||||
|
// putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetHost?.allocateAppWidgetId())
|
||||||
|
// putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, ArrayList())
|
||||||
|
// putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, ArrayList())
|
||||||
|
// putExtra(requestCodeString, requestPickWidget)
|
||||||
|
// }.let { widgetPicker.launch(it) }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private val widgetPicker =
|
||||||
|
// registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
// val data = result.data
|
||||||
|
// val appWidgetId = data?.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
|
||||||
|
// if (result.resultCode == RESULT_OK) {
|
||||||
|
// when (data?.getIntExtra(requestCodeString, requestPickWidget)) {
|
||||||
|
// requestPickWidget -> configureWidget(appWidgetId!!)
|
||||||
|
// requestCreateWidget -> createWidget(appWidgetId!!, null)
|
||||||
|
// }
|
||||||
|
// } else if (result.resultCode == RESULT_CANCELED && data != null) {
|
||||||
|
// if (appWidgetId != -1) appWidgetHost?.deleteAppWidgetId(appWidgetId!!)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun configureWidget(appWidgetId: Int) {
|
||||||
|
// when (val appWidgetConfig = appWidgetManager!!.getAppWidgetInfo(appWidgetId).configure) {
|
||||||
|
// null -> createWidget(appWidgetId, null)
|
||||||
|
// else -> {
|
||||||
|
// Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE).apply {
|
||||||
|
// component = appWidgetConfig
|
||||||
|
// putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
// putExtra(requestCodeString, requestCreateWidget)
|
||||||
|
// }.let {
|
||||||
|
// try { widgetPicker.launch(it) }
|
||||||
|
// catch (e: Exception) { e.printStackTrace() }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun createWidget(appWidgetId: Int, height: Int?) {
|
||||||
|
// if (appWidgetId == -1) return
|
||||||
|
//
|
||||||
|
// val appWidgetInfo = appWidgetManager!!.getAppWidgetInfo(appWidgetId)
|
||||||
|
// val params: ConstraintLayout.LayoutParams?
|
||||||
|
//
|
||||||
|
// when (height) {
|
||||||
|
// null -> {
|
||||||
|
// params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, appWidgetInfo.minHeight)
|
||||||
|
// val updatedIds = splitWidgetIds.plus("$appWidgetId")
|
||||||
|
// val updatedHeights = splitWidgetHeights.plus("${appWidgetInfo.minHeight}")
|
||||||
|
// saveWidgetData(updatedIds, updatedHeights)
|
||||||
|
// }
|
||||||
|
// else -> params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, height)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// (appWidgetHost?.createView(lActivity!!.applicationContext, appWidgetId, appWidgetInfo) as WidgetHostView)
|
||||||
|
// .apply {
|
||||||
|
// setAppWidget(appWidgetId, appWidgetInfo)
|
||||||
|
// }.let {
|
||||||
|
// binding.widgetContainer.addView(it, params)
|
||||||
|
// widgetMenu(it)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun updateWidgets() {
|
||||||
|
// if (splitWidgetIds.size > 0) {
|
||||||
|
// viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
// binding.widgetContainer.removeAllViews()
|
||||||
|
// splitWidgetIds.indices.forEach { i: Int ->
|
||||||
|
// createWidget(splitWidgetIds[i]!!.int(), splitWidgetHeights[i]!!.int())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun widgetMenu(hostView: WidgetHostView) {
|
||||||
|
// val appWidgetId = hostView.appWidgetId
|
||||||
|
// hostView.setOnLongClickListener {
|
||||||
|
// PopupMenu(requireContext(), it, Gravity.END).apply {
|
||||||
|
// menuInflater.inflate(R.menu.widget_menu, this.menu)
|
||||||
|
// show()
|
||||||
|
// setOnMenuItemClickListener { menuItem ->
|
||||||
|
// when (menuItem.itemId) {
|
||||||
|
// R.id.move_up -> moveWidget(appWidgetId, true)
|
||||||
|
// R.id.move_down -> moveWidget(appWidgetId, false)
|
||||||
|
// R.id.increase_height -> resizeWidget(appWidgetId, true)
|
||||||
|
// R.id.decrease_height -> resizeWidget(appWidgetId, false)
|
||||||
|
// R.id.delete_widget -> removeWidget(it as WidgetHostView)
|
||||||
|
// }
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun moveWidget(widgetId: Int, moveUp: Boolean) {
|
||||||
|
// val tempIds = splitWidgetIds
|
||||||
|
// val tempHeights = splitWidgetHeights
|
||||||
|
//
|
||||||
|
// splitWidgetIds.indexOf(widgetId.toString()).let { i ->
|
||||||
|
// when {
|
||||||
|
// moveUp && i > 0 -> {
|
||||||
|
// tempIds.swap(i-1, i)
|
||||||
|
// tempHeights.swap(i-1, i)
|
||||||
|
// }
|
||||||
|
// !moveUp && i < splitWidgetIds.size - 1 -> {
|
||||||
|
// tempIds.swap(i, i+1)
|
||||||
|
// tempHeights.swap(i, i+1)
|
||||||
|
// }
|
||||||
|
// else -> return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// saveWidgetData(tempIds, tempHeights)
|
||||||
|
// updateWidgets()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun resizeWidget(widgetId: Int, shouldAdd: Boolean) {
|
||||||
|
// val tempList = splitWidgetHeights
|
||||||
|
//
|
||||||
|
// splitWidgetIds.indexOf(widgetId.toString()).let { i ->
|
||||||
|
// tempList[i] = when (shouldAdd) {
|
||||||
|
// true -> (splitWidgetHeights[i]!!.int().plus(50)).toString()
|
||||||
|
// false -> (splitWidgetHeights[i]!!.int().minus(50)).toString()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// widgetPref.edit().putString(KEY_WIDGET_HEIGHTS, tempList.joinToString(separator = SEPARATOR)).apply()
|
||||||
|
// updateWidgets()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun removeWidget(hostView: WidgetHostView) {
|
||||||
|
// hostView.let { v ->
|
||||||
|
// appWidgetHost?.deleteAppWidgetId(v.appWidgetId)
|
||||||
|
// binding.widgetContainer.removeView(v)
|
||||||
|
//
|
||||||
|
// splitWidgetIds.indexOf(v.appWidgetId.toString()).let { i ->
|
||||||
|
// saveWidgetData(splitWidgetIds.minus(splitWidgetIds[i]), splitWidgetHeights.minus(splitWidgetHeights[i]))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun saveWidgetData(idList: List<String?>, heightList: List<String?>) {
|
||||||
|
// widgetPref.edit()
|
||||||
|
// .putString(KEY_WIDGET_IDS, idList.joinToString(separator = SEPARATOR))
|
||||||
|
// .putString(KEY_WIDGET_HEIGHTS, heightList.joinToString(separator = SEPARATOR))
|
||||||
|
// .apply()
|
||||||
|
// }
|
||||||
|
|
||||||
|
private val widgetPref: SharedPreferences get() = lActivity!!.getSharedPreferences(PREFS_WIDGETS, 0)
|
||||||
|
private val widgetIds: String? get() = widgetPref.getString(KEY_WIDGET_IDS, "")
|
||||||
|
private val widgetHeights: String? get() = widgetPref.getString(KEY_WIDGET_HEIGHTS, "")
|
||||||
|
private val splitWidgetIds: MutableList<String?> get() = widgetIds!!.split(SEPARATOR).toMutableList()
|
||||||
|
private val splitWidgetHeights: MutableList<String?> get() = widgetHeights!!.split(SEPARATOR).toMutableList()
|
||||||
|
|
||||||
|
private fun <T> MutableList<T>.swap(index1: Int, index2: Int){
|
||||||
|
val temp = this[index1]
|
||||||
|
this[index1] = this[index2]
|
||||||
|
this[index2] = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.int() : Int {
|
||||||
|
return try {
|
||||||
|
this.toInt()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package bums.lunatic.launcher.feeds
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import bums.lunatic.launcher.common.DismissCalback
|
||||||
|
import bums.lunatic.launcher.databinding.FeedsResultMenuBinding
|
||||||
|
import bums.lunatic.launcher.model.LocationLog
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
import io.realm.kotlin.query.Sort
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
internal class FeedsResult : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: FeedsResultMenuBinding
|
||||||
|
private lateinit var searchWord: String
|
||||||
|
private lateinit var packageManager: PackageManager
|
||||||
|
private lateinit var appInfo: ApplicationInfo
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = FeedsResultMenuBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
/* get package name from fragment's tag */
|
||||||
|
searchWord = tag.toString()
|
||||||
|
WorkersDb.getRealm().query<LocationLog>().sort("time", Sort.DESCENDING).find()?.let {
|
||||||
|
if (it.size > 0) {
|
||||||
|
binding.logs.text = it.map {
|
||||||
|
Blog.LOGE("LocLog >> ${it.toString()}")
|
||||||
|
SimpleDateFormat("yyyy/MM/dd-HH:mm:ss").format(Date(it.time)).plus("\n").plus(it.mAddressLines.joinToString(" ,\n"))
|
||||||
|
}.joinToString( ",\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var mDismissCalback : DismissCalback? = null
|
||||||
|
|
||||||
|
fun show(manager: FragmentManager, tag: String?, dismissCalback : DismissCalback?) {
|
||||||
|
this.mDismissCalback = dismissCalback
|
||||||
|
this.show(manager, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun show(manager: FragmentManager, tag: String?) {
|
||||||
|
super.show(manager, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dismiss() {
|
||||||
|
Blog.LOGE("dismiss()")
|
||||||
|
mDismissCalback?.invoke()
|
||||||
|
super.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
Blog.LOGE("onDismiss(dialog: DialogInterface)")
|
||||||
|
mDismissCalback?.invoke()
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-7
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.feeds
|
package bums.lunatic.launcher.feeds
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
@@ -32,14 +32,14 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.widget.LinearLayoutCompat
|
import androidx.appcompat.widget.LinearLayoutCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.ChildSysInfoBinding
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_TEMP_UNIT
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.isNetworkAvailable
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
|
||||||
import rasel.lunar.launcher.R
|
|
||||||
import rasel.lunar.launcher.databinding.ChildSysInfoBinding
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_TEMP_UNIT
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
|
||||||
import rasel.lunar.launcher.helpers.UniUtils.Companion.isNetworkAvailable
|
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.feeds
|
package bums.lunatic.launcher.feeds
|
||||||
|
|
||||||
import android.appwidget.AppWidgetHost
|
import android.appwidget.AppWidgetHost
|
||||||
import android.appwidget.AppWidgetHostView
|
import android.appwidget.AppWidgetHostView
|
||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.feeds
|
package bums.lunatic.launcher.feeds
|
||||||
|
|
||||||
import android.appwidget.AppWidgetHostView
|
import android.appwidget.AppWidgetHostView
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.feeds.rss
|
package bums.lunatic.launcher.feeds.rss
|
||||||
|
|
||||||
|
|
||||||
internal class Rss(
|
internal class Rss(
|
||||||
+7
-7
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.feeds.rss
|
package bums.lunatic.launcher.feeds.rss
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -28,13 +28,13 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.databinding.ListItemWithBinding
|
||||||
|
import bums.lunatic.launcher.home.adapters.RssItemDiffUtil
|
||||||
|
import bums.lunatic.launcher.model.JGuru
|
||||||
|
import bums.lunatic.launcher.model.RssDataInterface
|
||||||
|
import bums.lunatic.launcher.model.RssDataType
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
|
||||||
import rasel.lunar.launcher.databinding.ListItemWithBinding
|
|
||||||
import rasel.lunar.launcher.model.RssDataInterface
|
|
||||||
import rasel.lunar.launcher.model.RssDataType
|
|
||||||
import rasel.lunar.launcher.model.JGuru
|
|
||||||
import rasel.lunar.launcher.home.adapters.RssItemDiffUtil
|
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.feeds.rss
|
package bums.lunatic.launcher.feeds.rss
|
||||||
|
|
||||||
import android.util.Xml
|
import android.util.Xml
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
+5
-5
@@ -16,17 +16,17 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.feeds.rss
|
package bums.lunatic.launcher.feeds.rss
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.ResultReceiver
|
import android.os.ResultReceiver
|
||||||
import androidx.core.app.JobIntentService
|
import androidx.core.app.JobIntentService
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_RSS_URL
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_RSS_URL
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.RSS_ITEMS
|
import bums.lunatic.launcher.helpers.Constants.Companion.RSS_ITEMS
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.RSS_RECEIVER
|
import bums.lunatic.launcher.helpers.Constants.Companion.RSS_RECEIVER
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.helpers
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
import android.app.admin.DeviceAdminReceiver
|
import android.app.admin.DeviceAdminReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.bluetooth.BluetoothAdapter
|
||||||
|
import android.bluetooth.BluetoothDevice
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.ConnectionPool
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
class BluetoothManager {
|
||||||
|
|
||||||
|
enum class BLUETOOTH_STATE(val statestr: String) {
|
||||||
|
ENABLED("enabledBlutooth"),
|
||||||
|
DISABLED("disableBlutooth"),
|
||||||
|
NOT_SUPPORT("notSupport")
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var context: Context
|
||||||
|
var blueToothAdapter:BluetoothAdapter? = null
|
||||||
|
|
||||||
|
constructor(context: Context) {
|
||||||
|
this.context = context
|
||||||
|
}
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// init {
|
||||||
|
// this.context = context
|
||||||
|
// }
|
||||||
|
|
||||||
|
fun initBluetoothAdapter(){
|
||||||
|
if ( blueToothAdapter == null ){
|
||||||
|
val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as android.bluetooth.BluetoothManager
|
||||||
|
blueToothAdapter = bluetoothManager.getAdapter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun register(){
|
||||||
|
if (context == null) return
|
||||||
|
context.registerReceiver(bluetoothreceiver, addFilterAction())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregister(){
|
||||||
|
if (context == null) return
|
||||||
|
context.unregisterReceiver(bluetoothreceiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
//페어링된 디바이스 정보 가져오기
|
||||||
|
|
||||||
|
fun getPairedDevices() {
|
||||||
|
val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as android.bluetooth.BluetoothManager
|
||||||
|
blueToothAdapter = bluetoothManager.adapter
|
||||||
|
if (ActivityCompat.checkSelfPermission(context,Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) return
|
||||||
|
var pairedDevices = blueToothAdapter?.bondedDevices
|
||||||
|
if (pairedDevices?.size ?: 0 > 0) {
|
||||||
|
pairedDevices?.forEach { i ->
|
||||||
|
//bondState : 12 (페어링 등록된 상태)
|
||||||
|
//bondState : 10 (페어링 등록 안됨)
|
||||||
|
// BLog.LOGE("getPairedDevices() / name : ${i.name}")
|
||||||
|
// BLog.LOGE("getPairedDevices() / bondState : ${i.bondState}")
|
||||||
|
val isConnected = isConnected(i)
|
||||||
|
if(PrefString.carName.get().length > 2 && i.name.equals(PrefString.carName.get()) && isConnected != PrefBoolean.isConnectedCar.get()) {
|
||||||
|
PrefBoolean.isConnectedCar.set(isConnected)
|
||||||
|
sendToI(PrefBoolean.isConnectedCar.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun sendToI(boolean: Boolean) {
|
||||||
|
if (PrefString.telegramSendTarget.get().length > 5) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val url =
|
||||||
|
"https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/sendMessage?chat_id=${PrefString.telegramSendTarget.get()}&text=${if(boolean) {
|
||||||
|
"돼지가 ${PrefString.carName.get()}에 탔다요."
|
||||||
|
}else {
|
||||||
|
"${PrefString.carName.get()}의 시동이 꺼졌다요."
|
||||||
|
}}"
|
||||||
|
//7068729507
|
||||||
|
// OkHttp 클라이언트 객체 생성
|
||||||
|
val client = OkHttpClient.Builder()
|
||||||
|
.connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
// GET 요청 객체 생성
|
||||||
|
val builder: Request.Builder = Request.Builder().url(url)
|
||||||
|
.addHeader("Content-Type", "application/json").get()
|
||||||
|
|
||||||
|
val request: Request = builder.build()
|
||||||
|
|
||||||
|
// BLog.LOGE("sendToI telegram before request ")
|
||||||
|
// OkHttp 클라이언트로 GET 요청 객체 전송
|
||||||
|
val response: Response = client.newCall(request).execute()
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
// 응답 받아서 처리
|
||||||
|
val body: ResponseBody? = response.body()
|
||||||
|
if (body != null) {
|
||||||
|
|
||||||
|
}
|
||||||
|
// BLog.LOGE("sendToI telegram response isSuccessful ${body}")
|
||||||
|
} else Blog.LOGE("sendToI telegram Error Occurred")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
fun isConnected(device: BluetoothDevice): Boolean {
|
||||||
|
try {
|
||||||
|
val m = device.javaClass.getMethod("isConnected")
|
||||||
|
val connected = m.invoke(device) as Boolean
|
||||||
|
// BLog.LOGE("D >> " + device.name + " || isConnected >>> " + (if (connected) "TRUE" else "FALSE"))
|
||||||
|
return connected
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//블루투스 상태(켜짐 / 꺼짐 / 지원 불가 기기)
|
||||||
|
fun blueToothState(): String {
|
||||||
|
if (blueToothAdapter != null) {
|
||||||
|
if (blueToothAdapter?.isEnabled == true) {
|
||||||
|
return BLUETOOTH_STATE.ENABLED.statestr
|
||||||
|
} else {
|
||||||
|
return BLUETOOTH_STATE.DISABLED.statestr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BLUETOOTH_STATE.NOT_SUPPORT.statestr
|
||||||
|
}
|
||||||
|
|
||||||
|
//add Receive action
|
||||||
|
private fun addFilterAction(): IntentFilter {
|
||||||
|
val stateFilter = IntentFilter()
|
||||||
|
stateFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED) //BluetoothAdapter.ACTION_STATE_CHANGED : 블루투스 상태변화 액션
|
||||||
|
stateFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)
|
||||||
|
stateFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED) //연결 확인
|
||||||
|
stateFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED) //연결 끊김 확인
|
||||||
|
/*
|
||||||
|
stateFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
|
||||||
|
stateFilter.addAction(BluetoothDevice.ACTION_FOUND) //기기 검색됨
|
||||||
|
stateFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED) //기기 검색 시작
|
||||||
|
stateFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED) //기기 검색 종료
|
||||||
|
stateFilter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST)
|
||||||
|
*/
|
||||||
|
return stateFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
//BlueTooth Receiver
|
||||||
|
private var bluetoothreceiver = object : BroadcastReceiver(){
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
var state = intent?.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
|
||||||
|
val action = intent!!.action
|
||||||
|
if (context == null) return
|
||||||
|
if (ActivityCompat.checkSelfPermission(context!!, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) return
|
||||||
|
getPairedDevices()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.helpers
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
+2
-2
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.helpers
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
|
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
|
||||||
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||||
@@ -72,7 +72,7 @@ internal class Constants {
|
|||||||
const val DEFAULT_ICON_PACK = "default_icon_pack"
|
const val DEFAULT_ICON_PACK = "default_icon_pack"
|
||||||
const val DEFAULT_GRID_COLUMNS = 4
|
const val DEFAULT_GRID_COLUMNS = 4
|
||||||
const val DEFAULT_SCROLLBAR_HEIGHT = 400
|
const val DEFAULT_SCROLLBAR_HEIGHT = 400
|
||||||
const val MAX_SHORTCUTS = 6
|
const val MAX_SHORTCUTS = 8
|
||||||
const val MAX_FAVORITE_APPS = 6
|
const val MAX_FAVORITE_APPS = 6
|
||||||
|
|
||||||
const val BOTTOM_SHEET_TAG = "rasel.lunar.launcher.TAG"
|
const val BOTTOM_SHEET_TAG = "rasel.lunar.launcher.TAG"
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.AudioManager
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import java.util.Timer
|
||||||
|
import java.util.TimerTask
|
||||||
|
|
||||||
|
|
||||||
|
class HeadsetActionButtonReceiver : BroadcastReceiver() {
|
||||||
|
interface Delegate {
|
||||||
|
fun onMediaButtonSingleClick()
|
||||||
|
fun onMediaButtonDoubleClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
Blog.LOGE("HeadsetActionButtonReceiver keyEvent >>>>> ${intent}")
|
||||||
|
intent?.extras?.keySet()?.forEach {
|
||||||
|
try {
|
||||||
|
Blog.LOGE("${it} ${intent?.extras?.get(it)}")
|
||||||
|
} catch (e :Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (intent == null || Intent.ACTION_MEDIA_BUTTON != intent.action) return
|
||||||
|
|
||||||
|
val keyEvent = intent.extras?.get(Intent.EXTRA_KEY_EVENT) as KeyEvent?
|
||||||
|
if (keyEvent == null || keyEvent.action != KeyEvent.ACTION_DOWN) return
|
||||||
|
Blog.LOGE("HeadsetActionButtonReceiver keyEvent >>>>> ${keyEvent}")
|
||||||
|
// counter++
|
||||||
|
// if (doublePressTimer != null) {
|
||||||
|
// doublePressTimer!!.cancel()
|
||||||
|
// }
|
||||||
|
// doublePressTimer = Timer()
|
||||||
|
// doublePressTimer!!.schedule(object : TimerTask() {
|
||||||
|
// override fun run() {
|
||||||
|
// if (counter == 1) {
|
||||||
|
// delegate!!.onMediaButtonSingleClick()
|
||||||
|
// } else {
|
||||||
|
// delegate!!.onMediaButtonDoubleClick()
|
||||||
|
// }
|
||||||
|
// counter = 0
|
||||||
|
// }
|
||||||
|
// }, doublePressSpeed.toLong())
|
||||||
|
abortBroadcast()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var delegate: Delegate? = null
|
||||||
|
|
||||||
|
private var mAudioManager: AudioManager? = null
|
||||||
|
private var mRemoteControlResponder: ComponentName? = null
|
||||||
|
|
||||||
|
private const val doublePressSpeed = 300 // double keypressed in ms
|
||||||
|
private var doublePressTimer: Timer? = null
|
||||||
|
private var counter = 0
|
||||||
|
|
||||||
|
fun register(context: Context) {
|
||||||
|
mAudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager?
|
||||||
|
mRemoteControlResponder = ComponentName(context, HeadsetActionButtonReceiver::class.java)
|
||||||
|
mAudioManager?.registerMediaButtonEventReceiver(mRemoteControlResponder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregister(context: Context?) {
|
||||||
|
mAudioManager?.unregisterMediaButtonEventReceiver(mRemoteControlResponder)
|
||||||
|
if (doublePressTimer != null) {
|
||||||
|
doublePressTimer!!.cancel()
|
||||||
|
doublePressTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.helpers
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
import android.accessibilityservice.AccessibilityService
|
import android.accessibilityservice.AccessibilityService
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo
|
import android.accessibilityservice.AccessibilityServiceInfo
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import bums.lunatic.launcher.model.RssDataType
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import kr.lunaticbum.utils.preferences.PrefJsonConvert
|
||||||
|
import kr.lunaticbum.utils.preferences.PrefKey
|
||||||
|
import kr.lunaticbum.utils.preferences.PreferencesHelper
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
|
||||||
|
enum class PrefString : PrefKey<String> {
|
||||||
|
defaultTimeFormat,
|
||||||
|
defaultDateFormat,
|
||||||
|
weatherApiKey,
|
||||||
|
locationApi,
|
||||||
|
telegramBotApi,
|
||||||
|
telegramMyId,
|
||||||
|
telegramSendTarget,
|
||||||
|
carName;
|
||||||
|
override fun set(value: String) {PrefHelper.putString(this.name, value)}
|
||||||
|
override fun get(def : String?) : String = PrefHelper.getString(this.name, def as? String ?: "") ?: ""
|
||||||
|
override fun getKey() = this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PrefLong(val def : Long) : PrefKey<Long> {
|
||||||
|
locationTimePeriod(20L),
|
||||||
|
locationDistance(200L),
|
||||||
|
shortTimePeriod(20L),
|
||||||
|
longTimePeriod(60L),
|
||||||
|
midTimePeriod(30L),
|
||||||
|
maxQueryCount(18L);
|
||||||
|
override fun set(value : Long) { PrefHelper.putLong(this.name, value) }
|
||||||
|
override fun get(def : Long?) : Long {
|
||||||
|
val value = PrefHelper.getLong(this.name, def ?: this.def) ?: this.def
|
||||||
|
|
||||||
|
// Blog.LOGE("$name : $value")
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
override fun getKey() = this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PrefBoolean : PrefKey<Boolean> {
|
||||||
|
displayBattery,
|
||||||
|
displayDateTime,
|
||||||
|
location,
|
||||||
|
rootPermisssion,
|
||||||
|
isConnectedCar,
|
||||||
|
useQuickLaunch,
|
||||||
|
openWithKayboard,
|
||||||
|
showAppResultCount,
|
||||||
|
weatherDress,
|
||||||
|
weatherState,
|
||||||
|
showCallHistory,
|
||||||
|
showSMSHistory,
|
||||||
|
showNotificationHistory,
|
||||||
|
showNewsHistory,
|
||||||
|
showNowPlaying,
|
||||||
|
;
|
||||||
|
override fun set(value : Boolean) {
|
||||||
|
PrefHelper.putBoolean(this.name, value)
|
||||||
|
}
|
||||||
|
override fun get(def : Boolean?) : Boolean = PrefHelper.getBoolean(this.name, def as? Boolean ?: false) ?: false
|
||||||
|
override fun getKey() = this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
object PrefHelper : PreferencesHelper() {
|
||||||
|
override fun getDefaultPrefix(): String { return "rasel.lunar.launcher.helpers" }
|
||||||
|
|
||||||
|
override fun getSettings() : Map<String,Any> {
|
||||||
|
var jsonObj = HashMap<String,Any>()
|
||||||
|
PrefString.values().forEach { jsonObj.put(it.name,it.get("")) }
|
||||||
|
PrefBoolean.values().forEach { jsonObj.put(it.name,it.get(false)) }
|
||||||
|
PrefLong.values().forEach { jsonObj.put(it.name,it.get(0L)) }
|
||||||
|
|
||||||
|
RssDataType.values().forEach { jsonObj.put(it.name,getBoolean(it.name, false)) }
|
||||||
|
return jsonObj
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun putSetting(json : Map<String,Any>) {
|
||||||
|
PrefString.values().forEach {
|
||||||
|
if (json.containsKey(it.getKey())) {
|
||||||
|
it.set(json.get(it.getKey()) as String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrefBoolean.values().forEach {
|
||||||
|
if (json.containsKey(it.getKey())) {
|
||||||
|
it.set(json.get(it.getKey()) as Boolean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrefLong.values().forEach {
|
||||||
|
if (json.containsKey(it.getKey())) {
|
||||||
|
it.set(BigDecimal(json.get(it.getKey()).toString()).toLong())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RssDataType.values().forEach { type ->
|
||||||
|
if (json.containsKey(type.name)) {
|
||||||
|
putBoolean(type.name,json.get(type.name) as Boolean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBoolean(key: String, def: Boolean) = get(getBooleanPrefix().plus(key), def)
|
||||||
|
fun putBoolean(key: String, value: Boolean) = put(getBooleanPrefix().plus(key), value)
|
||||||
|
fun getLong(key: String, def: Long) = get(getLongPrefix().plus(key), def)
|
||||||
|
fun putLong(key: String, value: Long) = put(getLongPrefix().plus(key), value)
|
||||||
|
fun getString(key: String, def: String) = get(getStringPrefix().plus(key), def)
|
||||||
|
fun putString(key: String, value: String) = put(getStringPrefix().plus(key), value)
|
||||||
|
|
||||||
|
|
||||||
|
// fun location(boolean: Boolean) = PrefBoolean.location.set(boolean)
|
||||||
|
// fun isLocationOn() = (PrefBoolean.location.get() as? Boolean) ?: false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.helpers
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
+5
-5
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.helpers
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
@@ -37,10 +37,10 @@ import androidx.appcompat.widget.LinearLayoutCompat
|
|||||||
import androidx.biometric.BiometricManager
|
import androidx.biometric.BiometricManager
|
||||||
import androidx.biometric.BiometricManager.BIOMETRIC_SUCCESS
|
import androidx.biometric.BiometricManager.BIOMETRIC_SUCCESS
|
||||||
import androidx.biometric.BiometricPrompt
|
import androidx.biometric.BiometricPrompt
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
import rasel.lunar.launcher.R
|
import bums.lunatic.launcher.R
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.ACCESSIBILITY_SERVICE_LOCK_SCREEN
|
import bums.lunatic.launcher.helpers.Constants.Companion.ACCESSIBILITY_SERVICE_LOCK_SCREEN
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.AUTHENTICATOR_TYPE
|
import bums.lunatic.launcher.helpers.Constants.Companion.AUTHENTICATOR_TYPE
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
|
|
||||||
|
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.helpers
|
package bums.lunatic.launcher.helpers
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home
|
package bums.lunatic.launcher.home
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,250 @@
|
|||||||
|
package bums.lunatic.launcher.home
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Environment
|
||||||
|
import android.webkit.CookieManager
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kr.lunaticbum.awesomewebview.helpers.DownPicUtil
|
||||||
|
import kr.lunaticbum.awesomewebview.helpers.DownPicUtil.DownFinishListener
|
||||||
|
import kr.lunaticbum.utils.log.LogUtil
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import org.jsoup.UnsupportedMimeTypeException
|
||||||
|
import java.io.BufferedWriter
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.net.URL
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
val defaultTime = 200L
|
||||||
|
class OfflineContents(val context: Context, val host : String, val cookie: String, val agent: String, val current: String, val newPath: String, val value: String, val autoCheck : Boolean, val mediaUrls : ArrayList<String>) {
|
||||||
|
val targetFile : File
|
||||||
|
val filePath = "index.html"
|
||||||
|
val path = File(
|
||||||
|
Environment.getExternalStorageDirectory(),
|
||||||
|
"bums"
|
||||||
|
)
|
||||||
|
val newFolder = File(path, newPath).apply { mkdirs() }
|
||||||
|
val newFile : File
|
||||||
|
var htmlString : StringBuffer
|
||||||
|
val urlPathMap : HashMap<String,String> = hashMapOf()
|
||||||
|
var reqCount = 0
|
||||||
|
var endOfLooPCheck = false
|
||||||
|
val lDownFinishListener = object : DownFinishListener {
|
||||||
|
override fun onDownFinish(url: String, path: String) {
|
||||||
|
LogUtil.e("Url >> ${url} path >> ${path}")
|
||||||
|
urlPathMap.put(url, path)
|
||||||
|
reqCount -= 1
|
||||||
|
if (reqCount == 0 && endOfLooPCheck) {
|
||||||
|
enofLoop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError() {
|
||||||
|
reqCount -= 1
|
||||||
|
if (reqCount == 0 && endOfLooPCheck) {
|
||||||
|
enofLoop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
targetFile = File(newFolder, filePath)
|
||||||
|
newFile = File(
|
||||||
|
path,
|
||||||
|
newPath.plus(SimpleDateFormat("yyyMMdd").format(Date())).plus(".html")
|
||||||
|
)
|
||||||
|
htmlString= trimHtnl(value, host)
|
||||||
|
}
|
||||||
|
|
||||||
|
var onItEndof = false
|
||||||
|
fun enofLoop() {
|
||||||
|
if (onItEndof) return
|
||||||
|
onItEndof = true
|
||||||
|
LogUtil.e("on it enofLoop")
|
||||||
|
urlPathMap.forEach { t, u ->
|
||||||
|
val file = File(u)
|
||||||
|
var contentsUriString = FileProvider.getUriForFile(
|
||||||
|
context,
|
||||||
|
"${context.packageName}.fileprovider",
|
||||||
|
file
|
||||||
|
).toString()
|
||||||
|
|
||||||
|
var targetString = t
|
||||||
|
var targetIdx = htmlString.indexOf(targetString)
|
||||||
|
if (targetIdx > 0) {
|
||||||
|
htmlString?.replace(
|
||||||
|
targetIdx,
|
||||||
|
targetIdx.plus(targetString.length),
|
||||||
|
contentsUriString
|
||||||
|
)
|
||||||
|
}
|
||||||
|
targetString = t.replace("&", "&")
|
||||||
|
targetIdx = htmlString.indexOf(targetString)
|
||||||
|
if (targetIdx > 0) {
|
||||||
|
htmlString?.replace(
|
||||||
|
targetIdx,
|
||||||
|
targetIdx.plus(targetString.length),
|
||||||
|
contentsUriString
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoCheck) {
|
||||||
|
LogUtil.e("on it enofLoop autoCheck ${autoCheck}")
|
||||||
|
moveFile()
|
||||||
|
context.startActivity(Intent(context,RssViewerActivity::class.java).apply {
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
data = FileProvider.getUriForFile(
|
||||||
|
context,
|
||||||
|
"${context.packageName}.fileprovider",
|
||||||
|
newFile
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
moveFile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveFile() {
|
||||||
|
indexSave(htmlString, targetFile, host)
|
||||||
|
targetFile.copyTo(newFile)
|
||||||
|
if (targetFile.parentFile.isDirectory) {
|
||||||
|
targetFile.parentFile.listFiles().forEach {
|
||||||
|
it.delete()
|
||||||
|
}
|
||||||
|
targetFile.parentFile.delete()
|
||||||
|
}
|
||||||
|
targetFile.delete()
|
||||||
|
}
|
||||||
|
fun excute() {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
LogUtil.e("onHtml value >> ${value}")
|
||||||
|
mediaUrls.forEach { url ->
|
||||||
|
var downPic = false
|
||||||
|
try {
|
||||||
|
LogUtil.e("try Jsoup.parse ${url}")
|
||||||
|
Jsoup.parse(URL(url), defaultTime.times(4).toInt()).let {
|
||||||
|
try {
|
||||||
|
LogUtil.e("onit Jsoup.parse ${it.title()}")
|
||||||
|
if (it.select("svg").size > 0) {
|
||||||
|
try {
|
||||||
|
downPic(url, agent, current!!, cookie!!, lDownFinishListener)
|
||||||
|
reqCount += 1
|
||||||
|
} catch (e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
it.getElementsByTag("video")?.forEach {
|
||||||
|
it.attribute("src").value?.let {
|
||||||
|
var url = if (it.startsWith("http")) {
|
||||||
|
it
|
||||||
|
} else {
|
||||||
|
"https:".plus(it)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
downMp4(url, agent, current!!, cookie!!, lDownFinishListener)
|
||||||
|
reqCount += 1
|
||||||
|
} catch (e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: UnsupportedMimeTypeException) {
|
||||||
|
LogUtil.e("e.message3 ${e.message}")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LogUtil.e("e.message4 ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: UnsupportedMimeTypeException) {
|
||||||
|
LogUtil.e("e.message ${e.message}")
|
||||||
|
LogUtil.e("e.message ${e.localizedMessage}")
|
||||||
|
if (e.message?.contains("Must be text") == true) {
|
||||||
|
downPic = true
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (url.contains("dcimg") == true) {
|
||||||
|
downPic = true
|
||||||
|
}
|
||||||
|
LogUtil.e("e.message2 ${e.message}")
|
||||||
|
} finally {
|
||||||
|
if (downPic) {
|
||||||
|
try {
|
||||||
|
downPic(url, agent, current!!, cookie!!, lDownFinishListener)
|
||||||
|
reqCount += 1
|
||||||
|
} catch (e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay(defaultTime)
|
||||||
|
}
|
||||||
|
LogUtil.e("END OF LOOP ${reqCount}")
|
||||||
|
endOfLooPCheck = true
|
||||||
|
delay(defaultTime.times(4))
|
||||||
|
if (reqCount <= 0) {
|
||||||
|
enofLoop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun indexSave(htmlString:StringBuffer, targetFile :File, host: String) {
|
||||||
|
BufferedWriter(FileWriter(targetFile)).use { writer ->
|
||||||
|
trimHtnl(htmlString.toString(), host)?.let { result ->
|
||||||
|
writer.write(result.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun trimHtnl(target : String, host : String) : StringBuffer {
|
||||||
|
var result = target.replace("\\\"","\"").replace("\\n\\t\\t\\t","").replace("\\n\\t\\t","").replace("\\n\\t","").replace("\\t", "").replace("\\n", "").replace("\"\"\"","").replace("href=\"//","href=\"https://").replace("src=\"//","src=\"https://").replace("url(\"//","url(\"https://").replace("url("//","url("https://")
|
||||||
|
if (host?.contains("clien") == true) {
|
||||||
|
result = result.replace("href=\"/service","href=\"https://m.clien.net/service").replace("href=\"\\"/service","href=\"\\"https://m.clien.net/service")
|
||||||
|
}
|
||||||
|
return StringBuffer(result)
|
||||||
|
}
|
||||||
|
fun downMp4(url : String, agent : String, current : String,cookie : String, listner :DownFinishListener) {
|
||||||
|
LogUtil.e("try imageFile down ${url}")
|
||||||
|
val path = File(
|
||||||
|
Environment.getExternalStorageDirectory(),
|
||||||
|
"bums"
|
||||||
|
)
|
||||||
|
DownPicUtil.downMp4(
|
||||||
|
File(
|
||||||
|
path,"private_mp4"
|
||||||
|
).path,
|
||||||
|
url,
|
||||||
|
agent,
|
||||||
|
current,
|
||||||
|
cookie,
|
||||||
|
listner
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fun downPic( url : String, agent : String, current : String,cookie : String, listner :DownFinishListener) {
|
||||||
|
LogUtil.e("try imageFile down ${url}")
|
||||||
|
val cookieManager =
|
||||||
|
CookieManager.getInstance()
|
||||||
|
val cookie =
|
||||||
|
cookieManager.getCookie(current)
|
||||||
|
val path = File(
|
||||||
|
Environment.getExternalStorageDirectory(),
|
||||||
|
"bums"
|
||||||
|
)
|
||||||
|
|
||||||
|
DownPicUtil.downPic(
|
||||||
|
File(path, "private_img").path,
|
||||||
|
url,
|
||||||
|
agent,
|
||||||
|
current,
|
||||||
|
cookie,
|
||||||
|
listner)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.home
|
||||||
|
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.RssViewerBinding
|
||||||
|
|
||||||
|
|
||||||
|
internal class RssViewer : DialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: RssViewerBinding
|
||||||
|
private lateinit var packageName: String
|
||||||
|
private lateinit var packageManager: PackageManager
|
||||||
|
private lateinit var defAppName: String
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, R.style.FilterFullScreenDialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
if (dialog != null) {
|
||||||
|
// val metrics = resources.displayMetrics
|
||||||
|
// val screenHeight = metrics.heightPixels
|
||||||
|
// val bottomSheet =
|
||||||
|
// dialog!!.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
|
||||||
|
// bottomSheet.layoutParams.height = (screenHeight * 0.95).toInt()
|
||||||
|
// val behavior = BottomSheetBehavior.from(bottomSheet)
|
||||||
|
// behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
// behavior.skipCollapsed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = RssViewerBinding.inflate(inflater, container, false)
|
||||||
|
binding.webview.loadUrl(tag!!)
|
||||||
|
binding.webview.setDesktopMode(false)
|
||||||
|
// binding.pdfPrint.setOnClickListener { pdfPring() }
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
// fun pdfPring() {
|
||||||
|
// val fileName = tag?.toUri()?.path?.replace("/","_")?.replace(".","_")
|
||||||
|
// val path = File(Environment.getExternalStorageDirectory(),"bums")
|
||||||
|
// if (path.exists() == false) {
|
||||||
|
// path.mkdirs()
|
||||||
|
// }
|
||||||
|
// val file = File(path, fileName.plus(".pdf"))
|
||||||
|
//
|
||||||
|
// BLog.LOGE("file >>> ${file.absolutePath}")
|
||||||
|
// try {
|
||||||
|
// PDFPrint.generatePDFFromWebView(file,binding.webview, object : PDFPrint.OnPDFPrintListener {
|
||||||
|
// override fun onSuccess(file: File?) {
|
||||||
|
// BLog.LOGE("file >>>> ${file!!.absolutePath}")
|
||||||
|
// val shareIntent: Intent = Intent().apply {
|
||||||
|
// action = Intent.ACTION_SEND
|
||||||
|
// this.`package` = "com.synology.dsdrive"
|
||||||
|
// val imageUri = FileProvider.getUriForFile(
|
||||||
|
// lActivity!!,
|
||||||
|
// "bums.lunatic.launcher.fileprovider", //(use your app signature + ".provider" )
|
||||||
|
// file
|
||||||
|
// )
|
||||||
|
// putExtra(Intent.EXTRA_STREAM, imageUri)
|
||||||
|
// type = "pdf"
|
||||||
|
// }
|
||||||
|
// lActivity!!.startActivity(shareIntent)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onError(exception: java.lang.Exception?) {
|
||||||
|
// Toast.makeText(lActivity!!,
|
||||||
|
// "Pdf Save Failk ${exception?.localizedMessage}", Toast.LENGTH_LONG).show()
|
||||||
|
// exception?.printStackTrace()
|
||||||
|
// }
|
||||||
|
// } )
|
||||||
|
// } catch (e: IOException) {
|
||||||
|
// e.printStackTrace()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
// (requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,922 @@
|
|||||||
|
package bums.lunatic.launcher.home
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.print.PDFPrint
|
||||||
|
import android.provider.AlarmClock
|
||||||
|
import android.util.Base64
|
||||||
|
import android.view.HapticFeedbackConstants
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.KeyEvent.ACTION_UP
|
||||||
|
import android.view.KeyEvent.KEYCODE_BUTTON_A
|
||||||
|
import android.view.KeyEvent.KEYCODE_BUTTON_B
|
||||||
|
import android.view.KeyEvent.KEYCODE_BUTTON_SELECT
|
||||||
|
import android.view.KeyEvent.KEYCODE_BUTTON_START
|
||||||
|
import android.view.KeyEvent.KEYCODE_BUTTON_X
|
||||||
|
import android.view.KeyEvent.KEYCODE_BUTTON_Y
|
||||||
|
import android.view.KeyEvent.KEYCODE_DPAD_DOWN
|
||||||
|
import android.view.KeyEvent.KEYCODE_DPAD_LEFT
|
||||||
|
import android.view.KeyEvent.KEYCODE_DPAD_RIGHT
|
||||||
|
import android.view.KeyEvent.KEYCODE_DPAD_UP
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.MotionEvent.ACTION_MOVE
|
||||||
|
import android.view.View
|
||||||
|
import android.webkit.CookieManager
|
||||||
|
import android.webkit.CookieSyncManager
|
||||||
|
import android.webkit.JavascriptInterface
|
||||||
|
import android.webkit.ValueCallback
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.core.view.postDelayed
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.behavior.Behavior
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.BOTTOM_SHEET_TAG
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_LOCK_METHOD
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.expandNotificationPanel
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.lockMethod
|
||||||
|
import bums.lunatic.launcher.model.CiliMagnet
|
||||||
|
import bums.lunatic.launcher.model.RssData
|
||||||
|
import bums.lunatic.launcher.qaccess.QuickAccess
|
||||||
|
import bums.lunatic.launcher.settings.SettingsActivity
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.utils.SimpleFingerGestures
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import io.realm.kotlin.UpdatePolicy
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
import io.realm.kotlin.ext.realmListOf
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kr.lunaticbum.awesomewebview.AwesomeWebView
|
||||||
|
import kr.lunaticbum.awesomewebview.AwesomeWebViewActivity
|
||||||
|
import kr.lunaticbum.awesomewebview.listeners.BroadCastManager
|
||||||
|
import kr.lunaticbum.utils.content.ContextUtil
|
||||||
|
import kr.lunaticbum.utils.log.LogUtil
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.text.Charsets.UTF_8
|
||||||
|
|
||||||
|
|
||||||
|
class RssViewBuilder(context: Context) : AwesomeWebView.Builder(context) {
|
||||||
|
var rssId : String = ""
|
||||||
|
var rssList: MutableList<String> = ArrayList()
|
||||||
|
fun setRssId(rssId: String): RssViewBuilder {
|
||||||
|
this.rssId = rssId
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun setRssList(rssList: ArrayList<String>): RssViewBuilder {
|
||||||
|
this.rssList.clear()
|
||||||
|
this.rssList.addAll(rssList)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
override fun show(url: String?, data: String?) {
|
||||||
|
this.url = url
|
||||||
|
this.data = data
|
||||||
|
this.key = System.identityHashCode(this)
|
||||||
|
|
||||||
|
if (!listeners.isEmpty()) BroadCastManager(context, key!!, listeners)
|
||||||
|
|
||||||
|
val intent = Intent(
|
||||||
|
context,
|
||||||
|
RssViewerActivity::class.java
|
||||||
|
)
|
||||||
|
intent.putExtra("builder", this)
|
||||||
|
|
||||||
|
ContextUtil.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
class RssViewerActivity : AwesomeWebViewActivity(), View.OnGenericMotionListener , View.OnTouchListener {
|
||||||
|
var actionButtonPressX = 0f
|
||||||
|
var actionButtonPressY = 0f
|
||||||
|
var rssId : String = ""
|
||||||
|
// var currentIdx = 0
|
||||||
|
var double = false
|
||||||
|
var rssList: MutableList<String> = ArrayList()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
LogUtil.e("intent >>>> ${intent}")
|
||||||
|
if (intent.action.equals(Intent.ACTION_VIEW)) {
|
||||||
|
intent.data.toString()?.let {
|
||||||
|
loadWithIntent = true
|
||||||
|
load(it)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadWithIntent = false
|
||||||
|
}
|
||||||
|
webView?.setOnTouchListener(this)
|
||||||
|
|
||||||
|
}
|
||||||
|
private var startX = 0f
|
||||||
|
private var startY = 0f
|
||||||
|
private var startTime = 0L
|
||||||
|
|
||||||
|
// 임계값(앱에 맞게 조정)
|
||||||
|
private val swipeThreshold = 150 // 스와이프 최소 거리(px)
|
||||||
|
private val swipeTime = 300 // 스와이프 최대 시간(ms)
|
||||||
|
private val clickThreshold = 30 // 클릭으로 인정할 최대 이동 거리(px)
|
||||||
|
override fun onTouch(v: View?, event: MotionEvent): Boolean {
|
||||||
|
if(event.device.name.equals("JX-12",true)) {
|
||||||
|
when (event.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
startX = event.x
|
||||||
|
startY = event.y
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
val endX = event.x
|
||||||
|
val endY = event.y
|
||||||
|
val endTime = System.currentTimeMillis()
|
||||||
|
val dx = endX - startX
|
||||||
|
val dy = endY - startY
|
||||||
|
val duration = endTime - startTime
|
||||||
|
|
||||||
|
// 클릭: 거의 움직이지 않고 짧은 시간
|
||||||
|
if (Math.abs(dx) < clickThreshold && Math.abs(dy) < clickThreshold && duration < 250) {
|
||||||
|
onClick() // View의 기본 클릭 호출
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 좌우 스와이프: 수평 이동이 크고, 빠르게
|
||||||
|
if (Math.abs(dx) > swipeThreshold && Math.abs(dx) > Math.abs(dy) && duration < swipeTime) {
|
||||||
|
if (dx > 0) {
|
||||||
|
onSwipeRight()
|
||||||
|
} else {
|
||||||
|
onSwipeLeft()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
Blog.LOGE("dy >>> $dy")
|
||||||
|
// 상하 스크롤: 수직 이동이 더 크고, 일정 거리 이상
|
||||||
|
// if (Math.abs(dy) > swipeThreshold && Math.abs(dy) > Math.abs(dx)) {
|
||||||
|
// if (dy > 0) {
|
||||||
|
// onScrollDown()
|
||||||
|
// } else {
|
||||||
|
// onScrollUp()
|
||||||
|
// }
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
else -> return super.onTouchEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onTouchEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onClick() {
|
||||||
|
Blog.LOGE("onClick")
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 아래 메서드에 원하는 동작 구현
|
||||||
|
private fun onSwipeLeft() {
|
||||||
|
Blog.LOGE("onSwipeLeft")
|
||||||
|
vote()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSwipeRight() {
|
||||||
|
Blog.LOGE("onSwipeRight")
|
||||||
|
doNextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onScrollUp() {
|
||||||
|
Blog.LOGE("onScrollUp")
|
||||||
|
webView?.let {
|
||||||
|
it.scrollBy(0, (it.contentHeight / 100).coerceAtLeast(200) * -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onScrollDown() {
|
||||||
|
Blog.LOGE("onScrollDown")
|
||||||
|
webView?.let {
|
||||||
|
it.scrollBy(0, (it.contentHeight / 100).coerceAtLeast(200) * 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
webView?.setOnGenericMotionListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent?) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
if (intent?.action?.equals(Intent.ACTION_VIEW) == true) {
|
||||||
|
intent?.data?.toString()?.let {
|
||||||
|
loadWithIntent = true
|
||||||
|
load(it)
|
||||||
|
}
|
||||||
|
} else {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lasteventTime = 0L
|
||||||
|
override fun onGenericMotion(p0: View?, ev: MotionEvent?): Boolean {
|
||||||
|
if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
|
||||||
|
if(ev.action == ACTION_MOVE && ev.x != ev.y) {
|
||||||
|
val correctTime = (ev.eventTime - lasteventTime) > 2
|
||||||
|
if (correctTime) {
|
||||||
|
// Blog.LOGE("onGenericMotionEvent webviews ${p0} ev?.device?.name >>> ${ev?.device?.name} >> ${ev}")
|
||||||
|
if (ev.x <= -1.0f) {
|
||||||
|
leftClick()
|
||||||
|
} else if (ev.x >= 1.0f) {
|
||||||
|
rightClick()
|
||||||
|
} else if (ev.y <= -1.0f) {
|
||||||
|
scrollUp()
|
||||||
|
} else if (ev.y >= 1.0f) {
|
||||||
|
scrollDown()
|
||||||
|
}
|
||||||
|
lasteventTime = ev.eventTime
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
private var lastX = 0f
|
||||||
|
private var lastY = 0f
|
||||||
|
private var onDown = false
|
||||||
|
|
||||||
|
override fun onGenericMotionEvent(ev: MotionEvent?): Boolean {
|
||||||
|
|
||||||
|
if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
|
||||||
|
// Blog.LOGE("onGenericMotionEvent ev?.device?.name >>> ${ev?.device?.name} >> ${ev}")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onGenericMotionEvent(ev)
|
||||||
|
}
|
||||||
|
override fun dispatchKeyEvent(ev: KeyEvent): Boolean {
|
||||||
|
// Blog.LOGE("dispatch ev?.device?.name >>> ${ev?.device?.name}")
|
||||||
|
if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
|
||||||
|
// Blog.LOGE("onGenericMotionEvent ev?.device?.name >>> ${ev?.device?.name} >> ${ev}")
|
||||||
|
when(ev.action) {
|
||||||
|
ACTION_UP -> {
|
||||||
|
when(ev.keyCode) {
|
||||||
|
KEYCODE_BUTTON_X -> {
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
KEYCODE_DPAD_LEFT ->{
|
||||||
|
leftClick()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
KEYCODE_BUTTON_B,KEYCODE_DPAD_RIGHT ->{
|
||||||
|
rightClick()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
KEYCODE_BUTTON_A, KEYCODE_DPAD_DOWN ->{
|
||||||
|
scrollDown()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
KEYCODE_BUTTON_Y,KEYCODE_DPAD_UP ->{
|
||||||
|
scrollUp()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
KEYCODE_BUTTON_START->{
|
||||||
|
hideRss()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
KEYCODE_BUTTON_SELECT ->{
|
||||||
|
vote()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else->{}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.dispatchKeyEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun vote(){
|
||||||
|
if (!loadWithIntent) {
|
||||||
|
|
||||||
|
Blog.LOGE("Arrow Center Click")
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
val result = query<RssData>().query("originPage == $0", rssId).find()
|
||||||
|
if (result.size > 0) {
|
||||||
|
result.forEach { it.vote = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doNextPage()
|
||||||
|
// webView?.evaluateJavascript("document.documentElement.outerHTML",
|
||||||
|
// object : ValueCallback<String> {
|
||||||
|
// override fun onReceiveValue(value: String?) {
|
||||||
|
// val html = value?.replace("\\u003C", "<")
|
||||||
|
// onHtml(html, false)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doNextPage() {
|
||||||
|
rssList.removeAll { it.equals(rssId) }
|
||||||
|
if (rssList.size > 0) {
|
||||||
|
rssId = rssList.removeAt(0)
|
||||||
|
load(rssId)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "없어 끄자", Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
registCancelSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hideRss() {
|
||||||
|
if (!loadWithIntent) {
|
||||||
|
Blog.LOGE("make no show")
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
val result =
|
||||||
|
query<RssData>().query("originPage == $0", rssId)
|
||||||
|
.find()
|
||||||
|
if (result.size > 0) {
|
||||||
|
result.forEach { it.read += 5 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doNextPage()
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rightClick() {
|
||||||
|
doNextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun leftClick() {
|
||||||
|
hideRss()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUnit() = ((webView?.height ?: 0) * 0.4).toInt()
|
||||||
|
|
||||||
|
fun scrollDown() {
|
||||||
|
try {
|
||||||
|
Blog.LOGE("Arrow Down Click")
|
||||||
|
registCancelSearch()
|
||||||
|
runOnUiThread {
|
||||||
|
webView?.scrollTo(webView?.scrollX?: 0,(webView?.scrollY?: 0) + getUnit())
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override var pdfListner : PDFPrint.OnPDFPrintListener? = object : PDFPrint.OnPDFPrintListener {
|
||||||
|
override fun onSuccess(file: File?) {
|
||||||
|
LogUtil.e("file.absolutePath >>> ${file?.absolutePath}")
|
||||||
|
|
||||||
|
Toast.makeText(
|
||||||
|
applicationContext,
|
||||||
|
resources.getString(
|
||||||
|
stringResPhotoSavedTo
|
||||||
|
) + file?.absolutePath,
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).apply {
|
||||||
|
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(exception: Exception?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// val tika: Tika = Tika()
|
||||||
|
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
|
||||||
|
if (ev?.device?.name?.contains("BLE-M3") == true) {
|
||||||
|
Blog.LOGE("keyEvent >>>>> dispatchGenericMotionEvent ${ev}")
|
||||||
|
ev?.action?.let { action ->
|
||||||
|
when(action) {
|
||||||
|
MotionEvent.ACTION_HOVER_ENTER -> {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_HOVER_MOVE ->{
|
||||||
|
Blog.LOGE("ACTION_HOVER_MOVE Click")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_BUTTON_PRESS -> {
|
||||||
|
if (actionButtonPressX * actionButtonPressY == 0f) {
|
||||||
|
actionButtonPressX = ev.x ?: 0f
|
||||||
|
actionButtonPressY = ev.y ?: 0f
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_BUTTON_RELEASE -> {
|
||||||
|
if (actionButtonPressX == ev.x && actionButtonPressY == ev.y) {
|
||||||
|
Blog.LOGE("Arrow Center Click")
|
||||||
|
if(actionButtonPressX.toInt() == 480 && actionButtonPressY < 2000) {
|
||||||
|
vote()
|
||||||
|
} else if(ev.y > 2000) {
|
||||||
|
hideRss()
|
||||||
|
}
|
||||||
|
registCancelSearch()
|
||||||
|
double = false
|
||||||
|
} else if (actionButtonPressY == ev.y) {
|
||||||
|
if (actionButtonPressX.minus(ev.x ?: 0f) > 0f) {
|
||||||
|
rightClick()
|
||||||
|
} else {
|
||||||
|
leftClick()
|
||||||
|
}
|
||||||
|
double = false
|
||||||
|
} else {
|
||||||
|
if (webView?.scrollY ?: 0 < 10 && actionButtonPressY.minus(ev.y ?: 0f) > 0f == false) {
|
||||||
|
if(double){
|
||||||
|
hideRss()
|
||||||
|
} else {
|
||||||
|
double = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
double = false
|
||||||
|
if (actionButtonPressY.minus(ev.y ?: 0f) > 0f) {
|
||||||
|
|
||||||
|
scrollDown()
|
||||||
|
} else {
|
||||||
|
scrollUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_HOVER_EXIT ->{
|
||||||
|
actionButtonPressX = 0f
|
||||||
|
actionButtonPressY = 0f
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
else -> {return false}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.dispatchGenericMotionEvent(ev)
|
||||||
|
}
|
||||||
|
fun scrollUp() {
|
||||||
|
webView?.scrollTo(webView?.scrollX?: 0,(webView?.scrollY?: 0) - getUnit())
|
||||||
|
Blog.LOGE("Arrow Up Click")
|
||||||
|
registCancelSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun load(newUrl: String) {
|
||||||
|
newUrl?.let { it ->
|
||||||
|
var url = if(it.startsWith("http://")) {
|
||||||
|
"https://${it.replace("http://","")}"
|
||||||
|
} else it
|
||||||
|
// LogUtil.e("newUrl >>> ${url}")
|
||||||
|
url.toUri().host?.let {
|
||||||
|
val splits = it.replace("http://","").replace("https://","").split(".")
|
||||||
|
when(splits.size) {
|
||||||
|
1-> host = splits[0]
|
||||||
|
2-> host = splits[0]
|
||||||
|
3-> host = splits[1]
|
||||||
|
4-> host = splits[2]
|
||||||
|
else -> {
|
||||||
|
host = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraHeaders == null) {
|
||||||
|
webView!!.loadUrl(url)
|
||||||
|
} else {
|
||||||
|
webView!!.loadUrl(url, extraHeaders!!)
|
||||||
|
}
|
||||||
|
registCancelSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initializeOptions() {
|
||||||
|
super.initializeOptions()
|
||||||
|
val intent = intent ?: return
|
||||||
|
val builder = intent.getSerializableExtra("builder") as RssViewBuilder?
|
||||||
|
this.rssId = builder?.rssId ?: ""
|
||||||
|
this.rssList.clear()
|
||||||
|
builder?.rssList?.let { this.rssList.addAll(it) }
|
||||||
|
|
||||||
|
Blog.LOGE("this.rssList >>>> ${this.rssList}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindViews() {
|
||||||
|
super.bindViews()
|
||||||
|
if (this.rssId.contains(".guru")|| this.rssId.contains("bookto")) {
|
||||||
|
webView?.clearCache(true)
|
||||||
|
Blog.LOGE("this.webView >>>> ${this.rssId}")
|
||||||
|
Blog.LOGE("this.webView >>>> ${this.webView}")
|
||||||
|
if (this.rssId.contains(".guru")) webView?.alpha = 0.2f
|
||||||
|
|
||||||
|
webView?.addJavascriptInterface(gji, "GJI")
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ByteArray.toHex() = joinToString(separator = "") { byte -> "%02x".format(byte) }
|
||||||
|
|
||||||
|
fun hashString(str: String, algorithm: String): ByteArray =
|
||||||
|
MessageDigest.getInstance(algorithm).digest(str.toByteArray(UTF_8))
|
||||||
|
|
||||||
|
fun getBase64ImageData(fileName : String) : String {
|
||||||
|
val inputStream: InputStream =
|
||||||
|
FileInputStream(fileName) // You can get an inputStream using any I/O API
|
||||||
|
val bytes: ByteArray
|
||||||
|
val buffer = ByteArray(8192)
|
||||||
|
var bytesRead: Int
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
try {
|
||||||
|
while ((inputStream.read(buffer).also { bytesRead = it }) != -1) {
|
||||||
|
output.write(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = output.toByteArray()
|
||||||
|
return Base64.encodeToString(bytes, Base64.DEFAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun run(value : String, autoCheck : Boolean) {
|
||||||
|
webView!!.setOnScrollChangeListener(null)
|
||||||
|
var mediaUrls = arrayListOf<String>()
|
||||||
|
mediaUrls.addAll(this.mediaUrls)
|
||||||
|
CookieSyncManager.createInstance(applicationContext)
|
||||||
|
CookieSyncManager.getInstance().sync()
|
||||||
|
val cookieManager =
|
||||||
|
CookieManager.getInstance()
|
||||||
|
val cookie =
|
||||||
|
cookieManager.getCookie(webView!!.url)
|
||||||
|
|
||||||
|
val agent = webView!!.settings.userAgentString
|
||||||
|
val current = webView!!.url
|
||||||
|
val newPath = hashString(current!!, "MD5").toHex()
|
||||||
|
Executors.newSingleThreadScheduledExecutor().schedule({
|
||||||
|
OfflineContents(this@RssViewerActivity, host!!,cookie,agent,current,newPath,value,autoCheck,mediaUrls).excute()
|
||||||
|
}, defaultTime, TimeUnit.MILLISECONDS)
|
||||||
|
runOnUiThread {
|
||||||
|
hideBlock()
|
||||||
|
if (!autoCheck) {
|
||||||
|
doNextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTrimMemory(level: Int) {
|
||||||
|
LogUtil.e("onTrimMemory >>> ${level} current ${url} current ${webView?.url ?: ""}")
|
||||||
|
super.onTrimMemory(level)
|
||||||
|
|
||||||
|
}
|
||||||
|
fun showDi(code : String, items : ArrayList<String>, links : ArrayList<String>) {
|
||||||
|
runOnUiThread {
|
||||||
|
registCancelSearch()
|
||||||
|
hideBlock()
|
||||||
|
val builder = AlertDialog.Builder(this@RssViewerActivity)
|
||||||
|
builder.setTitle("code : ${code}")
|
||||||
|
builder?.setItems(
|
||||||
|
items.toTypedArray()
|
||||||
|
) { dialog, which ->
|
||||||
|
LogUtil.e("hitTestResult.extra >>> ${dialog} ,${which}")
|
||||||
|
links?.get(which)?.let { link ->
|
||||||
|
(this.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager)?.let { mng ->
|
||||||
|
Blog.LOGE("link >>> ${link}")
|
||||||
|
mng.clearPrimaryClip()
|
||||||
|
mng.addPrimaryClipChangedListener {
|
||||||
|
mng.primaryClip?.getItemAt(0)?.text?.let {
|
||||||
|
if (it.length > 0 && it.startsWith("magnet:?xt=urn:")) {
|
||||||
|
Blog.LOGE("magnet >>>> $it")
|
||||||
|
try {
|
||||||
|
val launchIntent =
|
||||||
|
packageManager.getLaunchIntentForPackage("com.pikcloud.pikpak")
|
||||||
|
launchIntent?.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
|
||||||
|
startActivity(launchIntent)
|
||||||
|
}catch (e:Exception) {e.printStackTrace()}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mng.setPrimaryClip(ClipData.newPlainText("",link))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val dialog = builder?.create()
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val gji = GJInterface(this)
|
||||||
|
inner class GJInterface(val context: Context) {
|
||||||
|
@JavascriptInterface
|
||||||
|
fun onResult(result : String?) {
|
||||||
|
registCancelSearch()
|
||||||
|
result.toString()?.replace("\\u003C","<")?.replace("\\"","")?.let {
|
||||||
|
if (rssId.contains("guru")) {
|
||||||
|
Jsoup.parse(it)?.let { guru ->
|
||||||
|
Blog.LOGE("guru >>> ${guru.title()} ")
|
||||||
|
guru.getElementsByClass("row")?.forEach { row ->
|
||||||
|
row.getElementsByClass("grid1").first().getElementsByTag("a")?.first()
|
||||||
|
?.attr("title")?.let { title ->
|
||||||
|
Blog.LOGE("row >>> ${title.split("]")?.first()?.replace("[", "")}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(rssId.contains("book")){
|
||||||
|
Jsoup.parse(it)?.let { book ->
|
||||||
|
Blog.LOGE("book.title() >>> ${book.title()}")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
fun onCode(code : String) {
|
||||||
|
Blog.LOGE("onCode ${code}")
|
||||||
|
registCancelSearch()
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
var temp = arrayListOf<CiliMagnet>()
|
||||||
|
Jsoup.connect("https://cili.site/search?q=${URLEncoder.encode(code, Charset.defaultCharset().name())}").get().let { cili ->
|
||||||
|
|
||||||
|
cili.getElementsByTag("tr").forEach { cili_tr ->
|
||||||
|
CiliMagnet().let { ciliMgn ->
|
||||||
|
ciliMgn.link = if(cili_tr.getElementsByTag("a").size > 0)cili_tr.getElementsByTag("a").get(0).attr("href") else ""
|
||||||
|
ciliMgn.title = if(cili_tr.getElementsByTag("p").size > 0)cili_tr.getElementsByTag("p").text() else ""
|
||||||
|
ciliMgn.size = if(cili_tr.getElementsByClass("td-size").size > 0)cili_tr.getElementsByClass("td-size").text() else ""
|
||||||
|
Blog.LOGE("ciliMgn.size >>>> ${ciliMgn.size}")
|
||||||
|
Blog.LOGE("ciliMgn.size >>>> ${ciliMgn.title}")
|
||||||
|
if(ciliMgn.isValid() && temp.size < 8 ) {
|
||||||
|
try {
|
||||||
|
Jsoup.connect(ciliMgn.getMagnetPageLink()).get()
|
||||||
|
.let { mgn_Page ->
|
||||||
|
if (mgn_Page.getElementsByClass("input-group magnet-box").size > 0) {
|
||||||
|
mgn_Page.getElementsByClass("input-group magnet-box")
|
||||||
|
.get(0)?.let { magnet_box ->
|
||||||
|
magnet_box.getElementById(
|
||||||
|
"input-magnet"
|
||||||
|
)?.let { input_magnet ->
|
||||||
|
Blog.LOGE("input_magnet >>> ${input_magnet}")
|
||||||
|
ciliMgn.magnetLink =
|
||||||
|
input_magnet.attr("value")
|
||||||
|
.replace("&", "&")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.apply {
|
||||||
|
temp.add(ciliMgn)
|
||||||
|
|
||||||
|
}
|
||||||
|
}catch (e:Exception) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(temp.size > 3) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}.apply {
|
||||||
|
if (temp.size > 0) {
|
||||||
|
showDi(
|
||||||
|
code,
|
||||||
|
temp.map {
|
||||||
|
it.title.plus(" | ").plus(it.size).plus(" | ")
|
||||||
|
} as ArrayList<String>, temp.map {
|
||||||
|
it.magnetLink
|
||||||
|
} as ArrayList<String>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onHtml(value: String?, autoCheck : Boolean) {
|
||||||
|
vote()
|
||||||
|
// chechHandler.removeCallbacks(cancelSearch)
|
||||||
|
// if (loadWithIntent){
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// showBlock()
|
||||||
|
//
|
||||||
|
// var count = (webView!!.contentHeight / (webView!!.height * 0.3).toInt())
|
||||||
|
// LogUtil.e("count >>>> ${count} webView!!.contentHeight >>>> ${webView!!.contentHeight} , webView!!.height >>>> ${webView!!.height} :: ${(webView!!.height * 0.3).toInt()}")
|
||||||
|
// chechHandler.postDelayed(pageDown, defaultTime)
|
||||||
|
// webView!!.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
|
||||||
|
// val measuredHeight: Int = v.measuredHeight
|
||||||
|
// LogUtil.e("OnScrollChange >>> ${scrollY} , ${oldScrollY}")
|
||||||
|
// if(measuredHeight + scrollY == webView!!.computeVerticalScrollRange()){
|
||||||
|
// chechHandler.removeCallbacks(scrollDown)
|
||||||
|
// chechHandler.removeCallbacks(pageDown)
|
||||||
|
// chechHandler.postDelayed({
|
||||||
|
// webView!!.evaluateJavascript("document.documentElement.outerHTML",object : ValueCallback<String> {
|
||||||
|
// override fun onReceiveValue(value: String?) {
|
||||||
|
// val html = value?.replace("\\u003C", "<")
|
||||||
|
// this@RssViewerActivity.run(html!!, autoCheck)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// },defaultTime.times(2))
|
||||||
|
// } else {
|
||||||
|
// chechHandler.removeCallbacks(cancelSearch)
|
||||||
|
// Blog.LOGE("onScrollChanged called PageDown")
|
||||||
|
//// chechHandler.removeCallbacks(scrollDown)
|
||||||
|
// if (switch) {
|
||||||
|
// chechHandler.removeCallbacks(pageDown)
|
||||||
|
// chechHandler.postDelayed(scrollDown, defaultTime)
|
||||||
|
// switch = false
|
||||||
|
// } else {
|
||||||
|
// switch = true
|
||||||
|
// chechHandler.removeCallbacks(scrollDown)
|
||||||
|
// chechHandler.postDelayed(pageDown, defaultTime)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//// else if (scrollY % 10 == 0 || oldScrollY % 10 == 0){
|
||||||
|
////// chechHandler.removeCallbacks(pageDown)
|
||||||
|
////// chechHandler.postDelayed(scrollDown, defaultTime)
|
||||||
|
//// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
var switch = false
|
||||||
|
var scrollDown : Runnable = Runnable{
|
||||||
|
webView?.let {
|
||||||
|
var times = if (it.scrollY > 50) it.scrollY / 50 else 5
|
||||||
|
it.scrollTo(it.scrollX,times.plus(1).times(50))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pageDown : Runnable = Runnable{
|
||||||
|
webView!!.pageDown(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var isFirst = true
|
||||||
|
override fun webviewOnPageFinished() {
|
||||||
|
if (rssId.contains(".guru")) {
|
||||||
|
registCancelSearch()
|
||||||
|
webView?.postDelayed(2000L,{
|
||||||
|
webView?.evaluateJavascript("try{GJI.log();}catch(e){console.log(e);}", {})
|
||||||
|
webView?.evaluateJavascript("try{GJI.onResult(document.documentElement.outerHTML);}catch(e){console.log(e);}", {})
|
||||||
|
webView?.evaluateJavascript("document.getElementsByClassName('banner-ad-wrapper')[0].remove()",{})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if(rssId.contains("booktoki")) {
|
||||||
|
registCancelSearch()
|
||||||
|
webView?.postDelayed(2000L,{
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
double = false
|
||||||
|
registCancelSearch()
|
||||||
|
if (hasYoutubePlayer) {
|
||||||
|
LogUtil.e("hasYoutubePlayer >>> ${hasYoutubePlayer}")
|
||||||
|
}
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
val result =
|
||||||
|
query<RssData>().query("originPage == $0", rssId)
|
||||||
|
.find()
|
||||||
|
// if (result.size == 1) {
|
||||||
|
// result.first().read += 1
|
||||||
|
// } else {
|
||||||
|
result.forEach { it.read += 1 }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val muted =
|
||||||
|
"try{" +
|
||||||
|
"var videos = document.getElementsByTagName('video');" +
|
||||||
|
"for (var i = 0; i < videos.length; i++) {" +
|
||||||
|
"videos[i].muted = true;" +
|
||||||
|
"}" +
|
||||||
|
"}catch(e){}"
|
||||||
|
webView?.evaluateJavascript(muted,{
|
||||||
|
Blog.LOGE("RESULT >> $it")
|
||||||
|
})
|
||||||
|
}catch (e : Exception) {e.printStackTrace()}
|
||||||
|
try {
|
||||||
|
val muted =
|
||||||
|
"try{" +
|
||||||
|
"var videos = document.getElementsByTagName('video');" +
|
||||||
|
"for (var i = 0; i < videos.length; i++) {" +
|
||||||
|
"videos[i].controlsList.remove('nodownload');"
|
||||||
|
"}" +
|
||||||
|
"}catch(e){}"
|
||||||
|
webView?.evaluateJavascript(muted,{
|
||||||
|
Blog.LOGE("RESULT >> $it")
|
||||||
|
})
|
||||||
|
}catch (e : Exception) {e.printStackTrace()}
|
||||||
|
webView?.postDelayed({
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
val muted =
|
||||||
|
"try{" +
|
||||||
|
"var videos = document.getElementsByTagName('video');" +
|
||||||
|
"for (var i = 0; i < videos.length; i++) {" +
|
||||||
|
"videos[i].muted = true;" +
|
||||||
|
"}" +
|
||||||
|
"}catch(e){console.log(e);}"
|
||||||
|
webView?.evaluateJavascript(muted,{
|
||||||
|
Blog.LOGE("RESULT >> $it")
|
||||||
|
})
|
||||||
|
}catch (e : Exception) {e.printStackTrace()}
|
||||||
|
try {
|
||||||
|
val muted =
|
||||||
|
"try{" +
|
||||||
|
"var videos = document.getElementsByTagName('video');" +
|
||||||
|
"for (var i = 0; i < videos.length; i++) {" +
|
||||||
|
"videos[i].controlsList.remove('nodownload');"
|
||||||
|
"}" +
|
||||||
|
"}catch(e){console.log(e);}"
|
||||||
|
webView?.evaluateJavascript(muted,{
|
||||||
|
Blog.LOGE("RESULT >> $it")
|
||||||
|
})
|
||||||
|
}catch (e : Exception) {e.printStackTrace()}
|
||||||
|
},1000)
|
||||||
|
if (loadWithIntent) {
|
||||||
|
webView?.evaluateJavascript(
|
||||||
|
"try{document.querySelector('meta[name=viewport]').setAttribute('content','initial-scale=1.0')}catch(e){}",
|
||||||
|
null
|
||||||
|
)
|
||||||
|
webView?.evaluateJavascript(
|
||||||
|
"try{document.querySelector('meta[name=viewport]').setAttribute('content','initial-scale=1.0')}catch(e){}",
|
||||||
|
null
|
||||||
|
)
|
||||||
|
webView?.settings?.useWideViewPort = true
|
||||||
|
}
|
||||||
|
if (webView?.url?.contains("dcinside") == true) {
|
||||||
|
webView?.evaluateJavascript(
|
||||||
|
"try{document.querySelector('#div_adnmore_area').hidden = true;}catch(e){}",
|
||||||
|
null
|
||||||
|
)
|
||||||
|
} else if (webView?.url?.contains("fmkorea") == true) {
|
||||||
|
if (loadWithIntent) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
webView?.postDelayed({
|
||||||
|
webView?.evaluateJavascript(
|
||||||
|
"try{document.querySelector('.m_rd_nav_side').hidden = true;}catch(e){}",
|
||||||
|
null
|
||||||
|
)
|
||||||
|
webView?.evaluateJavascript(
|
||||||
|
"try{document.querySelector('[class*='bd bd_mobile ']').remove();}catch(e){}",
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}, 500L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class BookHelper {
|
||||||
|
@JavascriptInterface
|
||||||
|
fun sendValueFromHtml(string: String) {
|
||||||
|
|
||||||
|
Jsoup.parse(string)?.let { html ->
|
||||||
|
|
||||||
|
val toon_intro = html.getElementsByClass("toon_index")?.first()
|
||||||
|
val view_padding = html.select("#bo_v_con")
|
||||||
|
if (toon_intro != null) {
|
||||||
|
|
||||||
|
}else if (view_padding.size > 0){
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
Blog.LOGE("finishedUrl >>> ${rssId} :::: ${html.title()}")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.home.adapters
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
+5
-8
@@ -16,25 +16,22 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.adapters
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
import rasel.lunar.launcher.databinding.ListItemWithBinding
|
import bums.lunatic.launcher.databinding.ListItemWithBinding
|
||||||
import rasel.lunar.launcher.model.NotificationItem
|
import bums.lunatic.launcher.model.NotificationItem
|
||||||
import rasel.lunar.launcher.utils.BLog
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import rasel.lunar.launcher.workers.WorkersDb
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
+6
-6
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.adapters
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -29,11 +29,11 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
import rasel.lunar.launcher.R
|
import bums.lunatic.launcher.R
|
||||||
import rasel.lunar.launcher.databinding.CalllogItemBinding
|
import bums.lunatic.launcher.databinding.CalllogItemBinding
|
||||||
import rasel.lunar.launcher.utils.getContactId
|
import bums.lunatic.launcher.utils.getContactId
|
||||||
import rasel.lunar.launcher.workers.RecentCall
|
import bums.lunatic.launcher.workers.RecentCall
|
||||||
|
|
||||||
|
|
||||||
internal class RecentCallsAdapter(
|
internal class RecentCallsAdapter(
|
||||||
+46
-20
@@ -1,25 +1,25 @@
|
|||||||
package rasel.lunar.launcher.home.adapters
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
import android.util.Xml
|
import android.util.Xml
|
||||||
|
import bums.lunatic.launcher.model.NewsData
|
||||||
|
import bums.lunatic.launcher.model.RssDataInterface
|
||||||
|
import bums.lunatic.launcher.model.others.Reddit
|
||||||
|
import bums.lunatic.launcher.utils.beforeOneDay
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
import org.xmlpull.v1.XmlPullParserException
|
import org.xmlpull.v1.XmlPullParserException
|
||||||
import rasel.lunar.launcher.model.RssDataInterface
|
|
||||||
import rasel.lunar.launcher.model.NewsData
|
|
||||||
import rasel.lunar.launcher.model.others.Reddit
|
|
||||||
import rasel.lunar.launcher.utils.beforeDay
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
|
||||||
object RssFeedsParser {
|
object RssFeedsParser {
|
||||||
var parseDateFormat: SimpleDateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH)
|
var parseDateFormat: SimpleDateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH)
|
||||||
var limitDateTime = beforeDay(Date(),3)
|
var parseDateFormat2: SimpleDateFormat = SimpleDateFormat("E, dd MM yyyy HH:mm:ss ZZ", Locale.ENGLISH)
|
||||||
|
var limitDateTime = beforeOneDay()
|
||||||
fun getFeeds(url : String) : List<RssDataInterface> {
|
fun getFeeds(url : String) : List<RssDataInterface> {
|
||||||
var returnList = mutableListOf<RssDataInterface>()
|
var returnList = mutableListOf<RssDataInterface>()
|
||||||
try {
|
try {
|
||||||
@@ -30,15 +30,18 @@ object RssFeedsParser {
|
|||||||
return returnList
|
return returnList
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getReddit(url : String): List<RssDataInterface> {
|
fun getReddit(url : String, nsfw : Boolean): List<RssDataInterface> {
|
||||||
var returnList = mutableListOf<RssDataInterface>()
|
var returnList = mutableListOf<RssDataInterface>()
|
||||||
var dateTime = beforeDay(Date(),3)
|
var dateTime = beforeOneDay()
|
||||||
try {
|
try {
|
||||||
var mReddit = Gson().fromJson(InputStreamReader(getInputStream(url)!!), Reddit::class.java)
|
var mReddit = Gson().fromJson(InputStreamReader(getInputStream(url)!!), Reddit::class.java)
|
||||||
mReddit.data?.children?.forEach {
|
mReddit.data?.children?.forEach {
|
||||||
|
it.data?.nsfw = nsfw
|
||||||
if(((it.data?.created_utc ?: 0).toLong() * 1000L > dateTime)) {
|
if(((it.data?.created_utc ?: 0).toLong() * 1000L > dateTime)) {
|
||||||
(it.data as? RssDataInterface)?.let { rss ->
|
(it.data as? RssDataInterface)?.let { rss ->
|
||||||
returnList.add(rss)
|
if (rss.title().contains("request", true) == false) {
|
||||||
|
returnList.add(rss)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,6 +84,7 @@ object RssFeedsParser {
|
|||||||
var date = 0L
|
var date = 0L
|
||||||
var desc : String? = null
|
var desc : String? = null
|
||||||
var source : String? = null
|
var source : String? = null
|
||||||
|
|
||||||
val items: MutableList<NewsData> = ArrayList()
|
val items: MutableList<NewsData> = ArrayList()
|
||||||
|
|
||||||
while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
@@ -91,21 +95,29 @@ object RssFeedsParser {
|
|||||||
val name = parser.name
|
val name = parser.name
|
||||||
if (name == "title") {
|
if (name == "title") {
|
||||||
title = readTitle(parser)
|
title = readTitle(parser)
|
||||||
} else if (name == "link") {
|
}else if (name == "ht:news_item_title") {
|
||||||
|
title = readByTag(parser,"ht:news_item_title")
|
||||||
|
}else if (name == "ht:news_item_url") {
|
||||||
|
link = readByTag(parser,"ht:news_item_url")
|
||||||
|
}else if (name == "ht:news_item_picture") {
|
||||||
|
source = readByTag(parser,"ht:news_item_picture")
|
||||||
|
}else if (name == "ht:picture") {
|
||||||
|
source = readByTag(parser,"ht:picture")
|
||||||
|
} else if (name == "link") {
|
||||||
link = readLink(parser)
|
link = readLink(parser)
|
||||||
} else if (name == "pubDate") {
|
} else if (name == "pubDate") {
|
||||||
try {
|
val dateStr = readDate(parser)
|
||||||
date = parseDateFormat.parse(readDate(parser))?.time ?: 0L
|
try { date = parseDateFormat.parse(dateStr)?.time ?: 0L } catch (e : Exception) { date = 0L }
|
||||||
}catch (e : Exception) {
|
if (date == 0L) { try { date = parseDateFormat2.parse(dateStr)?.time ?: 0L } catch (e: Exception) { } }
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
} else if (name == "description") {
|
} else if (name == "description") {
|
||||||
desc = readDesc(parser)
|
desc = readDesc(parser)
|
||||||
} else if (name == "source") {
|
} else if (name == "source") {
|
||||||
source = readThumbnail(parser)
|
source = readThumbnail(parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (date > limitDateTime && title != null && link != null) {
|
if (date > limitDateTime && title != null && link != null) {
|
||||||
|
// Blog.LOGE("date ${date} title ${title} link ${link}")
|
||||||
val item = NewsData(title, link)
|
val item = NewsData(title, link)
|
||||||
item.pubDate = date
|
item.pubDate = date
|
||||||
item.source = source
|
item.source = source
|
||||||
@@ -115,7 +127,7 @@ object RssFeedsParser {
|
|||||||
link = null
|
link = null
|
||||||
source = null
|
source = null
|
||||||
desc = null
|
desc = null
|
||||||
date = 0
|
// date = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
@@ -137,11 +149,25 @@ object RssFeedsParser {
|
|||||||
return title
|
return title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(XmlPullParserException::class, IOException::class)
|
||||||
|
private fun readByTag(parser: XmlPullParser, tag : String): String {
|
||||||
|
parser.require(XmlPullParser.START_TAG, null, tag)
|
||||||
|
val title = readText(parser)
|
||||||
|
// Blog.LOGE("readByTag >>>> ${tag} >> ${title}")
|
||||||
|
parser.require(XmlPullParser.END_TAG, null, tag)
|
||||||
|
return title
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(XmlPullParserException::class, IOException::class)
|
@Throws(XmlPullParserException::class, IOException::class)
|
||||||
private fun readDate(parser: XmlPullParser): String {
|
private fun readDate(parser: XmlPullParser): String {
|
||||||
parser.require(XmlPullParser.START_TAG, null, "pubDate")
|
var date = ""
|
||||||
val date = readText(parser)
|
try {
|
||||||
parser.require(XmlPullParser.END_TAG, null, "pubDate")
|
parser.require(XmlPullParser.START_TAG, null, "pubDate")
|
||||||
|
date = readText(parser)
|
||||||
|
parser.require(XmlPullParser.END_TAG, null, "pubDate")
|
||||||
|
} catch (e : Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
return date
|
return date
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.ListItemWithBinding
|
||||||
|
import bums.lunatic.launcher.home.RssViewBuilder
|
||||||
|
import bums.lunatic.launcher.model.RssData
|
||||||
|
import bums.lunatic.launcher.model.RssDataInterface
|
||||||
|
import bums.lunatic.launcher.model.RssDataType
|
||||||
|
import bums.lunatic.launcher.openClient
|
||||||
|
import bums.lunatic.launcher.openDotax
|
||||||
|
import bums.lunatic.launcher.openReddit
|
||||||
|
import bums.lunatic.launcher.openYouTube
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import com.google.android.material.imageview.ShapeableImageView
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
import kr.lunaticbum.awesomewebview.AwesomeWebView
|
||||||
|
import io.realm.kotlin.UpdatePolicy
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kr.lunaticbum.awesomewebview.listeners.WebViewListener
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
|
||||||
|
internal class RssItemAdapter (
|
||||||
|
private val context: Context) : RecyclerView.Adapter<RssHolder>() {
|
||||||
|
companion object {
|
||||||
|
@SuppressLint("SimpleDateFormat")
|
||||||
|
val dateFormat = SimpleDateFormat("a HH:mm / yy - MM - dd")
|
||||||
|
val emptyDate = " - "
|
||||||
|
var rssList: ArrayList<String> = ArrayList()
|
||||||
|
val webViewListener = object : WebViewListener() {
|
||||||
|
override fun onCustomMenuClick(menuCode: String?) {
|
||||||
|
super.onCustomMenuClick(menuCode)
|
||||||
|
if ("PDF".equals(menuCode)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val dateViewClick = View.OnClickListener { v ->
|
||||||
|
(v?.tag as? RssData)?.let { rss ->
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
rss.read = rss.read + 1
|
||||||
|
if(rss.getCho()?.length ?: 0 < 1) {
|
||||||
|
rss.chosung = rss.title
|
||||||
|
}
|
||||||
|
copyToRealm(rss,UpdatePolicy.ALL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when(rss.category()) {
|
||||||
|
RssDataType.GURU,RssDataType.MOST,RssDataType.REDDIT_NSFW -> {
|
||||||
|
v.findViewById<ShapeableImageView>(R.id.circle_preview)?.let {
|
||||||
|
if (it.visibility == View.GONE) {
|
||||||
|
it.visibility = View.VISIBLE
|
||||||
|
it.postDelayed({
|
||||||
|
it.visibility = View.GONE
|
||||||
|
}, 2000L)
|
||||||
|
} else {
|
||||||
|
if (RssDataType.REDDIT_NSFW.equals(rss.category())) {
|
||||||
|
openReddit(rss.originPage())
|
||||||
|
} else {
|
||||||
|
RssViewBuilder(lActivity!!)
|
||||||
|
.setRssList(arrayListOf<String>().apply {
|
||||||
|
var jjjj = hashSetOf<String>()
|
||||||
|
jjjj.addAll(rssList)
|
||||||
|
this.addAll(jjjj)
|
||||||
|
})
|
||||||
|
.setRssId(rss.originPage())
|
||||||
|
.showIconClose(true).showIconBack(false).showProgressBar(true).backPressToClose(false).webViewMixedContentMode(1)
|
||||||
|
.show(rss.originPage!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RssDataType.REDDIT -> {
|
||||||
|
openReddit(rss.originPage())
|
||||||
|
}
|
||||||
|
RssDataType.DOTAX -> {
|
||||||
|
RssViewBuilder(lActivity!!)
|
||||||
|
.setRssList(arrayListOf<String>().apply {
|
||||||
|
var jjjj = hashSetOf<String>()
|
||||||
|
jjjj.addAll(rssList)
|
||||||
|
this.addAll(jjjj)
|
||||||
|
})
|
||||||
|
.setRssId(rss.originPage())
|
||||||
|
.showIconClose(true).showIconBack(false).showProgressBar(true).webViewMixedContentMode(0)
|
||||||
|
.show(rss.originPage!!)
|
||||||
|
}
|
||||||
|
RssDataType.YOUTUBE -> { openYouTube(rss.originPage())
|
||||||
|
}
|
||||||
|
RssDataType.CLIEN -> {
|
||||||
|
openClient(rss.originPage())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
RssViewBuilder(lActivity!!)
|
||||||
|
.setRssList(arrayListOf<String>().apply {
|
||||||
|
var jjjj = hashSetOf<String>()
|
||||||
|
jjjj.addAll(rssList)
|
||||||
|
this.addAll(jjjj)
|
||||||
|
})
|
||||||
|
.setRssId(rss.originPage())
|
||||||
|
.showIconClose(true).showIconBack(false).showProgressBar(true).webViewMixedContentMode(0)
|
||||||
|
.show(rss.originPage!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var rssDataItemLis: ArrayList<RssData> = arrayListOf()
|
||||||
|
val mLongClickListener = View.OnLongClickListener { v ->
|
||||||
|
(v?.tag as? RssData)?.let { rss ->
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
rss.vote = !rss.vote
|
||||||
|
copyToRealm(rss,UpdatePolicy.ALL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dateViewClick.onClick(v)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RssHolder {
|
||||||
|
val binding = ListItemWithBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false)
|
||||||
|
return RssHolder(binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return rssDataItemLis.size
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onBindViewHolder(holder: RssHolder, position: Int) {
|
||||||
|
val rssData = rssDataItemLis[position]
|
||||||
|
if (rssData.pubDate() > 1000L) {
|
||||||
|
holder.view.date.text = dateFormat.format(Date(rssData.pubDate()))
|
||||||
|
} else {
|
||||||
|
holder.view.date.text = emptyDate
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(RssDataType.NEWSFEED.equals(rssData.category())) {
|
||||||
|
// Blog.LOGE("rssData >>>> ${rssData.thumbnailUrl()}")
|
||||||
|
// }
|
||||||
|
|
||||||
|
holder.view.title.text = "".plus(if(rssData.vote) " * " else "").plus(rssData.title().plus("[R:${rssData.read}]"))
|
||||||
|
holder.view.desc.text = rssData.description()
|
||||||
|
|
||||||
|
var param = holder.view.circlePreview.layoutParams
|
||||||
|
holder.view.circlePreview.layoutParams = ConstraintLayout.LayoutParams(rssData.category().defaultImgSize(), param.height)
|
||||||
|
holder.view.circlePreview.visibility = rssData.category().getDefaultVisibiliy()
|
||||||
|
Picasso.get().cancelRequest(holder.view.circlePreview)
|
||||||
|
|
||||||
|
if(rssData.thumbnailUrl()?.length ?: 0 > 6) {
|
||||||
|
Picasso.get().load(rssData.thumbnailUrl().replace("&","&").toUri()).into(holder.view.circlePreview)
|
||||||
|
} else if (rssData.category().getResId() > 0 ) {
|
||||||
|
holder.view.circlePreview.setImageResource(rssData.category().getResId())
|
||||||
|
} else {
|
||||||
|
holder.view.circlePreview.setImageDrawable(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.itemView.tag = rssData
|
||||||
|
holder.itemView.setOnClickListener(dateViewClick)
|
||||||
|
// v.setOnLongClickListener {
|
||||||
|
// WorkersDb.getRealm().apply {
|
||||||
|
// copyFromRealm(rss)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
holder.itemView.setOnLongClickListener(mLongClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
var layoutManager : LinearLayoutManager? = null
|
||||||
|
var recyclerView: RecyclerView? = null
|
||||||
|
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||||
|
layoutManager = recyclerView.layoutManager as? LinearLayoutManager
|
||||||
|
this.recyclerView = recyclerView
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateData(newList: List<RssData>) {
|
||||||
|
try {
|
||||||
|
DiffUtil.calculateDiff(RssItemDiffUtil(rssDataItemLis, newList)).apply {
|
||||||
|
|
||||||
|
}.dispatchUpdatesTo(this).apply {
|
||||||
|
val visibleItemCount = (layoutManager?.findLastVisibleItemPosition() ?: 0) - (layoutManager?.findFirstVisibleItemPosition() ?: 0)
|
||||||
|
val first = layoutManager?.findLastVisibleItemPosition() ?: 0
|
||||||
|
if (visibleItemCount > 0) {
|
||||||
|
this@RssItemAdapter.notifyItemRangeChanged(first, visibleItemCount)
|
||||||
|
// recyclerView?.scrollToPosition(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rssDataItemLis.clear()
|
||||||
|
rssDataItemLis.addAll(newList)
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
rssList.clear()
|
||||||
|
rssList.addAll(newList.map { it.originPage() })
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun refresh() {
|
||||||
|
try {
|
||||||
|
val visibleItemCount = (layoutManager?.findLastVisibleItemPosition() ?: 0) - (layoutManager?.findFirstVisibleItemPosition() ?: 0)
|
||||||
|
val first = layoutManager?.findLastVisibleItemPosition() ?: 0
|
||||||
|
if (visibleItemCount > 0) {
|
||||||
|
this@RssItemAdapter.notifyItemRangeChanged(first, visibleItemCount)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class RssHolder(var view: ListItemWithBinding) : RecyclerView.ViewHolder(view.root) {}
|
||||||
|
internal class RssItemDiffUtil(
|
||||||
|
var oldList: List<RssDataInterface>, var newList: List<RssDataInterface>
|
||||||
|
) : DiffUtil.Callback() {
|
||||||
|
|
||||||
|
override fun getOldListSize(): Int = oldList.size
|
||||||
|
override fun getNewListSize(): Int = newList.size
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
oldList[oldItemPosition].originPage() == if (newList.size > newItemPosition) newList[newItemPosition].originPage() else ""
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
oldList[oldItemPosition].originPage() == if (newList.size > newItemPosition) newList[newItemPosition].originPage() else ""
|
||||||
|
}
|
||||||
+5
-5
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.adapters
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -24,11 +24,11 @@ import android.view.LayoutInflater
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.ListItemBinding
|
||||||
|
import bums.lunatic.launcher.model.jGuruTag
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
|
||||||
import rasel.lunar.launcher.R
|
|
||||||
import rasel.lunar.launcher.databinding.ListItemBinding
|
|
||||||
import rasel.lunar.launcher.model.jGuruTag
|
|
||||||
|
|
||||||
internal class RssTagAdapter(
|
internal class RssTagAdapter(
|
||||||
private val smsList: ArrayList<jGuruTag>,
|
private val smsList: ArrayList<jGuruTag>,
|
||||||
+6
-6
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.adapters
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -26,11 +26,11 @@ import android.view.LayoutInflater
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
import rasel.lunar.launcher.R
|
import bums.lunatic.launcher.R
|
||||||
import rasel.lunar.launcher.databinding.SmsItemBinding
|
import bums.lunatic.launcher.databinding.SmsItemBinding
|
||||||
import rasel.lunar.launcher.utils.getContactName
|
import bums.lunatic.launcher.utils.getContactName
|
||||||
import rasel.lunar.launcher.workers.RecentSms
|
import bums.lunatic.launcher.workers.RecentSms
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
|
import android.R
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffXfermode
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
|
|
||||||
|
abstract class SwipeToDeleteCallback internal constructor(context: Context) :
|
||||||
|
ItemTouchHelper.Callback() {
|
||||||
|
var mContext: Context = context
|
||||||
|
private val mClearPaint = Paint()
|
||||||
|
private val mBackground = ColorDrawable()
|
||||||
|
private val backgroundColor = Color.parseColor("#55b80f0a")
|
||||||
|
private val reverseColor = Color.parseColor("#55b80fb8")
|
||||||
|
private val deleteDrawable: Drawable?
|
||||||
|
private val intrinsicWidth: Int
|
||||||
|
private val intrinsicHeight: Int
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
mClearPaint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.DARKEN))
|
||||||
|
deleteDrawable = ContextCompat.getDrawable(mContext, R.drawable.ic_delete)
|
||||||
|
intrinsicWidth = deleteDrawable!!.intrinsicWidth
|
||||||
|
intrinsicHeight = deleteDrawable.intrinsicHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getMovementFlags(
|
||||||
|
@NonNull recyclerView: RecyclerView,
|
||||||
|
@NonNull viewHolder: RecyclerView.ViewHolder
|
||||||
|
): Int {
|
||||||
|
return makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
@NonNull recyclerView: RecyclerView,
|
||||||
|
@NonNull viewHolder: RecyclerView.ViewHolder,
|
||||||
|
@NonNull viewHolder1: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChildDraw(
|
||||||
|
@NonNull c: Canvas,
|
||||||
|
@NonNull recyclerView: RecyclerView,
|
||||||
|
@NonNull viewHolder: RecyclerView.ViewHolder,
|
||||||
|
dX: Float,
|
||||||
|
dY: Float,
|
||||||
|
actionState: Int,
|
||||||
|
isCurrentlyActive: Boolean
|
||||||
|
) {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||||
|
|
||||||
|
val itemView = viewHolder.itemView
|
||||||
|
val itemHeight = itemView.height
|
||||||
|
|
||||||
|
val isCancelled = (dX == 0f) && !isCurrentlyActive
|
||||||
|
if (isCancelled) {
|
||||||
|
clearCanvas(
|
||||||
|
c,
|
||||||
|
itemView.right + dX,
|
||||||
|
itemView.top.toFloat(),
|
||||||
|
itemView.right.toFloat(),
|
||||||
|
itemView.bottom.toFloat()
|
||||||
|
)
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (dX.toInt() < 0) {
|
||||||
|
mBackground.color = backgroundColor
|
||||||
|
mBackground.setBounds(
|
||||||
|
itemView.right + dX.toInt(),
|
||||||
|
itemView.top,
|
||||||
|
itemView.right,
|
||||||
|
itemView.bottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
mBackground.color = reverseColor
|
||||||
|
mBackground.setBounds(
|
||||||
|
itemView.left,
|
||||||
|
itemView.top,
|
||||||
|
itemView.left + dX.toInt(),
|
||||||
|
itemView.bottom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
mBackground.draw(c)
|
||||||
|
|
||||||
|
// val deleteIconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
|
||||||
|
// val deleteIconMargin = (itemHeight - intrinsicHeight) / 2
|
||||||
|
// val deleteIconLeft = itemView.right - deleteIconMargin - intrinsicWidth
|
||||||
|
// val deleteIconRight = itemView.right - deleteIconMargin
|
||||||
|
// val deleteIconBottom = deleteIconTop + intrinsicHeight
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// deleteDrawable!!.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom)
|
||||||
|
// deleteDrawable.draw(c)
|
||||||
|
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearCanvas(c: Canvas, left: Float, top: Float, right: Float, bottom: Float) {
|
||||||
|
c.drawRect(left, top, right, bottom, mClearPaint)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSwipeThreshold(@NonNull viewHolder: RecyclerView.ViewHolder): Float {
|
||||||
|
return 0.35f
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.LinearSnapHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.databinding.WeatherBookBinding
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
|
||||||
|
class WeatherAdapter(
|
||||||
|
private val pages: List<Int>,
|
||||||
|
private val adatpers: List<RecyclerView.Adapter<out RecyclerView.ViewHolder>?>,
|
||||||
|
private val weatherBook: WeatherBookBinding? = null)
|
||||||
|
: RecyclerView.Adapter<WeatherAdapter.PageViewHolder>() {
|
||||||
|
|
||||||
|
class PageViewHolder(val view: View): RecyclerView.ViewHolder(view)
|
||||||
|
|
||||||
|
|
||||||
|
var childs : ArrayList<RecyclerView> = arrayListOf<RecyclerView>()
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("ResourceType")
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageViewHolder {
|
||||||
|
|
||||||
|
|
||||||
|
val layoutInflater = LayoutInflater.from(parent.context).inflate(pages[viewType], parent, false)
|
||||||
|
// var first = layoutInflater.findViewById<RecyclerView>(R.id.recycler_hourly_weather)
|
||||||
|
// var second = layoutInflater.findViewById<RecyclerView>(R.id.weather_dress_recycller)
|
||||||
|
|
||||||
|
return PageViewHolder(layoutInflater)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun syncScroll(newPosition: Int) {
|
||||||
|
childs[newPosition].let {recyclerView ->
|
||||||
|
Blog.LOGE("recyclerView >>> ${recyclerView} 1 ")
|
||||||
|
if (!isSyncingScroll) {
|
||||||
|
isSyncingScroll = true
|
||||||
|
Blog.LOGE("recyclerView >>> ${recyclerView} 2 ")
|
||||||
|
childs.forEach { c ->
|
||||||
|
// val visibleItemCount = (layoutManager?.findLastVisibleItemPosition() ?: 0) - (layoutManager?.findFirstVisibleItemPosition() ?: 0)
|
||||||
|
if (c != recyclerView) {
|
||||||
|
(c.layoutManager as LinearLayoutManager)?.let {
|
||||||
|
it.findFirstVisibleItemPosition()?.let {
|
||||||
|
(recyclerView?.layoutManager as? LinearLayoutManager)?.let { target ->
|
||||||
|
target.scrollToPositionWithOffset(it, 0)
|
||||||
|
}
|
||||||
|
// .scrollToPosition(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Blog.LOGE("recyclerView >>> ${recyclerView} 3 ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isSyncingScroll = false
|
||||||
|
Blog.LOGE("recyclerView >>> ${recyclerView} 4 ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val mOnScrollListener = object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
|
// recyclerView.postDelayed({syncScroll(recyclerView)},10L)
|
||||||
|
// recyclerView.post{syncScroll(recyclerView)}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var isSyncingScroll = false
|
||||||
|
override fun onBindViewHolder(holder: PageViewHolder, position: Int) {
|
||||||
|
if (adatpers[position] != null) {
|
||||||
|
(holder.view as RecyclerView).apply {
|
||||||
|
this.adapter = adatpers[position]
|
||||||
|
this.layoutManager = LinearLayoutManager(this.context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
|
if (!childs.contains(this)) {
|
||||||
|
childs.add(this)
|
||||||
|
this.addOnScrollListener(mOnScrollListener)
|
||||||
|
LinearSnapHelper().attachToRecyclerView(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// when (position) {
|
||||||
|
// 0 -> holder.view.findViewById<RecyclerView>(R.id.recycler_hourly_weather).apply {
|
||||||
|
// this.adapter = adatpers[position]
|
||||||
|
// this.layoutManager =
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// else -> holder.view.findViewById<RecyclerView>(R.id.weather_dress_recycller).apply {
|
||||||
|
// this.adapter = adatpers[position]
|
||||||
|
// this.layoutManager =
|
||||||
|
// LinearLayoutManager(this.context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = pages.size
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int = position
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.databinding.ItemRecHourlyDressBinding
|
||||||
|
import bums.lunatic.launcher.model.Hour
|
||||||
|
import bums.lunatic.launcher.model.WeatherInfoManager
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
class WeatherDressAdatper (private val dataSet: ArrayList<Hour>) : RecyclerView.Adapter<WeatherDressAdatper.ViewHolder>(){
|
||||||
|
var isChangedAmOrPm: Boolean = true
|
||||||
|
|
||||||
|
class ViewHolder(val viewItem: ItemRecHourlyDressBinding): RecyclerView.ViewHolder(viewItem.root)
|
||||||
|
|
||||||
|
// @SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun update(li: Collection<Hour>) {
|
||||||
|
li.toList()
|
||||||
|
this.dataSet.clear()
|
||||||
|
this.dataSet.addAll(li)
|
||||||
|
// notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeatherDressAdatper.ViewHolder {
|
||||||
|
// val view = LayoutInflater.from(parent.context)
|
||||||
|
// .inflate(R.layout.item_rec_hourly_dress, parent, false)
|
||||||
|
// val itemBinding: ItemRecHourlyDressBinding = DataBindingUtil.
|
||||||
|
val binding = ItemRecHourlyDressBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return WeatherDressAdatper.ViewHolder(binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getToday() = Calendar.getInstance().get(Calendar.DAY_OF_YEAR)
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onBindViewHolder(holder: WeatherDressAdatper.ViewHolder, position: Int) {
|
||||||
|
val data = dataSet[position] as? Hour
|
||||||
|
// BLog.LOGE("saved weatherForcast >>> asFlow ${dataSet.size}")
|
||||||
|
// val today = Calendar.getInstance()
|
||||||
|
// today.time = Date(data?.time_epoch?.toLong()?.times(1000L) ?: 0L)
|
||||||
|
// val dayOfItem = today.get(Calendar.DAY_OF_YEAR)
|
||||||
|
data?.let {
|
||||||
|
// total.loc = WorkersDb.getRealm().query<Location>().also {
|
||||||
|
// BLog.LOGE("re >>> ${it.description()}") // 쿼리 로그
|
||||||
|
// }.find().first()
|
||||||
|
WeatherInfoManager.getShowingInfo(it).apply {
|
||||||
|
// total.setInfo(this)
|
||||||
|
holder.viewItem.setInfo(this)
|
||||||
|
}
|
||||||
|
// BLog.LOGE("reeeeeeeeeee >>> ${holder.viewItem.hour.text}")
|
||||||
|
holder.viewItem.amOrPm.visibility =
|
||||||
|
if (arrayListOf(12, 0).contains(WeatherInfoManager.toZonedDateTime(it.time_epoch).hour) || position == 0) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else View.INVISIBLE
|
||||||
|
holder.viewItem.hour.apply {
|
||||||
|
if (WeatherInfoManager.toZonedDateTime(it.time_epoch).hour == 0) {
|
||||||
|
this@apply.setTextColor(Color.BLACK)
|
||||||
|
this@apply.isSelected = true
|
||||||
|
} else {
|
||||||
|
this@apply.setTextColor(Color.WHITE)
|
||||||
|
this@apply.isSelected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
holder.viewItem.imgWeather.setImageLevel(it.temp_c.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = dataSet.size
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package bums.lunatic.launcher.home.adapters
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bums.lunatic.launcher.databinding.ItemHourlyWeatherBinding
|
||||||
|
import bums.lunatic.launcher.model.Hour
|
||||||
|
import bums.lunatic.launcher.model.WeatherInfoManager
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
|
class WeatherHourlyAdapter(private val dataSet: ArrayList<Hour>): RecyclerView.Adapter<WeatherHourlyAdapter.ViewHolder>() {
|
||||||
|
class ViewHolder(val viewItem: ItemHourlyWeatherBinding): RecyclerView.ViewHolder(viewItem.root)
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, type: Int): WeatherHourlyAdapter.ViewHolder {
|
||||||
|
val binding = ItemHourlyWeatherBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return WeatherHourlyAdapter.ViewHolder(binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val data = dataSet[position] as? Hour
|
||||||
|
// BLog.LOGE("saved weatherForcast >>> asFlow ${dataSet.size}")
|
||||||
|
data?.let {
|
||||||
|
WeatherInfoManager.getShowingInfo(it).apply {
|
||||||
|
holder.viewItem.setInfo(this)
|
||||||
|
Picasso.get()
|
||||||
|
.load(this.urlImgWeather)
|
||||||
|
.into(holder.viewItem.imgWeather)
|
||||||
|
}
|
||||||
|
// BLog.LOGE("reeeeeeeeeee >>> ${holder.viewItem.hour.text}")
|
||||||
|
// holder.viewItem.amOrPm.visibility =
|
||||||
|
// if (arrayListOf(12, 0).contains(WeatherInfoManager.toZonedDateTime(it.time_epoch).hour) || position == 0) {
|
||||||
|
// View.VISIBLE
|
||||||
|
// } else View.INVISIBLE
|
||||||
|
holder.viewItem.hour.apply {
|
||||||
|
if (WeatherInfoManager.toZonedDateTime(it.time_epoch).hour == 0) {
|
||||||
|
this@apply.setTextColor(Color.BLACK)
|
||||||
|
this@apply.isSelected = true
|
||||||
|
} else {
|
||||||
|
this@apply.setTextColor(Color.WHITE)
|
||||||
|
this@apply.isSelected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = dataSet.size
|
||||||
|
|
||||||
|
fun update(li: Collection<Hour>) {
|
||||||
|
li.toList()
|
||||||
|
this.dataSet.clear()
|
||||||
|
this.dataSet.addAll(li)
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.weather
|
package bums.lunatic.launcher.home.weather
|
||||||
|
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.weather
|
package bums.lunatic.launcher.home.weather
|
||||||
|
|
||||||
|
|
||||||
internal class Weather {
|
internal class Weather {
|
||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.weather
|
package bums.lunatic.launcher.home.weather
|
||||||
|
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
+6
-6
@@ -16,19 +16,19 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.home.weather
|
package bums.lunatic.launcher.home.weather
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_CITY_NAME
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_OWM_API
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_SHOW_CITY
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_TEMP_UNIT
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.isNetworkAvailable
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_CITY_NAME
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_OWM_API
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_SHOW_CITY
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_TEMP_UNIT
|
|
||||||
import rasel.lunar.launcher.helpers.UniUtils.Companion.isNetworkAvailable
|
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
|
||||||
+4
-41
@@ -1,46 +1,9 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
import rasel.lunar.launcher.beforeDay
|
import bums.lunatic.launcher.beforeDay
|
||||||
import rasel.lunar.launcher.utils.JamoUtils
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class MissD : RssDataInterface {
|
|
||||||
var link : String? = null
|
|
||||||
|
|
||||||
var title : String? = null
|
|
||||||
|
|
||||||
var thumb : String? = null
|
|
||||||
|
|
||||||
var desc : String? = null
|
|
||||||
|
|
||||||
override fun title(): String {
|
|
||||||
return title ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun thumbnailUrl(): String {
|
|
||||||
return thumb ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun originPage(): String {
|
|
||||||
return link ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun description(): String {
|
|
||||||
return desc ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pubDate(): Long {
|
|
||||||
return beforeDay(Date())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun category(): RssDataType {
|
|
||||||
return RssDataType.GURU
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCho(): String? {
|
|
||||||
return JamoUtils.split(title!!).joinToString("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MostItem : JGuru , RssDataInterface {
|
class MostItem : JGuru , RssDataInterface {
|
||||||
|
|
||||||
@@ -67,7 +30,7 @@ class MostItem : JGuru , RssDataInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.Most
|
return RssDataType.MOST
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCho(): String? {
|
override fun getCho(): String? {
|
||||||
+3
-1
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
import io.realm.kotlin.types.RealmObject
|
import io.realm.kotlin.types.RealmObject
|
||||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||||
@@ -16,4 +16,6 @@ class AppInfo : RealmObject {
|
|||||||
var clickCount : Int = 0
|
var clickCount : Int = 0
|
||||||
var lastUseDate : Long = 0L
|
var lastUseDate : Long = 0L
|
||||||
var category : String? = null
|
var category : String? = null
|
||||||
|
var currentInstalled : Boolean = false
|
||||||
|
var isInstalled : Boolean = false
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
class CiliMagnet {
|
class CiliMagnet {
|
||||||
var link : String? = null
|
var link : String? = null
|
||||||
+23
-20
@@ -1,12 +1,12 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
|
import bums.lunatic.launcher.utils.afterDay
|
||||||
|
import bums.lunatic.launcher.utils.beforeDayBy
|
||||||
import io.realm.kotlin.types.RealmObject
|
import io.realm.kotlin.types.RealmObject
|
||||||
import io.realm.kotlin.types.annotations.Ignore
|
import io.realm.kotlin.types.annotations.Ignore
|
||||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||||
import org.jsoup.select.Elements
|
import org.jsoup.select.Elements
|
||||||
import rasel.lunar.launcher.utils.JamoUtils
|
|
||||||
import rasel.lunar.launcher.utils.afterDay
|
|
||||||
import rasel.lunar.launcher.utils.beforeDay
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@@ -21,7 +21,7 @@ class Clien : DcInside() {
|
|||||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
|
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
}
|
}
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.Clien
|
return RssDataType.CLIEN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ class Arca : RssDataInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.Arca
|
return RssDataType.ARCA
|
||||||
}
|
}
|
||||||
override fun getCho(): String? {
|
override fun getCho(): String? {
|
||||||
return JamoUtils.split(title!!).joinToString("")
|
return JamoUtils.split(title!!).joinToString("")
|
||||||
@@ -179,7 +179,7 @@ open class DcInside : RssDataInterface {
|
|||||||
dateTiemL = cal.timeInMillis
|
dateTiemL = cal.timeInMillis
|
||||||
dateTiemL
|
dateTiemL
|
||||||
} else {
|
} else {
|
||||||
0L
|
Date().time
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return dateTiemL
|
return dateTiemL
|
||||||
@@ -187,7 +187,7 @@ open class DcInside : RssDataInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.DcInside
|
return RssDataType.DCINSIDE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCho(): String? {
|
override fun getCho(): String? {
|
||||||
@@ -198,12 +198,12 @@ open class DcInside : RssDataInterface {
|
|||||||
|
|
||||||
class RuliWeb : DcInside() {
|
class RuliWeb : DcInside() {
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.RuliWeb
|
return RssDataType.RULIWEB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class TheQoo : DcInside() {
|
class TheQoo : DcInside() {
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.TheQoo
|
return RssDataType.THEQOO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +212,7 @@ class RssData : RealmObject, RssDataInterface {
|
|||||||
|
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
var originPage : String? = null
|
var originPage : String? = null
|
||||||
|
|
||||||
var title : String? = null
|
var title : String? = null
|
||||||
var description : String? = null
|
var description : String? = null
|
||||||
var thumbnail : String? = null
|
var thumbnail : String? = null
|
||||||
@@ -219,17 +220,19 @@ class RssData : RealmObject, RssDataInterface {
|
|||||||
var category : String? = null
|
var category : String? = null
|
||||||
|
|
||||||
var chosung : String? = null
|
var chosung : String? = null
|
||||||
|
var vote : Boolean = false
|
||||||
|
var read : Int = 0
|
||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
var mRssDataType : RssDataType? = null
|
var mRssDataType : RssDataType? = null
|
||||||
override fun title(): String {
|
override fun title(): String {
|
||||||
return when(category()){
|
return when(category()){
|
||||||
RssDataType.NewsFeed -> {
|
RssDataType.NEWSFEED -> {
|
||||||
if(title?.length ?: 0 > 30) title?.substring(0,30).plus("...") else title ?: ""
|
if(title?.length ?: 0 > 30) title?.substring(0,30).plus("...") else title ?: ""
|
||||||
}
|
}
|
||||||
else -> title ?: ""
|
else -> title ?: ""
|
||||||
}.apply {
|
}.apply {
|
||||||
chosung = JamoUtils.split(this).joinToString("")
|
chosung = JamoUtils.split(title).joinToString("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +250,7 @@ class RssData : RealmObject, RssDataInterface {
|
|||||||
RssDataType.YOUTUBE -> {
|
RssDataType.YOUTUBE -> {
|
||||||
if(description?.contains("게시자") == true) description!!.split("게시자")[0] else description ?: ""
|
if(description?.contains("게시자") == true) description!!.split("게시자")[0] else description ?: ""
|
||||||
}
|
}
|
||||||
RssDataType.NewsFeed -> {
|
RssDataType.NEWSFEED -> {
|
||||||
category().name
|
category().name
|
||||||
}
|
}
|
||||||
else -> description.plus(" / ").plus(category().name)
|
else -> description.plus(" / ").plus(category().name)
|
||||||
@@ -260,7 +263,7 @@ class RssData : RealmObject, RssDataInterface {
|
|||||||
|
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
if (mRssDataType == null)
|
if (mRssDataType == null)
|
||||||
mRssDataType = RssDataType.valueOf(category!!)
|
mRssDataType = RssDataType.valueOf(category!!.uppercase())
|
||||||
return mRssDataType!!
|
return mRssDataType!!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,15 +308,15 @@ open class Dotax(var pageLink : String,
|
|||||||
before = dayString.toInt()
|
before = dayString.toInt()
|
||||||
if (dateDesc.contains("년")) {
|
if (dateDesc.contains("년")) {
|
||||||
before = 365 * before
|
before = 365 * before
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("월")) {
|
} else if (dateDesc.contains("월")) {
|
||||||
before = 30 * before
|
before = 30 * before
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("주")) {
|
} else if (dateDesc.contains("주")) {
|
||||||
before = 7 * before
|
before = 7 * before
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("일")) {
|
} else if (dateDesc.contains("일")) {
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("시간")) {
|
} else if (dateDesc.contains("시간")) {
|
||||||
dateTime =
|
dateTime =
|
||||||
if (isBefore) dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus(
|
if (isBefore) dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus(
|
||||||
@@ -344,7 +347,7 @@ open class Dotax(var pageLink : String,
|
|||||||
return dateTime
|
return dateTime
|
||||||
}
|
}
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.Dotax
|
return RssDataType.DOTAX
|
||||||
}
|
}
|
||||||
override fun getCho(): String? {
|
override fun getCho(): String? {
|
||||||
return JamoUtils.split(title!!).joinToString("")
|
return JamoUtils.split(title!!).joinToString("")
|
||||||
@@ -360,7 +363,7 @@ data class FmKorea(var apageLink : String,
|
|||||||
return pageLink
|
return pageLink
|
||||||
}
|
}
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.FmKorae
|
return RssDataType.FMKORAE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
import io.realm.kotlin.types.RealmObject
|
import io.realm.kotlin.types.RealmObject
|
||||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
|
import android.location.Address
|
||||||
|
import io.realm.kotlin.ext.realmListOf
|
||||||
|
import io.realm.kotlin.types.RealmList
|
||||||
|
import io.realm.kotlin.types.RealmObject
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
class LocationLog : RealmObject {
|
||||||
|
var mFeatureName: String? = null
|
||||||
|
var mAddressLines: RealmList<String> = realmListOf()
|
||||||
|
var mAdminArea: String? = null
|
||||||
|
var mSubAdminArea: String? = null
|
||||||
|
var mLocality: String? = null
|
||||||
|
var mSubLocality: String? = null
|
||||||
|
var mThoroughfare: String? = null
|
||||||
|
var mSubThoroughfare: String? = null
|
||||||
|
var mPremises: String? = null
|
||||||
|
var mPostalCode: String? = null
|
||||||
|
var mCountryCode: String? = null
|
||||||
|
var mCountryName: String? = null
|
||||||
|
var mLatitude = 0.0
|
||||||
|
var mLongitude = 0.0
|
||||||
|
|
||||||
|
var mPhone: String? = null
|
||||||
|
var mUrl: String? = null
|
||||||
|
var time : Long = 0L
|
||||||
|
var timeString : String? = null
|
||||||
|
var userId : String? = null
|
||||||
|
|
||||||
|
fun fillData(address: Address) {
|
||||||
|
time = System.currentTimeMillis()
|
||||||
|
timeString = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
|
||||||
|
mFeatureName = address.featureName
|
||||||
|
mAddressLines.apply {
|
||||||
|
for (i in 0..address.maxAddressLineIndex) {
|
||||||
|
this.add(address.getAddressLine(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mAdminArea = address.adminArea
|
||||||
|
mSubAdminArea = address.subAdminArea
|
||||||
|
mLocality = address.locality
|
||||||
|
mSubLocality = address.subLocality
|
||||||
|
mThoroughfare = address.thoroughfare
|
||||||
|
mSubThoroughfare = address.subThoroughfare
|
||||||
|
mPremises = address.premises
|
||||||
|
mPostalCode = address.postalCode
|
||||||
|
mCountryCode = address.countryCode
|
||||||
|
mCountryName = address.countryName
|
||||||
|
mLatitude = address.latitude
|
||||||
|
mLongitude = address.longitude
|
||||||
|
mPhone = address.phone
|
||||||
|
mUrl = address.url
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val buffer = StringBuffer()
|
||||||
|
buffer.append(mFeatureName).append("|").append("\n")
|
||||||
|
buffer.append(mAddressLines.joinToString(" , ")).append("|").append("\n")
|
||||||
|
buffer.append(mAdminArea).append("|").append("\n")
|
||||||
|
buffer.append(mSubAdminArea).append("|").append("\n")
|
||||||
|
buffer.append(mLocality).append("|").append("\n")
|
||||||
|
buffer.append(mSubLocality).append("|").append("\n")
|
||||||
|
buffer.append(mThoroughfare).append("|").append("\n")
|
||||||
|
buffer.append(mSubThoroughfare).append("|").append("\n")
|
||||||
|
buffer.append(mPremises).append("|").append("\n")
|
||||||
|
buffer.append(mPostalCode).append("|").append("\n")
|
||||||
|
buffer.append(mCountryCode).append("|").append("\n")
|
||||||
|
buffer.append(mCountryName).append("|").append("\n")
|
||||||
|
buffer.append(mLatitude).append("|").append("\n")
|
||||||
|
buffer.append(mLongitude).append("|").append("\n")
|
||||||
|
buffer.append(mPhone).append("|").append("\n")
|
||||||
|
buffer.append(mUrl).append("|").append("\n")
|
||||||
|
return buffer.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+5
-4
@@ -1,6 +1,6 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
import rasel.lunar.launcher.utils.JamoUtils
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
|
|
||||||
class NewsData : RssDataInterface {
|
class NewsData : RssDataInterface {
|
||||||
|
|
||||||
@@ -37,9 +37,10 @@ class NewsData : RssDataInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return RssDataType.NewsFeed
|
return RssDataType.NEWSFEED
|
||||||
}
|
}
|
||||||
override fun getCho(): String? {
|
override fun getCho(): String? {
|
||||||
return JamoUtils.split(title()).joinToString("")
|
var cho = JamoUtils.split(title()).joinToString("")
|
||||||
|
return if(cho.length > 0 ) cho else title()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
import io.realm.kotlin.types.RealmObject
|
import io.realm.kotlin.types.RealmObject
|
||||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
|
|
||||||
|
enum class RssDataType {
|
||||||
|
NO_DATA,
|
||||||
|
YOUTUBE,
|
||||||
|
NEWSFEED,
|
||||||
|
GURU,
|
||||||
|
MOST,
|
||||||
|
TAGS,
|
||||||
|
REDDIT,
|
||||||
|
REDDIT_NSFW,
|
||||||
|
DOTAX,
|
||||||
|
FMKORAE,
|
||||||
|
DCINSIDE,
|
||||||
|
RULIWEB,
|
||||||
|
CLIEN,
|
||||||
|
THEQOO,
|
||||||
|
ARCA;
|
||||||
|
|
||||||
|
fun getResId() = when (this) {
|
||||||
|
YOUTUBE -> R.drawable.youtube
|
||||||
|
REDDIT, REDDIT_NSFW -> R.drawable.reddit
|
||||||
|
DOTAX -> R.drawable.daum
|
||||||
|
FMKORAE -> R.drawable.fmk
|
||||||
|
DCINSIDE -> R.drawable.dcinside
|
||||||
|
ARCA -> R.drawable.arca
|
||||||
|
else -> {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun defaultImgSize() = when (this) {
|
||||||
|
YOUTUBE -> 200
|
||||||
|
REDDIT_NSFW,GURU,MOST -> 360
|
||||||
|
else -> { 120 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDefaultVisibiliy() = when (this) {
|
||||||
|
REDDIT_NSFW,GURU,MOST,NEWSFEED -> View.GONE
|
||||||
|
else -> { View.VISIBLE }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOn(block : ()->Unit) {
|
||||||
|
if(PrefHelper.getBoolean(name,false)) {
|
||||||
|
block.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getExcAdt() = arrayListOf(NEWSFEED, REDDIT, DOTAX, FMKORAE, DCINSIDE, RULIWEB, CLIEN, THEQOO, ARCA).map { it.name }
|
||||||
|
fun getAdts() = arrayListOf( REDDIT_NSFW, MOST,GURU).map { it.name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RssDataInterface {
|
||||||
|
fun title() : String
|
||||||
|
fun thumbnailUrl() : String
|
||||||
|
fun originPage() : String
|
||||||
|
fun description() : String
|
||||||
|
fun pubDate() : Long
|
||||||
|
fun category() : RssDataType
|
||||||
|
fun getCho() : String?
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.model
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
import io.realm.kotlin.ext.realmListOf
|
import io.realm.kotlin.ext.realmListOf
|
||||||
import io.realm.kotlin.types.RealmList
|
import io.realm.kotlin.types.RealmList
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
|
import com.ibm.icu.util.ChineseCalendar
|
||||||
|
import io.realm.kotlin.types.RealmObject
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
class UserActionModel: RealmObject {
|
||||||
|
|
||||||
|
var actionType: String = ""
|
||||||
|
// var timestamp: Date = Realm()
|
||||||
|
|
||||||
|
var weekOfYear : Int = 0
|
||||||
|
var weekOfMonth : Int = 0
|
||||||
|
var dayOfWeek : Int = 0
|
||||||
|
var dayOfYear : Int = 0
|
||||||
|
var dayOfMonth : Int = 0
|
||||||
|
var hourOfDay : Int = 0
|
||||||
|
var month: Int = 0
|
||||||
|
var lunMonth : Int = 0
|
||||||
|
var lunDayOFMonth : Int = 0
|
||||||
|
var lunDayOfYear : Int = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
// val cal = Calendar.getInstance()
|
||||||
|
// cal.time = timestamp
|
||||||
|
// weekOfYear = cal.get(Calendar.WEEK_OF_YEAR)
|
||||||
|
// weekOfMonth = cal.get(Calendar.WEEK_OF_MONTH)
|
||||||
|
// dayOfWeek = cal.get(Calendar.DAY_OF_WEEK)
|
||||||
|
// hourOfDay = cal.get(Calendar.HOUR_OF_DAY)
|
||||||
|
// month = cal.get(Calendar.MONTH)
|
||||||
|
// dayOfYear = cal.get(Calendar.DAY_OF_YEAR)
|
||||||
|
// dayOfMonth = cal.get(Calendar.DAY_OF_MONTH)
|
||||||
|
// var cinCal = ChineseCalendar()
|
||||||
|
// cinCal.time = timestamp
|
||||||
|
// lunMonth = cinCal.get(ChineseCalendar.MONTH)
|
||||||
|
// lunDayOFMonth = cinCal.get(ChineseCalendar.DAY_OF_MONTH)
|
||||||
|
// lunDayOfYear = cinCal.get(ChineseCalendar.DAY_OF_YEAR)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
|
import io.realm.kotlin.ext.realmListOf
|
||||||
|
import io.realm.kotlin.types.RealmList
|
||||||
|
import io.realm.kotlin.types.RealmObject
|
||||||
|
import io.realm.kotlin.types.annotations.Ignore
|
||||||
|
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||||
|
|
||||||
|
|
||||||
|
class WeatherForcast: RealmObject {
|
||||||
|
@PrimaryKey
|
||||||
|
var isOnlyKey = "isOnlyKey"
|
||||||
|
|
||||||
|
var location: Location? = null
|
||||||
|
var current: Current? = null
|
||||||
|
var forecast: Forecast? = null
|
||||||
|
var lastUpdateTime : Long = 0L
|
||||||
|
|
||||||
|
// fun readyForSaving() {
|
||||||
|
// lastUpdateTime = System.currentTimeMillis()
|
||||||
|
// forecast?.fill()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
class Location: RealmObject {
|
||||||
|
var name: String? = null
|
||||||
|
var region: String? = null
|
||||||
|
var country: String? = null
|
||||||
|
var lat = 0.0
|
||||||
|
var lon = 0.0
|
||||||
|
var tz_id: String? = null
|
||||||
|
var localtime_epoch = 0
|
||||||
|
var localtime: String? = null
|
||||||
|
|
||||||
|
// fun getTextLocation(): String = "$name / $country"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Current: RealmObject {
|
||||||
|
var last_updated_epoch = 0
|
||||||
|
var last_updated: String? = null
|
||||||
|
var temp_c = 0.0
|
||||||
|
var temp_f = 0.0
|
||||||
|
var is_day = 0
|
||||||
|
var condition: Condition? = null
|
||||||
|
var wind_mph = 0.0
|
||||||
|
var wind_kph = 0.0
|
||||||
|
var wind_degree = 0
|
||||||
|
var wind_dir: String? = null
|
||||||
|
var pressure_mb = 0.0
|
||||||
|
var pressure_in = 0.0
|
||||||
|
var precip_mm = 0.0
|
||||||
|
var precip_in = 0.0
|
||||||
|
var humidity = 0
|
||||||
|
var cloud = 0
|
||||||
|
var feelslike_c = 0.0
|
||||||
|
var feelslike_f = 0.0
|
||||||
|
var windchill_c = 0.0
|
||||||
|
var windchill_f = 0.0
|
||||||
|
var heatindex_c = 0.0
|
||||||
|
var heatindex_f = 0.0
|
||||||
|
var dewpoint_c = 0.0
|
||||||
|
var dewpoint_f = 0.0
|
||||||
|
var vis_km = 0.0
|
||||||
|
var vis_miles = 0.0
|
||||||
|
var uv = 0.0
|
||||||
|
var gust_mph = 0.0
|
||||||
|
var gust_kph = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
class Forecast: RealmObject {
|
||||||
|
@Ignore
|
||||||
|
var forecastday: ArrayList<Forecastday> = arrayListOf()
|
||||||
|
var forecastdayRealm: RealmList<Forecastday> = realmListOf()
|
||||||
|
|
||||||
|
// fun fill() {
|
||||||
|
// if (forecastdayRealm.addAll(forecastday)) {
|
||||||
|
// forecastdayRealm.forEach { f -> f.fill() }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// Current
|
||||||
|
class Condition: RealmObject {
|
||||||
|
var text: String? = null
|
||||||
|
var icon: String? = null
|
||||||
|
var code = 0
|
||||||
|
}
|
||||||
|
// Forecast
|
||||||
|
class Forecastday: RealmObject {
|
||||||
|
var date: String? = null
|
||||||
|
@PrimaryKey
|
||||||
|
var date_epoch = 0
|
||||||
|
var day: Day? = null
|
||||||
|
var astro: Astro? = null
|
||||||
|
@Ignore
|
||||||
|
var hour: ArrayList<Hour> = arrayListOf()
|
||||||
|
var hourRealm: RealmList<Hour> = realmListOf()
|
||||||
|
|
||||||
|
// fun fill() {
|
||||||
|
// hourRealm.addAll(hour)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// Forecastday
|
||||||
|
class Day: RealmObject {
|
||||||
|
var maxtemp_c = 0.0
|
||||||
|
var maxtemp_f = 0.0
|
||||||
|
var mintemp_c = 0.0
|
||||||
|
var mintemp_f = 0.0
|
||||||
|
var avgtemp_c = 0.0
|
||||||
|
var avgtemp_f = 0.0
|
||||||
|
var maxwind_mph = 0.0
|
||||||
|
var maxwind_kph = 0.0
|
||||||
|
var totalprecip_mm = 0.0
|
||||||
|
var totalprecip_in = 0.0
|
||||||
|
var totalsnow_cm = 0.0
|
||||||
|
var avgvis_km = 0.0
|
||||||
|
var avgvis_miles = 0.0
|
||||||
|
var avghumidity = 0
|
||||||
|
var daily_will_it_rain = 0
|
||||||
|
var daily_chance_of_rain = 0
|
||||||
|
var daily_will_it_snow = 0
|
||||||
|
var daily_chance_of_snow = 0
|
||||||
|
var condition: Condition? = null
|
||||||
|
var uv = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
class Astro: RealmObject {
|
||||||
|
var sunrise: String? = null
|
||||||
|
var sunset: String? = null
|
||||||
|
var moonrise: String? = null
|
||||||
|
var moonset: String? = null
|
||||||
|
var moon_phase: String? = null
|
||||||
|
var moon_illumination = 0
|
||||||
|
var is_moon_up = 0
|
||||||
|
var is_sun_up = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class Hour: RealmObject {
|
||||||
|
var lat : Double = 0.0
|
||||||
|
var lon : Double = 0.0
|
||||||
|
|
||||||
|
@PrimaryKey
|
||||||
|
var time_epoch = 0
|
||||||
|
var time: String? = null
|
||||||
|
var temp_c = 0.0
|
||||||
|
var temp_f = 0.0
|
||||||
|
var is_day = 0
|
||||||
|
var condition: Condition? = null
|
||||||
|
var wind_mph = 0.0
|
||||||
|
var wind_kph = 0.0
|
||||||
|
var wind_degree = 0
|
||||||
|
var wind_dir: String? = null
|
||||||
|
var pressure_mb = 0.0
|
||||||
|
var pressure_in = 0.0
|
||||||
|
var precip_mm = 0.0
|
||||||
|
var precip_in = 0.0
|
||||||
|
var snow_cm = 0.0
|
||||||
|
var humidity = 0
|
||||||
|
var cloud = 0
|
||||||
|
var feelslike_c = 0.0
|
||||||
|
var feelslike_f = 0.0
|
||||||
|
var windchill_c = 0.0
|
||||||
|
var windchill_f = 0.0
|
||||||
|
var heatindex_c = 0.0
|
||||||
|
var heatindex_f = 0.0
|
||||||
|
var dewpoint_c = 0.0
|
||||||
|
var dewpoint_f = 0.0
|
||||||
|
var will_it_rain = 0
|
||||||
|
var chance_of_rain = 0
|
||||||
|
var will_it_snow = 0
|
||||||
|
var chance_of_snow = 0
|
||||||
|
var vis_km = 0.0
|
||||||
|
var vis_miles = 0.0
|
||||||
|
var gust_mph = 0.0
|
||||||
|
var gust_kph = 0.0
|
||||||
|
var uv = 0.0
|
||||||
|
|
||||||
|
// fun toZonedDateTime(timeEpoch: Int) = Instant.ofEpochSecond(timeEpoch.toLong())
|
||||||
|
// .atZone(ZoneId.systemDefault())
|
||||||
|
//
|
||||||
|
// fun getAmOrPm(): String = toZonedDateTime(time_epoch).hour.run {
|
||||||
|
// if (this < 12) "오전" else "오후"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun getTextHour(): String = toZonedDateTime(time_epoch)
|
||||||
|
// .run {
|
||||||
|
// if (this.hour == 0) {
|
||||||
|
// when (this.dayOfYear - Calendar.getInstance().get(Calendar.DAY_OF_YEAR)) {
|
||||||
|
// 1 -> "내일"
|
||||||
|
// 2 -> "모레"
|
||||||
|
// 3 -> "글피"
|
||||||
|
// else -> "${this.dayOfMonth}일"
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// "${this.hour}시"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun getDress(): String =
|
||||||
|
// if (temp_c >= 23) {
|
||||||
|
// "반팔"
|
||||||
|
// } else if ((23 > temp_c) && (temp_c >= 20)) {
|
||||||
|
// "긴팔"
|
||||||
|
// } else if ((20 > temp_c) && (temp_c >= 17)) {
|
||||||
|
// "니트"
|
||||||
|
// } else if ((17 > temp_c) && (temp_c >= 12)) {
|
||||||
|
// "얇은겉옷"
|
||||||
|
// } else if ((12 > temp_c) && (temp_c >= 6)) {
|
||||||
|
// "두꺼운겉옷"
|
||||||
|
// } else {
|
||||||
|
// "패딩"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun getImgDress() =
|
||||||
|
// if (temp_c >= 23) {
|
||||||
|
// R.drawable.dress_short_sleeves
|
||||||
|
// } else if ((23 > temp_c) && (temp_c >= 20)) {
|
||||||
|
// "긴팔"
|
||||||
|
// } else if ((20 > temp_c) && (temp_c >= 17)) {
|
||||||
|
// "니트"
|
||||||
|
// } else if ((17 > temp_c) && (temp_c >= 12)) {
|
||||||
|
// "얇은겉옷"
|
||||||
|
// } else if ((12 > temp_c) && (temp_c >= 6)) {
|
||||||
|
// "두꺼운겉옷"
|
||||||
|
// } else {
|
||||||
|
// "패딩"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun getTemp(): String = "${temp_c}도"
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package bums.lunatic.launcher.model
|
||||||
|
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
import io.realm.kotlin.types.RealmList
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
class ShowingWeatherInfo() {
|
||||||
|
var textLocation: String? = null
|
||||||
|
var amOrPm: String? = null
|
||||||
|
var textHour: String? = null
|
||||||
|
var dress: String? = null
|
||||||
|
var imgDress: Int? = null
|
||||||
|
var temp: String? = null
|
||||||
|
var textCondition: String? = null
|
||||||
|
var urlImgWeather: String? = null
|
||||||
|
|
||||||
|
fun setLocation(loc: Location?): ShowingWeatherInfo {
|
||||||
|
textLocation = "${loc?.name ?: "도시"} / ${loc?.country ?: "나라"}"
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
fun setHour(hour: Hour): ShowingWeatherInfo {
|
||||||
|
setAmOrPm(hour)
|
||||||
|
setTextHour(hour)
|
||||||
|
setDress(hour)
|
||||||
|
setTemp(hour)
|
||||||
|
setTextCondition(hour)
|
||||||
|
setUrlImgWeather(hour)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
private fun setAmOrPm(hour: Hour) = WeatherInfoManager.toZonedDateTime(hour.time_epoch).hour.run {
|
||||||
|
amOrPm = if (this < 12) "오전" else "오후"
|
||||||
|
}
|
||||||
|
private fun setTextHour(hour: Hour) {
|
||||||
|
textHour = WeatherInfoManager.toZonedDateTime(hour.time_epoch).run {
|
||||||
|
if (this.hour == 0) {
|
||||||
|
when (this.dayOfYear - Calendar.getInstance().get(Calendar.DAY_OF_YEAR)) {
|
||||||
|
1 -> "내일"
|
||||||
|
2 -> "모레"
|
||||||
|
3 -> "글피"
|
||||||
|
else -> "${this.dayOfMonth}일"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"${this.hour}시"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun setDress(hour: Hour) {
|
||||||
|
if (hour.temp_c >= 23) {
|
||||||
|
dress = "반팔"
|
||||||
|
imgDress = R.drawable.dress_short_sleeves
|
||||||
|
} else if ((23 > hour.temp_c) && (hour.temp_c >= 20)) {
|
||||||
|
dress = "긴팔"
|
||||||
|
imgDress = R.drawable.dress_long_sleeves
|
||||||
|
} else if ((20 > hour.temp_c) && (hour.temp_c >= 17)) {
|
||||||
|
dress = "니트"
|
||||||
|
imgDress = R.drawable.dress_knitwear
|
||||||
|
} else if ((17 > hour.temp_c) && (hour.temp_c >= 12)) {
|
||||||
|
dress = "얇은겉옷"
|
||||||
|
imgDress = R.drawable.dress_flimsy_outer
|
||||||
|
} else if ((12 > hour.temp_c) && (hour.temp_c >= 6)) {
|
||||||
|
dress = "두꺼운겉옷"
|
||||||
|
imgDress = R.drawable.dress_heavy_outer
|
||||||
|
} else {
|
||||||
|
dress = "패딩"
|
||||||
|
imgDress = R.drawable.dress_padded_coat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun setTemp(hour: Hour) {temp = "${hour.temp_c}도"}
|
||||||
|
|
||||||
|
private fun setTextCondition(hour: Hour) {textCondition = hour.condition?.text}
|
||||||
|
|
||||||
|
private fun setUrlImgWeather(hour: Hour) {
|
||||||
|
hour.condition?.icon?.let {
|
||||||
|
urlImgWeather = if (!it.contains("https:")) "https:$it" else it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object WeatherInfoManager {
|
||||||
|
var info: WeatherForcast? = null
|
||||||
|
// var showingInfo: ShowingWeatherInfo? = null
|
||||||
|
|
||||||
|
|
||||||
|
// fun setInfo(data: WeatherForcast) {
|
||||||
|
// this.info = data
|
||||||
|
// BLog.LOGE("Now WeatherForcast updated. info : ${this.info}")
|
||||||
|
// }
|
||||||
|
|
||||||
|
fun readyForSaving(lat: Double, lon: Double) {
|
||||||
|
this.info?.lastUpdateTime = System.currentTimeMillis()
|
||||||
|
this.fill()
|
||||||
|
setLatitudeAndLongitude(lat, lon)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setLatitudeAndLongitude(lat: Double, lon: Double) {
|
||||||
|
info?.forecast?.forecastdayRealm?.forEach {
|
||||||
|
it.hourRealm.forEach {h ->
|
||||||
|
h.lat = lat
|
||||||
|
h.lon = lon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fill() {
|
||||||
|
getForecast()?.let {
|
||||||
|
if (it.forecastdayRealm.addAll(it.forecastday)) {
|
||||||
|
it.forecastdayRealm.forEach { f -> f.hourRealm.addAll(f.hour) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toZonedDateTime(timeEpoch: Int): ZonedDateTime = Instant.ofEpochSecond(timeEpoch.toLong())
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
|
||||||
|
fun getShowingInfo(hour: Hour): ShowingWeatherInfo = ShowingWeatherInfo().setLocation(getLocation()).setHour(hour)
|
||||||
|
|
||||||
|
|
||||||
|
private fun getLocation(): Location? {
|
||||||
|
return if (info?.location == null) {
|
||||||
|
WorkersDb.getRealm().query<Location>().also {
|
||||||
|
Blog.LOGE("re >>> ${it.description()}") // 쿼리 로그
|
||||||
|
}.find().first()
|
||||||
|
} else {
|
||||||
|
info?.location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getForecast(): Forecast? = info?.forecast
|
||||||
|
fun getAllForecastDay(): RealmList<Forecastday>? = getForecast()?.forecastdayRealm
|
||||||
|
fun getAllHour(day: Forecastday): RealmList<Hour> = day.hourRealm
|
||||||
|
}
|
||||||
+9
-7
@@ -1,8 +1,8 @@
|
|||||||
package rasel.lunar.launcher.model.others
|
package bums.lunatic.launcher.model.others
|
||||||
|
|
||||||
import rasel.lunar.launcher.model.RssDataInterface
|
import bums.lunatic.launcher.model.RssDataInterface
|
||||||
import rasel.lunar.launcher.model.RssDataType
|
import bums.lunatic.launcher.model.RssDataType
|
||||||
import rasel.lunar.launcher.utils.JamoUtils
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
|
|
||||||
|
|
||||||
class Child {
|
class Child {
|
||||||
@@ -242,6 +242,7 @@ class Data : RssDataInterface {
|
|||||||
var media: Media? = null
|
var media: Media? = null
|
||||||
var is_video: Boolean = false
|
var is_video: Boolean = false
|
||||||
|
|
||||||
|
var nsfw : Boolean = false
|
||||||
override fun title(): String {
|
override fun title(): String {
|
||||||
return title ?: ""
|
return title ?: ""
|
||||||
}
|
}
|
||||||
@@ -272,12 +273,13 @@ class Data : RssDataInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun category(): RssDataType {
|
override fun category(): RssDataType {
|
||||||
return if (description()?.contains("nsfw") == true) {
|
return if (nsfw || description()?.contains("nsfw") == true) {
|
||||||
RssDataType.REDDIT_nsfw
|
RssDataType.REDDIT_NSFW
|
||||||
} else RssDataType.REDDIT
|
} else RssDataType.REDDIT
|
||||||
}
|
}
|
||||||
override fun getCho(): String? {
|
override fun getCho(): String? {
|
||||||
return JamoUtils.split(title!!).joinToString("")
|
val realChoSung = JamoUtils.split(title!!).joinToString("").trim()
|
||||||
|
return if(realChoSung.length > 0 ) realChoSung else title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+10
-10
@@ -1,11 +1,11 @@
|
|||||||
package rasel.lunar.launcher.model.others
|
package bums.lunatic.launcher.model.others
|
||||||
|
|
||||||
|
import bums.lunatic.launcher.model.RssDataInterface
|
||||||
|
import bums.lunatic.launcher.model.RssDataType
|
||||||
|
import bums.lunatic.launcher.utils.JamoUtils
|
||||||
|
import bums.lunatic.launcher.utils.afterDay
|
||||||
|
import bums.lunatic.launcher.utils.beforeDayBy
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import rasel.lunar.launcher.model.RssDataInterface
|
|
||||||
import rasel.lunar.launcher.model.RssDataType
|
|
||||||
import rasel.lunar.launcher.utils.JamoUtils
|
|
||||||
import rasel.lunar.launcher.utils.afterDay
|
|
||||||
import rasel.lunar.launcher.utils.beforeDay
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
|
|
||||||
@@ -1621,15 +1621,15 @@ open class VideoRenderer : RssDataInterface {
|
|||||||
before = dayString.toInt()
|
before = dayString.toInt()
|
||||||
if (dateDesc.contains("년")) {
|
if (dateDesc.contains("년")) {
|
||||||
before = 365 * before
|
before = 365 * before
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("월")) {
|
} else if (dateDesc.contains("월")) {
|
||||||
before = 30 * before
|
before = 30 * before
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("주")) {
|
} else if (dateDesc.contains("주")) {
|
||||||
before = 7 * before
|
before = 7 * before
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("일")) {
|
} else if (dateDesc.contains("일")) {
|
||||||
dateTime = if (isBefore) beforeDay(date, before) else afterDay(date, before)
|
dateTime = if (isBefore) beforeDayBy(date, before) else afterDay(date, before)
|
||||||
} else if (dateDesc.contains("시간")) {
|
} else if (dateDesc.contains("시간")) {
|
||||||
dateTime = if (isBefore)dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus(before.times(1000L * 60L * 60L))
|
dateTime = if (isBefore)dateTime.minus(before.times(1000L * 60L * 60L)) else dateTime.plus(before.times(1000L * 60L * 60L))
|
||||||
} else if (dateDesc.contains("분")) {
|
} else if (dateDesc.contains("분")) {
|
||||||
+67
-23
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.qaccess
|
package bums.lunatic.launcher.qaccess
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
@@ -43,27 +43,33 @@ import android.view.ViewGroup
|
|||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.appcompat.widget.LinearLayoutCompat
|
import androidx.appcompat.widget.LinearLayoutCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.apps.SimpleContact
|
||||||
|
import bums.lunatic.launcher.databinding.QuickAccessBinding
|
||||||
|
import bums.lunatic.launcher.databinding.ShortcutMakerBinding
|
||||||
|
import bums.lunatic.launcher.helpers.ColorPicker
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.DEFAULT_ICON_SIZE
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_ICON_SIZE
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_SHORTCUT_COUNT
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_SHORTCUT_NO_
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.MAX_SHORTCUTS
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SHORTCUTS
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.SEPARATOR
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.SHORTCUT_TYPE_PHONE
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.SHORTCUT_TYPE_URL
|
||||||
|
import bums.lunatic.launcher.model.AppInfo
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.google.android.material.button.MaterialButtonToggleGroup
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider
|
import com.google.android.material.slider.Slider
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
import io.realm.kotlin.ext.query
|
||||||
import rasel.lunar.launcher.R
|
import io.realm.kotlin.query.RealmResults
|
||||||
import rasel.lunar.launcher.databinding.QuickAccessBinding
|
|
||||||
import rasel.lunar.launcher.databinding.ShortcutMakerBinding
|
|
||||||
import rasel.lunar.launcher.helpers.ColorPicker
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.DEFAULT_ICON_SIZE
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_ICON_SIZE
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_SHORTCUT_COUNT
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_SHORTCUT_NO_
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.MAX_SHORTCUTS
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SHORTCUTS
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.SEPARATOR
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.SHORTCUT_TYPE_PHONE
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.SHORTCUT_TYPE_URL
|
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
@@ -240,14 +246,31 @@ internal class QuickAccess : BottomSheetDialogFragment() {
|
|||||||
/* type is url */
|
/* type is url */
|
||||||
if (shortcutType == SHORTCUT_TYPE_URL) {
|
if (shortcutType == SHORTCUT_TYPE_URL) {
|
||||||
var url = intentString
|
var url = intentString
|
||||||
|
Blog.LOGE("intentString >>>> ${intentString}")
|
||||||
/* add http before the url if it doesn't have http/https prefix */
|
/* add http before the url if it doesn't have http/https prefix */
|
||||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
if (!url.startsWith("http")) {
|
||||||
url = "http://$intentString"
|
// url = "http://$intentString"
|
||||||
|
/* open the url */
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
var result = query<AppInfo>("appName CONTAINS $0 OR koreanName CONTAINS $0", url).find()
|
||||||
|
if (result.size == 1) {
|
||||||
|
result.first().pkgName?.let {
|
||||||
|
try {
|
||||||
|
context?.startActivity(context?.packageManager?.getLaunchIntentForPackage(it))
|
||||||
|
}catch (e : Exception) {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lActivity!!.startActivity(
|
||||||
|
Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lActivity!!.startActivity(
|
||||||
|
Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/* open the url */
|
|
||||||
lActivity!!.startActivity(
|
|
||||||
Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
)
|
|
||||||
/* type is contact */
|
/* type is contact */
|
||||||
} else if (shortcutType == SHORTCUT_TYPE_PHONE) {
|
} else if (shortcutType == SHORTCUT_TYPE_PHONE) {
|
||||||
/* if the necessary permission is not granted already,
|
/* if the necessary permission is not granted already,
|
||||||
@@ -256,12 +279,33 @@ internal class QuickAccess : BottomSheetDialogFragment() {
|
|||||||
lActivity!!.requestPermissions(arrayOf(Manifest.permission.CALL_PHONE), 1)
|
lActivity!!.requestPermissions(arrayOf(Manifest.permission.CALL_PHONE), 1)
|
||||||
} else {
|
} else {
|
||||||
/* make phone call */
|
/* make phone call */
|
||||||
|
|
||||||
|
WorkersDb.getRealm().writeBlocking {
|
||||||
|
Blog.LOGE(">>>> ${query<SimpleContact>().query("phoneNumber CONTAINS $0", intentString).description()}")
|
||||||
|
var result : RealmResults<SimpleContact>? = null
|
||||||
|
if (intentString.startsWith("0")) {
|
||||||
|
result = query<SimpleContact>().query("phoneNumber CONTAINS $0 or phoneNumber CONTAINS $1", intentString, intentString.removeRange(0,1)).find()
|
||||||
|
} else {
|
||||||
|
result = query<SimpleContact>().query("phoneNumber CONTAINS $0", intentString).find()
|
||||||
|
}
|
||||||
|
Blog.LOGE(">>>> ${result.size}")
|
||||||
|
if(result.size > 0){
|
||||||
|
result.forEach {
|
||||||
|
it.touchCount = 1 + it.touchCount
|
||||||
|
it.lastedTouchDateTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
lActivity!!.startActivity(
|
lActivity!!.startActivity(
|
||||||
Intent(Intent.ACTION_DIAL, Uri.parse("tel:$intentString"))
|
Intent(Intent.ACTION_DIAL, Uri.parse("tel:$intentString"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.dismiss()
|
try {
|
||||||
|
this.dismissAllowingStateLoss()
|
||||||
|
} catch (e : Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset the shortcut on long click */
|
/* reset the shortcut on long click */
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package bums.lunatic.launcher.receiver
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.media.MediaMetadata
|
||||||
|
import android.media.session.MediaSessionManager
|
||||||
|
import android.media.session.PlaybackState.STATE_PLAYING
|
||||||
|
import android.os.Build
|
||||||
|
import android.service.notification.NotificationListenerService
|
||||||
|
import android.service.notification.StatusBarNotification
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import bums.lunatic.launcher.model.CurrentPlayItem
|
||||||
|
import bums.lunatic.launcher.model.NotificationItem
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.utils.BitmapConverter
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import io.realm.kotlin.UpdatePolicy
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
|
||||||
|
|
||||||
|
class NLService : NotificationListenerService() {
|
||||||
|
private val TAG: String = this.javaClass.simpleName
|
||||||
|
private var nlservicereciver: NLServiceReceiver? = null
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
nlservicereciver = NLServiceReceiver()
|
||||||
|
val filter = IntentFilter()
|
||||||
|
// filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
|
||||||
|
registerReceiver(nlservicereciver, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
unregisterReceiver(nlservicereciver)
|
||||||
|
}
|
||||||
|
|
||||||
|
val skips = arrayListOf("com.wssyncmldm")
|
||||||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||||||
|
override fun onNotificationPosted(sbn: StatusBarNotification) {
|
||||||
|
// BLog.LOGE("NLService********** onNotificationPosted")
|
||||||
|
// BLog.LOGE("NLServiceID :" + sbn.id + "\t${sbn.notification.tickerText}\t" + sbn.packageName)
|
||||||
|
// sbn.notification.extras.keySet().forEach {
|
||||||
|
// BLog.LOGE("NLService********** keySet >> ${it} ${sbn.notification.extras.get(it)}")
|
||||||
|
// }
|
||||||
|
try {
|
||||||
|
if (sbn.id != 0 && (sbn.packageName.contains(".") || sbn.packageName.contains("android")) && sbn.packageName.length > 0) {
|
||||||
|
NotificationItem().apply {
|
||||||
|
notiId = sbn.id
|
||||||
|
pkgName = sbn.packageName
|
||||||
|
title = sbn.notification?.extras?.getString("android.title") ?: ""
|
||||||
|
subtext = sbn.notification?.extras?.getString("android.subText") ?: ""
|
||||||
|
selfDisplayName = sbn.notification?.extras?.getString("android.selfDisplayName") ?: ""
|
||||||
|
tikerMsg = sbn.notification?.tickerText?.toString() ?: ""
|
||||||
|
postTime = sbn.postTime
|
||||||
|
var uniq = title ?: subtext ?: selfDisplayName ?: tikerMsg ?: ""
|
||||||
|
uniq_id = "${sbn.id}_${sbn.packageName}_${if (uniq.length > 3) uniq.substring(0,3) else uniq}"
|
||||||
|
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${true == "bumssavor".equals(title)}")
|
||||||
|
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${(true == "org.telegram.messenger".equals(pkgName))}")
|
||||||
|
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${sbn.notification?.extras?.getString("android.text")?.startsWith("/") == true}")
|
||||||
|
}.apply {
|
||||||
|
if (skips.contains(pkgName)) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// WorkersDb.insertNoti(this)
|
||||||
|
// BLog.LOGE("NLService********** onNotificationPosted ${Gson().toJson(this)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (sbn.packageName.contains("youtube")) {
|
||||||
|
val m = getSystemService<MediaSessionManager>()!!
|
||||||
|
val component = ComponentName(this, NLService::class.java)
|
||||||
|
val sessions = m.getActiveSessions(component)
|
||||||
|
sessions.forEach { session ->
|
||||||
|
WorkersDb.getRealm().writeBlocking {
|
||||||
|
// Blog.LOGE("session.playbackState >>> ${session.playbackState}")
|
||||||
|
if (session.playbackState != null) {
|
||||||
|
if (session.playbackState?.isActive == true && session.playbackState?.state?.equals(
|
||||||
|
STATE_PLAYING
|
||||||
|
) == true
|
||||||
|
) {
|
||||||
|
session.playbackState?.state
|
||||||
|
val result = query<CurrentPlayItem>().find()
|
||||||
|
var current: CurrentPlayItem? = null
|
||||||
|
if (result.size > 0) {
|
||||||
|
current = result.first()
|
||||||
|
} else {
|
||||||
|
current = CurrentPlayItem()
|
||||||
|
copyToRealm(current, UpdatePolicy.ALL)
|
||||||
|
}
|
||||||
|
if (session?.metadata?.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART) == true) {
|
||||||
|
current.albumArt = BitmapConverter.BitmapToString(
|
||||||
|
session.metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
current.albumArt = ""
|
||||||
|
}
|
||||||
|
current.title =
|
||||||
|
session?.metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
|
||||||
|
current.artists =
|
||||||
|
session?.metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
|
||||||
|
} else {
|
||||||
|
delete(query<CurrentPlayItem>().find())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}}catch (e : Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||||
|
// i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n")
|
||||||
|
// sendBroadcast(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNotificationRemoved(sbn: StatusBarNotification) {
|
||||||
|
//// BLog.LOGE("NLService********** onNOtificationRemoved")
|
||||||
|
//// BLog.LOGE("NLService ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
|
||||||
|
// var uniq_id = "${sbn.id}_${sbn.packageName}"
|
||||||
|
// try {
|
||||||
|
// WorkersDb.getRealm()?.apply {
|
||||||
|
// this.writeBlocking {
|
||||||
|
//// delete(query<NotificationItem>().query("pkgName == $0", sbn.packageName).find())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }catch (e : Exception){e.printStackTrace()}
|
||||||
|
//// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||||
|
//// i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n")
|
||||||
|
//// sendBroadcast(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inner class NLServiceReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent) {
|
||||||
|
// BLog.LOGE("NLService intent >>> ${intent.action}")
|
||||||
|
if (intent.getStringExtra("command") == "clearall") {
|
||||||
|
this@NLService.cancelAllNotifications()
|
||||||
|
} else if (intent.getStringExtra("command") == "list") {
|
||||||
|
// val i1 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||||
|
// i1.putExtra("notification_event", "=====================")
|
||||||
|
// sendBroadcast(i1)
|
||||||
|
var i = 1
|
||||||
|
for (sbn in this@NLService.activeNotifications) {
|
||||||
|
// BLog.LOGE("NLService sbn >>> ${sbn.packageName} , ${Gson().toJson(sbn.notification.extras.keySet())}")
|
||||||
|
// val i2 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||||
|
// i2.putExtra("notification_event", i.toString() + " " + sbn.packageName + "\n")
|
||||||
|
// sendBroadcast(i2)
|
||||||
|
// i++
|
||||||
|
}
|
||||||
|
// val i3 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||||
|
// i3.putExtra("notification_event", "===== Notification List ====")
|
||||||
|
// sendBroadcast(i3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+7
-7
@@ -1,15 +1,15 @@
|
|||||||
package rasel.lunar.launcher.receiver
|
package bums.lunatic.launcher.receiver
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
|
import bums.lunatic.launcher.model.AppInfo
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.AppInfoGetter
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import io.realm.kotlin.ext.query
|
import io.realm.kotlin.ext.query
|
||||||
import rasel.lunar.launcher.model.AppInfo
|
|
||||||
import rasel.lunar.launcher.utils.BLog
|
|
||||||
import rasel.lunar.launcher.workers.AppInfoGetter
|
|
||||||
import rasel.lunar.launcher.workers.WorkersDb
|
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ class PackageEventReceiver : BroadcastReceiver() {
|
|||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
val action = intent.action
|
val action = intent.action
|
||||||
|
|
||||||
BLog.LOGE("action >>>> ${action}")
|
Blog.LOGE("action >>>> ${action}")
|
||||||
when(action) {
|
when(action) {
|
||||||
Intent.ACTION_PACKAGE_ADDED,Intent.ACTION_PACKAGE_INSTALL -> {
|
Intent.ACTION_PACKAGE_ADDED,Intent.ACTION_PACKAGE_INSTALL -> {
|
||||||
startAppInfoGetter(context)
|
startAppInfoGetter(context)
|
||||||
@@ -30,7 +30,7 @@ class PackageEventReceiver : BroadcastReceiver() {
|
|||||||
WorkersDb.getRealm().writeBlocking {
|
WorkersDb.getRealm().writeBlocking {
|
||||||
val result = query<AppInfo>("pkgName == $0", packageName).find()
|
val result = query<AppInfo>("pkgName == $0", packageName).find()
|
||||||
if (result.size == 1) {
|
if (result.size == 1) {
|
||||||
delete(result)
|
result.first().currentInstalled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.settings
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
|
import bums.lunatic.launcher.BuildConfig
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.apps.SimpleContact
|
||||||
|
import bums.lunatic.launcher.common.CommonActivity
|
||||||
|
import bums.lunatic.launcher.databinding.AboutBinding
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsActivityBinding
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.BOTTOM_SHEET_TAG
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
|
import bums.lunatic.launcher.model.AppInfo
|
||||||
|
import bums.lunatic.launcher.settings.childs.Advance
|
||||||
|
import bums.lunatic.launcher.settings.childs.Appearances
|
||||||
|
import bums.lunatic.launcher.settings.childs.Apps
|
||||||
|
import bums.lunatic.launcher.settings.childs.HomeSettings
|
||||||
|
import bums.lunatic.launcher.settings.childs.Misc
|
||||||
|
import bums.lunatic.launcher.settings.childs.TopInfos
|
||||||
|
import bums.lunatic.launcher.settings.childs.WeatherSettings
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import io.realm.kotlin.UpdatePolicy
|
||||||
|
import io.realm.kotlin.ext.query
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
|
internal class SettingsActivity : CommonActivity() {
|
||||||
|
|
||||||
|
private lateinit var binding: SettingsActivityBinding
|
||||||
|
private val sourceCode = "https://github.com/iamrasel/lunar-launcher"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic var settingsPrefs: SharedPreferences? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
DynamicColors.applyToActivityIfAvailable(this)
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
/* set up view */
|
||||||
|
binding = SettingsActivityBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
settingsPrefs = this.getSharedPreferences(PREFS_SETTINGS, 0)
|
||||||
|
|
||||||
|
/* launch child settings dialogs on button clicks */
|
||||||
|
binding.timeDate.setOnClickListener {
|
||||||
|
TopInfos().show(supportFragmentManager, BOTTOM_SHEET_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.weather.setOnClickListener {
|
||||||
|
WeatherSettings().show(supportFragmentManager, BOTTOM_SHEET_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.todo.setOnClickListener {
|
||||||
|
HomeSettings().show(supportFragmentManager, BOTTOM_SHEET_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.apps.setOnClickListener {
|
||||||
|
Apps().show(supportFragmentManager, BOTTOM_SHEET_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.appearances.setOnClickListener {
|
||||||
|
Appearances().show(supportFragmentManager, BOTTOM_SHEET_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.misc.setOnClickListener {
|
||||||
|
Misc().show(supportFragmentManager, BOTTOM_SHEET_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.advance.setOnClickListener {
|
||||||
|
Advance().show(supportFragmentManager, BOTTOM_SHEET_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* about and support dialogs */
|
||||||
|
binding.about.setOnClickListener { aboutDialog() }
|
||||||
|
binding.support.setOnClickListener { supportDialog() }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* show app version name */
|
||||||
|
binding.version.text = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})${if(PrefBoolean.rootPermisssion.get(false)) "[Root]" else ""}"
|
||||||
|
|
||||||
|
binding.version.setOnClickListener {
|
||||||
|
binding.version.removeCallbacks(cancelCount)
|
||||||
|
clickCount += 1
|
||||||
|
binding.version.postDelayed(cancelCount, 2000L)
|
||||||
|
if (clickCount > 5) {
|
||||||
|
PrefHelper.putBoolean("rootPermisssion",!PrefBoolean.rootPermisssion.get(false))
|
||||||
|
binding.version.text = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})${if(PrefBoolean.rootPermisssion.get(false)) "[Root]" else ""}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var cancelCount = Runnable{
|
||||||
|
clickCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var clickCount = 0
|
||||||
|
|
||||||
|
override fun getTheme(): Resources.Theme {
|
||||||
|
val theme = super.getTheme()
|
||||||
|
theme.applyStyle(R.style.SettingsNavBar, true)
|
||||||
|
return theme
|
||||||
|
}
|
||||||
|
|
||||||
|
/* about dialog */
|
||||||
|
private fun aboutDialog() {
|
||||||
|
val bottomSheetDialog = BottomSheetDialog(this)
|
||||||
|
val aboutBinding = AboutBinding.inflate(this.layoutInflater)
|
||||||
|
bottomSheetDialog.setContentView(aboutBinding.root)
|
||||||
|
bottomSheetDialog.show()
|
||||||
|
bottomSheetDialog.dismissWithAnimation = true
|
||||||
|
|
||||||
|
/* source code at github */
|
||||||
|
aboutBinding.sourceCode.setOnClickListener {
|
||||||
|
bottomSheetDialog.dismiss()
|
||||||
|
// startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(sourceCode)))
|
||||||
|
}
|
||||||
|
/* wiki at github */
|
||||||
|
aboutBinding.wiki.setOnClickListener {
|
||||||
|
bottomSheetDialog.dismiss()
|
||||||
|
// startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("$sourceCode/wiki")))
|
||||||
|
}
|
||||||
|
/* telegram community */
|
||||||
|
aboutBinding.telegramGroup.setOnClickListener {
|
||||||
|
bottomSheetDialog.dismiss()
|
||||||
|
// startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/LunarLauncher_chats")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun supportDialog() {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.support)
|
||||||
|
.setMessage(R.string.support_message)
|
||||||
|
/* star button */
|
||||||
|
.setNeutralButton("backup") { _, _ ->
|
||||||
|
val path = File(Environment.getExternalStorageDirectory(),"bums")
|
||||||
|
if (path.exists() == false) {
|
||||||
|
path.mkdirs()
|
||||||
|
}
|
||||||
|
saveObjToJson(path,"prefSettings.txt",PrefHelper.getSettings())
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
val foundAppInfo = query<AppInfo>().find()
|
||||||
|
Blog.LOGE("foundAppInfo >>> ${foundAppInfo}")
|
||||||
|
val apps = arrayListOf<AppInfo>().apply { addAll((copyFromRealm(foundAppInfo))) }
|
||||||
|
Blog.LOGE("foundAppInfo >>> ${apps.size}")
|
||||||
|
saveObjToJson(path,"appInfos.txt",apps)
|
||||||
|
val foundSimpleContact = query<SimpleContact>().find()
|
||||||
|
Blog.LOGE("foundSimpleContact >>> ${foundSimpleContact.size}")
|
||||||
|
val contacts = arrayListOf<SimpleContact>().apply { addAll(copyFromRealm(foundSimpleContact)) }
|
||||||
|
saveObjToJson(path,"contactInfos.txt",contacts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* affiliate button */
|
||||||
|
.setNegativeButton("restore") { d, c ->
|
||||||
|
d.dismiss()
|
||||||
|
restoreSetting()
|
||||||
|
}
|
||||||
|
/* donate button */
|
||||||
|
.setPositiveButton(R.string.donate) { _, _ ->
|
||||||
|
// startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://iamrasel.github.io/donate")))
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun restoreSetting() {
|
||||||
|
val fileName = "prefSettings.txt"
|
||||||
|
val path = File(Environment.getExternalStorageDirectory(),"bums")
|
||||||
|
val file = File(path, fileName)
|
||||||
|
if (path.exists() && file.exists()) {
|
||||||
|
val retMap = readMap(file)
|
||||||
|
decodeString(File(path, "appInfos.txt"))?.let {
|
||||||
|
val appInfos = Gson().fromJson(it, object : TypeToken<ArrayList<AppInfo?>?>() {}.type) as ArrayList<AppInfo>
|
||||||
|
Blog.LOGE("appInfos >>>> ${appInfos.size}")
|
||||||
|
WorkersDb.getRealm().writeBlocking { appInfos.forEach { copyToRealm(it,UpdatePolicy.ALL) } }
|
||||||
|
}
|
||||||
|
decodeString(File(path,"contactInfos.txt"))?.let {
|
||||||
|
val contacts = Gson().fromJson(it, object : TypeToken<ArrayList<SimpleContact?>?>() {}.type) as ArrayList<SimpleContact>
|
||||||
|
Blog.LOGE("contacts >>>> ${contacts.size}")
|
||||||
|
WorkersDb.getRealm().writeBlocking { contacts.forEach { copyToRealm(it,UpdatePolicy.ALL) } }
|
||||||
|
}
|
||||||
|
Blog.LOGE("retMap >>>> ${Gson().toJson(retMap)}")
|
||||||
|
PrefHelper.putSetting(retMap)
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.restart_now)
|
||||||
|
.setMessage(R.string.restart_message)
|
||||||
|
.setPositiveButton(R.string.restart) { _, _ ->
|
||||||
|
exitProcess(0)
|
||||||
|
}.setCancelable(false)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Blog.LOGE("파일 없는뎅?!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.settings.childs
|
package bums.lunatic.launcher.settings.childs
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@@ -24,11 +24,11 @@ import android.provider.Settings
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsAdvanceBinding
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import rasel.lunar.launcher.R
|
|
||||||
import rasel.lunar.launcher.databinding.SettingsAdvanceBinding
|
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
+10
-10
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package rasel.lunar.launcher.settings.childs
|
package bums.lunatic.launcher.settings.childs
|
||||||
|
|
||||||
import android.Manifest.permission.READ_EXTERNAL_STORAGE
|
import android.Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
import android.Manifest.permission.READ_MEDIA_IMAGES
|
import android.Manifest.permission.READ_MEDIA_IMAGES
|
||||||
@@ -42,18 +42,18 @@ import androidx.appcompat.app.AppCompatDelegate
|
|||||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
||||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.ColorPickerBinding
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsAppearancesBinding
|
||||||
|
import bums.lunatic.launcher.helpers.ColorPicker
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_APPLICATION_THEME
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_STATUS_BAR
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_WINDOW_BACKGROUND
|
||||||
|
import bums.lunatic.launcher.helpers.UniUtils.Companion.getColorResId
|
||||||
|
import bums.lunatic.launcher.settings.SettingsActivity.Companion.settingsPrefs
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import rasel.lunar.launcher.R
|
|
||||||
import rasel.lunar.launcher.databinding.ColorPickerBinding
|
|
||||||
import rasel.lunar.launcher.databinding.SettingsAppearancesBinding
|
|
||||||
import rasel.lunar.launcher.helpers.ColorPicker
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APPLICATION_THEME
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_STATUS_BAR
|
|
||||||
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_WINDOW_BACKGROUND
|
|
||||||
import rasel.lunar.launcher.helpers.UniUtils.Companion.getColorResId
|
|
||||||
import rasel.lunar.launcher.settings.SettingsActivity.Companion.settingsPrefs
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
|
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.settings.childs
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsAppsBinding
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
|
import bums.lunatic.launcher.helpers.PrefLong
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.slider.Slider
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
|
internal class Apps : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: SettingsAppsBinding
|
||||||
|
private var settingsChanged: Boolean = false
|
||||||
|
private var packageManager: PackageManager? = null
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val bottomSheetView = View.inflate(context, R.layout.settings_apps, null)
|
||||||
|
val dialog = super.onCreateDialog(savedInstanceState).apply {
|
||||||
|
setContentView(bottomSheetView)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the height to wrap_content
|
||||||
|
BottomSheetBehavior.from(bottomSheetView.parent as View)
|
||||||
|
.peekHeight = resources.displayMetrics.heightPixels // Adjust this if needed
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("RtlHardcoded")
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = SettingsAppsBinding.inflate(inflater, container, false)
|
||||||
|
packageManager = requireActivity().packageManager
|
||||||
|
|
||||||
|
|
||||||
|
binding.keyboardAutoGroup.isChecked = PrefBoolean.openWithKayboard.get()
|
||||||
|
binding.keyboardAutoGroup.setOnCheckedChangeListener { c,v ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefBoolean.openWithKayboard.set(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.quickLaunchGroup.isChecked = PrefBoolean.useQuickLaunch.get()
|
||||||
|
binding.quickLaunchGroup.setOnCheckedChangeListener { c,v ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefBoolean.useQuickLaunch.get(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.appsCountGroup.isChecked = PrefBoolean.showAppResultCount.get()
|
||||||
|
binding.appsCountGroup.setOnCheckedChangeListener { c,v ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefBoolean.showAppResultCount.set(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
((PrefLong.maxQueryCount.get(18L) as? Long)?.toFloat() ?: 18F).let {
|
||||||
|
binding.columnsCountTitle.text = getString(R.string.grid_columns_count) +" [${it.toInt()}]"
|
||||||
|
binding.columnsCount.value = it
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefLong.shortTimePeriod.get(20L).let {
|
||||||
|
binding.shortTimeTitle.text = getString(R.string.shortTimeTitle) +" [${it.toInt()}분 마다]"
|
||||||
|
binding.shortTime.value = it.toFloat()
|
||||||
|
}
|
||||||
|
PrefLong.midTimePeriod.get(30L).let {
|
||||||
|
binding.middleTimeTitle.text = getString(R.string.middleTimeTitle) +" [${it.toInt()}분 마다]"
|
||||||
|
binding.middleTime.value = it.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefLong.longTimePeriod.get(60L).let {
|
||||||
|
binding.longTimeTitle.text = getString(R.string.longTimeTitle) +" [${it.toInt()}분 마다]"
|
||||||
|
binding.longTime.value = it.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefLong.locationTimePeriod.get(20L).let {
|
||||||
|
binding.locationTimeTitle.text = getString(R.string.locationTimeTitle) +" [${it.toInt()}분 마다]"
|
||||||
|
binding.locationTime.value = it.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefLong.locationDistance.get(200L).let {
|
||||||
|
binding.locationDistanceTitle.text = getString(R.string.locationDistanceTitle) +" [${it.toInt()}분 마다]"
|
||||||
|
binding.locationDistance.value = it.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
// binding.scrollbarHeight.value = settingsPrefs!!.getInt(KEY_SCROLLBAR_HEIGHT, DEFAULT_SCROLLBAR_HEIGHT).toFloat()
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("RtlHardcoded")
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
|
||||||
|
|
||||||
|
binding.columnsCount.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefLong.maxQueryCount.set(value.toLong())
|
||||||
|
binding.columnsCountTitle.text = getString(R.string.grid_columns_count) +" [${value.toInt()}]"
|
||||||
|
})
|
||||||
|
|
||||||
|
binding.shortTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefLong.shortTimePeriod.set(value.toLong())
|
||||||
|
binding.shortTimeTitle.text = getString(R.string.shortTimeTitle) +" [${value.toInt()}분 마다]"
|
||||||
|
Blog.LOGE("binding.shortTimeTitle.text >>> ${binding.shortTimeTitle.text}")
|
||||||
|
})
|
||||||
|
binding.middleTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefLong.midTimePeriod.set(value.toLong())
|
||||||
|
binding.middleTimeTitle.text = getString(R.string.middleTimeTitle) +" [${value.toInt()}분 마다]"
|
||||||
|
Blog.LOGE("binding.shortTimeTitle.text >>> ${binding.middleTimeTitle.text}")
|
||||||
|
})
|
||||||
|
binding.longTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefLong.longTimePeriod.set(value.toLong())
|
||||||
|
binding.longTimeTitle.text = getString(R.string.longTimeTitle) +" [${value.toInt()}]분 마다]"
|
||||||
|
Blog.LOGE("binding.shortTimeTitle.text >>> ${binding.longTimeTitle.text}")
|
||||||
|
})
|
||||||
|
|
||||||
|
binding.locationDistance.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefLong.locationDistance.set(value.toLong())
|
||||||
|
binding.locationDistanceTitle.text = getString(R.string.locationDistanceTitle) +" [${value.toInt()}]미터 마다]"
|
||||||
|
})
|
||||||
|
binding.locationTime.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||||
|
settingsChanged = true
|
||||||
|
PrefLong.locationTimePeriod.set(value.toLong())
|
||||||
|
binding.locationTimeTitle.text = getString(R.string.locationTimeTitle) +" [${value.toInt()}]분 마다]"
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
if (settingsChanged) {
|
||||||
|
MaterialAlertDialogBuilder(requireActivity())
|
||||||
|
.setTitle(R.string.restart_now)
|
||||||
|
.setMessage(R.string.restart_message)
|
||||||
|
.setPositiveButton(R.string.restart) { _, _ ->
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.later, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.settings.childs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TableRow
|
||||||
|
import androidx.core.view.children
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsTodoBinding
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
|
internal class HomeSettings : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding : SettingsTodoBinding
|
||||||
|
private var settingsChanged: Boolean = false
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = SettingsTodoBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
|
||||||
|
setTableItem(binding.admin02)
|
||||||
|
setTableItem(binding.admin01)
|
||||||
|
setTableItem(binding.normal01)
|
||||||
|
setTableItem(binding.normal02)
|
||||||
|
setTableItem(binding.normal03)
|
||||||
|
setTableItem(binding.normal04)
|
||||||
|
|
||||||
|
|
||||||
|
binding.callInfo.isChecked = PrefBoolean.showCallHistory.get(false)
|
||||||
|
binding.callInfo.setOnCheckedChangeListener { buttonView, isChecked -> PrefBoolean.showCallHistory.set(isChecked)
|
||||||
|
settingsChanged = true}
|
||||||
|
binding.smsInfos.isChecked = PrefBoolean.showSMSHistory.get(false)
|
||||||
|
binding.smsInfos.setOnCheckedChangeListener { buttonView, isChecked -> PrefBoolean.showSMSHistory.set(isChecked)
|
||||||
|
settingsChanged = true}
|
||||||
|
binding.notificationInfos.isChecked = PrefBoolean.showNotificationHistory.get(false)
|
||||||
|
binding.notificationInfos.setOnCheckedChangeListener { buttonView, isChecked -> PrefBoolean.showNotificationHistory.set(isChecked)
|
||||||
|
settingsChanged = true}
|
||||||
|
binding.nowPlaying.isChecked = PrefBoolean.showNowPlaying.get(false)
|
||||||
|
binding.nowPlaying.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
PrefBoolean.showNowPlaying.set(isChecked)
|
||||||
|
settingsChanged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(!PrefHelper.getBoolean("rootPermisssion",false)) {
|
||||||
|
binding.admin01.visibility = View.GONE
|
||||||
|
binding.admin02.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkdCount = 0
|
||||||
|
set(value) {
|
||||||
|
if (value >= 0) {
|
||||||
|
field = value
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
Blog.LOGE("field > 0 >>> ${field}")
|
||||||
|
PrefBoolean.showNewsHistory.set(field > 0)
|
||||||
|
Blog.LOGE("field > 0 >>> ${PrefBoolean.showNewsHistory.get(false)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun setTableItem(tableRow : TableRow) {
|
||||||
|
tableRow.children.forEach { (it as? SwitchMaterial)?.let {
|
||||||
|
it.text?.toString()?.toUpperCase()?.let { key ->
|
||||||
|
it.isChecked = PrefHelper.getBoolean(key, false)
|
||||||
|
checkdCount += if (it.isChecked) 1 else -1
|
||||||
|
it.setOnCheckedChangeListener { v , isBool ->
|
||||||
|
PrefHelper.putBoolean(key, isBool)
|
||||||
|
checkdCount += if (isBool) 1 else -1
|
||||||
|
settingsChanged = true
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
if (settingsChanged) {
|
||||||
|
MaterialAlertDialogBuilder(requireActivity())
|
||||||
|
.setTitle(R.string.restart_now)
|
||||||
|
.setMessage(R.string.restart_message)
|
||||||
|
.setPositiveButton(R.string.restart) { _, _ ->
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.later, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.settings.childs
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsPrivitServiceBinding
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_RSS_URL
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_RSS_URL2
|
||||||
|
import bums.lunatic.launcher.helpers.PrefString
|
||||||
|
import bums.lunatic.launcher.settings.SettingsActivity.Companion.settingsPrefs
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import java.util.Objects
|
||||||
|
|
||||||
|
|
||||||
|
internal class Misc : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding : SettingsPrivitServiceBinding
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = SettingsPrivitServiceBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
/* initialize views according to the saved values */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
binding.inputFeedUrl.setText(PrefString.telegramBotApi.get(""))
|
||||||
|
binding.inputFeedUrl.doOnTextChanged { t,s,b,l -> PrefString.telegramBotApi.set(t.toString())
|
||||||
|
|
||||||
|
}
|
||||||
|
binding.inputFeedUrl2.setText(PrefString.telegramMyId.get(""))
|
||||||
|
binding.inputFeedUrl2.doOnTextChanged { t,s,b,l -> PrefString.telegramMyId.set(t.toString())
|
||||||
|
|
||||||
|
}
|
||||||
|
binding.inputFeedUrl3.setText(PrefString.telegramSendTarget.get(""))
|
||||||
|
binding.inputFeedUrl3.doOnTextChanged { t,s,b,l -> PrefString.telegramSendTarget.set(t.toString())
|
||||||
|
|
||||||
|
}
|
||||||
|
binding.inputFeedUrl4.setText(PrefString.locationApi.get(""))
|
||||||
|
binding.inputFeedUrl4.doOnTextChanged { t,s,b,l -> PrefString.locationApi.set(t.toString())}
|
||||||
|
|
||||||
|
binding.inputFeedUrl5.setText(PrefString.carName.get(""))
|
||||||
|
binding.inputFeedUrl5.doOnTextChanged { t,s,b,l -> PrefString.carName.set(t.toString())}
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save input field value while closing the dialog */
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
settingsPrefs!!.edit().putString(KEY_RSS_URL,
|
||||||
|
Objects.requireNonNull(binding.inputFeedUrl.text).toString().trim { it <= ' ' }).apply()
|
||||||
|
settingsPrefs!!.edit().putString(KEY_RSS_URL2,
|
||||||
|
Objects.requireNonNull(binding.inputFeedUrl2.text).toString().trim { it <= ' ' }).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.settings.childs
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.widget.doAfterTextChanged
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsTimeDateBinding
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefHelper
|
||||||
|
import bums.lunatic.launcher.helpers.PrefString
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
|
internal class TopInfos : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding : SettingsTimeDateBinding
|
||||||
|
private var settingsChanged: Boolean = false
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = SettingsTimeDateBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
binding.useBattery.isChecked = PrefBoolean.displayBattery.get(true)
|
||||||
|
binding.useDateTime.isChecked = PrefBoolean.displayDateTime.get(true)
|
||||||
|
Blog.LOGE("PrefHelper.getSettings() >>> ${Gson().toJson(PrefHelper.getSettings())}")
|
||||||
|
binding.useBattery.setOnCheckedChangeListener { button, b ->
|
||||||
|
PrefBoolean.displayBattery.set(b)
|
||||||
|
settingsChanged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
updateViews()
|
||||||
|
|
||||||
|
binding.useDateTime.setOnCheckedChangeListener { button, b ->
|
||||||
|
PrefBoolean.displayDateTime.set(b)
|
||||||
|
settingsChanged = true
|
||||||
|
updateViews()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
binding.timeFormat.setText(PrefString.defaultTimeFormat.get("a HH:mm:ss"))
|
||||||
|
binding.dateFormat.setText(PrefString.defaultDateFormat.get("yyyy년 MM월 W주차 dd일 E요일"))
|
||||||
|
binding.previewDateTime.defaultTimeFormat = PrefString.defaultTimeFormat.get("a HH:mm:ss")
|
||||||
|
binding.previewDateTime.defaultDateFormat = PrefString.defaultDateFormat.get("yyyy년 MM월 W주차 dd일 E요일")
|
||||||
|
binding.timeFormat.doAfterTextChanged {
|
||||||
|
try {
|
||||||
|
SimpleDateFormat(it.toString()).format(Date())
|
||||||
|
binding.previewDateTime.defaultTimeFormat = it.toString()
|
||||||
|
settingsChanged = true
|
||||||
|
PrefString.defaultTimeFormat.set(it.toString())
|
||||||
|
} catch (e : Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.dateFormat.doAfterTextChanged {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
SimpleDateFormat(it.toString()).format(Date())
|
||||||
|
binding.previewDateTime.defaultDateFormat = it.toString()
|
||||||
|
settingsChanged = true
|
||||||
|
PrefString.defaultDateFormat.set(it.toString())
|
||||||
|
} catch (e : Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
fun updateViews() {
|
||||||
|
with(if (binding.useBattery.isChecked) View.VISIBLE else View.GONE){
|
||||||
|
binding.timeFormat.visibility = this
|
||||||
|
binding.dateFormat.visibility = this
|
||||||
|
binding.previewDateTime.visibility = this
|
||||||
|
binding.previewDateTime.visibility = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
|
||||||
|
/* change time format value */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the input field is empty, then save the default value.
|
||||||
|
else save the value from input field while closing the dialog */
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
if (settingsChanged) {
|
||||||
|
MaterialAlertDialogBuilder(requireActivity())
|
||||||
|
.setTitle(R.string.restart_now)
|
||||||
|
.setMessage(R.string.restart_message)
|
||||||
|
.setPositiveButton(R.string.restart) { _, _ ->
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.later, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Lunar Launcher
|
||||||
|
* Copyright (C) 2022 Md Rasel Hossain
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bums.lunatic.launcher.settings.childs
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.databinding.SettingsWeatherBinding
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_CITY_NAME
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_OWM_API
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_SHOW_CITY
|
||||||
|
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_TEMP_UNIT
|
||||||
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
|
import bums.lunatic.launcher.helpers.PrefString
|
||||||
|
import bums.lunatic.launcher.settings.SettingsActivity.Companion.settingsPrefs
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import java.util.Objects
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
open class SettingChild : BottomSheetDialogFragment() {
|
||||||
|
protected var settingsChanged: Boolean = false
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
if (settingsChanged) {
|
||||||
|
MaterialAlertDialogBuilder(requireActivity())
|
||||||
|
.setTitle(R.string.restart_now)
|
||||||
|
.setMessage(R.string.restart_message)
|
||||||
|
.setPositiveButton(R.string.restart) { _, _ ->
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.later, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class WeatherSettings : SettingChild() {
|
||||||
|
|
||||||
|
private lateinit var binding : SettingsWeatherBinding
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = SettingsWeatherBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
/* initialize views according to the saved values */
|
||||||
|
|
||||||
|
binding.inputOwm.setText(PrefString.weatherApiKey.get(""))
|
||||||
|
binding.inputOwm.doOnTextChanged { text, start, before, count ->
|
||||||
|
PrefString.weatherApiKey.set(text.toString())
|
||||||
|
settingsChanged = true
|
||||||
|
}
|
||||||
|
binding.dress.isChecked = PrefBoolean.weatherDress.get(false)
|
||||||
|
binding.weather.isChecked = PrefBoolean.weatherState.get(false)
|
||||||
|
binding.weather.setOnCheckedChangeListener { buttonView, isChecked -> PrefBoolean.weatherState.set(isChecked)
|
||||||
|
settingsChanged = true}
|
||||||
|
binding.dress.setOnCheckedChangeListener { buttonView, isChecked -> PrefBoolean.weatherDress.set(isChecked)
|
||||||
|
settingsChanged = true}
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save input field values while closing the dialog */
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package rasel.lunar.launcher.utils
|
package bums.lunatic.launcher.utils
|
||||||
|
|
||||||
object AlphabetToChosungMap {
|
object AlphabetToChosungMap {
|
||||||
val map = hashMapOf<String,String>(
|
val map = hashMapOf<String,String>(
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user