diff --git a/.github/apk-badge.png b/.github/apk-badge.png
new file mode 100644
index 00000000..5d112c2f
Binary files /dev/null and b/.github/apk-badge.png differ
diff --git a/.github/google-play-badge.png b/.github/google-play-badge.png
new file mode 100644
index 00000000..7da103b5
Binary files /dev/null and b/.github/google-play-badge.png differ
diff --git a/.gitignore b/.gitignore
index 1864dd01..07e9f679 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,11 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/android,androidstudio,gradle,java,kotlin
+# Edit at https://www.toptal.com/developers/gitignore?templates=android,androidstudio,gradle,java,kotlin
+
+### Android ###
# Built application files
*.apk
+*.aar
*.ap_
*.aab
@@ -23,7 +29,7 @@ build/
local.properties
# Proguard folder generated by Eclipse
-#proguard/
+# proguard/
# Log Files
*.log
@@ -40,22 +46,22 @@ captures/
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
-.idea/dictionaries
+#.idea/dictionaries
.idea/libraries
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml
-.idea/copyright/profiles_settings.xml
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
-*.jks
-*.keystore
+#*.jks
+#*.keystore
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
+.cxx/
# Google Services (e.g. APIs or Firebase)
# google-services.json
@@ -82,9 +88,180 @@ lint/outputs/
lint/tmp/
# lint/reports/
-app/schemas/
+### Android Patch ###
+gen-external-apklibs
+output-metadata.json
+
+# Replacement of .externalNativeBuild directories introduced
+# with Android Studio 3.5.
+
+### Java ###
+# Compiled class file
+
+# Log file
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+!/*/libs/*.jar
+
+### Kotlin ###
+# Compiled class file
+
+# Log file
+
+# BlueJ files
+
+# Mobile Tools for Java (J2ME)
+
+# Package Files #
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+
+### Gradle ###
+.gradle
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Cache of project
+.gradletasknamecache
+
+# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
+# gradle/wrapper/gradle-wrapper.properties
+
+### Gradle Patch ###
+**/build/
+
+### AndroidStudio ###
+# Covers files to be ignored for android development using Android Studio.
+
+# Built application files
+
+# Files for the ART/Dalvik VM
+
+# Java class files
+
+# Generated files
+
+# Gradle files
+
+# Signing files
+.signing/
+
+# Local configuration file (sdk path, etc)
+
+# Proguard folder generated by Eclipse
+
+# Log Files
+
+# Android Studio
+/*/build/
+/*/local.properties
+/*/out
+/*/*/build
+/*/*/production
+*.ipr
+*~
+*.swp
+
+# Keystore files
+*.jks
+*.keystore
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Android Patch
+
+# External native build folder generated in Android Studio 2.2 and later
+
+# NDK
+obj/
+
+# IntelliJ IDEA
+*.iws
+/out/
+
+# User-specific configurations
+.idea/caches/
+.idea/libraries/
+.idea/shelf/
+.idea/.name
+.idea/compiler.xml
+.idea/copyright/profiles_settings.xml
+.idea/encodings.xml
+.idea/misc.xml
+.idea/scopes/scope_settings.xml
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+.idea/datasources.xml
+.idea/dataSources.ids
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+.idea/jarRepositories.xml
+
+# OS-specific files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# Legacy Eclipse project files
+.classpath
+.project
+.cproject
+.settings/
+
+# Mobile Tools for Java (J2ME)
+
+# Package Files #
+
+# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
+
+## Plugin-specific files:
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Mongo Explorer plugin
+.idea/mongoSettings.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+### AndroidStudio Patch ###
+
+!/gradle/wrapper/gradle-wrapper.jar
+
+# End of https://www.toptal.com/developers/gitignore/api/android,androidstudio,gradle,java,kotlin
signatures/
-
-app/.cxx
-/i18n/
diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index 9ffcbb8a..00000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-Szkolny.eu
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 8b487d4c..00000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/dictionaries/Kuba.xml b/.idea/dictionaries/Kuba.xml
new file mode 100644
index 00000000..7910687c
--- /dev/null
+++ b/.idea/dictionaries/Kuba.xml
@@ -0,0 +1,17 @@
+
+
+
+ autoryzacji
+ ciasteczko
+ csrf
+ edziennik
+ gson
+ hebe
+ idziennik
+ kuba
+ synergia
+ szczodrzyński
+ szkolny
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 15a15b21..00000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
deleted file mode 100644
index 276cd1ca..00000000
--- a/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 2f82ed79..00000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..810fce6e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,621 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
diff --git a/README.md b/README.md
index 3cf34f9b..0726f161 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,83 @@
-Szkolny.eu
+# Szkolny.eu
+
+Nieoficjalna aplikacja do obsługi najpopularniejszych dzienników elektronicznych w Polsce.
+
+
+
+[](https://szkolny.eu/discord)
+[](https://szkolny.eu/)
+[](https://szkolny.eu/facebook)
+
+
+[](https://github.com/szkolny-eu/szkolny-android/releases/latest)
+
+
+
+
+## Ważna informacja
+
+Jak zapewne już wiecie, we wrześniu 2020r. **firma Librus zabroniła nam** publikowania w sklepie Google Play naszej aplikacji z obsługą dziennika Librus® Synergia. Prowadziliśmy rozmowy, aby **umożliwić Wam wygodny, bezpłatny dostęp do Waszych ocen, wiadomości, zadań domowych**, jednak oczekiwania firmy Librus zdecydowanie przekroczyły wszelkie nasze możliwości finansowe. Mając na uwadze powyższe względy, zdecydowaliśmy się opublikować kod źródłowy aplikacji Szkolny.eu. Liczymy, że dzięki temu aplikacja będzie mogła dalej funkcjonować, być rozwijana, pomagając Wam w czasie zdalnego nauczania i przez kolejne lata nauki.
+
+__Zachęcamy do [przeczytania całej informacji](https://szkolny.eu/informacja) na naszej stronie.__
+
+*- Autorzy Szkolny.eu*
+
+## O aplikacji
+
+Szkolny.eu jest nieoficjalną aplikacją, umożliwiającą rodzicom i uczniom dostęp do danych z e-dziennika w każdym smartfonie. Jest to jedyna aplikacja, która posiada wsparcie dla wszystkich najpopularniejszych e-dzienników. Oznacza to, że mając kilka kont w różnych szkołach, wystarczy mieć tylko jedną aplikację.
+
+### Funkcje aplikacji
+
+- plan lekcji, terminarz, oceny, wiadomości, zadania domowe, uwagi, frekwencja
+- wygodne **widgety** na ekran główny
+- łatwa komunikacja z nauczycielami - **odbieranie, wyszukiwanie i wysyłanie wiadomości**
+- pobieranie **załączników wiadomości i zadań domowych**
+- **powiadomienia** o nowych informacjach na telefonie lub na komputerze
+- organizacja zadań domowych i sprawdzianów - łatwe oznaczanie jako wykonane
+- obliczanie **średniej ocen** ze wszystkich przedmiotów, oceny proponowane i końcowe
+- Symulator edycji ocen - obliczanie średniej z przedmiotu po zmianie dowolnych jego ocen
+- **dodawanie własnych wydarzeń** i zadań do terminarza
+- nowoczesny i intuicyjny interfejs użytkownika
+- **obsługa wielu profili** uczniów - jeżeli jesteś Rodzicem, możesz skonfigurować wszystkie swoje konta uczniowskie i łatwo między nimi przełączać
+- opcja **automatycznej synchronizacji** z E-dziennikiem
+- opcja Ciszy nocnej - nigdy więcej budzących Cię dźwięków z telefonu
+
+[Zobacz porównanie funkcji z innymi aplikacjami](https://szkolny.eu/funkcje)
+
+### Pobieranie
+
+Najnowsze wersje możesz pobrać z Google Play lub bezpośrednio z naszej strony, w formacie .APK.
+
+[ ](https://szkolny.eu/pobierz/android)
+[ ](https://szkolny.eu/pobierz)
+
+### Kompilacja
+
+Aby uruchomić aplikację "ze źródeł" należy użyć Android Studio w wersji co najmniej 4.2 Beta 6. Wersja `debug` może wtedy zostać zainstalowana np. na emulatorze Androida.
+
+Aby zbudować wersję produkcyjną, tzn. `release` należy użyć wariantu `mainRelease` oraz podpisać wyjściowy plik .APK sygnaturą w wersji V1 i V2.
+
+Warianty `play` oraz `official` są zastrzeżone dla wydań oficjalnych.
+
+## Współpraca
+
+PRy wprowadzające nowe funkcje lub naprawiające błędy są mile widziane!
+
+__Jeśli masz jakieś pytania, zapraszamy na [nasz serwer Discord](https://szkolny.eu/discord).__
+
+## Licencja
+
+Szkolny.eu publikowany jest na licencji [GNU GPLv3](LICENSE). W szczególności, deweloper:
+- może modyfikować oraz usprawniać kod aplikacji
+- może dystrybuować wersje produkcyjne
+- musi opublikować wszelkie wprowadzone zmiany, tzn. publiczny fork tego repozytorium
+- nie może zmieniać licencji ani copyrightu aplikacji
+
+Dodatkowo:
+- zabronione jest modyfikowanie lub usuwanie kodu odpowiedzialnego za zgodność wersji produkcyjnych z licencją
+
+- **wersje skompilowane nie mogą być dystrybuowane za pomocą Google Play oraz żadnej platformy, na której istnieje oficjalna wersja aplikacji**
+
+**Autorzy aplikacji nie biorą odpowiedzialności za używanie aplikacji, modyfikowanie oraz dystrybuowanie.**
+
+Znaki towarowe zamieszczone w aplikacji oraz tym dokumencie należą do ich prawowitych właścicieli i są używane wyłącznie w celach informacyjnych.
diff --git a/agendacalendarview/.gitignore b/agendacalendarview/.gitignore
deleted file mode 100644
index 796b96d1..00000000
--- a/agendacalendarview/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/agendacalendarview/build.gradle b/agendacalendarview/build.gradle
deleted file mode 100644
index 92731fb9..00000000
--- a/agendacalendarview/build.gradle
+++ /dev/null
@@ -1,54 +0,0 @@
-apply plugin: 'com.android.library'
-//apply plugin: 'me.tatarka.retrolambda'
-
-android {
- compileSdkVersion setup.compileSdk
-
- android {
- lintOptions {
- abortOnError false
- }
- }
-
- defaultConfig {
- minSdkVersion 14
- targetSdkVersion setup.targetSdk
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- debugMinify {
- debuggable = true
- minifyEnabled = true
- proguardFiles 'proguard-android.txt'
- }
- }
- sourceSets {
- main {
- assets.srcDirs = ['assets']
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
-}
-
-//apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- // Google libraries
- implementation "androidx.appcompat:appcompat:${versions.appcompat}"
- implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}"
- implementation "com.google.android.material:material:${versions.material}"
-
- // other libraries
- //implementation 'se.emilsjolander:stickylistheaders:2.7.0'
- implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar'
- implementation 'io.reactivex:rxjava:1.1.1'
-}
diff --git a/agendacalendarview/src/main/AndroidManifest.xml b/agendacalendarview/src/main/AndroidManifest.xml
deleted file mode 100644
index 38e54711..00000000
--- a/agendacalendarview/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java
deleted file mode 100644
index 0d0c0cf4..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java
+++ /dev/null
@@ -1,264 +0,0 @@
-package com.github.tibolte.agendacalendarview;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.os.Handler;
-import androidx.annotation.NonNull;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.AbsListView;
-import android.widget.AdapterView;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.github.tibolte.agendacalendarview.agenda.AgendaAdapter;
-import com.github.tibolte.agendacalendarview.agenda.AgendaView;
-import com.github.tibolte.agendacalendarview.calendar.CalendarView;
-import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent;
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-import com.github.tibolte.agendacalendarview.models.DayItem;
-import com.github.tibolte.agendacalendarview.models.IDayItem;
-import com.github.tibolte.agendacalendarview.models.IWeekItem;
-import com.github.tibolte.agendacalendarview.models.WeekItem;
-import com.github.tibolte.agendacalendarview.render.DefaultEventRenderer;
-import com.github.tibolte.agendacalendarview.render.EventRenderer;
-import com.github.tibolte.agendacalendarview.utils.BusProvider;
-import com.github.tibolte.agendacalendarview.utils.Events;
-import com.github.tibolte.agendacalendarview.utils.ListViewScrollTracker;
-import com.github.tibolte.agendacalendarview.widgets.FloatingActionButton;
-
-import java.util.Calendar;
-import java.util.List;
-import java.util.Locale;
-
-import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
-
-/**
- * View holding the agenda and calendar view together.
- */
-public class AgendaCalendarView extends FrameLayout implements StickyListHeadersListView.OnStickyHeaderChangedListener {
-
- private static final String LOG_TAG = AgendaCalendarView.class.getSimpleName();
-
- private CalendarView mCalendarView;
- private AgendaView mAgendaView;
- private FloatingActionButton mFloatingActionButton;
-
- private int mAgendaCurrentDayTextColor, mCalendarHeaderColor, mCalendarHeaderTextColor, mCalendarBackgroundColor, mCalendarDayTextColor, mCalendarPastDayTextColor, mCalendarCurrentDayColor, mFabColor;
- private CalendarPickerController mCalendarPickerController;
-
- public AgendaView getAgendaView() {
- return mAgendaView;
- }
-
- private ListViewScrollTracker mAgendaListViewScrollTracker;
- private AbsListView.OnScrollListener mAgendaScrollListener = new AbsListView.OnScrollListener() {
- int mCurrentAngle;
- int mMaxAngle = 85;
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
-
- }
-
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- int scrollY = mAgendaListViewScrollTracker.calculateScrollY(firstVisibleItem, visibleItemCount);
- if (scrollY != 0) {
- mFloatingActionButton.show();
- }
- //Log.d(LOG_TAG, String.format("Agenda listView scrollY: %d", scrollY));
- /*int toAngle = scrollY / 100;
- if (toAngle > mMaxAngle) {
- toAngle = mMaxAngle;
- } else if (toAngle < -mMaxAngle) {
- toAngle = -mMaxAngle;
- }
- RotateAnimation rotate = new RotateAnimation(mCurrentAngle, toAngle, mFloatingActionButton.getWidth() / 2, mFloatingActionButton.getHeight() / 2);
- rotate.setFillAfter(true);
- mCurrentAngle = toAngle;
- mFloatingActionButton.startAnimation(rotate);*/
- }
- };
-
- // region Constructors
-
- public AgendaCalendarView(Context context) {
- super(context);
- }
-
- public AgendaCalendarView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorOptionsView, 0, 0);
- mAgendaCurrentDayTextColor = a.getColor(R.styleable.ColorOptionsView_agendaCurrentDayTextColor, getResources().getColor(R.color.theme_primary));
- mCalendarHeaderColor = a.getColor(R.styleable.ColorOptionsView_calendarHeaderColor, getResources().getColor(R.color.theme_primary_dark));
- mCalendarHeaderTextColor = a.getColor(R.styleable.ColorOptionsView_calendarHeaderTextColor, getResources().getColor(R.color.theme_text_icons));
- mCalendarBackgroundColor = a.getColor(R.styleable.ColorOptionsView_calendarColor, getResources().getColor(R.color.theme_primary));
- mCalendarDayTextColor = a.getColor(R.styleable.ColorOptionsView_calendarDayTextColor, getResources().getColor(R.color.theme_text_icons));
- mCalendarCurrentDayColor = a.getColor(R.styleable.ColorOptionsView_calendarCurrentDayTextColor, getResources().getColor(R.color.calendar_text_current_day));
- mCalendarPastDayTextColor = a.getColor(R.styleable.ColorOptionsView_calendarPastDayTextColor, getResources().getColor(R.color.theme_light_primary));
- mFabColor = a.getColor(R.styleable.ColorOptionsView_fabColor, getResources().getColor(R.color.theme_accent));
-
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.view_agendacalendar, this, true);
-
- setAlpha(0f);
- }
-
- // endregion
-
- // region Class - View
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mCalendarView = (CalendarView) findViewById(R.id.calendar_view);
- mAgendaView = (AgendaView) findViewById(R.id.agenda_view);
- mFloatingActionButton = (FloatingActionButton) findViewById(R.id.floating_action_button);
- ColorStateList csl = new ColorStateList(new int[][]{new int[0]}, new int[]{mFabColor});
- mFloatingActionButton.setBackgroundTintList(csl);
-
- LinearLayout mDayNamesHeader = mCalendarView.findViewById(R.id.cal_day_names);
- mDayNamesHeader.setBackgroundColor(mCalendarHeaderColor);
- for (int i = 0; i < mDayNamesHeader.getChildCount(); i++) {
- TextView txtDay = (TextView) mDayNamesHeader.getChildAt(i);
- txtDay.setTextColor(mCalendarHeaderTextColor);
- }
- mCalendarView.findViewById(R.id.list_week).setBackgroundColor(mCalendarBackgroundColor);
-
- mAgendaView.getAgendaListView().setOnItemClickListener((AdapterView> parent, View view, int position, long id) -> {
- mCalendarPickerController.onEventSelected(CalendarManager.getInstance().getEvents().get(position));
- });
-
- BusProvider.getInstance().toObserverable()
- .subscribe(event -> {
- if (event instanceof Events.DayClickedEvent) {
- if (mCalendarPickerController != null)
- mCalendarPickerController.onDaySelected(((Events.DayClickedEvent) event).getDay());
- } else if (event instanceof Events.EventsFetched) {
- ObjectAnimator alphaAnimation = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 1f).setDuration(500);
- alphaAnimation.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
-
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- long fabAnimationDelay = 500;
- // Just after setting the alpha from this view to 1, we hide the fab.
- // It will reappear as soon as the user is scrolling the Agenda view.
- new Handler().postDelayed(() -> {
- mFloatingActionButton.hide();
- mAgendaListViewScrollTracker = new ListViewScrollTracker(mAgendaView.getAgendaListView());
- mAgendaView.getAgendaListView().setOnScrollListener(mAgendaScrollListener);
- mFloatingActionButton.setOnClickListener((v) -> {
- mAgendaView.translateList(0);
- mAgendaView.getAgendaListView().smoothScrollBy(0, 0);
- //mAgendaView.getAgendaListView().getWrappedList().smoothScrollBy(0, 0);
- mAgendaView.getAgendaListView().scrollToCurrentDate(CalendarManager.getInstance().getToday());
- new Handler().postDelayed(() -> mFloatingActionButton.hide(), fabAnimationDelay);
- });
- }, fabAnimationDelay);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
-
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
- });
- alphaAnimation.start();
- }
- });
- }
-
- // endregion
-
- // region Interface - StickyListHeadersListView.OnStickyHeaderChangedListener
-
- @Override
- public void onStickyHeaderChanged(StickyListHeadersListView stickyListHeadersListView, View header, int position, long headerId) {
- //Log.d(LOG_TAG, String.format("onStickyHeaderChanged, position = %d, headerId = %d", position, headerId));
-
- if (CalendarManager.getInstance().getEvents().size() > 0) {
- CalendarEvent event = CalendarManager.getInstance().getEvents().get(position);
- if (event != null) {
- mCalendarView.scrollToDate(event);
- mCalendarPickerController.onScrollToDate(event.getInstanceDay());
- }
- }
- }
-
- // endregion
-
- // region Public methods
-
- public void init(List eventList, Calendar minDate, Calendar maxDate, Locale locale, CalendarPickerController calendarPickerController, EventRenderer> ... renderers) {
- mCalendarPickerController = calendarPickerController;
-
- CalendarManager.getInstance(getContext()).buildCal(minDate, maxDate, locale, new DayItem(), new WeekItem());
-
- // Feed our views with weeks list and events
- mCalendarView.init(CalendarManager.getInstance(getContext()), mCalendarDayTextColor, mCalendarCurrentDayColor, mCalendarPastDayTextColor, eventList);
-
- // Load agenda events and scroll to current day
- AgendaAdapter agendaAdapter = new AgendaAdapter(mAgendaCurrentDayTextColor);
- mAgendaView.getAgendaListView().setAdapter(agendaAdapter);
- mAgendaView.getAgendaListView().setOnStickyHeaderChangedListener(this);
-
- CalendarManager.getInstance().loadEvents(eventList, new BaseCalendarEvent());
- BusProvider.getInstance().send(new Events.EventsFetched());
- Log.d(LOG_TAG, "CalendarEventTask finished, event count "+eventList.size());
-
- // add default event renderer
- addEventRenderer(new DefaultEventRenderer());
- for (EventRenderer> renderer: renderers) {
- addEventRenderer(renderer);
- }
- }
-
- public void init(Locale locale, List lWeeks, List lDays, List lEvents, CalendarPickerController calendarPickerController) {
- mCalendarPickerController = calendarPickerController;
-
- CalendarManager.getInstance(getContext()).loadCal(locale, lWeeks, lDays, lEvents);
-
- // Feed our views with weeks list and events
- mCalendarView.init(CalendarManager.getInstance(getContext()), mCalendarDayTextColor, mCalendarCurrentDayColor, mCalendarPastDayTextColor, lEvents);
-
- // Load agenda events and scroll to current day
- AgendaAdapter agendaAdapter = new AgendaAdapter(mAgendaCurrentDayTextColor);
- mAgendaView.getAgendaListView().setAdapter(agendaAdapter);
- mAgendaView.getAgendaListView().setOnStickyHeaderChangedListener(this);
-
- // notify that actually everything is loaded
- BusProvider.getInstance().send(new Events.EventsFetched());
- Log.d(LOG_TAG, "CalendarEventTask finished");
-
- // add default event renderer
- addEventRenderer(new DefaultEventRenderer());
- }
-
- public void addEventRenderer(@NonNull final EventRenderer> renderer) {
- AgendaAdapter adapter = (AgendaAdapter) mAgendaView.getAgendaListView().getAdapter();
- adapter.addEventRenderer(renderer);
- }
-
- public void enableFloatingIndicator(boolean enable) {
- mFloatingActionButton.setVisibility(enable ? VISIBLE : GONE);
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java
deleted file mode 100644
index c661d32b..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java
+++ /dev/null
@@ -1,267 +0,0 @@
-package com.github.tibolte.agendacalendarview;
-
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-import com.github.tibolte.agendacalendarview.models.IDayItem;
-import com.github.tibolte.agendacalendarview.models.IWeekItem;
-import com.github.tibolte.agendacalendarview.utils.DateHelper;
-
-import android.content.Context;
-import android.util.Log;
-
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * This class manages information about the calendar. (Events, weather info...)
- * Holds reference to the days list of the calendar.
- * As the app is using several views, we want to keep everything in one place.
- */
-public class CalendarManager {
-
- private static final String LOG_TAG = CalendarManager.class.getSimpleName();
-
- private static CalendarManager mInstance;
-
- private Context mContext;
- private Locale mLocale;
- private Calendar mToday = Calendar.getInstance();
- private SimpleDateFormat mWeekdayFormatter;
- private SimpleDateFormat mMonthHalfNameFormat;
-
- /// instances of classes provided from outside
- private IDayItem mCleanDay;
- private IWeekItem mCleanWeek;
-
- /**
- * List of days used by the calendar
- */
- private List mDays = new ArrayList<>();
- /**
- * List of weeks used by the calendar
- */
- private List mWeeks = new ArrayList<>();
- /**
- * List of events instances
- */
- private List mEvents = new ArrayList<>();
-
- // region Constructors
-
- public CalendarManager(Context context) {
- this.mContext = context;
- }
-
- public static CalendarManager getInstance(Context context) {
- if (mInstance == null) {
- mInstance = new CalendarManager(context);
- }
- return mInstance;
- }
-
- public static CalendarManager getInstance() {
- return mInstance;
- }
-
- // endregion
-
- // region Getters/Setters
-
- public Locale getLocale() {
- return mLocale;
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public Calendar getToday() {
- return mToday;
- }
-
- public void setToday(Calendar today) {
- this.mToday = today;
- }
-
- public List getWeeks() {
- return mWeeks;
- }
-
- public List getEvents() {
- return mEvents;
- }
-
- public List getDays() {
- return mDays;
- }
-
- public SimpleDateFormat getWeekdayFormatter() {
- return mWeekdayFormatter;
- }
-
- public SimpleDateFormat getMonthHalfNameFormat() {
- return mMonthHalfNameFormat;
- }
-
- // endregion
-
- // region Public methods
-
- public void buildCal(Calendar minDate, Calendar maxDate, Locale locale, IDayItem cleanDay, IWeekItem cleanWeek) {
- if (minDate == null || maxDate == null) {
- throw new IllegalArgumentException(
- "minDate and maxDate must be non-null.");
- }
- if (minDate.after(maxDate)) {
- throw new IllegalArgumentException(
- "minDate must be before maxDate.");
- }
- if (locale == null) {
- throw new IllegalArgumentException("Locale is null.");
- }
-
- setLocale(locale);
-
- mDays.clear();
- mWeeks.clear();
- mEvents.clear();
-
- mCleanDay = cleanDay;
- mCleanWeek = cleanWeek;
-
- Calendar mMinCal = Calendar.getInstance(mLocale);
- Calendar mMaxCal = Calendar.getInstance(mLocale);
- Calendar mWeekCounter = Calendar.getInstance(mLocale);
-
- mMinCal.setTime(minDate.getTime());
- mMaxCal.setTime(maxDate.getTime());
-
- // maxDate is exclusive, here we bump back to the previous day, as maxDate if December 1st, 2020,
- // we don't include that month in our list
- mMaxCal.add(Calendar.MINUTE, -1);
-
- // Now iterate we iterate between mMinCal and mMaxCal so we build our list of weeks
- mWeekCounter.setTime(mMinCal.getTime());
- int maxMonth = mMaxCal.get(Calendar.MONTH);
- int maxYear = mMaxCal.get(Calendar.YEAR);
-
- int currentMonth = mWeekCounter.get(Calendar.MONTH);
- int currentYear = mWeekCounter.get(Calendar.YEAR);
-
- // Loop through the weeks
- while ((currentMonth <= maxMonth // Up to, including the month.
- || currentYear < maxYear) // Up to the year.
- && currentYear < maxYear + 1) { // But not > next yr.
-
- Date date = mWeekCounter.getTime();
- // Build our week list
- int currentWeekOfYear = mWeekCounter.get(Calendar.WEEK_OF_YEAR);
-
- IWeekItem weekItem = cleanWeek.copy();
- weekItem.setWeekInYear(currentWeekOfYear);
- weekItem.setYear(currentYear);
- weekItem.setDate(date);
- weekItem.setMonth(currentMonth);
- weekItem.setLabel(mMonthHalfNameFormat.format(date));
- List dayItems = getDayCells(mWeekCounter); // gather days for the built week
- weekItem.setDayItems(dayItems);
- mWeeks.add(weekItem);
-
- //Log.d(LOG_TAG, String.format("Adding week: %s", weekItem));
-
- mWeekCounter.add(Calendar.WEEK_OF_YEAR, 1);
-
- currentMonth = mWeekCounter.get(Calendar.MONTH);
- currentYear = mWeekCounter.get(Calendar.YEAR);
- }
- }
-
- public void loadEvents(List eventList, CalendarEvent noEvent) {
-
- for (IWeekItem weekItem : getWeeks()) {
- for (IDayItem dayItem : weekItem.getDayItems()) {
- boolean isEventForDay = false;
- boolean isShowBadgeForDay = false;
- for (CalendarEvent event : eventList) {
- if (DateHelper.isBetweenInclusive(dayItem.getDate(), event.getStartTime(), event.getEndTime())) {
- CalendarEvent copy = event.copy();
-
- if (copy.getShowBadge()) {
- isShowBadgeForDay = true;
- }
-
- Calendar dayInstance = Calendar.getInstance();
- dayInstance.setTime(dayItem.getDate());
- copy.setInstanceDay(dayInstance);
- copy.setDayReference(dayItem);
- copy.setWeekReference(weekItem);
- // add instances in chronological order
- getEvents().add(copy);
- isEventForDay = true;
- }
- }
- if (!isEventForDay) {
- Calendar dayInstance = Calendar.getInstance();
- dayInstance.setTime(dayItem.getDate());
- CalendarEvent copy = noEvent.copy();
-
- copy.setInstanceDay(dayInstance);
- copy.setDayReference(dayItem);
- copy.setWeekReference(weekItem);
- copy.setLocation("");
- copy.setTitle(getContext().getResources().getString(R.string.agenda_event_no_events));
- copy.setPlaceholder(true);
- getEvents().add(copy);
- }
- dayItem.setShowBadge(isShowBadgeForDay);
- }
- }
- }
-
- public void loadCal (Locale locale, List lWeeks, List lDays, List lEvents) {
- mWeeks = lWeeks;
- mDays = lDays;
- mEvents = lEvents;
- setLocale(locale);
- }
-
- // endregion
-
- // region Private methods
-
- private List getDayCells(Calendar startCal) {
- Calendar cal = Calendar.getInstance(mLocale);
- cal.setTime(startCal.getTime());
- List dayItems = new ArrayList<>();
-
- int firstDayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
- int offset = cal.getFirstDayOfWeek() - firstDayOfWeek;
- if (offset > 0) {
- offset -= 7;
- }
- cal.add(Calendar.DATE, offset);
-
- //Log.d(LOG_TAG, String.format("Buiding row week starting at %s", cal.getTime()));
- for (int c = 0; c < 7; c++) {
- IDayItem dayItem = mCleanDay.copy();
- dayItem.buildDayItemFromCal(cal);
- dayItems.add(dayItem);
- cal.add(Calendar.DATE, 1);
- }
-
- mDays.addAll(dayItems);
- return dayItems;
- }
-
- private void setLocale(Locale locale) {
- this.mLocale = locale;
- setToday(Calendar.getInstance(mLocale));
- mWeekdayFormatter = new SimpleDateFormat(getContext().getString(R.string.day_name_format), mLocale);
- mMonthHalfNameFormat = new SimpleDateFormat(getContext().getString(R.string.month_half_name_format), locale);
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarPickerController.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarPickerController.java
deleted file mode 100644
index a2a86dde..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarPickerController.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.github.tibolte.agendacalendarview;
-
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-import com.github.tibolte.agendacalendarview.models.IDayItem;
-
-import java.util.Calendar;
-
-public interface CalendarPickerController {
- void onDaySelected(IDayItem dayItem);
-
- void onEventSelected(CalendarEvent event);
-
- void onScrollToDate(Calendar calendar);
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaAdapter.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaAdapter.java
deleted file mode 100644
index 2e6c6d31..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaAdapter.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.github.tibolte.agendacalendarview.agenda;
-
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-import com.github.tibolte.agendacalendarview.render.DefaultEventRenderer;
-import com.github.tibolte.agendacalendarview.render.EventRenderer;
-
-import androidx.annotation.NonNull;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
-
-/**
- * Adapter for the agenda, implements StickyListHeadersAdapter.
- * Days as sections and CalendarEvents as list items.
- */
-public class AgendaAdapter extends BaseAdapter implements StickyListHeadersAdapter {
-
- private List mEvents = new ArrayList<>();
- private List> mRenderers = new ArrayList<>();
- private int mCurrentDayColor;
-
- // region Constructor
-
- public AgendaAdapter(int currentDayTextColor) {
- this.mCurrentDayColor = currentDayTextColor;
- }
-
- // endregion
-
- // region Public methods
-
- public void updateEvents(List events) {
- this.mEvents.clear();
- this.mEvents.addAll(events);
- notifyDataSetChanged();
- }
-
- // endregion
-
- // region Interface - StickyListHeadersAdapter
-
- @Override
- public View getHeaderView(int position, View convertView, ViewGroup parent) {
- AgendaHeaderView agendaHeaderView = (AgendaHeaderView) convertView;
- if (agendaHeaderView == null) {
- agendaHeaderView = AgendaHeaderView.inflate(parent);
- }
- agendaHeaderView.setDay(getItem(position).getInstanceDay(), mCurrentDayColor, getItem(position).getDayReference().getShowBadge());
- return agendaHeaderView;
- }
-
- @Override
- public long getHeaderId(int position) {
- return mEvents.get(position).getInstanceDay().getTimeInMillis();
- }
-
- // endregion
-
- // region Class - BaseAdapter
-
- @Override
- public int getCount() {
- return mEvents.size();
- }
-
- @Override
- public CalendarEvent getItem(int position) {
- return mEvents.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- EventRenderer eventRenderer = new DefaultEventRenderer();
- final CalendarEvent event = getItem(position);
-
- // Search for the correct event renderer
- for (EventRenderer renderer : mRenderers) {
- if(event.getClass().isAssignableFrom(renderer.getRenderType())) {
- eventRenderer = renderer;
- break;
- }
- }
- convertView = LayoutInflater.from(parent.getContext())
- .inflate(eventRenderer.getEventLayout(), parent, false);
- eventRenderer.render(convertView, event);
- return convertView;
- }
-
- public void addEventRenderer(@NonNull final EventRenderer> renderer) {
- mRenderers.add(renderer);
- }
-
- // endregion
-}
\ No newline at end of file
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaEventView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaEventView.java
deleted file mode 100644
index 198f65cd..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaEventView.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.github.tibolte.agendacalendarview.agenda;
-
-import com.github.tibolte.agendacalendarview.R;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-/**
- * List item view for the StickyHeaderListView of the agenda view
- */
-public class AgendaEventView extends LinearLayout {
- public static AgendaEventView inflate(ViewGroup parent) {
- return (AgendaEventView) LayoutInflater.from(parent.getContext()).inflate(R.layout.view_agenda_event, parent, false);
- }
-
- // region Constructors
-
- public AgendaEventView(Context context) {
- this(context, null);
- }
-
- public AgendaEventView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public AgendaEventView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- setPadding(getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_left),
- getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_top),
- getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_right),
- getResources().getDimensionPixelSize(R.dimen.agenda_event_view_padding_bottom));
- }
-
- // endregion
-}
\ No newline at end of file
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaHeaderView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaHeaderView.java
deleted file mode 100644
index 36b16ddb..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaHeaderView.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.github.tibolte.agendacalendarview.agenda;
-
-import com.github.tibolte.agendacalendarview.CalendarManager;
-import com.github.tibolte.agendacalendarview.R;
-import com.github.tibolte.agendacalendarview.utils.DateHelper;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.GradientDrawable;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-
-/**
- * Header view for the StickyHeaderListView of the agenda view
- */
-public class AgendaHeaderView extends LinearLayout {
-
- public static AgendaHeaderView inflate(ViewGroup parent) {
- return (AgendaHeaderView) LayoutInflater.from(parent.getContext()).inflate(R.layout.view_agenda_header, parent, false);
- }
-
- // region Constructors
-
- public AgendaHeaderView(Context context) {
- super(context);
- }
-
- public AgendaHeaderView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public AgendaHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- // endregion
-
- // region Public methods
-
- public void setDay(Calendar day, int currentDayTextColor, boolean showBadge) {
- TextView txtDayOfMonth = (TextView) findViewById(R.id.view_agenda_day_of_month);
- TextView txtDayOfWeek = (TextView) findViewById(R.id.view_agenda_day_of_week);
- TextView txtDay = (TextView) findViewById(R.id.view_agenda_day_text);
- View circleView = findViewById(R.id.view_day_circle_selected);
-
- Calendar today = CalendarManager.getInstance().getToday();
-
- SimpleDateFormat dayWeekFormatter = new SimpleDateFormat(getContext().getString(R.string.day_name_format), CalendarManager.getInstance().getLocale());
- SimpleDateFormat dayWeekLongFormatter = new SimpleDateFormat("EEEE", CalendarManager.getInstance().getLocale());
-
- txtDayOfMonth.setTextColor(getResources().getColor(R.color.calendar_text_default));
- txtDayOfWeek.setTextColor(getResources().getColor(R.color.calendar_text_default));
-
- if (DateHelper.sameDate(day, today)) {
- txtDayOfMonth.setTextColor(currentDayTextColor);
- circleView.setVisibility(VISIBLE);
- GradientDrawable drawable = (GradientDrawable) circleView.getBackground();
- drawable.setStroke((int) (2 * Resources.getSystem().getDisplayMetrics().density), currentDayTextColor);
- } else if (showBadge) {
- circleView.setVisibility(VISIBLE);
- GradientDrawable drawable = (GradientDrawable) circleView.getBackground();
- drawable.setStroke((int) (2 * Resources.getSystem().getDisplayMetrics().density), 0xffff0000);
- }
- else {
- circleView.setVisibility(INVISIBLE);
- }
-
- txtDayOfMonth.setText(String.valueOf(day.get(Calendar.DAY_OF_MONTH)));
- txtDayOfWeek.setText(dayWeekFormatter.format(day.getTime()));
- //txtDay.setText(dayWeekLongFormatter.format(day.getTime()));
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaListView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaListView.java
deleted file mode 100644
index 235b04c6..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaListView.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.github.tibolte.agendacalendarview.agenda;
-
-import com.github.tibolte.agendacalendarview.CalendarManager;
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-import com.github.tibolte.agendacalendarview.utils.DateHelper;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import java.util.Calendar;
-import java.util.List;
-
-import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
-
-/**
- * StickyListHeadersListView to scroll chronologically through events.
- */
-public class AgendaListView extends StickyListHeadersListView {
-
- // region Constructors
-
- public AgendaListView(Context context) {
- super(context);
- }
-
- public AgendaListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public AgendaListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- // endregion
-
- // region Public methods
-
- public void scrollToCurrentDate(Calendar today) {
- List events = CalendarManager.getInstance().getEvents();
-
- int toIndex = 0;
- for (int i = 0; i < events.size(); i++) {
- if (DateHelper.sameDate(today, events.get(i).getInstanceDay())) {
- toIndex = i;
- break;
- }
- }
-
- final int finalToIndex = toIndex;
- post(()->setSelection(finalToIndex));
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaView.java
deleted file mode 100644
index 80b317da..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/agenda/AgendaView.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.github.tibolte.agendacalendarview.agenda;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-
-import com.github.tibolte.agendacalendarview.CalendarManager;
-import com.github.tibolte.agendacalendarview.R;
-import com.github.tibolte.agendacalendarview.utils.BusProvider;
-import com.github.tibolte.agendacalendarview.utils.Events;
-
-public class AgendaView extends FrameLayout {
-
- private AgendaListView mAgendaListView;
- private View mShadowView;
-
- // region Constructors
-
- public AgendaView(Context context) {
- super(context);
- }
-
- public AgendaView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.view_agenda, this, true);
- }
-
- // endregion
-
- // region Class - View
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mAgendaListView = (AgendaListView) findViewById(R.id.agenda_listview);
- mShadowView = findViewById(R.id.view_shadow);
-
- BusProvider.getInstance().toObserverable()
- .subscribe(event -> {
- if (event instanceof Events.DayClickedEvent) {
- Events.DayClickedEvent clickedEvent = (Events.DayClickedEvent) event;
- getAgendaListView().scrollToCurrentDate(clickedEvent.getCalendar());
- } else if (event instanceof Events.CalendarScrolledEvent) {
- int offset = (int) (3 * getResources().getDimension(R.dimen.day_cell_height));
- translateList(offset);
- } else if (event instanceof Events.EventsFetched) {
- if (getAgendaListView().getAdapter() != null)
- ((AgendaAdapter) getAgendaListView().getAdapter()).updateEvents(CalendarManager.getInstance().getEvents());
-
- getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (getWidth() != 0 && getHeight() != 0) {
- // display only two visible rows on the calendar view
- ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
- int height = getHeight();
- int margin = (int) (getContext().getResources().getDimension(R.dimen.calendar_header_height) + 2 * getContext().getResources().getDimension(R.dimen.day_cell_height));
- layoutParams.height = height;
- layoutParams.setMargins(0, margin, 0, 0);
- setLayoutParams(layoutParams);
-
- getAgendaListView().scrollToCurrentDate(CalendarManager.getInstance().getToday());
-
- getViewTreeObserver().removeGlobalOnLayoutListener(this);
- }
- }
- }
-
- );
- } else if (event instanceof Events.ForecastFetched) {
- ((AgendaAdapter) getAgendaListView().getAdapter()).updateEvents(CalendarManager.getInstance().getEvents());
- }
- });
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- int eventaction = event.getAction();
-
- switch (eventaction) {
- case MotionEvent.ACTION_DOWN:
- // if the user touches the listView, we put it back to the top
- translateList(0);
- break;
- default:
- break;
- }
-
- return super.dispatchTouchEvent(event);
- }
-
- // endregion
-
- // region Public methods
-
- public AgendaListView getAgendaListView() {
- return mAgendaListView;
- }
-
- public void translateList(int targetY) {
- if (targetY != getTranslationY()) {
- ObjectAnimator mover = ObjectAnimator.ofFloat(this, "translationY", targetY);
- mover.setDuration(150);
- mover.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- //mShadowView.setVisibility(GONE);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (targetY == 0) {
- BusProvider.getInstance().send(new Events.AgendaListViewTouchedEvent());
- }
- //mShadowView.setVisibility(VISIBLE);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
-
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
- });
- mover.start();
- }
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java
deleted file mode 100644
index 67d7490c..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java
+++ /dev/null
@@ -1,279 +0,0 @@
-package com.github.tibolte.agendacalendarview.calendar;
-
-import com.github.tibolte.agendacalendarview.CalendarManager;
-import com.github.tibolte.agendacalendarview.R;
-import com.github.tibolte.agendacalendarview.calendar.weekslist.WeekListView;
-import com.github.tibolte.agendacalendarview.calendar.weekslist.WeeksAdapter;
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-import com.github.tibolte.agendacalendarview.models.IDayItem;
-import com.github.tibolte.agendacalendarview.models.IWeekItem;
-import com.github.tibolte.agendacalendarview.utils.BusProvider;
-import com.github.tibolte.agendacalendarview.utils.DateHelper;
-import com.github.tibolte.agendacalendarview.utils.Events;
-
-import android.content.Context;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * The calendar view is a freely scrolling view that allows the user to browse between days of the
- * year.
- */
-public class CalendarView extends LinearLayout {
-
- private static final String LOG_TAG = CalendarView.class.getSimpleName();
-
- /**
- * Top of the calendar view layout, the week days list
- */
- private LinearLayout mDayNamesHeader;
- /**
- * Part of the calendar view layout always visible, the weeks list
- */
- private WeekListView mListViewWeeks;
- /**
- * The adapter for the weeks list
- */
- private WeeksAdapter mWeeksAdapter;
- /**
- * The current highlighted day in blue
- */
- private IDayItem mSelectedDay;
- /**
- * The current row displayed at top of the list
- */
- private int mCurrentListPosition;
-
- // region Constructors
-
- public CalendarView(Context context) {
- super(context);
- }
-
- public CalendarView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.view_calendar, this, true);
-
- setOrientation(VERTICAL);
- }
-
- // endregion
-
- public IDayItem getSelectedDay() {
- return mSelectedDay;
- }
-
- public void setSelectedDay(IDayItem mSelectedDay) {
- this.mSelectedDay = mSelectedDay;
- }
-
- public WeekListView getListViewWeeks() {
- return mListViewWeeks;
- }
-
- // region Class - View
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mDayNamesHeader = (LinearLayout) findViewById(R.id.cal_day_names);
- mListViewWeeks = (WeekListView) findViewById(R.id.list_week);
- mListViewWeeks.setLayoutManager(new LinearLayoutManager(getContext()));
- mListViewWeeks.setHasFixedSize(true);
- mListViewWeeks.setItemAnimator(null);
- mListViewWeeks.setSnapEnabled(true);
-
- // display only two visible rows on the calendar view
- getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (getWidth() != 0 && getHeight() != 0) {
- collapseCalendarView();
- getViewTreeObserver().removeGlobalOnLayoutListener(this);
- }
- }
- }
- );
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- BusProvider.getInstance().toObserverable()
- .subscribe(event -> {
- if (event instanceof Events.CalendarScrolledEvent) {
- expandCalendarView();
- } else if (event instanceof Events.AgendaListViewTouchedEvent) {
- collapseCalendarView();
- } else if (event instanceof Events.DayClickedEvent) {
- Events.DayClickedEvent clickedEvent = (Events.DayClickedEvent) event;
- updateSelectedDay(clickedEvent.getCalendar(), clickedEvent.getDay());
- }
- });
- }
-
- // endregion
-
- // region Public methods
-
- public void init(CalendarManager calendarManager, int dayTextColor, int currentDayTextColor, int pastDayTextColor, List eventList) {
- Calendar today = calendarManager.getToday();
- Locale locale = calendarManager.getLocale();
- SimpleDateFormat weekDayFormatter = calendarManager.getWeekdayFormatter();
- List weeks = calendarManager.getWeeks();
-
- setUpHeader(today, weekDayFormatter, locale);
- setUpAdapter(today, weeks, dayTextColor, currentDayTextColor, pastDayTextColor, eventList);
- scrollToDate(today, weeks);
- }
-
- /**
- * Fired when the Agenda list view changes section.
- *
- * @param calendarEvent The event for the selected position in the agenda listview.
- */
- public void scrollToDate(final CalendarEvent calendarEvent) {
- mListViewWeeks.post(()->scrollToPosition(updateSelectedDay(calendarEvent.getInstanceDay(), calendarEvent.getDayReference())));
- }
-
- public void scrollToDate(Calendar today, List weeks) {
- Integer currentWeekIndex = null;
-
- for (int c = 0; c < weeks.size(); c++) {
- if (DateHelper.sameWeek(today, weeks.get(c))) {
- currentWeekIndex = c;
- break;
- }
- }
-
- if (currentWeekIndex != null) {
- final Integer finalCurrentWeekIndex = currentWeekIndex;
- mListViewWeeks.post(() -> scrollToPosition(finalCurrentWeekIndex));
- }
- }
-
- public void setBackgroundColor(int color) {
- mListViewWeeks.setBackgroundColor(color);
- }
-
- // endregion
-
- // region Private methods
-
- private void scrollToPosition(int targetPosition) {
- LinearLayoutManager layoutManager = ((LinearLayoutManager) mListViewWeeks.getLayoutManager());
- layoutManager.scrollToPosition(targetPosition);
- }
-
- private void updateItemAtPosition(int position) {
- WeeksAdapter weeksAdapter = (WeeksAdapter) mListViewWeeks.getAdapter();
- weeksAdapter.notifyItemChanged(position);
- }
-
- /**
- * Creates a new adapter if necessary and sets up its parameters.
- */
- private void setUpAdapter(Calendar today, List weeks, int dayTextColor, int currentDayTextColor, int pastDayTextColor, List events) {
- BusProvider.getInstance().toObserverable()
- .subscribe(event -> {
- if (event instanceof Events.EventsFetched) {
- //Log.d("CalendarView", "events size "+events.size());
- if (mWeeksAdapter == null) {
- //Log.d(LOG_TAG, "Setting adapter with today's calendar: " + today.toString());
- mWeeksAdapter = new WeeksAdapter(getContext(), today, dayTextColor, currentDayTextColor, pastDayTextColor, events);
- mListViewWeeks.setAdapter(mWeeksAdapter);
- }
- mWeeksAdapter.updateWeeksItems(weeks);
- }});
-
- }
-
- private void setUpHeader(Calendar today, SimpleDateFormat weekDayFormatter, Locale locale) {
- int daysPerWeek = 7;
- String[] dayLabels = new String[daysPerWeek];
- Calendar cal = Calendar.getInstance(CalendarManager.getInstance(getContext()).getLocale());
- cal.setTime(today.getTime());
- int firstDayOfWeek = cal.getFirstDayOfWeek();
- for (int count = 0; count < 7; count++) {
- cal.set(Calendar.DAY_OF_WEEK, firstDayOfWeek + count);
- if (locale.getLanguage().equals("en")) {
- dayLabels[count] = weekDayFormatter.format(cal.getTime()).toUpperCase(locale);
- } else {
- dayLabels[count] = weekDayFormatter.format(cal.getTime());
- }
- }
-
- for (int i = 0; i < mDayNamesHeader.getChildCount(); i++) {
- TextView txtDay = (TextView) mDayNamesHeader.getChildAt(i);
- txtDay.setText(dayLabels[i]);
- }
- }
-
- private void expandCalendarView() {
- ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
- layoutParams.height = (int) (getResources().getDimension(R.dimen.calendar_header_height) + 5 * getResources().getDimension(R.dimen.day_cell_height));
- setLayoutParams(layoutParams);
- }
-
- private void collapseCalendarView() {
- ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
- layoutParams.height = (int) (getResources().getDimension(R.dimen.calendar_header_height) + 2 * getResources().getDimension(R.dimen.day_cell_height));
- setLayoutParams(layoutParams);
- }
-
- /**
- * Update a selected cell day item.
- *
- * @param calendar The Calendar instance of the day selected.
- * @param dayItem The DayItem information held by the cell item.
- * @return The selected row of the weeks list, to be updated.
- */
- private int updateSelectedDay(Calendar calendar, IDayItem dayItem) {
- Integer currentWeekIndex = null;
-
- // update highlighted/selected day
- if (!dayItem.equals(getSelectedDay())) {
- dayItem.setSelected(true);
- if (getSelectedDay() != null) {
- getSelectedDay().setSelected(false);
- }
- setSelectedDay(dayItem);
- }
-
- for (int c = 0; c < CalendarManager.getInstance().getWeeks().size(); c++) {
- if (DateHelper.sameWeek(calendar, CalendarManager.getInstance().getWeeks().get(c))) {
- currentWeekIndex = c;
- break;
- }
- }
-
- if (currentWeekIndex != null) {
- // highlighted day has changed, update the rows concerned
- if (currentWeekIndex != mCurrentListPosition) {
- updateItemAtPosition(mCurrentListPosition);
- }
- mCurrentListPosition = currentWeekIndex;
- updateItemAtPosition(currentWeekIndex);
- }
-
- return mCurrentListPosition;
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeekListView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeekListView.java
deleted file mode 100644
index 099bc6eb..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeekListView.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.github.tibolte.agendacalendarview.calendar.weekslist;
-
-import com.github.tibolte.agendacalendarview.utils.BusProvider;
-import com.github.tibolte.agendacalendarview.utils.Events;
-
-import android.content.Context;
-import androidx.recyclerview.widget.RecyclerView;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class WeekListView extends RecyclerView {
- private boolean mUserScrolling = false;
- private boolean mScrolling = false;
-
- // region Constructors
-
- public WeekListView(Context context) {
- super(context);
- }
-
- public WeekListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public WeekListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- // endregion
-
- // region Public methods
-
- /**
- * Enable snapping behaviour for this recyclerView
- *
- * @param enabled enable or disable the snapping behaviour
- */
- public void setSnapEnabled(boolean enabled) {
- if (enabled) {
- addOnScrollListener(mScrollListener);
- } else {
- removeOnScrollListener(mScrollListener);
- }
- }
-
- // endregion
-
- // region Private methods
-
- private OnScrollListener mScrollListener = new OnScrollListener() {
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- super.onScrolled(recyclerView, dx, dy);
- }
-
- @Override
- public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- super.onScrollStateChanged(recyclerView, newState);
- final WeeksAdapter weeksAdapter = (WeeksAdapter) getAdapter();
-
- switch (newState) {
- case SCROLL_STATE_IDLE:
- if (mUserScrolling) {
- scrollToView(getCenterView());
- postDelayed(() -> weeksAdapter.setDragging(false), 700); // Wait for recyclerView to settle
- }
-
- mUserScrolling = false;
- mScrolling = false;
- break;
- // If scroll is caused by a touch (scroll touch, not any touch)
- case SCROLL_STATE_DRAGGING:
- BusProvider.getInstance().send(new Events.CalendarScrolledEvent());
- // If scroll was initiated already, this is not a user scrolling, but probably a tap, else set userScrolling
- if (!mScrolling) {
- mUserScrolling = true;
- }
- weeksAdapter.setDragging(true);
- break;
- case SCROLL_STATE_SETTLING:
- // The user's finger is not touching the list anymore, no need
- // for any alpha animation then
- weeksAdapter.setAlphaSet(true);
- mScrolling = true;
- break;
- }
- }
- };
-
- private View getChildClosestToPosition(int y) {
- if (getChildCount() <= 0) {
- return null;
- }
-
- int itemHeight = getChildAt(0).getMeasuredHeight();
-
- int closestY = 9999;
- View closestChild = null;
-
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
-
- int childCenterY = ((int) child.getY() + (itemHeight / 2));
- int yDistance = childCenterY - y;
-
- // If child center is closer than previous closest, set it as closest
- if (Math.abs(yDistance) < Math.abs(closestY)) {
- closestY = yDistance;
- closestChild = child;
- }
- }
-
- return closestChild;
- }
-
- private View getCenterView() {
- return getChildClosestToPosition(getMeasuredHeight() / 2);
- }
-
- private void scrollToView(View child) {
- if (child == null) {
- return;
- }
-
- stopScroll();
-
- int scrollDistance = getScrollDistance(child);
-
- if (scrollDistance != 0) {
- smoothScrollBy(0, scrollDistance);
- }
- }
-
- private int getScrollDistance(View child) {
- int itemHeight = getChildAt(0).getMeasuredHeight();
- int centerY = getMeasuredHeight() / 2;
-
- int childCenterY = ((int) child.getY() + (itemHeight / 2));
-
- return childCenterY - centerY;
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java
deleted file mode 100644
index df2177df..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java
+++ /dev/null
@@ -1,321 +0,0 @@
-package com.github.tibolte.agendacalendarview.calendar.weekslist;
-
-import com.github.tibolte.agendacalendarview.CalendarManager;
-import com.github.tibolte.agendacalendarview.R;
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-import com.github.tibolte.agendacalendarview.models.IDayItem;
-import com.github.tibolte.agendacalendarview.models.IWeekItem;
-import com.github.tibolte.agendacalendarview.utils.BusProvider;
-import com.github.tibolte.agendacalendarview.utils.DateHelper;
-import com.github.tibolte.agendacalendarview.utils.Events;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Typeface;
-import android.graphics.drawable.GradientDrawable;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-
-public class WeeksAdapter extends RecyclerView.Adapter {
-
- public static final long FADE_DURATION = 250;
-
- private Context mContext;
- private Calendar mToday;
- private List mWeeksList = new ArrayList<>();
- private List mEventList = new ArrayList<>();
- private boolean mDragging;
- private boolean mAlphaSet;
- private int mDayTextColor, mPastDayTextColor, mCurrentDayColor;
-
- // region Constructor
-
- public WeeksAdapter(Context context, Calendar today, int dayTextColor, int currentDayTextColor, int pastDayTextColor, List events) {
- this.mToday = today;
- this.mContext = context;
- this.mDayTextColor = dayTextColor;
- this.mCurrentDayColor = currentDayTextColor;
- this.mPastDayTextColor = pastDayTextColor;
- this.mEventList = events;
- }
-
- // endregion
-
- public void updateWeeksItems(List weekItems) {
- this.mWeeksList.clear();
- this.mWeeksList.addAll(weekItems);
- notifyDataSetChanged();
- }
-
- // region Getters/setters
-
- public List getWeeksList() {
- return mWeeksList;
- }
-
- public boolean isDragging() {
- return mDragging;
- }
-
- public void setDragging(boolean dragging) {
- if (dragging != this.mDragging) {
- this.mDragging = dragging;
- notifyItemRangeChanged(0, mWeeksList.size());
- }
- }
-
- public boolean isAlphaSet() {
- return mAlphaSet;
- }
-
- public void setAlphaSet(boolean alphaSet) {
- mAlphaSet = alphaSet;
- }
-
- // endregion
-
- // region RecyclerView.Adapter methods
-
- @Override
- public WeekViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_week, parent, false);
- return new WeekViewHolder(view);
- }
-
- @Override
- public void onBindViewHolder(WeekViewHolder weekViewHolder, int position) {
- IWeekItem weekItem = mWeeksList.get(position);
- weekViewHolder.bindWeek(weekItem, mToday);
- }
-
- @Override
- public int getItemCount() {
- return mWeeksList.size();
- }
-
- // endregion
-
- // region Class - WeekViewHolder
-
- public class WeekViewHolder extends RecyclerView.ViewHolder {
-
- /**
- * List of layout containers for each day
- */
- private List mCells;
- private TextView mTxtMonth;
- private FrameLayout mMonthBackground;
-
- public WeekViewHolder(View itemView) {
- super(itemView);
- mTxtMonth = (TextView) itemView.findViewById(R.id.month_label);
- mMonthBackground = (FrameLayout) itemView.findViewById(R.id.month_background);
- LinearLayout daysContainer = (LinearLayout) itemView.findViewById(R.id.week_days_container);
- setUpChildren(daysContainer);
- }
-
- public void bindWeek(IWeekItem weekItem, Calendar today) {
- setUpMonthOverlay();
-
- List dayItems = weekItem.getDayItems();
-
- for (int c = 0; c < dayItems.size(); c++) {
- final IDayItem dayItem = dayItems.get(c);
- LinearLayout cellItem = mCells.get(c);
- TextView txtDay = (TextView) cellItem.findViewById(R.id.view_day_day_label);
- TextView txtMonth = (TextView) cellItem.findViewById(R.id.view_day_month_label);
- View circleView = cellItem.findViewById(R.id.view_day_circle_selected);
- View eventIndicator1 = cellItem.findViewById(R.id.view_day_event_indicator1);
- View eventIndicator2 = cellItem.findViewById(R.id.view_day_event_indicator2);
- View eventIndicator3 = cellItem.findViewById(R.id.view_day_event_indicator3);
- cellItem.setOnClickListener(v->BusProvider.getInstance().send(new Events.DayClickedEvent(dayItem)));
-
- eventIndicator1.setVisibility(View.INVISIBLE);
- eventIndicator2.setVisibility(View.INVISIBLE);
- eventIndicator3.setVisibility(View.INVISIBLE);
-
- Calendar dayItemCalendar = Calendar.getInstance();
- dayItemCalendar.setTime(dayItem.getDate());
- int eventCount = 0;
- for (CalendarEvent event: mEventList) {
- if (event.getStartTime().get(Calendar.YEAR) == dayItemCalendar.get(Calendar.YEAR)
- && event.getStartTime().get(Calendar.MONTH) == dayItemCalendar.get(Calendar.MONTH)
- && event.getStartTime().get(Calendar.DAY_OF_MONTH) == dayItemCalendar.get(Calendar.DAY_OF_MONTH)) {
- eventCount++;
- if (eventCount == 1) {
- eventIndicator1.setVisibility(View.VISIBLE);
- eventIndicator1.getBackground().setColorFilter(new PorterDuffColorFilter(event.getColor(),PorterDuff.Mode.MULTIPLY));
- }
- if (eventCount == 2) {
- eventIndicator2.setVisibility(View.VISIBLE);
- eventIndicator2.getBackground().setColorFilter(new PorterDuffColorFilter(event.getColor(),PorterDuff.Mode.MULTIPLY));
- }
- if (eventCount == 3) {
- eventIndicator3.setVisibility(View.VISIBLE);
- eventIndicator3.getBackground().setColorFilter(new PorterDuffColorFilter(event.getColor(),PorterDuff.Mode.MULTIPLY));
- }
- }
- }
-
- //Log.d("CalendarView", "Event count for day "+dayItem.getValue()+" is "+eventCount);
-
- txtMonth.setVisibility(View.GONE);
- txtDay.setTextColor(mDayTextColor);
- txtMonth.setTextColor(mDayTextColor);
- circleView.setVisibility(View.GONE);
-
- txtDay.setTypeface(null, Typeface.NORMAL);
- txtMonth.setTypeface(null, Typeface.NORMAL);
-
- // Display the day
- txtDay.setText(Integer.toString(dayItem.getValue()));
-
- // Highlight first day of the month
- if (dayItem.isFirstDayOfTheMonth() && !dayItem.isSelected()) {
- txtMonth.setVisibility(View.VISIBLE);
- txtMonth.setText(dayItem.getMonth());
- txtDay.setTypeface(null, Typeface.BOLD);
- txtMonth.setTypeface(null, Typeface.BOLD);
- }
-
- // Check if this day is in the past
- if (today.getTime().after(dayItem.getDate()) && !DateHelper.sameDate(today, dayItem.getDate())) {
- txtDay.setTextColor(mPastDayTextColor);
- txtMonth.setTextColor(mPastDayTextColor);
- }
-
- // Highlight the cell if this day is today
- if (dayItem.isToday() && !dayItem.isSelected()) {
- txtDay.setTextColor(mCurrentDayColor);
- }
-
- if (dayItem.getShowBadge()) {
- circleView.setVisibility(View.VISIBLE);
- GradientDrawable drawable = (GradientDrawable) circleView.getBackground();
- drawable.setStroke((int) (2 * Resources.getSystem().getDisplayMetrics().density), 0xffff0000);
- }
-
- // Show a circle if the day is selected
- if (dayItem.isSelected()) {
- txtDay.setTextColor(mDayTextColor);
- circleView.setVisibility(View.VISIBLE);
- GradientDrawable drawable = (GradientDrawable) circleView.getBackground();
- drawable.setStroke((int) (1 * Resources.getSystem().getDisplayMetrics().density), mDayTextColor);
- }
-
- // Check if the month label has to be displayed
- if (dayItem.getValue() == 15) {
- mTxtMonth.setVisibility(View.VISIBLE);
- SimpleDateFormat monthDateFormat = new SimpleDateFormat(mContext.getResources().getString(R.string.month_name_format), CalendarManager.getInstance().getLocale());
- String month = monthDateFormat.format(weekItem.getDate()).toUpperCase();
- if (today.get(Calendar.YEAR) != weekItem.getYear()) {
- month = month + String.format(" %d", weekItem.getYear());
- }
- mTxtMonth.setText(month);
- }
- }
- }
-
- private void setUpChildren(LinearLayout daysContainer) {
- mCells = new ArrayList<>();
- for (int i = 0; i < daysContainer.getChildCount(); i++) {
- mCells.add((LinearLayout) daysContainer.getChildAt(i));
- }
- }
-
- private void setUpMonthOverlay() {
- mTxtMonth.setVisibility(View.GONE);
-
- if (isDragging()) {
- AnimatorSet animatorSetFadeIn = new AnimatorSet();
- animatorSetFadeIn.setDuration(FADE_DURATION);
- ObjectAnimator animatorTxtAlphaIn = ObjectAnimator.ofFloat(mTxtMonth, "alpha", mTxtMonth.getAlpha(), 1f);
- ObjectAnimator animatorBackgroundAlphaIn = ObjectAnimator.ofFloat(mMonthBackground, "alpha", mMonthBackground.getAlpha(), 1f);
- animatorSetFadeIn.playTogether(
- animatorTxtAlphaIn
- //animatorBackgroundAlphaIn
- );
- animatorSetFadeIn.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
-
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- setAlphaSet(true);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
-
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
- });
- animatorSetFadeIn.start();
- } else {
- AnimatorSet animatorSetFadeOut = new AnimatorSet();
- animatorSetFadeOut.setDuration(FADE_DURATION);
- ObjectAnimator animatorTxtAlphaOut = ObjectAnimator.ofFloat(mTxtMonth, "alpha", mTxtMonth.getAlpha(), 0f);
- ObjectAnimator animatorBackgroundAlphaOut = ObjectAnimator.ofFloat(mMonthBackground, "alpha", mMonthBackground.getAlpha(), 0f);
- animatorSetFadeOut.playTogether(
- animatorTxtAlphaOut
- //animatorBackgroundAlphaOut
- );
- animatorSetFadeOut.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
-
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- setAlphaSet(false);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
-
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
- });
- animatorSetFadeOut.start();
- }
-
- if (isAlphaSet()) {
- //mMonthBackground.setAlpha(1f);
- mTxtMonth.setAlpha(1f);
- } else {
- //mMonthBackground.setAlpha(0f);
- mTxtMonth.setAlpha(0f);
- }
- }
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/BaseCalendarEvent.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/BaseCalendarEvent.java
deleted file mode 100644
index 642eea2c..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/BaseCalendarEvent.java
+++ /dev/null
@@ -1,345 +0,0 @@
-package com.github.tibolte.agendacalendarview.models;
-
-import java.util.Calendar;
-
-/**
- * Event model class containing the information to be displayed on the agenda view.
- */
-public class BaseCalendarEvent implements CalendarEvent {
-
- /**
- * Id of the event.
- */
- private long mId;
- /**
- * Color to be displayed in the agenda view.
- */
- private int mColor;
- /**
- * Text color displayed on the background color
- */
- private int mTextColor;
- /**
- * Title of the event.
- */
- private String mTitle;
- /**
- * Description of the event.
- */
- private String mDescription;
- /**
- * Where the event takes place.
- */
- private String mLocation;
- /**
- * Calendar instance helping sorting the events per section in the agenda view.
- */
- private Calendar mInstanceDay;
- /**
- * Start time of the event.
- */
- private Calendar mStartTime;
- /**
- * End time of the event.
- */
- private Calendar mEndTime;
- /**
- * Indicates if the event lasts all day.
- */
- private boolean mAllDay;
- /**
- * Tells if this BaseCalendarEvent instance is used as a placeholder in the agenda view, if there's
- * no event for that day.
- */
- private boolean mPlaceHolder;
- /**
- * Tells if this BaseCalendarEvent instance is used as a forecast information holder in the agenda
- * view.
- */
- private boolean mWeather;
- /**
- * Duration of the event.
- */
- private String mDuration;
- /**
- * References to a DayItem instance for that event, used to link interaction between the
- * calendar view and the agenda view.
- */
- private IDayItem mDayReference;
- /**
- * References to a WeekItem instance for that event, used to link interaction between the
- * calendar view and the agenda view.
- */
- private IWeekItem mWeekReference;
- /**
- * Weather icon string returned by the Dark Sky API.
- */
- private String mWeatherIcon;
- /**
- * Temperature value returned by the Dark Sky API.
- */
- private double mTemperature;
-
- private boolean mShowBadge;
-
- // region Constructor
-
- /**
- * Initializes the event
- *
- * @param id The id of the event.
- * @param color The color of the event.
- * @param textColor The color of the event description text.
- * @param title The title of the event.
- * @param description The description of the event.
- * @param location The location of the event.
- * @param dateStart The start date of the event.
- * @param dateEnd The end date of the event.
- * @param allDay Int that can be equal to 0 or 1.
- * @param duration The duration of the event in RFC2445 format.
- */
- public BaseCalendarEvent(long id, int color, int textColor, String title, String description, String location, long dateStart, long dateEnd, int allDay, String duration) {
- this.mId = id;
- this.mColor = color;
- this.mTextColor = textColor;
- this.mAllDay = (allDay == 1);
- this.mDuration = duration;
- this.mTitle = title;
- this.mDescription = description;
- this.mLocation = location;
-
- this.mStartTime = Calendar.getInstance();
- this.mStartTime.setTimeInMillis(dateStart);
- this.mEndTime = Calendar.getInstance();
- this.mEndTime.setTimeInMillis(dateEnd);
- }
-
- public BaseCalendarEvent() {
-
- }
-
- /**
- * Initializes the event
- * @param title The title of the event.
- * @param description The description of the event.
- * @param location The location of the event.
- * @param color The color of the event (for display in the app).
- * @param textColor The color of the event description text.
- * @param startTime The start time of the event.
- * @param endTime The end time of the event.
- * @param allDay Indicates if the event lasts the whole day.
- */
- public BaseCalendarEvent(String title, String description, String location, int color, int textColor, Calendar startTime, Calendar endTime, boolean allDay) {
- this.mTitle = title;
- this.mDescription = description;
- this.mLocation = location;
- this.mColor = color;
- this.mTextColor = textColor;
- this.mStartTime = startTime;
- this.mEndTime = endTime;
- this.mAllDay = allDay;
- }
-
- public BaseCalendarEvent(String title, String description, String location, int color, int textColor, Calendar startTime, Calendar endTime, boolean allDay, long id, boolean showBadge) {
- this.mTitle = title;
- this.mDescription = description;
- this.mLocation = location;
- this.mColor = color;
- this.mTextColor = textColor;
- this.mStartTime = startTime;
- this.mEndTime = endTime;
- this.mAllDay = allDay;
- this.mId = id;
- this.mShowBadge = showBadge;
- }
-
- public BaseCalendarEvent(BaseCalendarEvent calendarEvent) {
- this.mId = calendarEvent.getId();
- this.mColor = calendarEvent.getColor();
- this.mTextColor = calendarEvent.getTextColor();
- this.mAllDay = calendarEvent.isAllDay();
- this.mDuration = calendarEvent.getDuration();
- this.mTitle = calendarEvent.getTitle();
- this.mDescription = calendarEvent.getDescription();
- this.mLocation = calendarEvent.getLocation();
- this.mStartTime = calendarEvent.getStartTime();
- this.mEndTime = calendarEvent.getEndTime();
- this.mShowBadge = calendarEvent.getShowBadge();
- }
-
- // endregion
-
- // region Getters/Setters
-
- public int getColor() {
- return mColor;
- }
-
- public void setColor(int mColor) {
- this.mColor = mColor;
- }
-
- public int getTextColor() {
- return mTextColor;
- }
-
- public void setTextColor(int mTextColor) {
- this.mTextColor = mTextColor;
- }
-
- public String getDescription() {
- return mDescription;
- }
-
- public boolean isAllDay() {
- return mAllDay;
- }
-
- public void setAllDay(boolean allDay) {
- this.mAllDay = allDay;
- }
-
- public void setDescription(String mDescription) {
- this.mDescription = mDescription;
- }
-
- public Calendar getInstanceDay() {
- return mInstanceDay;
- }
-
- public void setInstanceDay(Calendar mInstanceDay) {
- this.mInstanceDay = mInstanceDay;
- this.mInstanceDay.set(Calendar.HOUR, 0);
- this.mInstanceDay.set(Calendar.MINUTE, 0);
- this.mInstanceDay.set(Calendar.SECOND, 0);
- this.mInstanceDay.set(Calendar.MILLISECOND, 0);
- this.mInstanceDay.set(Calendar.AM_PM, 0);
- }
-
- public Calendar getEndTime() {
- return mEndTime;
- }
-
- public void setEndTime(Calendar mEndTime) {
- this.mEndTime = mEndTime;
- }
- public void setPlaceholder(boolean placeholder) {
- mPlaceHolder = placeholder;
- }
- public boolean isPlaceholder() {
- return mPlaceHolder;
- }
-
- public long getId() {
- return mId;
- }
-
- public void setId(long mId) {
- this.mId = mId;
- }
-
- public boolean getShowBadge() {
- return mShowBadge;
- }
-
- public void setShowBadge(boolean mShowBadge) {
- this.mShowBadge = mShowBadge;
- }
-
- public String getLocation() {
- return mLocation;
- }
-
- public void setLocation(String mLocation) {
- this.mLocation = mLocation;
- }
-
- public Calendar getStartTime() {
- return mStartTime;
- }
-
- public void setStartTime(Calendar mStartTime) {
- this.mStartTime = mStartTime;
- }
-
- public String getTitle() {
- return mTitle;
- }
-
- public void setTitle(String mTitle) {
- this.mTitle = mTitle;
- }
-
- public String getDuration() {
- return mDuration;
- }
-
- public void setDuration(String duration) {
- this.mDuration = duration;
- }
-
- public boolean isPlaceHolder() {
- return mPlaceHolder;
- }
-
- public void setPlaceHolder(boolean mPlaceHolder) {
- this.mPlaceHolder = mPlaceHolder;
- }
-
- public boolean isWeather() {
- return mWeather;
- }
-
- public void setWeather(boolean mWeather) {
- this.mWeather = mWeather;
- }
-
- public IDayItem getDayReference() {
- return mDayReference;
- }
-
- public void setDayReference(IDayItem mDayReference) {
- this.mDayReference = mDayReference;
- }
-
- public IWeekItem getWeekReference() {
- return mWeekReference;
- }
-
- public void setWeekReference(IWeekItem mWeekReference) {
- this.mWeekReference = mWeekReference;
- }
-
- public String getWeatherIcon() {
- return mWeatherIcon;
- }
-
- public void setWeatherIcon(String mWeatherIcon) {
- this.mWeatherIcon = mWeatherIcon;
- }
-
- public double getTemperature() {
- return mTemperature;
- }
-
- public void setTemperature(double mTemperature) {
- this.mTemperature = mTemperature;
- }
-
- @Override
- public CalendarEvent copy() {
- return new BaseCalendarEvent(this);
- }
-
- // endregion
-
- @Override
- public String toString() {
- return "BaseCalendarEvent{"
- + "title='"
- + mTitle
- + ", instanceDay= "
- + mInstanceDay.getTime()
- + "}";
- }
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/CalendarEvent.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/CalendarEvent.java
deleted file mode 100644
index 05df9a0f..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/CalendarEvent.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.github.tibolte.agendacalendarview.models;
-
-import java.util.Calendar;
-
-public interface CalendarEvent {
-
-
- void setPlaceholder(boolean placeholder);
-
- boolean isPlaceholder();
-
- public String getLocation();
-
- public void setLocation(String mLocation);
-
- long getId();
-
- void setId(long mId);
-
- boolean getShowBadge();
-
- void setShowBadge(boolean mShowBadge);
-
- int getTextColor();
-
- void setTextColor(int mTextColor);
-
- String getDescription();
-
- void setDescription(String mDescription);
-
- boolean isAllDay();
-
- void setAllDay(boolean allDay);
-
- Calendar getStartTime();
-
- void setStartTime(Calendar mStartTime);
-
- Calendar getEndTime();
-
- void setEndTime(Calendar mEndTime);
-
- String getTitle();
-
- void setTitle(String mTitle);
-
- Calendar getInstanceDay();
-
- void setInstanceDay(Calendar mInstanceDay);
-
- IDayItem getDayReference();
-
- void setDayReference(IDayItem mDayReference);
-
- IWeekItem getWeekReference();
-
- void setWeekReference(IWeekItem mWeekReference);
-
- CalendarEvent copy();
-
- int getColor();
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/DayItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/DayItem.java
deleted file mode 100644
index 39be4985..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/DayItem.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.github.tibolte.agendacalendarview.models;
-
-import com.github.tibolte.agendacalendarview.CalendarManager;
-import com.github.tibolte.agendacalendarview.utils.DateHelper;
-
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * Day model class.
- */
-public class DayItem implements IDayItem {
- private Date mDate;
- private int mValue;
- private int mDayOfTheWeek;
- private boolean mToday;
- private boolean mFirstDayOfTheMonth;
- private boolean mSelected;
- private String mMonth;
- private boolean mShowBadge;
-
- // region Constructor
-
- public DayItem(Date date, int value, boolean today, String month) {
- this.mDate = date;
- this.mValue = value;
- this.mToday = today;
- this.mMonth = month;
- }
- // only for cleanDay
- public DayItem() {
-
- }
- public DayItem(DayItem original) {
-
- this.mDate = original.getDate();
- this.mValue = original.getValue();
- this.mToday = original.isToday();
- this.mDayOfTheWeek = original.getDayOftheWeek();
- this.mFirstDayOfTheMonth = original.isFirstDayOfTheMonth();
- this.mSelected = original.isSelected();
- this.mMonth = original.getMonth();
- this.mShowBadge = original.mShowBadge;
- }
- // endregion
-
- // region Getters/Setters
-
- public Date getDate() {
- return mDate;
- }
-
- public void setDate(Date date) {
- this.mDate = date;
- }
-
- public int getValue() {
- return mValue;
- }
-
- public void setValue(int value) {
- this.mValue = value;
- }
-
- public boolean isToday() {
- return mToday;
- }
-
- public void setToday(boolean today) {
- this.mToday = today;
- }
-
- public boolean isSelected() {
- return mSelected;
- }
-
- public void setSelected(boolean selected) {
- this.mSelected = selected;
- }
-
- public boolean isFirstDayOfTheMonth() {
- return mFirstDayOfTheMonth;
- }
-
- public void setFirstDayOfTheMonth(boolean firstDayOfTheMonth) {
- this.mFirstDayOfTheMonth = firstDayOfTheMonth;
- }
-
- public String getMonth() {
- return mMonth;
- }
-
- public void setMonth(String month) {
- this.mMonth = month;
- }
-
- public int getDayOftheWeek() {
- return mDayOfTheWeek;
- }
-
- public void setDayOftheWeek(int mDayOftheWeek) {
- this.mDayOfTheWeek = mDayOftheWeek;
- }
-
- public void setShowBadge(boolean showBadge) {
- this.mShowBadge = showBadge;
- }
-
- public boolean getShowBadge() {
- return this.mShowBadge;
- }
-
- // region Public methods
-
- public void buildDayItemFromCal(Calendar calendar) {
- Date date = calendar.getTime();
- this.mDate = date;
-
- this.mValue = calendar.get(Calendar.DAY_OF_MONTH);
- this.mToday = DateHelper.sameDate(calendar, CalendarManager.getInstance().getToday());
- this.mMonth = CalendarManager.getInstance().getMonthHalfNameFormat().format(date);
- if (this.mValue == 1) {
- this.mFirstDayOfTheMonth = true;
- }
- }
-
- // endregion
-
- @Override
- public String toString() {
- return "DayItem{"
- + "Date='"
- + mDate.toString()
- + ", value="
- + mValue
- + '}';
- }
-
- @Override
- public IDayItem copy() {
- return new DayItem(this);
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IDayItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IDayItem.java
deleted file mode 100644
index acfe3c76..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IDayItem.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.github.tibolte.agendacalendarview.models;
-
-import java.util.Calendar;
-import java.util.Date;
-
-public interface IDayItem {
-
- // region Getters/Setters
-
- Date getDate();
-
- void setDate(Date date);
-
- int getValue();
-
- void setValue(int value);
-
- boolean isToday();
-
- void setToday(boolean today);
-
- boolean isSelected();
-
- void setSelected(boolean selected);
-
- boolean isFirstDayOfTheMonth();
-
- void setFirstDayOfTheMonth(boolean firstDayOfTheMonth);
-
- String getMonth();
-
- void setMonth(String month);
-
- int getDayOftheWeek();
-
- void setDayOftheWeek(int mDayOftheWeek);
-
- // endregion
-
- void buildDayItemFromCal(Calendar calendar);
-
- String toString();
-
- IDayItem copy();
-
- void setShowBadge(boolean showBadge);
-
- boolean getShowBadge();
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IWeekItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IWeekItem.java
deleted file mode 100644
index bb08b89a..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/IWeekItem.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.github.tibolte.agendacalendarview.models;
-
-import java.util.Date;
-import java.util.List;
-
-public interface IWeekItem {
-
-
- int getWeekInYear();
-
- void setWeekInYear(int weekInYear);
-
- int getYear();
-
- void setYear(int year);
-
- int getMonth();
-
- void setMonth(int month);
-
- Date getDate();
-
- void setDate(Date date);
-
- String getLabel();
-
- void setLabel(String label);
-
- List getDayItems();
-
- void setDayItems(List dayItems);
-
- IWeekItem copy();
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/WeekItem.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/WeekItem.java
deleted file mode 100644
index 40b94902..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/models/WeekItem.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.github.tibolte.agendacalendarview.models;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * Week model class.
- */
-public class WeekItem implements IWeekItem {
- private int mWeekInYear;
- private int mYear;
- private int mMonth;
- private Date mDate;
- private String mLabel;
- private List mDayItems;
-
- // region Constructor
-
- public WeekItem(int weekInYear, int year, Date date, String label, int month) {
- this.mWeekInYear = weekInYear;
- this.mYear = year;
- this.mDate = date;
- this.mLabel = label;
- this.mMonth = month;
- }
- public WeekItem(WeekItem original) {
- this.mWeekInYear = original.getWeekInYear();
- this.mYear = original.getYear();
- this.mMonth = original.getMonth();
- this.mDate = original.getDate();
- this.mLabel = original.getLabel();
- this.mDayItems = original.getDayItems();
- }
-
- public WeekItem(){
-
- }
-
- // endregion
-
- // region Getters/Setters
-
- public int getWeekInYear() {
- return mWeekInYear;
- }
-
- public void setWeekInYear(int weekInYear) {
- this.mWeekInYear = weekInYear;
- }
-
- public int getYear() {
- return mYear;
- }
-
- public void setYear(int year) {
- this.mYear = year;
- }
-
- public int getMonth() {
- return mMonth;
- }
-
- public void setMonth(int month) {
- this.mMonth = month;
- }
-
- public Date getDate() {
- return mDate;
- }
-
- public void setDate(Date date) {
- this.mDate = date;
- }
-
- public String getLabel() {
- return mLabel;
- }
-
- public void setLabel(String label) {
- this.mLabel = label;
- }
-
- public List getDayItems() {
- return mDayItems;
- }
-
- public void setDayItems(List dayItems) {
- this.mDayItems = dayItems;
- }
-
- @Override
- public IWeekItem copy() {
- return new WeekItem(this);
- }
-
- // endregion
-
- @Override
- public String toString() {
- return "WeekItem{"
- + "label='"
- + mLabel
- + '\''
- + ", weekInYear="
- + mWeekInYear
- + ", year="
- + mYear
- + '}';
- }
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/DefaultEventRenderer.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/DefaultEventRenderer.java
deleted file mode 100644
index 729ad706..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/DefaultEventRenderer.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.github.tibolte.agendacalendarview.render;
-
-import android.content.Context;
-import android.content.res.Resources;
-import androidx.annotation.NonNull;
-import androidx.cardview.widget.CardView;
-import androidx.core.content.ContextCompat;
-
-import android.graphics.Color;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.github.tibolte.agendacalendarview.R;
-import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent;
-import com.google.android.material.internal.ViewUtils;
-
-/**
- * Class helping to inflate our default layout in the AgendaAdapter
- */
-public class DefaultEventRenderer extends EventRenderer {
-
- public static int themeAttributeToColor(int themeAttributeId,
- Context context,
- int fallbackColorId) {
- TypedValue outValue = new TypedValue();
- Resources.Theme theme = context.getTheme();
- boolean wasResolved =
- theme.resolveAttribute(
- themeAttributeId, outValue, true);
- if (wasResolved) {
- return ContextCompat.getColor(
- context, outValue.resourceId);
- } else {
- // fallback colour handling
- return fallbackColorId;
- }
- }
-
- // region class - EventRenderer
-
- @Override
- public void render(@NonNull View view, @NonNull BaseCalendarEvent event) {
- CardView card = view.findViewById(R.id.view_agenda_event_card_view);
- TextView txtTitle = view.findViewById(R.id.view_agenda_event_title);
- TextView txtLocation = view.findViewById(R.id.view_agenda_event_location);
- LinearLayout descriptionContainer = view.findViewById(R.id.view_agenda_event_description_container);
- LinearLayout locationContainer = view.findViewById(R.id.view_agenda_event_location_container);
-
- descriptionContainer.setVisibility(View.VISIBLE);
-
- txtTitle.setText(event.getTitle());
- txtLocation.setText(event.getLocation());
- if (event.getLocation().length() > 0) {
- locationContainer.setVisibility(View.VISIBLE);
- txtLocation.setText(event.getLocation());
- } else {
- locationContainer.setVisibility(View.GONE);
- }
-
- if (!event.isPlaceholder()/*!event.getTitle().equals(view.getResources().getString(R.string.agenda_event_no_events))*/) {
- txtTitle.setTextColor(event.getTextColor());
- card.setCardBackgroundColor(event.getColor());
- txtLocation.setTextColor(event.getTextColor());
- }
- else {
- card.setCardBackgroundColor(Color.TRANSPARENT);
- card.setCardElevation(0);
- card.setBackgroundColor(Color.TRANSPARENT);
- card.setRadius(0);
- card.setBackgroundDrawable(null);
- }
- }
-
- @Override
- public int getEventLayout() {
- return R.layout.view_agenda_event;
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/EventRenderer.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/EventRenderer.java
deleted file mode 100644
index e62f23b5..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/render/EventRenderer.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.github.tibolte.agendacalendarview.render;
-
-import androidx.annotation.LayoutRes;
-import android.view.View;
-
-import com.github.tibolte.agendacalendarview.models.CalendarEvent;
-
-import java.lang.reflect.ParameterizedType;
-
-/**
- * Base class for helping layout rendering
- */
-public abstract class EventRenderer {
- public abstract void render(final View view, final T event);
-
- @LayoutRes
- public abstract int getEventLayout();
-
- public Class getRenderType() {
- ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
- return (Class) type.getActualTypeArguments()[0];
- }
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/BusProvider.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/BusProvider.java
deleted file mode 100644
index 99bdbf3d..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/BusProvider.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.github.tibolte.agendacalendarview.utils;
-
-import rx.Observable;
-import rx.subjects.PublishSubject;
-import rx.subjects.SerializedSubject;
-import rx.subjects.Subject;
-
-public class BusProvider {
-
- public static BusProvider mInstance;
-
- private final Subject mBus = new SerializedSubject<>(PublishSubject.create());
-
- // region Constructors
-
- public static BusProvider getInstance() {
- if (mInstance == null) {
- mInstance = new BusProvider();
- }
- return mInstance;
- }
-
- // endregion
-
- // region Public methods
-
- public void send(Object object) {
- mBus.onNext(object);
- }
-
- public Observable toObserverable() {
- return mBus;
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/DateHelper.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/DateHelper.java
deleted file mode 100644
index f9439d04..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/DateHelper.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.github.tibolte.agendacalendarview.utils;
-
-import com.github.tibolte.agendacalendarview.CalendarManager;
-import com.github.tibolte.agendacalendarview.R;
-import com.github.tibolte.agendacalendarview.models.IWeekItem;
-
-import android.content.Context;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Class containing helper functions for dates
- */
-public class DateHelper {
-
- // region Public methods
-
- /**
- * Check if two Calendar instances have the same time (by month, year and day of month)
- *
- * @param cal The first Calendar instance.
- * @param selectedDate The second Calendar instance.
- * @return True if both instances have the same time.
- */
- public static boolean sameDate(Calendar cal, Calendar selectedDate) {
- return cal.get(Calendar.MONTH) == selectedDate.get(Calendar.MONTH)
- && cal.get(Calendar.YEAR) == selectedDate.get(Calendar.YEAR)
- && cal.get(Calendar.DAY_OF_MONTH) == selectedDate.get(Calendar.DAY_OF_MONTH);
- }
-
- /**
- * Check if a Date instance and a Calendar instance have the same time (by month, year and day
- * of month)
- *
- * @param cal The Calendar instance.
- * @param selectedDate The Date instance.
- * @return True if both have the same time.
- */
- public static boolean sameDate(Calendar cal, Date selectedDate) {
- Calendar selectedCal = Calendar.getInstance();
- selectedCal.setTime(selectedDate);
- return cal.get(Calendar.MONTH) == selectedCal.get(Calendar.MONTH)
- && cal.get(Calendar.YEAR) == selectedCal.get(Calendar.YEAR)
- && cal.get(Calendar.DAY_OF_MONTH) == selectedCal.get(Calendar.DAY_OF_MONTH);
- }
-
- /**
- * Check if a Date instance is between two Calendar instances' dates (inclusively) in time.
- *
- * @param selectedDate The date to verify.
- * @param startCal The start time.
- * @param endCal The end time.
- * @return True if the verified date is between the two specified dates.
- */
- public static boolean isBetweenInclusive(Date selectedDate, Calendar startCal, Calendar endCal) {
- Calendar selectedCal = Calendar.getInstance();
- selectedCal.setTime(selectedDate);
- // Check if we deal with the same day regarding startCal and endCal
- return sameDate(selectedCal, startCal) || selectedCal.after(startCal) && selectedCal.before(endCal);
- }
-
- /**
- * Check if Calendar instance's date is in the same week, as the WeekItem instance.
- *
- * @param cal The Calendar instance to verify.
- * @param week The WeekItem instance to compare to.
- * @return True if both instances are in the same week.
- */
- public static boolean sameWeek(Calendar cal, IWeekItem week) {
- return (cal.get(Calendar.WEEK_OF_YEAR) == week.getWeekInYear() && cal.get(Calendar.YEAR) == week.getYear());
- }
-
- /**
- * Convert a millisecond duration to a string format
- *
- * @param millis A duration to convert to a string form
- * @return A string of the form "Xd" or either "XhXm".
- */
- public static String getDuration(Context context, long millis) {
- if (millis < 0) {
- throw new IllegalArgumentException("Duration must be greater than zero!");
- }
-
- long days = TimeUnit.MILLISECONDS.toDays(millis);
- millis -= TimeUnit.DAYS.toMillis(days);
- long hours = TimeUnit.MILLISECONDS.toHours(millis);
- millis -= TimeUnit.HOURS.toMillis(hours);
- long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
-
- StringBuilder sb = new StringBuilder(64);
- if (days > 0) {
- sb.append(days);
- sb.append(context.getResources().getString(R.string.agenda_event_day_duration));
- return (sb.toString());
- } else {
- if (hours > 0) {
- sb.append(hours);
- sb.append("h");
- }
- if (minutes > 0) {
- sb.append(minutes);
- sb.append("m");
- }
- }
-
- return (sb.toString());
- }
-
- /**
- * Used for displaying the date in any section of the agenda view.
- *
- * @param calendar The date of the section.
- * @param locale The locale used by the Sunrise calendar.
- * @return The formatted date without the year included.
- */
- public static String getYearLessLocalizedDate(Calendar calendar, Locale locale) {
- SimpleDateFormat sdf = (SimpleDateFormat) SimpleDateFormat.getDateInstance(DateFormat.FULL, CalendarManager.getInstance().getLocale());
- String pattern = sdf.toPattern();
-
- String yearLessPattern = pattern.replaceAll("\\W?[Yy]+\\W?", "");
- SimpleDateFormat yearLessSDF = new SimpleDateFormat(yearLessPattern, locale);
- String yearLessDate = yearLessSDF.format(calendar.getTime()).toUpperCase();
- if (yearLessDate.endsWith(",")) {
- yearLessDate = yearLessDate.substring(0, yearLessDate.length() - 1);
- }
- return yearLessDate;
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/Events.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/Events.java
deleted file mode 100644
index 98d13f20..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/Events.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.github.tibolte.agendacalendarview.utils;
-
-import com.github.tibolte.agendacalendarview.models.IDayItem;
-
-import java.util.Calendar;
-
-/**
- * Events emitted by the bus provider.
- */
-public class Events {
-
- public static class DayClickedEvent {
-
- public Calendar mCalendar;
- public IDayItem mDayItem;
-
- public DayClickedEvent(IDayItem dayItem) {
- this.mCalendar = Calendar.getInstance();
- this.mCalendar.setTime(dayItem.getDate());
- this.mDayItem = dayItem;
- }
-
- public Calendar getCalendar() {
- return mCalendar;
- }
-
- public IDayItem getDay() {
- return mDayItem;
- }
- }
-
- public static class CalendarScrolledEvent {
- }
-
- public static class AgendaListViewTouchedEvent {
- }
-
- public static class EventsFetched {
- }
-
- public static class ForecastFetched {
- }
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/ListViewScrollTracker.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/ListViewScrollTracker.java
deleted file mode 100644
index 47e16de3..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/utils/ListViewScrollTracker.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.github.tibolte.agendacalendarview.utils;
-
-import com.github.tibolte.agendacalendarview.agenda.AgendaListView;
-
-import android.util.SparseArray;
-import android.view.View;
-
-/**
- * Helper class calculating the scrolling distance in the AgendaListView.
- */
-public class ListViewScrollTracker {
- private AgendaListView mListView;
- private SparseArray mPositions;
- private SparseArray mListViewItemHeights = new SparseArray<>();
- private int mFirstVisiblePosition;
- private int mReferencePosition = -1; // Position of the current date in the Agenda listView
-
- // region Constructor and Accessor(s)
-
- public ListViewScrollTracker(AgendaListView listView) {
- mListView = listView;
- }
-
- public int getReferencePosition() {
- return mReferencePosition;
- }
-
- // endregion
-
- // region Public methods
-
- /**
- * Call from an AbsListView.OnScrollListener to calculate the incremental offset (change in
- * scroll offset
- * since the last calculation).
- *
- * @param firstVisiblePosition First visible item position in the list.
- * @param visibleItemCount Number of visible items in the list.
- * @return The incremental offset, or 0 if it wasn't possible to calculate the offset.
- */
- public int calculateIncrementalOffset(int firstVisiblePosition, int visibleItemCount) {
- // Remember previous positions, if any
- SparseArray previousPositions = mPositions;
-
- // Store new positions
- mPositions = new SparseArray<>();
- for (int i = 0; i < visibleItemCount; i++) {
- mPositions.put(firstVisiblePosition + i, mListView.getListChildAt(i).getTop());
- }
-
- if (previousPositions != null) {
- // Find position which exists in both mPositions and previousPositions, then return the difference
- // of the new and old Y values.
- for (int i = 0; i < previousPositions.size(); i++) {
- int previousPosition = previousPositions.keyAt(i);
- int previousTop = previousPositions.get(previousPosition);
- Integer newTop = mPositions.get(previousPosition);
- if (newTop != null) {
- return newTop - previousTop;
- }
- }
- }
-
- return 0; // No view's position was in both previousPositions and mPositions
- }
-
- /**
- * Call from an AbsListView.OnScrollListener to calculate the scrollY (Here
- * we definite as the distance in pixels compared to the position representing the current
- * date).
- *
- * @param firstVisiblePosition First visible item position in the list.
- * @param visibleItemCount Number of visible items in the list.
- * @return Distance in pixels compared to current day position (negative if firstVisiblePosition less than mReferencePosition)
- */
- public int calculateScrollY(int firstVisiblePosition, int visibleItemCount) {
- mFirstVisiblePosition = firstVisiblePosition;
- if (mReferencePosition < 0) {
- mReferencePosition = mFirstVisiblePosition;
- }
-
- if (visibleItemCount > 0) {
- View c = mListView.getListChildAt(0); // this is the first visible row
- int scrollY = -c.getTop();
- mListViewItemHeights.put(firstVisiblePosition, c.getMeasuredHeight());
-
- if (mFirstVisiblePosition >= mReferencePosition) {
- for (int i = mReferencePosition; i < firstVisiblePosition; ++i) {
- if (mListViewItemHeights.get(i) == null) {
- mListViewItemHeights.put(i, c.getMeasuredHeight());
- }
- scrollY += mListViewItemHeights.get(i); // add all heights of the views that are gone
- }
- return scrollY;
- } else {
- for (int i = mReferencePosition - 1; i >= firstVisiblePosition; --i) {
- if (mListViewItemHeights.get(i) == null) {
- mListViewItemHeights.put(i, c.getMeasuredHeight());
- }
- scrollY -= mListViewItemHeights.get(i);
- }
- return scrollY;
- }
-
- }
- return 0;
- }
-
- public void clear() {
- mPositions = null;
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/widgets/FloatingActionButton.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/widgets/FloatingActionButton.java
deleted file mode 100644
index bd008910..00000000
--- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/widgets/FloatingActionButton.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.github.tibolte.agendacalendarview.widgets;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.Interpolator;
-
-/**
- * Floating action button helping to scroll back to the current date.
- */
-public class FloatingActionButton extends com.google.android.material.floatingactionbutton.FloatingActionButton {
- private static final int TRANSLATE_DURATION_MILLIS = 200;
-
- private boolean mVisible = true;
-
- private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
-
- // region Constructors
-
- public FloatingActionButton(Context context) {
- super(context);
- }
-
- public FloatingActionButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- // endregion
-
- // region Overrides
-
- @Override
- public void show() {
- show(true);
- }
-
- @Override
- public void hide() {
- hide(true);
- }
-
- // endregion
-
- // region Public methods
-
- public void show(boolean animate) {
- toggle(true, animate, false);
- }
-
- public void hide(boolean animate) {
- toggle(false, animate, false);
- }
-
- public boolean isVisible() {
- return mVisible;
- }
-
- // endregion
-
- // region Private methods
-
- private void toggle(final boolean visible, final boolean animate, boolean force) {
- if (mVisible != visible || force) {
- mVisible = visible;
- int height = getHeight();
- if (height == 0 && !force) {
- ViewTreeObserver vto = getViewTreeObserver();
- if (vto.isAlive()) {
- vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- ViewTreeObserver currentVto = getViewTreeObserver();
- if (currentVto.isAlive()) {
- currentVto.removeOnPreDrawListener(this);
- }
- toggle(visible, animate, true);
- return true;
- }
- });
- return;
- }
- }
- int translationY = visible ? 0 : height + getMarginBottom();
- if (animate) {
- animate().setInterpolator(mInterpolator)
- .setDuration(TRANSLATE_DURATION_MILLIS)
- .translationY(translationY);
- } else {
- setTranslationY(translationY);
- }
- }
- }
-
- private int getMarginBottom() {
- int marginBottom = 0;
- final ViewGroup.LayoutParams layoutParams = getLayoutParams();
- if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
- marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;
- }
- return marginBottom;
- }
-
- // endregion
-}
diff --git a/agendacalendarview/src/main/res/drawable/agenda_day_circle.xml b/agendacalendarview/src/main/res/drawable/agenda_day_circle.xml
deleted file mode 100644
index e1398e00..00000000
--- a/agendacalendarview/src/main/res/drawable/agenda_day_circle.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/drawable/event_color_circle.xml b/agendacalendarview/src/main/res/drawable/event_color_circle.xml
deleted file mode 100644
index 3cc72359..00000000
--- a/agendacalendarview/src/main/res/drawable/event_color_circle.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/drawable/fab_arrow.xml b/agendacalendarview/src/main/res/drawable/fab_arrow.xml
deleted file mode 100644
index 3b4d3a8c..00000000
--- a/agendacalendarview/src/main/res/drawable/fab_arrow.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/drawable/selected_day_color_circle.xml b/agendacalendarview/src/main/res/drawable/selected_day_color_circle.xml
deleted file mode 100644
index 3d53cf8c..00000000
--- a/agendacalendarview/src/main/res/drawable/selected_day_color_circle.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/drawable/shadow.xml b/agendacalendarview/src/main/res/drawable/shadow.xml
deleted file mode 100644
index 7ab76207..00000000
--- a/agendacalendarview/src/main/res/drawable/shadow.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/list_item_week.xml b/agendacalendarview/src/main/res/layout/list_item_week.xml
deleted file mode 100644
index 846ba637..00000000
--- a/agendacalendarview/src/main/res/layout/list_item_week.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/view_agenda.xml b/agendacalendarview/src/main/res/layout/view_agenda.xml
deleted file mode 100644
index 5f4a704e..00000000
--- a/agendacalendarview/src/main/res/layout/view_agenda.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/view_agenda_event.xml b/agendacalendarview/src/main/res/layout/view_agenda_event.xml
deleted file mode 100644
index 92329386..00000000
--- a/agendacalendarview/src/main/res/layout/view_agenda_event.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/view_agenda_header.xml b/agendacalendarview/src/main/res/layout/view_agenda_header.xml
deleted file mode 100644
index e0391dd5..00000000
--- a/agendacalendarview/src/main/res/layout/view_agenda_header.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/view_agendacalendar.xml b/agendacalendarview/src/main/res/layout/view_agendacalendar.xml
deleted file mode 100644
index e2df4255..00000000
--- a/agendacalendarview/src/main/res/layout/view_agendacalendar.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/view_calendar.xml b/agendacalendarview/src/main/res/layout/view_calendar.xml
deleted file mode 100644
index 4b3839e0..00000000
--- a/agendacalendarview/src/main/res/layout/view_calendar.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/view_day_calendar_header.xml b/agendacalendarview/src/main/res/layout/view_day_calendar_header.xml
deleted file mode 100644
index 2326af49..00000000
--- a/agendacalendarview/src/main/res/layout/view_day_calendar_header.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/layout/view_day_cell.xml b/agendacalendarview/src/main/res/layout/view_day_cell.xml
deleted file mode 100644
index cebb97db..00000000
--- a/agendacalendarview/src/main/res/layout/view_day_cell.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/values-en/strings.xml b/agendacalendarview/src/main/res/values-en/strings.xml
deleted file mode 100644
index 1d9b1040..00000000
--- a/agendacalendarview/src/main/res/values-en/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- Today
- Tomorrow
- d
- All day
- No events
-
-
- LLLL
- MMM
-
diff --git a/agendacalendarview/src/main/res/values/attrs.xml b/agendacalendarview/src/main/res/values/attrs.xml
deleted file mode 100644
index 6750df84..00000000
--- a/agendacalendarview/src/main/res/values/attrs.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/agendacalendarview/src/main/res/values/colors.xml b/agendacalendarview/src/main/res/values/colors.xml
deleted file mode 100644
index 7904509d..00000000
--- a/agendacalendarview/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- #000000
- #9C9CA0
- #CCFFFFFF
- #F3F3F3
-
-
-
- #00000000
-
-
- #2196F3
- #1976D2
- #2196F3
- #BBDEFB
- #4caf50
- #FFFFFF
-
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/values/dimens.xml b/agendacalendarview/src/main/res/values/dimens.xml
deleted file mode 100644
index 7b639f8d..00000000
--- a/agendacalendarview/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
- 20dp
- 52dp
- 14dp
- 32dp
-
-
- 60dp
-
-
-
-
- 70dp
- 5dp
- 15dp
- 5dp
-
\ No newline at end of file
diff --git a/agendacalendarview/src/main/res/values/strings.xml b/agendacalendarview/src/main/res/values/strings.xml
deleted file mode 100644
index 7c2c5f8a..00000000
--- a/agendacalendarview/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
- LLLL
- E
-
-
- Dziś
- Jutro
- d
- Cały dzień
- Brak wydarzeń
-
- MMM
-
diff --git a/agendacalendarview/src/main/res/values/styles.xml b/agendacalendarview/src/main/res/values/styles.xml
deleted file mode 100644
index b4bf4679..00000000
--- a/agendacalendarview/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/annotation/.gitignore b/annotation/.gitignore
deleted file mode 100644
index 796b96d1..00000000
--- a/annotation/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/annotation/build.gradle b/annotation/build.gradle
deleted file mode 100644
index ee7f6d51..00000000
--- a/annotation/build.gradle
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-3-28.
- */
-
-apply plugin: 'java-library'
-apply plugin: 'kotlin'
-apply plugin: 'kotlin-kapt'
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-}
-
-sourceCompatibility = "7"
-targetCompatibility = "7"
-
-repositories {
- mavenCentral()
-}
-compileKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
- }
-}
-compileTestKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
- }
-}
diff --git a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/SelectiveDao.kt b/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/SelectiveDao.kt
deleted file mode 100644
index d37e5b0a..00000000
--- a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/SelectiveDao.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-3-28.
- */
-
-package pl.szczodrzynski.edziennik.annotation
-
-import kotlin.reflect.KClass
-
-@Target(AnnotationTarget.CLASS)
-@Retention(AnnotationRetention.SOURCE)
-@MustBeDocumented
-annotation class SelectiveDao(
- val db: KClass<*>
-)
diff --git a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/UpdateSelective.kt b/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/UpdateSelective.kt
deleted file mode 100644
index 224fca1c..00000000
--- a/annotation/src/main/java/pl/szczodrzynski/edziennik/annotation/UpdateSelective.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-3-28.
- */
-
-package pl.szczodrzynski.edziennik.annotation
-
-@Target(AnnotationTarget.FUNCTION)
-@Retention(AnnotationRetention.SOURCE)
-@MustBeDocumented
-annotation class UpdateSelective(
- val primaryKeys: Array,
- val skippedColumns: Array = []
-)
diff --git a/app/build.gradle b/app/build.gradle
index 880d6f0f..7d22ea41 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,21 +1,27 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
-apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
+apply from: 'git-info.gradle'
+
android {
- signingConfigs {
- }
compileSdkVersion setup.compileSdk
+
defaultConfig {
applicationId 'pl.szczodrzynski.edziennik'
minSdkVersion setup.minSdk
targetSdkVersion setup.targetSdk
+
versionCode release.versionCode
versionName release.versionName
- multiDexEnabled true
+
+ buildConfigField "java.util.Map", "GIT_INFO", gitInfoMap
+ buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
+ buildConfigField "String", "VERSION_BASE", "\"${release.versionName}\""
+
+ multiDexEnabled = true
externalNativeBuild {
cmake {
@@ -23,46 +29,45 @@ android {
}
}
}
+
buildTypes {
- applicationVariants.all { variant ->
- variant.outputs.all {
- if (variant.buildType.name == "release") {
- outputFileName = "Edziennik_" + defaultConfig.versionName + ".apk"
- } else if (variant.buildType.name == "debugMinify") {
- outputFileName = "Edziennik_" + defaultConfig.versionName + "_debugMinify.apk"
- } else {
- outputFileName = "Edziennik_" + defaultConfig.versionName + "_debug.apk"
- }
- }
- }
debug {
- minifyEnabled false
+ minifyEnabled = false
}
release {
- minifyEnabled true
- shrinkResources true
- proguardFiles getDefaultProguardFile('proguard-android.txt')
+ minifyEnabled = true
+ shrinkResources = true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
proguardFiles fileTree('proguard').asList().toArray()
}
}
- dependencies {
- implementation "com.google.firebase:firebase-core:${versions.firebase}"
+ flavorDimensions "platform"
+ productFlavors {
+ main {
+ versionName gitInfo.versionHuman
+ }
+ official {}
+ play {}
}
+ variantFilter { variant ->
+ def flavors = variant.flavors*.name
+ setIgnore(variant.buildType.name == "debug" && !flavors.contains("main"))
+ }
+
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
lintOptions {
- checkReleaseBuilds false
+ checkReleaseBuilds = false
}
buildFeatures {
dataBinding = true
+ viewBinding = true
}
compileOptions {
- coreLibraryDesugaringEnabled true
- sourceCompatibility '1.8'
- targetCompatibility '1.8'
- }
- productFlavors {
+ coreLibraryDesugaringEnabled = true
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
@@ -76,145 +81,115 @@ android {
version "3.10.2"
}
}
- ndkVersion '21.3.6528147'
}
-/*task finalizeBundleDebug(type: Copy) {
- from("debug/debug")
- include "app.aab"
- destinationDir file("debug/debug")
- rename "app.aab", "Edziennik_debug.aab"
-}
-
-// it finalizes :bundleRelease
-task finalizeBundleRelease(type: Copy) {
- from("release/release")
- include "app.aab"
- destinationDir file("release/release")
- rename "app.aab", "Edziennik_${android.defaultConfig.versionCode}.aab"
-}*/
-/*
-// this adds the above two tasks
tasks.whenTaskAdded { task ->
- if (task.name == "bundleDebug") {
- task.finalizedBy finalizeBundleDebug
- } else if (task.name == "bundleRelease") {
- task.finalizedBy finalizeBundleRelease
+ if (!task.name.endsWith("Release") && !task.name.endsWith("ReleaseWithR8"))
+ return
+ def renameTaskName = "rename${task.name.capitalize()}"
+
+ def flavor = ""
+ if (task.name.startsWith("bundle"))
+ flavor = task.name.substring("bundle".length(), task.name.indexOf("Release")).uncapitalize()
+ if (task.name.startsWith("assemble"))
+ flavor = task.name.substring("assemble".length(), task.name.indexOf("Release")).uncapitalize()
+ if (task.name.startsWith("minify"))
+ flavor = task.name.substring("minify".length(), task.name.indexOf("Release")).uncapitalize()
+
+ if (flavor != "") {
+ tasks.create(renameTaskName, Copy) {
+ from file("${projectDir}/${flavor}/release/"), file("${buildDir}/outputs/mapping/${flavor}Release/")
+ include "*.aab", "*.apk", "mapping.txt", "output-metadata.json"
+ destinationDir file("${projectDir}/release/")
+ rename ".+?\\.(.+)", "Edziennik_${android.defaultConfig.versionName}_${flavor}." + '$1'
+ }
+ task.finalizedBy(renameTaskName)
}
-}*/
+}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
- coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
+ // Language cores
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
- kapt "androidx.room:room-compiler:${versions.room}"
- debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
+ // Android Jetpack
+ implementation "androidx.appcompat:appcompat:1.2.0"
+ implementation "androidx.cardview:cardview:1.0.0"
+ implementation "androidx.constraintlayout:constraintlayout:2.0.4"
+ implementation "androidx.core:core-ktx:1.3.2"
+ implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0"
+ implementation "androidx.navigation:navigation-fragment-ktx:2.3.4"
+ implementation "androidx.recyclerview:recyclerview:1.1.0"
+ implementation "androidx.room:room-runtime:2.2.6"
+ implementation "androidx.work:work-runtime-ktx:2.5.0"
+ kapt "androidx.room:room-compiler:2.2.6"
- implementation "android.arch.navigation:navigation-fragment-ktx:${versions.navigationFragment}"
- implementation "androidx.appcompat:appcompat:${versions.appcompat}"
- implementation "androidx.cardview:cardview:${versions.cardView}"
- implementation "androidx.constraintlayout:constraintlayout:${versions.constraintLayout}"
- implementation "androidx.core:core-ktx:${versions.ktx}"
- implementation "androidx.gridlayout:gridlayout:${versions.gridLayout}"
- implementation "androidx.legacy:legacy-support-v4:${versions.legacy}"
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:${versions.lifecycle}"
- implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}"
- implementation "androidx.room:room-runtime:${versions.room}"
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
+ // Google design libs
+ implementation "com.google.android.material:material:1.3.0"
+ implementation "com.google.android:flexbox:2.0.1"
- implementation "com.google.android.gms:play-services-wearable:${versions.play_services}"
- implementation "com.google.android.material:material:${versions.material}"
- implementation "com.google.firebase:firebase-messaging:${versions.firebasemessaging}"
+ // Play Services/Firebase
+ implementation "com.google.android.gms:play-services-wearable:17.0.0"
+ implementation "com.google.firebase:firebase-core:18.0.2"
+ implementation "com.google.firebase:firebase-crashlytics:17.4.0"
+ implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } }
- //implementation "com.github.kuba2k2.MaterialDrawer:library:e603091449"
- implementation "com.mikepenz:crossfader:1.6.0" // do not update
- implementation "com.mikepenz:iconics-core:${versions.iconics}"
- implementation "com.mikepenz:iconics-views:${versions.iconics}"
- implementation "com.mikepenz:community-material-typeface:${versions.font_cmd}@aar"
- implementation "com.mikepenz:materialize:1.2.1"
+ // OkHttp, Retrofit, Gson, Jsoup
+ implementation("com.squareup.okhttp3:okhttp") { version { strictly "3.12.13" } }
+ implementation "com.squareup.retrofit2:retrofit:2.9.0"
+ implementation "com.squareup.retrofit2:converter-gson:2.9.0"
+ implementation "com.squareup.retrofit2:converter-scalars:2.9.0"
+ implementation 'com.google.code.gson:gson:2.8.6'
+ implementation "org.jsoup:jsoup:1.13.1"
+ implementation "pl.droidsonroids:jspoon:1.3.2"
+ implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
- implementation "com.github.kuba2k2:NavLib:${versions.navlib}"
+ // Szkolny.eu libraries/forks
+ implementation "eu.szkolny:agendacalendarview:1799f8ef47"
+ implementation "eu.szkolny:cafebar:5bf0c618de"
+ implementation "eu.szkolny.fslogin:lib:2.0.0"
+ implementation "eu.szkolny:material-about-library:1d5ebaf47c"
+ implementation "eu.szkolny:mhttp:af4b62e6e9"
+ implementation "eu.szkolny:nachos:0e5dfcaceb"
+ implementation "eu.szkolny.selective-dao:annotation:27f8f3f194"
+ implementation "eu.szkolny:ssl-provider:1.0.0"
+ implementation "pl.szczodrzynski:navlib:0.8.0"
+ implementation "pl.szczodrzynski:numberslidingpicker:2921225f76"
+ implementation "pl.szczodrzynski:recyclertablayout:700f980584"
+ implementation "pl.szczodrzynski:tachyon:551943a6b5"
+ kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
- implementation "com.afollestad.material-dialogs:commons:${versions.materialdialogs}"
- implementation "com.afollestad.material-dialogs:core:${versions.materialdialogs}"
+ // Iconics & related
+ implementation "com.mikepenz:iconics-core:5.3.0-b01"
+ implementation "com.mikepenz:iconics-views:5.3.0-b01"
+ implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
+ implementation "eu.szkolny:szkolny-font:1.3"
- implementation "cat.ereza:customactivityoncrash:2.2.0"
+ // Other dependencies
+ implementation "cat.ereza:customactivityoncrash:2.3.0"
implementation "com.applandeo:material-calendar-view:1.5.0"
- implementation 'com.google.firebase:firebase-crashlytics:17.3.1'
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
- implementation "com.evernote:android-job:1.2.6"
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2"
implementation "com.github.bassaer:chatmessageview:2.0.1"
- implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true}
- implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update
- implementation "com.jaredrummler:colorpicker:1.0.2"
- implementation("com.squareup.okhttp3:okhttp") {
- version {
- strictly "3.12.13"
- }
- }
- implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update
- implementation "com.wdullaer:materialdatetimepicker:4.1.2"
+ implementation "com.github.CanHub:Android-Image-Cropper:2.2.2"
+ implementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
+ implementation "com.github.jetradarmobile:android-snowfall:1.2.0"
+ implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31"
+ implementation("com.heinrichreimersoftware:material-intro") { version { strictly "1.5.8" } }
+ implementation "com.hypertrack:hyperlog:0.0.10"
+ implementation "com.jaredrummler:colorpicker:1.1.0"
+ implementation "com.qifan.powerpermission:powerpermission-coroutines:1.3.0"
+ implementation "com.qifan.powerpermission:powerpermission:1.3.0"
implementation "com.yuyh.json:jsonviewer:1.0.6"
+ implementation "io.coil-kt:coil:1.1.1"
implementation "me.dm7.barcodescanner:zxing:1.9.8"
implementation "me.grantland:autofittextview:0.2.1"
implementation "me.leolin:ShortcutBadger:1.1.22@aar"
- implementation "org.greenrobot:eventbus:3.1.1"
- implementation "org.jsoup:jsoup:1.12.1"
- implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15"
- //implementation "se.emilsjolander:stickylistheaders:2.7.0"
- implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar'
- implementation "uk.co.samuelwall:material-tap-target-prompt:2.14.0"
+ implementation "org.greenrobot:eventbus:3.2.0"
+ implementation("pl.droidsonroids.gif:android-gif-drawable") { version { strictly "1.2.15" } }
- implementation project(":agendacalendarview")
- implementation project(":cafebar")
- implementation project(":material-about-library")
- implementation project(":mhttp")
- implementation project(":nachos")
- //implementation project(":Navigation")
- implementation project(":szkolny-font")
-
- implementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
- //releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1"
-
- //implementation 'com.github.wulkanowy:uonet-request-signer:master-SNAPSHOT'
- //implementation 'com.github.kuba2k2.uonet-request-signer:android:master-63f094b14a-1'
-
- //implementation "org.redundent:kotlin-xml-builder:1.5.3"
-
- implementation 'com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31'
-
- implementation "androidx.work:work-runtime-ktx:${versions.work}"
-
- implementation 'com.hypertrack:hyperlog:0.0.10'
-
- implementation 'com.github.kuba2k2:RecyclerTabLayout:700f980584'
-
- implementation 'com.github.kuba2k2:Tachyon:551943a6b5'
-
- implementation "com.squareup.retrofit2:retrofit:${versions.retrofit}"
- implementation "com.squareup.retrofit2:converter-gson:${versions.retrofit}"
-
- implementation 'com.github.jetradarmobile:android-snowfall:1.2.0'
-
- implementation "io.coil-kt:coil:0.9.2"
-
- implementation 'com.github.kuba2k2:NumberSlidingPicker:2921225f76'
-
- implementation project(":annotation")
- kapt project(":codegen")
-
- implementation 'com.google.android:flexbox:2.0.1'
-
- implementation 'com.qifan.powerpermission:powerpermission:1.3.0'
- implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.3.0'
-
- implementation 'com.github.kuba2k2.FSLogin:lib:2.0.0'
- implementation 'pl.droidsonroids:jspoon:1.3.2'
- implementation "com.squareup.retrofit2:converter-scalars:2.8.1"
- implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
-}
-repositories {
- mavenCentral()
+ // Debug-only dependencies
+ debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
}
diff --git a/app/git-info.gradle b/app/git-info.gradle
new file mode 100644
index 00000000..929d5307
--- /dev/null
+++ b/app/git-info.gradle
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-27.
+ */
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath "org.eclipse.jgit:org.eclipse.jgit:5.5.+"
+ }
+}
+
+import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.errors.RepositoryNotFoundException
+import org.eclipse.jgit.lib.Constants
+import org.eclipse.jgit.lib.Ref
+import org.eclipse.jgit.lib.Repository
+import org.eclipse.jgit.revwalk.RevCommit
+import org.eclipse.jgit.revwalk.RevTag
+import org.eclipse.jgit.revwalk.RevWalk
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder
+
+private def getGit() {
+ Repository repo
+ try {
+ repo = new FileRepositoryBuilder()
+ .readEnvironment()
+ .findGitDir(project.projectDir)
+ .build()
+ } catch (IllegalArgumentException | RepositoryNotFoundException ignore) {
+ def logger = LoggerFactory.getLogger("androidGitVersion")
+ logger.error("No git repository reachable from ${project.projectDir}")
+ return results
+ }
+ return Git.wrap(repo)
+}
+
+private static def getTags(Repository repo, Git git) {
+ RevWalk walk = new RevWalk(repo)
+ def tags = git.tagList().call().findResults { ref ->
+ def obj = walk.parseAny(ref.getObjectId())
+ def name = null
+ if (obj instanceof RevTag) {
+ name = obj.getTagName()
+ } else if (obj instanceof RevCommit) {
+ name = Repository.shortenRefName(ref.name)
+ }
+ [obj.id, name]
+ }
+ walk.close()
+ return tags
+}
+
+private static def getLastTag(Repository repo, Git git, Ref head) {
+ def tags = getTags(repo, git)
+
+ RevWalk revs = new RevWalk(repo)
+ revs.markStart(revs.parseCommit(head.getObjectId()))
+ def revCount = 0
+ Collection commitTags = null
+ for (RevCommit commit : revs) {
+ def tagsHere = tags.findAll { (it[0] == commit.id) }
+ if (tagsHere) {
+ commitTags = tagsHere.stream().map {
+ [it[0].name, it[1], revCount]
+ }.toArray()
+ break
+ }
+ revCount++
+ }
+
+ return commitTags.last()
+}
+
+private def buildGitInfo() {
+ Git git = getGit()
+ Repository repo = git.repository
+
+ def head = repo.findRef(Constants.HEAD).target
+
+ def remotes = git.remoteList().call()
+ .stream()
+ .map {
+ it.name + "(" + it.URIs.stream()
+ .map { it.rawPath }
+ .toArray()
+ .join(", ") + ")"
+ }
+ .toArray()
+ .join("; ")
+
+ def status = git.status().call()
+ def dirty = status.hasUncommittedChanges()
+
+ def tag = getLastTag(repo, git, head)
+ def tagName = tag[1]
+ def tagRevCount = tag[2]
+ def versionName = tagName.replace("v", "")
+
+ def result = [
+ hash : head.objectId.name,
+ branch : repo.branch,
+ dirty : dirty,
+ remotes : remotes,
+ unstaged : status.uncommittedChanges.join("; "),
+ tag : tagName,
+ revCount : tagRevCount,
+ version : """$tagName-$tagRevCount-g${head.objectId.name.substring(0, 8)}""" + (dirty ? ".dirty" : ""),
+ versionHuman: """$versionName-${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "")
+ ]
+ return result
+}
+
+private static def getMapString(map) {
+ def hashMap = "new java.util.HashMap() { {\n"
+ map.each { k, v -> hashMap += """\tput("${k}", "${v}");\n""" }
+ return hashMap + "} }"
+}
+
+ext {
+ gitInfo = buildGitInfo()
+ gitInfoMap = getMapString(gitInfo)
+}
diff --git a/app/proguard/app.pro b/app/proguard-rules.pro
similarity index 100%
rename from app/proguard/app.pro
rename to app/proguard-rules.pro
diff --git a/app/proguard/android-job.pro b/app/proguard/android-job.pro
deleted file mode 100644
index 3f1a67be..00000000
--- a/app/proguard/android-job.pro
+++ /dev/null
@@ -1,14 +0,0 @@
--dontwarn com.evernote.android.job.gcm.**
--dontwarn com.evernote.android.job.GcmAvailableHelper
--dontwarn com.evernote.android.job.work.**
--dontwarn com.evernote.android.job.WorkManagerAvailableHelper
-
--keep public class com.evernote.android.job.v21.PlatformJobService
--keep public class com.evernote.android.job.v14.PlatformAlarmService
--keep public class com.evernote.android.job.v14.PlatformAlarmReceiver
--keep public class com.evernote.android.job.JobBootReceiver
--keep public class com.evernote.android.job.JobRescheduleService
--keep public class com.evernote.android.job.gcm.PlatformGcmService
--keep public class com.evernote.android.job.work.PlatformWorker
-
--keep class com.evernote.android.job.** { *; }
\ No newline at end of file
diff --git a/app/proguard/blurry.pro b/app/proguard/blurry.pro
deleted file mode 100644
index 980f404e..00000000
--- a/app/proguard/blurry.pro
+++ /dev/null
@@ -1 +0,0 @@
--keep class android.support.v8.renderscript.** { *; }
\ No newline at end of file
diff --git a/app/proguard/cafebar.pro b/app/proguard/cafebar.pro
deleted file mode 100644
index 6f8147fd..00000000
--- a/app/proguard/cafebar.pro
+++ /dev/null
@@ -1,25 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in D:\AndroidSDK/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
--keep class !android.support.v7.internal.view.menu.**,android.support.** {*;}
--keep class android.support.v7.graphics.** { *; }
--dontwarn android.support.v7.graphics.**
-
--keep class android.support.design.widget.** { *; }
--keep interface android.support.design.widget.** { *; }
--dontwarn android.support.design.**
diff --git a/app/proguard/iconics.pro b/app/proguard/iconics.pro
deleted file mode 100644
index 0aa62122..00000000
--- a/app/proguard/iconics.pro
+++ /dev/null
@@ -1,14 +0,0 @@
-# Android iconics library - https://github.com/mikepenz/Android-Iconics
-# Warning: works ONLY with iconics > 1.0.0
-#
-# Tested on gradle config:
-#
-# compile 'com.mikepenz:iconics-core:1.7.1@aar'
-#
-
--keep class com.mikepenz.iconics.** { *; }
--keep class com.mikepenz.community_material_typeface_library.CommunityMaterial
--keep class com.mikepenz.fontawesome_typeface_library.FontAwesome
--keep class com.mikepenz.google_material_typeface_library.GoogleMaterial
--keep class com.mikepenz.meteocons_typeface_library.Meteoconcs
--keep class com.mikepenz.octicons_typeface_library.Octicons
\ No newline at end of file
diff --git a/app/proguard/mhttp.pro b/app/proguard/mhttp.pro
deleted file mode 100644
index 6d3e4e38..00000000
--- a/app/proguard/mhttp.pro
+++ /dev/null
@@ -1,48 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /Users/wangchao/Work/android-sdk/sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
--dontwarn im.wangchao.**
--dontwarn okio.**
--dontwarn javax.annotation.Nullable
--dontwarn javax.annotation.ParametersAreNonnullByDefault
--keep class im.wangchao.** { *; }
--keep class **_HttpBinder { *; }
--keepclasseswithmembernames class * {
- @im.wangchao.* ;
-}
--keepclasseswithmembernames class * {
- @im.wangchao.* ;
-}
--keepclassmembers class * implements java.io.Serializable {
- static final long serialVersionUID;
- private static final java.io.ObjectStreamField[] serialPersistentFields;
- !static !transient ;
- private void writeObject(java.io.ObjectOutputStream);
- private void readObject(java.io.ObjectInputStream);
- java.lang.Object writeReplace();
- java.lang.Object readResolve();
-}
-# okhttp
--dontwarn okhttp3.**
--dontwarn okio.**
--dontwarn javax.annotation.**
--dontwarn org.conscrypt.**
-# A resource is loaded with a relative path so the package of this class must be preserved.
--keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
-
-# If you do not use Rx:
--dontwarn rx.**
\ No newline at end of file
diff --git a/app/proguard/szkolny-font.pro b/app/proguard/szkolny-font.pro
deleted file mode 100644
index 4e48be73..00000000
--- a/app/proguard/szkolny-font.pro
+++ /dev/null
@@ -1 +0,0 @@
--keep class com.mikepenz.szkolny_font_typeface_library.SzkolnyFont { *; }
diff --git a/app/proguard/wear.pro b/app/proguard/wear.pro
deleted file mode 100644
index f1b42451..00000000
--- a/app/proguard/wear.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6e8fc491..5f295533 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -123,9 +123,6 @@
android:configChanges="orientation|screenSize|keyboardHidden"
android:process=":error_activity"
android:theme="@style/DeadTheme" />
-
-
-
+
-
diff --git a/app/src/main/assets/certificate.cer b/app/src/main/assets/certificate.cer
deleted file mode 100644
index 0002462c..00000000
--- a/app/src/main/assets/certificate.cer
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
------END CERTIFICATE-----
diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html
index 2850871b..ee275ca9 100644
--- a/app/src/main/assets/pl-changelog.html
+++ b/app/src/main/assets/pl-changelog.html
@@ -1,6 +1,12 @@
-Wersja 4.6.1, 2021-03-04
+Wersja 4.7-rc.1, 2021-04-01
- Przywrócono obsługę dziennika Librus Synergia.
+ Szkolny.eu jest teraz open source! Zapraszamy na stronę https://szkolny.eu/ po więcej ważnych informacji.
+ Poprawiono wybieranie obrazków (tła nagłówka, tła aplikacji oraz profilu) z dowolnego źródła.
+ Naprawiono zatrzymanie aplikacji na Androidzie 4.4 i starszych.
+ Naprawiono problemy z połączeniem internetowym na Androidzie 4.4 i starszych.
+ Dodano ekran informacji o kompilacji w Ustawieniach.
+ Zaktualizowano ekran licencji open source.
+ Zoptymalizowano wielkość aplikacji.
diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp
index df2ca9d7..fa0d780a 100644
--- a/app/src/main/cpp/szkolny-signing.cpp
+++ b/app/src/main/cpp/szkolny-signing.cpp
@@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/
static toys AES_IV[16] = {
- 0xdc, 0x61, 0x4d, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ 0xdd, 0x0a, 0x72, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt
index 88bdc603..a9186d94 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt
@@ -26,7 +26,8 @@ import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.Gson
import com.hypertrack.hyperlog.HyperLog
import com.mikepenz.iconics.Iconics
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
+import eu.szkolny.sslprovider.SSLProvider
+import eu.szkolny.sslprovider.enableSupportedTls
import im.wangchao.mhttp.MHttp
import kotlinx.coroutines.*
import me.leolin.shortcutbadger.ShortcutBadger
@@ -37,7 +38,6 @@ import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Profile
-import pl.szczodrzynski.edziennik.network.NetworkUtils
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
import pl.szczodrzynski.edziennik.sync.SyncWorker
import pl.szczodrzynski.edziennik.sync.UpdateWorker
@@ -45,6 +45,7 @@ import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity
import pl.szczodrzynski.edziennik.utils.*
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.managers.*
+import timber.log.Timber
import java.util.concurrent.TimeUnit
import kotlin.coroutines.CoroutineContext
@@ -52,8 +53,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
companion object {
@Volatile
lateinit var db: AppDb
- val config: Config by lazy { Config(db) }
- var profile: Profile by mutableLazy { Profile(0, 0, 0, "") }
+ lateinit var config: Config
+ lateinit var profile: Profile
val profileId
get() = profile.id
@@ -68,6 +69,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
val eventManager by lazy { EventManager(this) }
val permissionManager by lazy { PermissionManager(this) }
val attendanceManager by lazy { AttendanceManager(this) }
+ val buildManager by lazy { BuildManager(this) }
val db
get() = App.db
@@ -86,7 +88,6 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
.build()
val permissionChecker by lazy { PermissionChecker(this) }
- val networkUtils by lazy { NetworkUtils(this) }
val gson by lazy { Gson() }
/* _ _ _______ _______ _____
@@ -95,19 +96,22 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
| __ | | | | | | ___/
| | | | | | | | | |
|_| |_| |_| |_| |*/
- val http: OkHttpClient by lazy {
- val builder = OkHttpClient.Builder()
- .cache(null)
- .followRedirects(true)
- .followSslRedirects(true)
- .retryOnConnectionFailure(true)
- .cookieJar(cookieJar)
- .connectTimeout(15, TimeUnit.SECONDS)
- .writeTimeout(10, TimeUnit.SECONDS)
- .readTimeout(30, TimeUnit.SECONDS)
- builder.installHttpsSupport(this)
+ lateinit var http: OkHttpClient
+ lateinit var httpLazy: OkHttpClient
- if (devMode || BuildConfig.DEBUG) {
+ private fun buildHttp() {
+ val builder = OkHttpClient.Builder()
+ .cache(null)
+ .followRedirects(true)
+ .followSslRedirects(true)
+ .retryOnConnectionFailure(true)
+ .cookieJar(cookieJar)
+ .connectTimeout(15, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .enableSupportedTls(enableCleartext = true)
+
+ if (devMode) {
HyperLog.initialize(this)
HyperLog.setLogLevel(Log.VERBOSE)
HyperLog.setLogFormat(DebugLogFormat(this))
@@ -116,13 +120,14 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
builder.addInterceptor(chuckerInterceptor)
}
- builder.build()
- }
- val httpLazy: OkHttpClient by lazy {
- http.newBuilder()
- .followRedirects(false)
- .followSslRedirects(false)
- .build()
+ http = builder.build()
+
+ httpLazy = http.newBuilder()
+ .followRedirects(false)
+ .followSslRedirects(false)
+ .build()
+
+ MHttp.instance().customOkHttpClient(http)
}
val cookieJar by lazy { DumbCookieJar(this) }
@@ -159,33 +164,47 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
.errorActivity(CrashActivity::class.java)
.apply()
Iconics.init(applicationContext)
- Iconics.registerFont(SzkolnyFont)
+ Iconics.respectFontBoundsDefault = true
+
+ // initialize companion object values
App.db = AppDb(this)
- Themes.themeInt = config.ui.theme
- devMode = config.debugMode
- MHttp.instance().customOkHttpClient(http)
+ App.config = Config(App.db)
+ App.profile = Profile(0, 0, 0, "")
+ debugMode = BuildConfig.DEBUG
+ devMode = config.debugMode || debugMode
if (!profileLoadById(config.lastProfileId)) {
db.profileDao().firstId?.let { profileLoadById(it) }
}
+ buildHttp()
+
+ Themes.themeInt = config.ui.theme
config.ui.language?.let {
setLanguage(it)
}
- debugMode = BuildConfig.DEBUG
- if (BuildConfig.DEBUG)
- devMode = true
-
Signing.getCert(this)
launch {
withContext(Dispatchers.Default) {
config.migrate(this@App)
+ SSLProvider.install(
+ applicationContext,
+ downloadIfNeeded = true,
+ supportTls13 = false,
+ onFinish = {
+ buildHttp()
+ },
+ onError = {
+ Timber.e("Failed to install SSLProvider: $it")
+ it.printStackTrace()
+ }
+ )
+
if (config.devModePassword != null)
checkDevModePassword()
- devMode = debugMode || config.debugMode
if (config.sync.enabled)
SyncWorker.scheduleNext(this@App, false)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
index 71febada..a07634a1 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
@@ -1,12 +1,9 @@
package pl.szczodrzynski.edziennik
-import android.Manifest
-import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
-import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.content.res.Resources
import android.database.Cursor
@@ -29,7 +26,6 @@ import android.view.View
import android.view.WindowManager
import android.widget.*
import androidx.annotation.*
-import androidx.core.app.ActivityCompat
import androidx.core.database.getIntOrNull
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
@@ -40,8 +36,8 @@ import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.viewpager.widget.ViewPager
-import com.google.android.gms.security.ProviderInstaller
import com.google.android.material.button.MaterialButton
+import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.gson.*
import com.google.gson.JsonArray
@@ -50,10 +46,7 @@ import im.wangchao.mhttp.Response
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-import okhttp3.ConnectionSpec
-import okhttp3.OkHttpClient
import okhttp3.RequestBody
-import okhttp3.TlsVersion
import okio.Buffer
import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.models.ApiError
@@ -63,7 +56,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Notification
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.entity.Team
-import pl.szczodrzynski.edziennik.network.TLSSocketFactory
import pl.szczodrzynski.edziennik.utils.models.Time
import java.io.InterruptedIOException
import java.io.PrintWriter
@@ -73,17 +65,13 @@ import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.nio.charset.Charset
-import java.security.KeyStore
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.*
import java.util.zip.CRC32
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
-import javax.net.ssl.SSLContext
import javax.net.ssl.SSLException
-import javax.net.ssl.TrustManagerFactory
-import javax.net.ssl.X509TrustManager
import kotlin.Pair
@@ -304,19 +292,6 @@ fun colorFromCssName(name: String): Int {
fun List.filterOutArchived() = this.filter { !it.archived }
-fun Activity.isStoragePermissionGranted(): Boolean {
- return if (Build.VERSION.SDK_INT >= 23) {
- if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
- true
- } else {
- ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
- false
- }
- } else {
- true
- }
-}
-
fun Response?.getUnixDate(): Long {
val rfcDate = this?.headers()?.get("date") ?: return currentTimeUnix()
val pattern = "EEE, dd MMM yyyy HH:mm:ss Z"
@@ -1107,40 +1082,6 @@ fun Cursor?.getString(columnName: String) = this?.getStringOrNull(getColumnIndex
fun Cursor?.getInt(columnName: String) = this?.getIntOrNull(getColumnIndex(columnName))
fun Cursor?.getLong(columnName: String) = this?.getLongOrNull(getColumnIndex(columnName))
-fun OkHttpClient.Builder.installHttpsSupport(context: Context) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
- try {
- try {
- ProviderInstaller.installIfNeeded(context)
- } catch (e: Exception) {
- Log.e("OkHttpTLSCompat", "Play Services not found or outdated")
-
- val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
- trustManagerFactory.init(null as KeyStore?)
-
- val x509TrustManager = trustManagerFactory.trustManagers.singleOrNull { it is X509TrustManager } as X509TrustManager?
- ?: return
-
- val sc = SSLContext.getInstance("TLSv1.2")
- sc.init(null, null, null)
- sslSocketFactory(TLSSocketFactory(sc.socketFactory), x509TrustManager)
- val cs: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
- .tlsVersions(TlsVersion.TLS_1_0)
- .tlsVersions(TlsVersion.TLS_1_1)
- .tlsVersions(TlsVersion.TLS_1_2)
- .build()
- val specs: MutableList = ArrayList()
- specs.add(cs)
- specs.add(ConnectionSpec.COMPATIBLE_TLS)
- specs.add(ConnectionSpec.CLEARTEXT)
- connectionSpecs(specs)
- }
- } catch (exc: Exception) {
- Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc)
- }
- }
-}
-
fun CharSequence.containsAll(list: List, ignoreCase: Boolean = false): Boolean {
for (i in list) {
if (!contains(i, ignoreCase))
@@ -1172,7 +1113,30 @@ fun Throwable.toErrorCode() = when (this) {
is SzkolnyApiException -> this.error?.toErrorCode()
else -> null
}
-private fun ApiResponse.Error.toErrorCode() = when (this.code) {
+fun ApiResponse.Error.toErrorCode() = when (this.code) {
+ "PdoError" -> ERROR_API_PDO_ERROR
+ "InvalidClient" -> ERROR_API_INVALID_CLIENT
+ "InvalidArgument" -> ERROR_API_INVALID_ARGUMENT
+ "InvalidSignature" -> ERROR_API_INVALID_SIGNATURE
+ "MissingScopes" -> ERROR_API_MISSING_SCOPES
+ "ResourceNotFound" -> ERROR_API_RESOURCE_NOT_FOUND
+ "InternalServerError" -> ERROR_API_INTERNAL_SERVER_ERROR
+ "PhpError" -> ERROR_API_PHP_E_ERROR
+ "PhpWarning" -> ERROR_API_PHP_E_WARNING
+ "PhpParse" -> ERROR_API_PHP_E_PARSE
+ "PhpNotice" -> ERROR_API_PHP_E_NOTICE
+ "PhpOther" -> ERROR_API_PHP_E_OTHER
+ "ApiMaintenance" -> ERROR_API_MAINTENANCE
+ "MissingArgument" -> ERROR_API_MISSING_ARGUMENT
+ "MissingPayload" -> ERROR_API_PAYLOAD_EMPTY
+ "InvalidAction" -> ERROR_API_INVALID_ACTION
+ "VersionNotFound" -> ERROR_API_UPDATE_NOT_FOUND
+ "InvalidDeviceIdUserCode" -> ERROR_API_INVALID_DEVICEID_USERCODE
+ "InvalidPairToken" -> ERROR_API_INVALID_PAIRTOKEN
+ "InvalidBrowserId" -> ERROR_API_INVALID_BROWSERID
+ "InvalidDeviceId" -> ERROR_API_INVALID_DEVICEID
+ "InvalidDeviceIdBrowserId" -> ERROR_API_INVALID_DEVICEID_BROWSERID
+ "HelpCategoryNotFound" -> ERROR_API_HELP_CATEGORY_NOT_FOUND
else -> ERROR_API_EXCEPTION
}
fun Throwable.toApiError(tag: String) = ApiError.fromThrowable(tag, this)
@@ -1278,3 +1242,48 @@ operator fun Iterable>.get(key: K): V? {
}
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
+
+fun MutableList.after(what: E, insert: E) {
+ val index = indexOf(what)
+ if (index != -1)
+ add(index + 1, insert)
+}
+
+fun MutableList.before(what: E, insert: E) {
+ val index = indexOf(what)
+ if (index != -1)
+ add(index, insert)
+}
+
+fun MutableList.after(what: E, insert: Collection) {
+ val index = indexOf(what)
+ if (index != -1)
+ addAll(index + 1, insert)
+}
+
+fun MutableList.before(what: E, insert: Collection) {
+ val index = indexOf(what)
+ if (index != -1)
+ addAll(index, insert)
+}
+
+fun Context.getSyncInterval(interval: Int): String {
+ val hours = interval / 60 / 60
+ val minutes = interval / 60 % 60
+ val hoursText = if (hours > 0)
+ plural(R.plurals.time_till_hours, hours)
+ else
+ null
+ val minutesText = if (minutes > 0)
+ plural(R.plurals.time_till_minutes, minutes)
+ else
+ ""
+ return hoursText?.plus(" $minutesText") ?: minutesText
+}
+
+fun Profile.getSchoolYearConstrains(): CalendarConstraints {
+ return CalendarConstraints.Builder()
+ .setStart(dateSemester1Start.inMillisUtc)
+ .setEnd(dateYearEnd.inMillisUtc)
+ .build()
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/GenericFileProvider.java b/app/src/main/java/pl/szczodrzynski/edziennik/GenericFileProvider.java
deleted file mode 100644
index 69aef167..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/GenericFileProvider.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package pl.szczodrzynski.edziennik;
-
-import androidx.core.content.FileProvider;
-
-public class GenericFileProvider extends FileProvider {}
\ No newline at end of file
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
index 1e73e267..8dd83bf2 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
@@ -10,39 +10,39 @@ import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.os.Build
import android.os.Bundle
-import android.os.Environment
import android.provider.Settings
import android.view.Gravity
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.navigation.NavOptions
import com.danimahardhika.cafebar.CafeBar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.mikepenz.iconics.IconicsColor
import com.mikepenz.iconics.IconicsDrawable
-import com.mikepenz.iconics.IconicsSize
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
+import com.mikepenz.iconics.utils.colorInt
+import com.mikepenz.iconics.utils.sizeDp
import com.mikepenz.materialdrawer.model.DividerDrawerItem
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.*
import com.mikepenz.materialdrawer.model.utils.withIsHiddenInMiniDrawer
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.droidsonroids.gif.GifDrawable
+import pl.szczodrzynski.edziennik.data.api.ERROR_API_INVALID_SIGNATURE
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.*
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
+import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
@@ -56,7 +56,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog
import pl.szczodrzynski.edziennik.ui.dialogs.UpdateAvailableDialog
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
@@ -68,7 +68,6 @@ import pl.szczodrzynski.edziennik.ui.modules.debug.LabFragment
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDetailsDialog
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
-import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesListFragment
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
@@ -79,7 +78,7 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFragment
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
-import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsFragment
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
@@ -97,7 +96,6 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
import pl.szczodrzynski.navlib.drawer.NavDrawer
import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem
-import java.io.File
import java.io.IOException
import java.util.*
import kotlin.coroutines.CoroutineContext
@@ -110,8 +108,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
const val TAG = "MainActivity"
- const val REQUEST_LOGIN_ACTIVITY = 20222
-
const val DRAWER_PROFILE_ADD_NEW = 200
const val DRAWER_PROFILE_SYNC_ALL = 201
const val DRAWER_PROFILE_EXPORT_DATA = 202
@@ -131,7 +127,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
const val DRAWER_ITEM_DEBUG = 102
const val TARGET_GRADES_EDITOR = 501
- const val TARGET_HELP = 502
const val TARGET_FEEDBACK = 120
const val TARGET_MESSAGES_DETAILS = 503
const val TARGET_MESSAGES_COMPOSE = 504
@@ -152,7 +147,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
.withPopToHome(false)
list += NavTarget(DRAWER_ITEM_TIMETABLE, R.string.menu_timetable, TimetableFragment::class)
- .withIcon(CommunityMaterial.Icon2.cmd_timetable)
+ .withIcon(CommunityMaterial.Icon3.cmd_timetable)
.withBadgeTypeId(TYPE_LESSON_CHANGE)
.isInDrawer(true)
@@ -162,7 +157,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
.isInDrawer(true)
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class)
- .withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
+ .withIcon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline)
.withBadgeTypeId(TYPE_GRADE)
.isInDrawer(true)
@@ -199,8 +194,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
.isStatic(true)
.isBelowSeparator(true)
- list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
- .withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
+ list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsFragment::class)
+ .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.isInDrawer(true)
.isStatic(true)
.isBelowSeparator(true)
@@ -208,7 +203,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// profile settings items
list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null)
- .withIcon(CommunityMaterial.Icon2.cmd_plus)
+ .withIcon(CommunityMaterial.Icon3.cmd_plus)
.withDescription(R.string.drawer_add_new_profile_desc)
.isInProfileList(true)
@@ -229,7 +224,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// other target items, not directly navigated
list += NavTarget(TARGET_GRADES_EDITOR, R.string.menu_grades_editor, GradesEditorFragment::class)
- list += NavTarget(TARGET_HELP, R.string.menu_help, HelpFragment::class)
list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class)
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
@@ -237,7 +231,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (App.devMode) {
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_flask_outline)
+ .withIcon(CommunityMaterial.Icon2.cmd_flask_outline)
.isInDrawer(true)
.isBelowSeparator(true)
.isStatic(true)
@@ -257,6 +251,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
val mainSnackbar: MainSnackbar by lazy { MainSnackbar(this) }
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
+ val requestHandler by lazy { MainActivityRequestHandler(this) }
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
@@ -290,6 +285,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
setLanguage(it)
}
+ app.buildManager.validateBuild(this)
+
if (App.profileId == 0) {
onProfileListEmptyEvent(ProfileListEmptyEvent())
return
@@ -302,20 +299,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
- when {
- BuildConfig.VERSION_NAME.contains("nightly") -> {
- b.nightlyText.isVisible = true
- b.nightlyText.text = "Nightly\n"+BuildConfig.VERSION_NAME.substringAfterLast(".")
- }
- BuildConfig.VERSION_NAME.contains("daily") -> {
- b.nightlyText.isVisible = true
- b.nightlyText.text = "Daily\n"+BuildConfig.VERSION_NAME.substringAfterLast(".")
- }
- BuildConfig.DEBUG -> {
- b.nightlyText.isVisible = true
- b.nightlyText.text = "Debug\n"+BuildConfig.VERSION_NAME
- }
- else -> b.nightlyText.isVisible = false
+ val versionBadge = app.buildManager.versionBadge
+ b.nightlyText.isVisible = versionBadge != null
+ b.nightlyText.text = versionBadge
+ if (versionBadge != null) {
+ b.nightlyText.background.setTintColor(0xa0ff0000.toInt())
}
navLoading = true
@@ -392,7 +380,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
drawerProfileLongClickListener = { _, profile, _, view ->
if (view != null && profile is ProfileDrawerItem) {
- showProfileContextMenu(profile, view)
+ launch {
+ val appProfile = withContext(Dispatchers.IO) {
+ App.db.profileDao().getByIdNow(profile.identifier.toInt())
+ } ?: return@launch
+ drawer.close()
+ ProfileConfigDialog(this@MainActivity, appProfile)
+ }
true
}
else {
@@ -472,28 +466,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
// APP BACKGROUND
- if (app.config.ui.appBackground != null) {
- try {
- app.config.ui.appBackground?.let {
- var bg = it
- val bgDir = File(Environment.getExternalStoragePublicDirectory("Szkolny.eu"), "bg")
- if (bgDir.exists()) {
- val files = bgDir.listFiles()
- val r = Random()
- val i = r.nextInt(files.size)
- bg = files[i].toString()
- }
- val linearLayout = b.root
- if (bg.endsWith(".gif")) {
- linearLayout.background = GifDrawable(bg)
- } else {
- linearLayout.background = BitmapDrawable.createFromPath(bg)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
+ setAppBackground()
// IT'S WINTER MY DUDES
val today = Date.getToday()
@@ -519,7 +492,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
navView.coordinator.postDelayed({
CafeBar.builder(this)
.content(R.string.rate_snackbar_text)
- .icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
+ .icon(IconicsDrawable(this).apply {
+ icon = CommunityMaterial.Icon3.cmd_star_outline
+ sizeDp = 24
+ colorInt = Themes.getPrimaryTextColor(this@MainActivity)
+ })
.positiveText(R.string.rate_snackbar_positive)
.positiveColor(-0xb350b0)
.negativeText(R.string.rate_snackbar_negative)
@@ -532,12 +509,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
app.config.appRateSnackbarTime = 0
}
.onNegative { cafeBar ->
- Toast.makeText(this, "Szkoda, opinie innych pomagają mi rozwijać aplikację.", Toast.LENGTH_LONG).show()
+ Toast.makeText(this, R.string.rate_snackbar_negative_message, Toast.LENGTH_LONG).show()
cafeBar.dismiss()
app.config.appRateSnackbarTime = 0
}
.onNeutral { cafeBar ->
- Toast.makeText(this, "OK", Toast.LENGTH_LONG).show()
+ Toast.makeText(this, R.string.ok, Toast.LENGTH_LONG).show()
cafeBar.dismiss()
app.config.appRateSnackbarTime = System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
}
@@ -561,7 +538,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
BottomSheetSeparatorItem(false),
BottomSheetPrimaryItem(false)
.withTitle(R.string.menu_settings)
- .withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
+ .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
BottomSheetPrimaryItem(false)
.withTitle(R.string.menu_feedback)
@@ -571,7 +548,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (App.devMode) {
bottomSheet += BottomSheetPrimaryItem(false)
.withTitle(R.string.menu_debug)
- .withIcon(CommunityMaterial.Icon.cmd_android_studio)
+ .withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
}
}
@@ -579,7 +556,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
private var profileSettingClickListener = { id: Int, view: View? ->
when (id) {
DRAWER_PROFILE_ADD_NEW -> {
- startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY)
+ requestHandler.requestLogin()
}
DRAWER_PROFILE_SYNC_ALL -> {
EdziennikTask.sync().enqueue(this)
@@ -650,22 +627,40 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
app.profile.registerName?.let { registerName ->
var status = app.config.sync.registerAvailability[registerName]
if (status == null || status.nextCheckAt < currentTimeUnix()) {
- withContext(Dispatchers.IO) {
- val api = SzkolnyApi(app)
- api.runCatching(this@MainActivity) {
+ val api = SzkolnyApi(app)
+ val result = withContext(Dispatchers.IO) {
+ return@withContext api.runCatching({
val availability = getRegisterAvailability()
app.config.sync.registerAvailability = availability
- status = availability[registerName]
+ availability[registerName]
+ }, onError = {
+ if (it.toErrorCode() == ERROR_API_INVALID_SIGNATURE) {
+ return@withContext false
+ }
+ return@withContext it
+ })
+ }
+
+ when (result) {
+ false -> {
+ Toast.makeText(this@MainActivity, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
+ return@let
+ }
+ is Throwable -> {
+ errorSnackbar.addError(result.toApiError(TAG)).show()
+ return
+ }
+ is RegisterAvailabilityStatus -> {
+ status = result
}
}
}
- if (status?.available != true
- || status?.minVersionCode ?: BuildConfig.VERSION_CODE > BuildConfig.VERSION_CODE) {
+ if (status?.available != true || status.minVersionCode > BuildConfig.VERSION_CODE) {
swipeRefreshLayout.isRefreshing = false
loadTarget(DRAWER_ITEM_HOME)
if (status != null)
- RegisterUnavailableDialog(this, status!!)
+ RegisterUnavailableDialog(this, status)
return
}
}
@@ -827,7 +822,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
handleIntent(intent?.extras)
}
}
- private fun handleIntent(extras: Bundle?) {
+ fun handleIntent(extras: Bundle?) {
d(TAG, "handleIntent() {")
extras?.keySet()?.forEach { key ->
@@ -985,13 +980,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- if (requestCode == REQUEST_LOGIN_ACTIVITY) {
- if (!app.config.loginFinished)
- finish()
- else {
- handleIntent(data?.extras)
- }
- }
+ requestHandler.handleResult(requestCode, resultCode, data)
}
/* _ _ _ _ _
@@ -1217,6 +1206,19 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}, 3000)
}
+ fun setAppBackground() {
+ try {
+ b.root.background = app.config.ui.appBackground?.let {
+ if (it.endsWith(".gif"))
+ GifDrawable(it)
+ else
+ BitmapDrawable.createFromPath(it)
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+
/* _____ _ _
| __ \ (_) |
| | | |_ __ __ ___ _____ _ __ _| |_ ___ _ __ ___ ___
@@ -1292,26 +1294,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
drawer.addProfileSettings(*drawerProfiles.toTypedArray())
}
- private fun showProfileContextMenu(profile: IProfile, view: View) {
- val profileId = profile.identifier.toInt()
- val popupMenu = PopupMenu(this, view)
- popupMenu.menu.add(0, 1, 1, R.string.profile_menu_open_settings)
- popupMenu.menu.add(0, 2, 2, R.string.profile_menu_remove)
- popupMenu.setOnMenuItemClickListener { item ->
- if (item.itemId == 1) {
- if (profileId != app.profile.id) {
- loadProfile(profileId, DRAWER_ITEM_SETTINGS)
- return@setOnMenuItemClickListener true
- }
- loadTarget(DRAWER_ITEM_SETTINGS, null)
- } else if (item.itemId == 2) {
- ProfileRemoveDialog(this, profileId, profile.name?.getText(this) ?: "?")
- }
- true
- }
- popupMenu.show()
- }
-
private val targetPopToHomeList = arrayListOf()
private var targetHomeId: Int = -1
override fun onBackPressed() {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt
new file mode 100644
index 00000000..a39a5872
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-23.
+ */
+
+package pl.szczodrzynski.edziennik
+
+import android.app.Activity
+import android.content.Intent
+import android.net.Uri
+import android.provider.OpenableColumns
+import com.canhub.cropper.CropImage
+import com.canhub.cropper.CropImageView
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
+import java.io.File
+import java.io.FileOutputStream
+
+class MainActivityRequestHandler(val activity: MainActivity) {
+ companion object {
+ private const val REQUEST_LOGIN_ACTIVITY = 2000
+ private const val REQUEST_FILE_HEADER_BACKGROUND = 3000
+ private const val REQUEST_FILE_APP_BACKGROUND = 4000
+ private const val REQUEST_FILE_PROFILE_IMAGE = 5000
+ private const val REQUEST_CROP_HEADER_BACKGROUND = 3100
+ private const val REQUEST_CROP_APP_BACKGROUND = 4100
+ private const val REQUEST_CROP_PROFILE_IMAGE = 5100
+ }
+
+ private val app = activity.app
+ private val requestData = mutableMapOf()
+ private val listeners = mutableMapOf Unit>()
+
+ private val manager
+ get() = app.permissionManager
+
+ fun requestLogin() = activity.startActivityForResult(
+ Intent(activity, LoginActivity::class.java),
+ REQUEST_LOGIN_ACTIVITY
+ )
+
+ fun requestHeaderBackground(listener: (Any?) -> Unit) =
+ manager.requestCameraPermission(
+ activity, 0, isRequired = false
+ ) {
+ listeners[REQUEST_FILE_HEADER_BACKGROUND] = listener
+ activity.startActivityForResult(
+ CropImage.getPickImageChooserIntent(
+ activity,
+ activity.getString(R.string.pick_image_intent_chooser_title),
+ true,
+ true
+ ),
+ REQUEST_FILE_HEADER_BACKGROUND
+ )
+ }
+
+ fun requestAppBackground(listener: (Any?) -> Unit) =
+ manager.requestCameraPermission(
+ activity, 0, isRequired = false
+ ) {
+ listeners[REQUEST_FILE_APP_BACKGROUND] = listener
+ activity.startActivityForResult(
+ CropImage.getPickImageChooserIntent(
+ activity,
+ activity.getString(R.string.pick_image_intent_chooser_title),
+ true,
+ true
+ ),
+ REQUEST_FILE_APP_BACKGROUND
+ )
+ }
+
+ fun requestProfileImage(profile: Profile, listener: (Any?) -> Unit) =
+ manager.requestCameraPermission(
+ activity, 0, isRequired = false
+ ) {
+ listeners[REQUEST_FILE_PROFILE_IMAGE] = listener
+ requestData[REQUEST_FILE_PROFILE_IMAGE] = profile
+ activity.startActivityForResult(
+ CropImage.getPickImageChooserIntent(
+ activity,
+ activity.getString(R.string.pick_image_intent_chooser_title),
+ true,
+ true
+ ),
+ REQUEST_FILE_PROFILE_IMAGE
+ )
+ }
+
+ private fun getFileInfo(uri: Uri): Pair {
+ if (uri.scheme == "file") {
+ return (uri.lastPathSegment ?: "unknown") to null
+ }
+ val cursor = activity.contentResolver.query(
+ uri,
+ null,
+ null,
+ null,
+ null,
+ null
+ )
+
+ return cursor?.use {
+ if (it.moveToFirst()) {
+ val name = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
+ val mimeIndex = it.getColumnIndex("mime_type")
+ val mimeType = if (mimeIndex != -1) it.getString(mimeIndex) else null
+
+ name to mimeType
+ } else
+ null
+ } ?: "unknown" to null
+ }
+
+ private fun shouldCrop(uri: Uri): Boolean {
+ val (filename, mimeType) = getFileInfo(uri)
+ return !filename.endsWith(".gif") && mimeType?.endsWith("/gif") != true
+ }
+
+ private fun saveFile(uri: Uri, name: String): String {
+ val (filename, _) = getFileInfo(uri)
+ val extension = filename.substringAfterLast('.')
+ val file = File(activity.filesDir, "$name.$extension")
+ activity.contentResolver.openInputStream(uri)?.use { input ->
+ FileOutputStream(file).use { output ->
+ input.copyTo(output)
+ }
+ }
+ return file.absolutePath
+ }
+
+ fun handleResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (resultCode != Activity.RESULT_OK)
+ return
+ var uri = CropImage.getPickImageResultUri(activity, data)
+ when (requestCode) {
+ REQUEST_LOGIN_ACTIVITY -> {
+ if (!app.config.loginFinished)
+ activity.finish()
+ else {
+ activity.handleIntent(data?.extras)
+ }
+ }
+ REQUEST_FILE_HEADER_BACKGROUND -> {
+ if (uri == null)
+ return // TODO: 2021-03-24 if the app returns no data
+ if (shouldCrop(uri)) {
+ val intent = CropImage.activity(uri)
+ .setAspectRatio(512, 288)
+ .setGuidelines(CropImageView.Guidelines.ON_TOUCH)
+ .setAllowFlipping(true)
+ .setAllowRotation(true)
+ .setRequestedSize(512, 288)
+ .getIntent(activity)
+ activity.startActivityForResult(intent, REQUEST_CROP_HEADER_BACKGROUND)
+ } else {
+ val path = saveFile(uri, "header")
+ app.config.ui.headerBackground = path
+ listeners.remove(REQUEST_FILE_HEADER_BACKGROUND)?.invoke(path)
+ }
+ }
+ REQUEST_FILE_APP_BACKGROUND -> {
+ if (uri == null)
+ return
+ if (shouldCrop(uri)) {
+ val intent = CropImage.activity(uri)
+ .setGuidelines(CropImageView.Guidelines.ON_TOUCH)
+ .setAllowFlipping(true)
+ .setAllowRotation(true)
+ .getIntent(activity)
+ activity.startActivityForResult(intent, REQUEST_CROP_APP_BACKGROUND)
+ } else {
+ val path = saveFile(uri, "background")
+ app.config.ui.appBackground = path
+ listeners.remove(REQUEST_FILE_APP_BACKGROUND)?.invoke(path)
+ }
+ }
+ REQUEST_FILE_PROFILE_IMAGE -> {
+ if (uri == null)
+ return
+ if (shouldCrop(uri)) {
+ val intent = CropImage.activity(uri)
+ .setAspectRatio(1, 1)
+ .setCropShape(CropImageView.CropShape.OVAL)
+ .setGuidelines(CropImageView.Guidelines.ON_TOUCH)
+ .setAllowFlipping(true)
+ .setAllowRotation(true)
+ .setRequestedSize(512, 512)
+ .getIntent(activity)
+ activity.startActivityForResult(intent, REQUEST_CROP_PROFILE_IMAGE)
+ } else {
+ val profile =
+ requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return
+ val path = saveFile(uri, "profile${profile.id}")
+ profile.image = path
+ listeners.remove(REQUEST_FILE_PROFILE_IMAGE)?.invoke(profile)
+ }
+ }
+ REQUEST_CROP_HEADER_BACKGROUND -> {
+ uri = CropImage.getActivityResult(data)?.uri ?: return
+ val path = saveFile(uri, "header")
+ app.config.ui.headerBackground = path
+ listeners.remove(REQUEST_FILE_HEADER_BACKGROUND)?.invoke(path)
+ }
+ REQUEST_CROP_APP_BACKGROUND -> {
+ uri = CropImage.getActivityResult(data)?.uri ?: return
+ val path = saveFile(uri, "background")
+ app.config.ui.appBackground = path
+ listeners.remove(REQUEST_FILE_APP_BACKGROUND)?.invoke(path)
+ }
+ REQUEST_CROP_PROFILE_IMAGE -> {
+ uri = CropImage.getActivityResult(data)?.uri ?: return
+ val profile = requestData.remove(REQUEST_FILE_PROFILE_IMAGE) as? Profile ?: return
+ val path = saveFile(uri, "profile${profile.id}")
+ profile.image = path
+ listeners.remove(REQUEST_FILE_PROFILE_IMAGE)?.invoke(profile)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt
index 5cdf30bc..160deb23 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt
@@ -110,6 +110,16 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
get() { mArchiverEnabled = mArchiverEnabled ?: values.get("archiverEnabled", true); return mArchiverEnabled ?: true }
set(value) { set("archiverEnabled", value); mArchiverEnabled = value }
+ private var mValidation: String? = null
+ var validation: String?
+ get() { mValidation = mValidation ?: values["buildValidation"]; return mValidation }
+ set(value) { set("buildValidation", value); mValidation = value }
+
+ private var mApiInvalidCert: String? = null
+ var apiInvalidCert: String?
+ get() { mApiInvalidCert = mApiInvalidCert ?: values["apiInvalidCert"]; return mApiInvalidCert }
+ set(value) { set("apiInvalidCert", value); mApiInvalidCert = value }
+
private var rawEntries: List = db.configDao().getAllNow()
private val profileConfigs: HashMap = hashMapOf()
init {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt
index 153c30c2..5738064c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt
@@ -64,6 +64,30 @@ const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
const val ERROR_CAPTCHA_NEEDED = 3000
const val ERROR_CAPTCHA_LIBRUS_PORTAL = 3001
+const val ERROR_API_PDO_ERROR = 5000
+const val ERROR_API_INVALID_CLIENT = 5001
+const val ERROR_API_INVALID_ARGUMENT = 5002
+const val ERROR_API_INVALID_SIGNATURE = 5003
+const val ERROR_API_MISSING_SCOPES = 5004
+const val ERROR_API_RESOURCE_NOT_FOUND = 5005
+const val ERROR_API_INTERNAL_SERVER_ERROR = 5006
+const val ERROR_API_PHP_E_ERROR = 5007
+const val ERROR_API_PHP_E_WARNING = 5008
+const val ERROR_API_PHP_E_PARSE = 5009
+const val ERROR_API_PHP_E_NOTICE = 5010
+const val ERROR_API_PHP_E_OTHER = 5011
+const val ERROR_API_MAINTENANCE = 5012
+const val ERROR_API_MISSING_ARGUMENT = 5013
+const val ERROR_API_PAYLOAD_EMPTY = 5014
+const val ERROR_API_INVALID_ACTION = 5015
+const val ERROR_API_UPDATE_NOT_FOUND = 5016
+const val ERROR_API_INVALID_DEVICEID_USERCODE = 5017
+const val ERROR_API_INVALID_PAIRTOKEN = 5018
+const val ERROR_API_INVALID_BROWSERID = 5019
+const val ERROR_API_INVALID_DEVICEID = 5020
+const val ERROR_API_INVALID_DEVICEID_BROWSERID = 5021
+const val ERROR_API_HELP_CATEGORY_NOT_FOUND = 5022
+
const val CODE_INTERNAL_LIBRUS_ACCOUNT_410 = 120
const val CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED = 121
const val ERROR_LOGIN_LIBRUS_API_CAPTCHA_NEEDED = 124
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt
index 7a578356..e3692c33 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt
@@ -90,7 +90,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
return
}
- profile.registerName?.let { registerName ->
+ profile.registerName?.also { registerName ->
var status = app.config.sync.registerAvailability[registerName]
if (status == null || status.nextCheckAt < currentTimeUnix()) {
val api = SzkolnyApi(app)
@@ -99,7 +99,11 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
app.config.sync.registerAvailability = availability
status = availability[registerName]
}, onError = {
- taskCallback.onError(it.toApiError(TAG))
+ val apiError = it.toApiError(TAG)
+ if (apiError.errorCode == ERROR_API_INVALID_SIGNATURE) {
+ return@also
+ }
+ taskCallback.onError(apiError)
return
})
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt
index e6d970b8..95d61224 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt
@@ -5,6 +5,7 @@
package pl.szczodrzynski.edziennik.data.api.szkolny
import android.os.Build
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.gson.GsonBuilder
import kotlinx.coroutines.CoroutineScope
@@ -14,9 +15,12 @@ import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.ERROR_API_INVALID_SIGNATURE
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.DateAdapter
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.TimeAdapter
+import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.ApiCacheInterceptor
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor
+import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
import pl.szczodrzynski.edziennik.data.api.szkolny.request.*
import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
@@ -55,6 +59,7 @@ class SzkolnyApi(val app: App) : CoroutineScope {
val okHttpClient: OkHttpClient = app.http.newBuilder()
.followRedirects(true)
.callTimeout(10, SECONDS)
+ .addInterceptor(ApiCacheInterceptor(app))
.addInterceptor(SignatureInterceptor(app))
.build()
@@ -89,11 +94,17 @@ class SzkolnyApi(val app: App) : CoroutineScope {
}
catch (e: Exception) {
withContext(coroutineContext) {
+ val apiError = e.toApiError(TAG)
+ if (apiError.errorCode == ERROR_API_INVALID_SIGNATURE) {
+ Toast.makeText(activity, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
+ return@withContext null
+ }
ErrorDetailsDialog(
activity,
- listOf(e.toApiError(TAG)),
+ listOf(apiError),
R.string.error_occured
)
+ null
}
null
}
@@ -150,6 +161,10 @@ class SzkolnyApi(val app: App) : CoroutineScope {
}
}
+ if (body?.errors?.any { it.toErrorCode() == ERROR_API_INVALID_SIGNATURE } == true) {
+ app.config.apiInvalidCert = Signing.appCertificate.md5()
+ }
+
throw SzkolnyApiException(body?.errors?.firstOrNull())
}
@@ -352,8 +367,10 @@ class SzkolnyApi(val app: App) : CoroutineScope {
@Throws(Exception::class)
fun getRealms(registerName: String): List {
val response = api.fsLoginRealms(registerName).execute()
-
- return parseResponse(response)
+ if (response.isSuccessful && response.body() != null) {
+ return response.body()!!
+ }
+ throw SzkolnyApiException(null)
}
@Throws(Exception::class)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt
index 3fe78910..c4198130 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt
@@ -39,6 +39,6 @@ interface SzkolnyService {
@GET("registerAvailability")
fun registerAvailability(): Call>>
- @GET("fsLogin/{registerName}")
- fun fsLoginRealms(@Path("registerName") registerName: String): Call>>
+ @GET("https://szkolny-eu.github.io/FSLogin/realms/{registerName}.json")
+ fun fsLoginRealms(@Path("registerName") registerName: String): Call>
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/ApiCacheInterceptor.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/ApiCacheInterceptor.kt
new file mode 100644
index 00000000..ac34c6f7
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/ApiCacheInterceptor.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-29.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.szkolny.interceptor
+
+import okhttp3.*
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse
+import pl.szczodrzynski.edziennik.md5
+
+class ApiCacheInterceptor(val app: App) : Interceptor {
+
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val request = chain.request()
+ if (request.url().host() == "api.szkolny.eu"
+ && Signing.appCertificate.md5() == app.config.apiInvalidCert
+ ) {
+ val response = ApiResponse(
+ success = false,
+ errors = listOf(ApiResponse.Error("InvalidSignature", ""))
+ )
+
+ return Response.Builder()
+ .request(request)
+ .protocol(Protocol.HTTP_1_1)
+ .code(401)
+ .message("Unauthorized")
+ .addHeader("Content-Type", "application/json")
+ .body(
+ ResponseBody.create(
+ MediaType.parse("application/json"),
+ app.gson.toJson(response)
+ )
+ )
+ .build()
+ }
+
+ return chain.proceed(request)
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/SignatureInterceptor.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/SignatureInterceptor.kt
index 8d2becf4..30d0ec7e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/SignatureInterceptor.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/SignatureInterceptor.kt
@@ -26,6 +26,8 @@ class SignatureInterceptor(val app: App) : Interceptor {
.header("X-AppVersion", BuildConfig.VERSION_CODE.toString())
.header("X-Timestamp", timestamp.toString())
.header("X-Signature", sign(timestamp, body, url))
+ .header("X-AppBuild", BuildConfig.BUILD_TYPE)
+ .header("X-AppFlavor", BuildConfig.FLAVOR)
.build())
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt
index 5e706467..1ef1c9bb 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt
@@ -46,6 +46,6 @@ object Signing {
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
- return "$param1.MTIzNDU2Nzg5MDAXOgN264===.$param2".sha256()
+ return "$param1.MTIzNDU2Nzg5MDy+5jm3L0===.$param2".sha256()
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt
index c10bab3e..15482c53 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt
@@ -5,10 +5,13 @@
package pl.szczodrzynski.edziennik.data.api.task
import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.api.ERROR_API_INVALID_SIGNATURE
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
+import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApiException
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Notification
import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.toErrorCode
import pl.szczodrzynski.edziennik.utils.models.Date
class AppSync(val app: App, val notifications: MutableList, val profiles: List, val api: SzkolnyApi) {
@@ -27,7 +30,13 @@ class AppSync(val app: App, val notifications: MutableList, val pr
*/
fun run(lastSyncTime: Long, markAsSeen: Boolean = false): Int {
val blacklistedIds = app.db.eventDao().blacklistedIds
- val events = api.getEvents(profiles, notifications, blacklistedIds, lastSyncTime)
+ val events = try {
+ api.getEvents(profiles, notifications, blacklistedIds, lastSyncTime)
+ } catch (e: SzkolnyApiException) {
+ if (e.toErrorCode() == ERROR_API_INVALID_SIGNATURE)
+ return 0
+ throw e
+ }
app.config.sync.lastAppSync = System.currentTimeMillis()
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt
index 67e034c5..88b3ccd1 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt
@@ -8,9 +8,9 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt
index 97513689..3ffdc1b8 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt
@@ -8,9 +8,9 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt
index a532602b..897d53ff 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt
@@ -10,9 +10,9 @@ import androidx.room.RawQuery
import androidx.room.Transaction
import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt
index 4fcfc721..6254f80b 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt
@@ -9,9 +9,9 @@ import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.Transaction
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt
index ad44c0d3..3c752124 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt
@@ -8,9 +8,9 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt
index a0be36ab..51d56854 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt
@@ -8,9 +8,9 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt
index 79bae175..51f3e839 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt
@@ -8,9 +8,9 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Notice
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt
index 1528adf1..f12248b8 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt
@@ -8,9 +8,9 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsence
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt
index cc236dc6..c7cbee12 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt
@@ -8,9 +8,9 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
+import eu.szkolny.selectivedao.annotation.SelectiveDao
+import eu.szkolny.selectivedao.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/FirebaseBroadcastReceiver.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/FirebaseBroadcastReceiver.kt
deleted file mode 100644
index 25c2de48..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/FirebaseBroadcastReceiver.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-1-11.
- */
-
-package pl.szczodrzynski.edziennik.data.firebase
-
-import android.content.Context
-import android.content.Intent
-import android.util.Log
-import androidx.legacy.content.WakefulBroadcastReceiver
-import com.google.gson.JsonObject
-
-class FirebaseBroadcastReceiver : WakefulBroadcastReceiver() {
- companion object {
- private const val TAG = "FirebaseBroadcast"
- }
-
- override fun onReceive(context: Context, intent: Intent) {
- val extras = intent.extras
- val json = JsonObject()
- extras?.keySet()?.forEach { key ->
- extras.get(key)?.let {
- when (it) {
- is String -> json.addProperty(key, it)
- is Int -> json.addProperty(key, it)
- is Long -> json.addProperty(key, it)
- is Float -> json.addProperty(key, it)
- is Boolean -> json.addProperty(key, it)
- else -> json.addProperty(key, it.toString())
- }
- }
- }
- Log.d(TAG, "Intent(action=${intent?.action}, extras=$json)")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/MyFirebaseMessagingService.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/MyFirebaseMessagingService.java
deleted file mode 100644
index 34e341ed..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/MyFirebaseMessagingService.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-1-11.
- */
-
-package pl.szczodrzynski.edziennik.data.firebase;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.AsyncTask;
-
-import com.google.firebase.messaging.FirebaseMessagingService;
-import com.google.firebase.messaging.RemoteMessage;
-
-import java.util.List;
-
-import pl.szczodrzynski.edziennik.App;
-import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask;
-import pl.szczodrzynski.edziennik.data.db.entity.LoginStore;
-import pl.szczodrzynski.edziennik.data.db.entity.Profile;
-
-import static pl.szczodrzynski.edziennik.utils.Utils.d;
-import static pl.szczodrzynski.edziennik.utils.Utils.strToInt;
-
-public class MyFirebaseMessagingService extends FirebaseMessagingService {
- private static final String TAG = "FirebaseMessaging";
-
- @Override
- public void onNewToken(String s) {
- super.onNewToken(s);
-
- /* Log.d(TAG, "New token: "+s);
- App app = (App)getApplicationContext();
- if (app.config.getSync().getTokenApp() == null || !app.config.getSync().getTokenApp().equals(s)) {
- app.config.getSync().setTokenApp(s);
- }*/
- }
-
- @Override
- public void onMessageReceived(RemoteMessage remoteMessage) {
- /*App app = ((App) getApplicationContext());
- // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
-
- String from = remoteMessage.getFrom();
- if (from != null) {
- switch (from) {
- case "640759989760":
- app.debugLog("Firebase got push from App "+remoteMessage.getData().toString());
- //processAppPush
- processAppPush(app, remoteMessage);
- break;
- case "747285019373":
- app.debugLog("Firebase got push from Mobidziennik "+remoteMessage.getData().toString());
- processMobidziennikPush(app, remoteMessage);
- break;
- case "513056078587":
- app.debugLog("Firebase got push from Librus "+remoteMessage.getData().toString());
- processLibrusPush(app, remoteMessage);
- break;
- case "987828170337":
- app.debugLog("Firebase got push from Vulcan "+remoteMessage.getData().toString());
- processVulcanPush(app, remoteMessage);
- break;
- }
- }*/
- }
-
- private void processMobidziennikPush(App app, RemoteMessage remoteMessage) {
- SharedPreferences sharedPreferences = getSharedPreferences("pushtest_mobidziennik", Context.MODE_PRIVATE);
- sharedPreferences.edit().putString(Long.toString(System.currentTimeMillis()), remoteMessage.getData().toString()+"\n"+remoteMessage.toString()+"\n"+remoteMessage.getMessageType()).apply();
- String studentIdStr = remoteMessage.getData().get("id_ucznia");
- if (studentIdStr != null) {
- int studentId = strToInt(studentIdStr);
- AsyncTask.execute(() -> {
- List profileList = app.db.profileDao().getAllNow();
-
- Profile profile = null;
-
- for (Profile profileFull: profileList) {
- if (profileFull.getLoginStoreType() == LoginStore.LOGIN_TYPE_MOBIDZIENNIK
- && studentId == profileFull.getStudentData("studentId", -1)) {
- profile = profileFull;
- break;
- }
- }
-
- if (profile != null) {
- if (remoteMessage.getData().get("id_wiadomosci") != null) {
-
- d(TAG, "Syncing profile " + profile.getId());
- EdziennikTask.Companion.syncProfile(profile.getId(), null, null, null).enqueue(app);
- } else {
- /*app.notifier.add(new Notification(app.getContext(), remoteMessage.getData().get("message"))
- .withProfileData(profile.id, profile.name)
- .withTitle(remoteMessage.getData().get("title"))
- .withType(Notification.TYPE_SERVER_MESSAGE)
- .withFragmentRedirect(MainActivity.DRAWER_ITEM_HOME)
- );
- app.notifier.postAll(profile);
- app.saveConfig("notifications");*/
- d(TAG, "Syncing profile " + profile.getId());
- EdziennikTask.Companion.syncProfile(profile.getId(), null, null, null).enqueue(app);
- }
- }
- });
- }
- }
-
- private void processLibrusPush(App app, RemoteMessage remoteMessage) {
- SharedPreferences sharedPreferences = getSharedPreferences("pushtest_librus", Context.MODE_PRIVATE);
- sharedPreferences.edit().putString(Long.toString(System.currentTimeMillis()), remoteMessage.getData().toString()+"\n"+remoteMessage.toString()+"\n"+remoteMessage.getMessageType()).apply();
- }
-
- private void processVulcanPush(App app, RemoteMessage remoteMessage) {
- SharedPreferences sharedPreferences = getSharedPreferences("pushtest_vulcan", Context.MODE_PRIVATE);
- sharedPreferences.edit().putString(Long.toString(System.currentTimeMillis()), remoteMessage.getData().toString()+"\n"+remoteMessage.toString()+"\n"+remoteMessage.getMessageType()).apply();
- }
-
- private void processAppPush(App app, RemoteMessage remoteMessage) {
- // Check if message contains a data payload.
- /*String type = remoteMessage.getData().get("type");
- if (remoteMessage.getData().size() > 0
- && type != null) {
- //Log.d(TAG, "Message data payload: " + remoteMessage.sync());
- switch (type) {
- case "app_update":
- int versionCode = Integer.parseInt(remoteMessage.getData().get("update_version_code"));
- if (BuildConfig.VERSION_CODE < versionCode) {
- String updateVersion = remoteMessage.getData().get("update_version");
- String updateUrl = remoteMessage.getData().get("update_url");
- String updateFilename = remoteMessage.getData().get("update_filename");
- boolean updateMandatory = Boolean.parseBoolean(remoteMessage.getData().get("update_mandatory"));
- boolean updateDirect = Boolean.parseBoolean(remoteMessage.getData().get("update_direct"));
-
- if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
- app.appConfig.updateVersion = updateVersion;
- app.appConfig.updateUrl = updateUrl;
- app.appConfig.updateFilename = updateFilename;
- app.appConfig.updateMandatory = updateMandatory;
- app.appConfig.updateDirect = updateDirect;
- app.saveConfig("updateVersion", "updateUrl", "updateFilename", "updateMandatory");
- }
- if (!remoteMessage.getData().containsKey("update_silent")) {
- app.notifier.notificationUpdatesShow(
- updateVersion,
- updateUrl,
- updateFilename,
- updateDirect);
- }
- } else {
- if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
- app.appConfig.updateVersion = "";
- app.appConfig.updateMandatory = false;
- app.saveConfig("updateVersion", "updateMandatory");
- }
- app.notifier.notificationUpdatesHide();
- }
- break;
- case "message":
- app.notifier.add(new Notification(app.getContext(), remoteMessage.getData().get("message"))
- .withTitle(remoteMessage.getData().get("title"))
- .withType(pl.szczodrzynski.edziennik.data.db.entity.Notification.TYPE_SERVER_MESSAGE)
- .withFragmentRedirect(MainActivity.DRAWER_ITEM_NOTIFICATIONS)
- );
- app.notifier.postAll();
- app.saveConfig("notifications");
- break;
- case "feedback_message_from_dev":
- AsyncTask.execute(() -> {
- FeedbackMessage feedbackMessage = new FeedbackMessage(true, remoteMessage.getData().get("message"));
- if (feedbackMessage.text.startsWith("test")) {
- // todo
- }
- else {
- feedbackMessage.sentTime = Long.parseLong(remoteMessage.getData().get("sent_time"));
- if (feedbackMessage.text.startsWith("devmode")) {
- app.config.setDevModePassword(feedbackMessage.text.replace("devmode", ""));
- app.checkDevModePassword();
- feedbackMessage.text = "devmode "+(App.devMode ? "allowed" : "disallowed");
- }
- Intent intent = new Intent("pl.szczodrzynski.edziennik.ui.modules.base.FeedbackActivity");
- intent.putExtra("type", "user_chat");
- intent.putExtra("message", app.gson.toJson(feedbackMessage));
- app.sendBroadcast(intent);
- app.db.feedbackMessageDao().add(feedbackMessage);
-
- app.notifier.add(new Notification(app.getContext(), feedbackMessage.text)
- .withTitle(remoteMessage.getData().get("title"))
- .withType(pl.szczodrzynski.edziennik.data.db.entity.Notification.TYPE_FEEDBACK_MESSAGE)
- .withFragmentRedirect(MainActivity.TARGET_FEEDBACK)
- );
- app.notifier.postAll();
- app.saveConfig("notifications");
- }
- });
- break;
- case "feedback_message_from_user":
- AsyncTask.execute(() -> {
- FeedbackMessage feedbackMessage = new FeedbackMessage(true, remoteMessage.getData().get("message"));
- feedbackMessage.fromUser = remoteMessage.getData().get("from_user");
- feedbackMessage.fromUserName = remoteMessage.getData().get("from_user_name");
- feedbackMessage.sentTime = Long.parseLong(remoteMessage.getData().get("sent_time"));
- Intent intent = new Intent("pl.szczodrzynski.edziennik.ui.modules.base.FeedbackActivity");
- intent.putExtra("type", "user_chat");
- intent.putExtra("message", app.gson.toJson(feedbackMessage));
- app.sendBroadcast(intent);
- app.db.feedbackMessageDao().add(feedbackMessage);
- });
- app.notifier.add(new Notification(app.getContext(), remoteMessage.getData().get("message"))
- .withTitle(remoteMessage.getData().get("title"))
- .withType(pl.szczodrzynski.edziennik.data.db.entity.Notification.TYPE_FEEDBACK_MESSAGE)
- .withFragmentRedirect(MainActivity.TARGET_FEEDBACK)
- );
- app.notifier.postAll();
- app.saveConfig("notifications");
- break;
- case "ping":
- // just a ping
- break
- }
- }*/
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/network/NetworkUtils.java b/app/src/main/java/pl/szczodrzynski/edziennik/network/NetworkUtils.java
deleted file mode 100644
index dac636c6..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/network/NetworkUtils.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package pl.szczodrzynski.edziennik.network;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.Build;
-
-import pl.szczodrzynski.edziennik.App;
-
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
-import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
-
-public class NetworkUtils {
- private App app;
-
- public NetworkUtils(App _app)
- {
- this.app = _app;
- }
-
- public boolean isOnline() {
- assert app != null;
- ConnectivityManager cm =
- (ConnectivityManager) app.getSystemService(Context.CONNECTIVITY_SERVICE);
- assert cm != null;
- NetworkInfo netInfo = cm.getActiveNetworkInfo();
- return netInfo != null && netInfo.isConnectedOrConnecting();
- }
-
- public int checkBackgroundDataRestricted() {
-
- ConnectivityManager connMgr = (ConnectivityManager) app.getSystemService(Context.CONNECTIVITY_SERVICE);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- assert connMgr != null;
- switch (connMgr.getRestrictBackgroundStatus()) {
- case RESTRICT_BACKGROUND_STATUS_ENABLED:
- return 2;
-
- case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
- return 1;
-
- case RESTRICT_BACKGROUND_STATUS_DISABLED:
- return 0;
- }
- }
- else
- {
- return 0;
- }
- return 0;
- }
-
- /*public void setSelfSignedSSL(Context mContext, @Nullable String instanceName){
- try {
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- // cert file stored in \app\src\main\assets
- Log.d("ION", "certificate: before");
- AssetManager am = mContext.getAssets();
- InputStream caInput = new BufferedInputStream(am.open("certificate.cer"));
- Log.d("ION", "certificate: after");
-
- Certificate ca = cf.generateCertificate(caInput);
- caInput.close();
-
- KeyStore keyStore = KeyStore.getInstance("BKS");
- keyStore.load(null, null);
- keyStore.setCertificateEntry("ca", ca);
-
- String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
- tmf.init(keyStore);
-
- TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());
-
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, wrappedTrustManagers, null);
-
- AsyncSSLSocketMiddleware sslMiddleWare;
- if(TextUtils.isEmpty(instanceName)){
- sslMiddleWare = Ion.getDefault(mContext).getHttpClient().getSSLSocketMiddleware();
- }else {
- sslMiddleWare = Ion
- .getInstance(mContext, instanceName)
- .getHttpClient().getSSLSocketMiddleware();
- }
- sslMiddleWare.setTrustManagers(wrappedTrustManagers);
- sslMiddleWare.setHostnameVerifier(getHostnameVerifier());
- sslMiddleWare.setSSLContext(sslContext);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
-
- private HostnameVerifier getHostnameVerifier() {
- return new HostnameVerifier() {
- @Override
- public boolean verify(String hostname, SSLSession session) {
- return true;
- // or the following:
- // HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
- // return hv.verify("www.yourserver.com", session);
- }
- };
- }
-
- public TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
- final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
- return new TrustManager[]{
- new X509TrustManager() {
- public X509Certificate[] getAcceptedIssuers() {
- return originalTrustManager.getAcceptedIssuers();
- }
-
- public void checkClientTrusted(X509Certificate[] certs, String authType) {
- try {
- if (certs != null && certs.length > 0){
- certs[0].checkValidity();
- } else {
- originalTrustManager.checkClientTrusted(certs, authType);
- }
- } catch (CertificateException e) {
- Log.w("checkClientTrusted", e.toString());
- }
- }
-
- public void checkServerTrusted(X509Certificate[] certs, String authType) {
- try {
- if (certs != null && certs.length > 0){
- certs[0].checkValidity();
- } else {
- originalTrustManager.checkServerTrusted(certs, authType);
- }
- } catch (CertificateException e) {
- Log.w("checkServerTrusted", e.toString());
- }
- }
- }
- };
- }*/
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/network/TLSSocketFactory.java b/app/src/main/java/pl/szczodrzynski/edziennik/network/TLSSocketFactory.java
deleted file mode 100644
index 7cae49a2..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/network/TLSSocketFactory.java
+++ /dev/null
@@ -1,421 +0,0 @@
-package pl.szczodrzynski.edziennik.network;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.channels.SocketChannel;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.net.ssl.HandshakeCompletedListener;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-
-/**
- * Enables TLS v1.2 when creating SSLSockets.
- *
- * For some reason, android supports TLS v1.2 from API 16, but enables it by
- * default only from API 20.
- * @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
- * @see SSLSocketFactory
- */
-public class TLSSocketFactory extends SSLSocketFactory {
- private static final String[] TLS_V12 = {"TLSv1.2"};
- private static final String[] TLS_V11_V12 = {"TLSv1.1", "TLSv1.2"};
- private static final String[] TLS_V10_V11_V12 = {"TLSv1", "TLSv1.1", "TLSv1.2"};
-
- private final SSLSocketFactory delegate;
-
- public TLSSocketFactory(SSLSocketFactory base) {
- this.delegate = base;
- }
-
- @Override
- public String[] getDefaultCipherSuites() {
- return delegate.getDefaultCipherSuites();
- }
-
- @Override
- public String[] getSupportedCipherSuites() {
- return delegate.getSupportedCipherSuites();
- }
-
- @Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
- return patch(delegate.createSocket(s, host, port, autoClose));
- }
-
- @Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- return patch(delegate.createSocket(host, port));
- }
-
- @Override
- public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
- return patch(delegate.createSocket(host, port, localHost, localPort));
- }
-
- @Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- return patch(delegate.createSocket(host, port));
- }
-
- @Override
- public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
- return patch(delegate.createSocket(address, port, localAddress, localPort));
- }
-
- private Socket patch(Socket socket) {
- if (socket instanceof SSLSocket) {
- ((SSLSocket) socket).setEnabledProtocols(TLS_V10_V11_V12);
- //socket = new NoSSLv3SSLSocket((SSLSocket) socket);
- }
- return socket;
- }
-
-
- public class DelegateSSLSocket extends SSLSocket {
-
- protected final SSLSocket delegate;
-
- DelegateSSLSocket(SSLSocket delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public String[] getSupportedCipherSuites() {
- return delegate.getSupportedCipherSuites();
- }
-
- @Override
- public String[] getEnabledCipherSuites() {
- return delegate.getEnabledCipherSuites();
- }
-
- @Override
- public void setEnabledCipherSuites(String[] suites) {
- delegate.setEnabledCipherSuites(suites);
- }
-
- @Override
- public String[] getSupportedProtocols() {
- return delegate.getSupportedProtocols();
- }
-
- @Override
- public String[] getEnabledProtocols() {
- return delegate.getEnabledProtocols();
- }
-
- @Override
- public void setEnabledProtocols(String[] protocols) {
- delegate.setEnabledProtocols(protocols);
- }
-
- @Override
- public SSLSession getSession() {
- return delegate.getSession();
- }
-
- @Override
- public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
- delegate.addHandshakeCompletedListener(listener);
- }
-
- @Override
- public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
- delegate.removeHandshakeCompletedListener(listener);
- }
-
- @Override
- public void startHandshake() throws IOException {
- delegate.startHandshake();
- }
-
- @Override
- public void setUseClientMode(boolean mode) {
- delegate.setUseClientMode(mode);
- }
-
- @Override
- public boolean getUseClientMode() {
- return delegate.getUseClientMode();
- }
-
- @Override
- public void setNeedClientAuth(boolean need) {
- delegate.setNeedClientAuth(need);
- }
-
- @Override
- public void setWantClientAuth(boolean want) {
- delegate.setWantClientAuth(want);
- }
-
- @Override
- public boolean getNeedClientAuth() {
- return delegate.getNeedClientAuth();
- }
-
- @Override
- public boolean getWantClientAuth() {
- return delegate.getWantClientAuth();
- }
-
- @Override
- public void setEnableSessionCreation(boolean flag) {
- delegate.setEnableSessionCreation(flag);
- }
-
- @Override
- public boolean getEnableSessionCreation() {
- return delegate.getEnableSessionCreation();
- }
-
- @Override
- public void bind(SocketAddress localAddr) throws IOException {
- delegate.bind(localAddr);
- }
-
- @Override
- public synchronized void close() throws IOException {
- delegate.close();
- }
-
- @Override
- public void connect(SocketAddress remoteAddr) throws IOException {
- delegate.connect(remoteAddr);
- }
-
- @Override
- public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
- delegate.connect(remoteAddr, timeout);
- }
-
- @Override
- public SocketChannel getChannel() {
- return delegate.getChannel();
- }
-
- @Override
- public InetAddress getInetAddress() {
- return delegate.getInetAddress();
- }
-
- @Override
- public InputStream getInputStream() throws IOException {
- return delegate.getInputStream();
- }
-
- @Override
- public boolean getKeepAlive() throws SocketException {
- return delegate.getKeepAlive();
- }
-
- @Override
- public InetAddress getLocalAddress() {
- return delegate.getLocalAddress();
- }
-
- @Override
- public int getLocalPort() {
- return delegate.getLocalPort();
- }
-
- @Override
- public SocketAddress getLocalSocketAddress() {
- return delegate.getLocalSocketAddress();
- }
-
- @Override
- public boolean getOOBInline() throws SocketException {
- return delegate.getOOBInline();
- }
-
- @Override
- public OutputStream getOutputStream() throws IOException {
- return delegate.getOutputStream();
- }
-
- @Override
- public int getPort() {
- return delegate.getPort();
- }
-
- @Override
- public synchronized int getReceiveBufferSize() throws SocketException {
- return delegate.getReceiveBufferSize();
- }
-
- @Override
- public SocketAddress getRemoteSocketAddress() {
- return delegate.getRemoteSocketAddress();
- }
-
- @Override
- public boolean getReuseAddress() throws SocketException {
- return delegate.getReuseAddress();
- }
-
- @Override
- public synchronized int getSendBufferSize() throws SocketException {
- return delegate.getSendBufferSize();
- }
-
- @Override
- public int getSoLinger() throws SocketException {
- return delegate.getSoLinger();
- }
-
- @Override
- public synchronized int getSoTimeout() throws SocketException {
- return delegate.getSoTimeout();
- }
-
- @Override
- public boolean getTcpNoDelay() throws SocketException {
- return delegate.getTcpNoDelay();
- }
-
- @Override
- public int getTrafficClass() throws SocketException {
- return delegate.getTrafficClass();
- }
-
- @Override
- public boolean isBound() {
- return delegate.isBound();
- }
-
- @Override
- public boolean isClosed() {
- return delegate.isClosed();
- }
-
- @Override
- public boolean isConnected() {
- return delegate.isConnected();
- }
-
- @Override
- public boolean isInputShutdown() {
- return delegate.isInputShutdown();
- }
-
- @Override
- public boolean isOutputShutdown() {
- return delegate.isOutputShutdown();
- }
-
- @Override
- public void sendUrgentData(int value) throws IOException {
- delegate.sendUrgentData(value);
- }
-
- @Override
- public void setKeepAlive(boolean keepAlive) throws SocketException {
- delegate.setKeepAlive(keepAlive);
- }
-
- @Override
- public void setOOBInline(boolean oobinline) throws SocketException {
- delegate.setOOBInline(oobinline);
- }
-
- @Override
- public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
- delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
- }
-
- @Override
- public synchronized void setReceiveBufferSize(int size) throws SocketException {
- delegate.setReceiveBufferSize(size);
- }
-
- @Override
- public void setReuseAddress(boolean reuse) throws SocketException {
- delegate.setReuseAddress(reuse);
- }
-
- @Override
- public synchronized void setSendBufferSize(int size) throws SocketException {
- delegate.setSendBufferSize(size);
- }
-
- @Override
- public void setSoLinger(boolean on, int timeout) throws SocketException {
- delegate.setSoLinger(on, timeout);
- }
-
- @Override
- public synchronized void setSoTimeout(int timeout) throws SocketException {
- delegate.setSoTimeout(timeout);
- }
-
- @Override
- public void setTcpNoDelay(boolean on) throws SocketException {
- delegate.setTcpNoDelay(on);
- }
-
- @Override
- public void setTrafficClass(int value) throws SocketException {
- delegate.setTrafficClass(value);
- }
-
- @Override
- public void shutdownInput() throws IOException {
- delegate.shutdownInput();
- }
-
- @Override
- public void shutdownOutput() throws IOException {
- delegate.shutdownOutput();
- }
-
- @Override
- public String toString() {
- return delegate.toString();
- }
-
- @Override
- public boolean equals(Object o) {
- return delegate.equals(o);
- }
- }
-
- private class NoSSLv3SSLSocket extends DelegateSSLSocket {
-
- private NoSSLv3SSLSocket(SSLSocket delegate) {
- super(delegate);
-
- }
-
- @Override
- public void setEnabledProtocols(String[] protocols) {
- if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {
-
- List enabledProtocols = new ArrayList<>(Arrays.asList(delegate.getEnabledProtocols()));
- if (enabledProtocols.size() > 1) {
- if (enabledProtocols.remove("SSLv3")) {
- System.out.println("Removed SSLv3 from enabled protocols");
- }
- else {
- System.out.println("SSLv3 was not an enabled protocol");
- }
- } else {
- System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
- }
- protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
- }
-
- super.setEnabledProtocols(protocols);
- }
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/DialogExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/DialogExtensions.kt
new file mode 100644
index 00000000..5bf46d16
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/DialogExtensions.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-30.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs
+
+import android.text.InputType
+import android.view.LayoutInflater
+import androidx.core.view.isVisible
+import androidx.core.widget.addTextChangedListener
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.textfield.TextInputEditText
+import pl.szczodrzynski.edziennik.databinding.DialogEditTextBinding
+import pl.szczodrzynski.edziennik.isNotNullNorBlank
+
+fun MaterialAlertDialogBuilder.input(
+ message: CharSequence? = null,
+ type: Int = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE,
+ hint: CharSequence? = null,
+ value: CharSequence? = null,
+ changeListener: ((editText: TextInputEditText, input: String) -> Boolean)? = null,
+ positiveButton: Int? = null,
+ positiveListener: ((editText: TextInputEditText, input: String) -> Boolean)? = null
+): MaterialAlertDialogBuilder {
+ val b = DialogEditTextBinding.inflate(LayoutInflater.from(context), null, false)
+ b.title.text = message
+ b.title.isVisible = message.isNotNullNorBlank()
+ b.text1.hint = hint
+ b.text1.inputType = type
+ b.text1.setText(value)
+ b.text1.addTextChangedListener { text ->
+ if (changeListener?.invoke(b.text1, text?.toString() ?: "") != false)
+ b.text1.error = null
+ }
+ if (positiveButton != null) {
+ setPositiveButton(positiveButton) { dialog, _ ->
+ if (positiveListener?.invoke(b.text1, b.text1.text?.toString() ?: "") != false)
+ dialog.dismiss()
+ }
+ }
+ setView(b.root)
+
+ return this
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt
index 6ecd494f..b9e733b8 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/RegisterUnavailableDialog.kt
@@ -8,7 +8,7 @@ import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
-import coil.api.load
+import coil.load
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt
new file mode 100644
index 00000000..13dcb6f9
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-20.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.bell
+
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.widget.addTextChangedListener
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.textfield.TextInputEditText
+import com.google.android.material.textfield.TextInputLayout
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.utils.models.Time
+import kotlin.coroutines.CoroutineContext
+
+class BellSyncConfigDialog(
+ val activity: AppCompatActivity,
+ val onChangeListener: (() -> Unit)? = null,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "BellSyncConfigDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+
+ private fun parse(input: String): Pair? {
+ if (input.length < 8) {
+ return null
+ }
+ if (input[2] != ':' || input[5] != ':') {
+ return null
+ }
+ val multiplier = when {
+ input[0] == '+' -> 1
+ input[0] == '-' -> -1
+ else -> return null
+ }
+ val time = Time.fromH_m_s("0" + input.substring(1))
+
+ return time to multiplier
+ }
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ onShowListener?.invoke(TAG)
+ app = activity.applicationContext as App
+
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.bell_sync_title)
+ .setView(R.layout.dialog_edit_text)
+ .setPositiveButton(R.string.ok, null)
+ .setNegativeButton(R.string.cancel, null)
+ .setNeutralButton(R.string.reset) { _, _ ->
+ app.config.timetable.bellSyncDiff = null
+ app.config.timetable.bellSyncMultiplier = 0
+ onChangeListener?.invoke()
+ }
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
+
+ val message = dialog.findViewById(android.R.id.title)
+ val editText = dialog.findViewById(android.R.id.text1)
+ val textLayout = dialog.findViewById(R.id.text_input_layout)
+
+ message?.setText(R.string.bell_sync_adjust_content)
+ editText?.hint = "±H:MM:SS"
+ editText?.setText(app.config.timetable.bellSyncDiff?.let {
+ (if (app.config.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS
+ } ?: "+0:00:00")
+ editText?.addTextChangedListener { text ->
+ val input = text?.toString()
+ textLayout?.error =
+ if (input != null && parse(input) == null)
+ activity.getString(R.string.bell_sync_adjust_error)
+ else
+ null
+ }
+
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.onClick {
+ val input = editText?.text?.toString() ?: return@onClick
+ val parsed = parse(input)
+ if (parsed == null) {
+ Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show()
+ return@onClick
+ }
+
+ val (time, multiplier) = parsed
+ app.config.timetable.bellSyncDiff =
+ if (time.value == 0)
+ null
+ else
+ time
+ app.config.timetable.bellSyncMultiplier = multiplier
+
+ onChangeListener?.invoke()
+ dialog.dismiss()
+ }
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt
index c6a7b2f9..e5b7768d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/day/DayDialog.kt
@@ -10,8 +10,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.android.synthetic.main.row_lesson_change_item.view.*
-import kotlinx.android.synthetic.main.row_teacher_absence_item.view.*
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
@@ -111,7 +109,7 @@ class DayDialog(
}
lessonChanges.ifNotEmpty {
- b.lessonChangeContainer.visibility = View.VISIBLE
+ b.lessonChangeContainer.root.visibility = View.VISIBLE
b.lessonChangeContainer.lessonChangeCount.text = it.size.toString()
b.lessonChangeLayout.onClick {
@@ -130,7 +128,7 @@ class DayDialog(
}
teacherAbsences.ifNotEmpty {
- b.teacherAbsenceContainer.visibility = View.VISIBLE
+ b.teacherAbsenceContainer.root.visibility = View.VISIBLE
b.teacherAbsenceContainer.teacherAbsenceCount.text = it.size.toString()
b.teacherAbsenceLayout.onClick {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt
index 06b5f1a6..97e34009 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt
@@ -33,7 +33,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
-import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationEnableDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog
import pl.szczodrzynski.edziennik.ui.modules.views.TimeDropdown.Companion.DISPLAY_LESSONS
import pl.szczodrzynski.edziennik.utils.Anim
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
@@ -64,7 +64,7 @@ class EventManualDialog(
private val app by lazy { activity.application as App }
private lateinit var b: DialogEventManualV2Binding
private lateinit var dialog: AlertDialog
- private var profile: Profile? = null
+ private lateinit var profile: Profile
private var customColor: Int? = null
private val editingShared = editingEvent?.sharedBy != null
@@ -80,11 +80,11 @@ class EventManualDialog(
private var progressDialog: AlertDialog? = null
- init { run {
+ init { launch {
if (activity.isFinishing)
- return@run
+ return@launch
onShowListener?.invoke(TAG)
- EventBus.getDefault().register(this)
+ EventBus.getDefault().register(this@EventManualDialog)
b = DialogEventManualV2Binding.inflate(activity.layoutInflater)
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.dialog_event_manual_title)
@@ -236,8 +236,15 @@ class EventManualDialog(
progressDialog?.dismiss()
}
- private fun loadLists() { launch {
- profile = withContext(Dispatchers.Default) { app.db.profileDao().getByIdNow(profileId) }
+ private fun loadLists() = launch {
+ val profile = withContext(Dispatchers.Default) {
+ app.db.profileDao().getByIdNow(profileId)
+ }
+ if (profile == null) {
+ Toast.makeText(activity, R.string.event_manual_no_profile, Toast.LENGTH_SHORT).show()
+ return@launch
+ }
+ this@EventManualDialog.profile = profile
with (b.dateDropdown) {
db = app.db
@@ -378,9 +385,9 @@ class EventManualDialog(
customColor = color
}
})
- colorPickerDialog.show(activity.fragmentManager, "color-picker-dialog")
+ colorPickerDialog.show(activity.supportFragmentManager, "color-picker-dialog")
}
- }}
+ }
private fun showRemoveEventDialog() {
val shareNotice = when {
@@ -417,12 +424,11 @@ class EventManualDialog(
val share = b.shareSwitch.isChecked
- if (share && profile?.registration != Profile.REGISTRATION_ENABLED) {
- RegistrationEnableDialog(activity, profileId).showEventShareDialog {
- if (it != null)
- profile = it
- saveEvent()
- }
+ if (share && profile.registration != Profile.REGISTRATION_ENABLED) {
+ RegistrationConfigDialog(activity, profile, onChangeListener = { enabled ->
+ if (enabled)
+ saveEvent()
+ }).showEventShareDialog()
return
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt
index 4877413f..5b9579ed 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt
@@ -13,7 +13,6 @@ import pl.szczodrzynski.edziennik.data.db.full.GradeFull
import pl.szczodrzynski.edziennik.databinding.DialogGradeDetailsBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.setTintColor
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt
similarity index 99%
rename from app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt
index e74f3577..20325447 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt
@@ -2,7 +2,7 @@
* Copyright (c) Kacper Ziubryniewicz 2020-1-16
*/
-package pl.szczodrzynski.edziennik.ui.dialogs.settings
+package pl.szczodrzynski.edziennik.ui.dialogs.grade
import android.annotation.SuppressLint
import androidx.appcompat.app.AlertDialog
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/home/StudentNumberDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/home/StudentNumberDialog.kt
index 265bd17b..3f3f8176 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/home/StudentNumberDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/home/StudentNumberDialog.kt
@@ -5,12 +5,11 @@
package pl.szczodrzynski.edziennik.ui.dialogs.home
import android.text.InputType
-import android.widget.Toast
-import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
-import com.afollestad.materialdialogs.MaterialDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.ui.dialogs.input
class StudentNumberDialog(
val activity: AppCompatActivity,
@@ -22,25 +21,27 @@ class StudentNumberDialog(
private const val TAG = "StudentNumberDialog"
}
- private lateinit var dialog: AlertDialog
-
init { run {
if (activity.isFinishing)
return@run
onShowListener?.invoke(TAG)
- MaterialDialog.Builder(activity)
- .title(R.string.card_lucky_number_set_title)
- .content(R.string.card_lucky_number_set_text)
- .inputType(InputType.TYPE_CLASS_NUMBER)
- .input(null, if (profile.studentNumber == -1) "" else profile.studentNumber.toString()) { _: MaterialDialog?, input: CharSequence ->
- try {
- profile.studentNumber = input.toString().toInt()
- } catch (e: Exception) {
- Toast.makeText(activity, R.string.incorrect_format, Toast.LENGTH_SHORT).show()
- }
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.card_lucky_number_set_title)
+ .input(
+ message = activity.getString(R.string.card_lucky_number_set_text),
+ type = InputType.TYPE_CLASS_NUMBER,
+ hint = null,
+ value = if (profile.studentNumber == -1) null else profile.studentNumber.toString(),
+ positiveButton = R.string.ok,
+ positiveListener = { _, input ->
+ profile.studentNumber = input.toIntOrNull() ?: -1
+ true
}
- .dismissListener {
- onDismissListener?.invoke(TAG)
- }.show()
+ )
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
}}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt
new file mode 100644
index 00000000..e9204090
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileConfigDialog.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-23.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.profile
+
+import android.content.res.ColorStateList
+import androidx.appcompat.app.AlertDialog
+import androidx.core.widget.addTextChangedListener
+import com.google.android.material.color.MaterialColors
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.shape.MaterialShapeDrawable
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.databinding.DialogProfileConfigBinding
+import kotlin.coroutines.CoroutineContext
+
+class ProfileConfigDialog(
+ val activity: MainActivity,
+ val profile: Profile,
+ val onProfileSaved: ((profile: Profile) -> Unit)? = null,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "ProfileConfigDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var b: DialogProfileConfigBinding
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+ private var profileChanged = false
+ private var profileRemoved = false
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ onShowListener?.invoke(TAG)
+ app = activity.applicationContext as App
+ b = DialogProfileConfigBinding.inflate(activity.layoutInflater)
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setView(b.root)
+ .setPositiveButton(R.string.close, null)
+ .setOnDismissListener {
+ if (!profileRemoved && profileChanged) {
+ app.profileSave(profile)
+ onProfileSaved?.invoke(profile)
+ }
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
+
+ b.profile = profile
+ profile.applyImageTo(b.image)
+
+ // I can't believe how simple it is to get the dialog's background color !!
+ val shape = MaterialShapeDrawable(activity, null, R.attr.alertDialogStyle, R.style.MaterialAlertDialog_MaterialComponents)
+ val surface = MaterialColors.getColor(activity, R.attr.colorSurface, TAG)
+ shape.setCornerSize(18.dp.toFloat())
+ shape.initializeElevationOverlay(activity)
+ shape.fillColor = ColorStateList.valueOf(surface)
+ shape.elevation = 16.dp.toFloat()
+ b.circleView.background = shape
+
+ b.nameEdit.addTextChangedListener {
+ profileChanged = true
+ }
+
+ b.syncSwitch.onChange { _, _ ->
+ profileChanged = true
+ }
+
+ b.imageButton.onClick {
+ activity.requestHandler.requestProfileImage(profile) {
+ val profile = it as? Profile ?: return@requestProfileImage
+ if (this@ProfileConfigDialog.profile == profile) {
+ profileChanged = true
+ b.profile = profile
+ b.image.setImageDrawable(profile.getImageDrawable(activity))
+ }
+ }
+ }
+
+ b.logoutButton.onClick {
+ ProfileRemoveDialog(activity, profile.id, profile.name) {
+ profileRemoved = true
+ dialog.dismiss()
+ }
+ }
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ProfileRemoveDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileRemoveDialog.kt
similarity index 95%
rename from app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ProfileRemoveDialog.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileRemoveDialog.kt
index 1fa16230..7071f00d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ProfileRemoveDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/profile/ProfileRemoveDialog.kt
@@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
*/
-package pl.szczodrzynski.edziennik.ui.dialogs.settings
+package pl.szczodrzynski.edziennik.ui.dialogs.profile
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
@@ -18,7 +18,8 @@ class ProfileRemoveDialog(
val activity: MainActivity,
val profileId: Int,
val profileName: String,
- val noProfileRemoval: Boolean = false
+ val noProfileRemoval: Boolean = false,
+ val onRemove: (() -> Unit)? = null
) : CoroutineScope {
companion object {
private const val TAG = "ProfileRemoveDialog"
@@ -95,5 +96,6 @@ class ProfileRemoveDialog(
dialog.dismiss()
activity.reloadTarget()
Toast.makeText(activity, R.string.dialog_profile_remove_success, Toast.LENGTH_LONG).show()
+ onRemove?.invoke()
}}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt
new file mode 100644
index 00000000..6db33e70
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-19.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.settings
+
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.*
+import kotlin.coroutines.CoroutineContext
+
+class AppLanguageDialog(
+ val activity: AppCompatActivity,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "AppLanguageDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ onShowListener?.invoke(TAG)
+ app = activity.applicationContext as App
+
+ val languages = mapOf(
+ null to R.string.language_system,
+ "pl" to R.string.language_polish,
+ "en" to R.string.language_english,
+ "de" to R.string.language_german
+ )
+ val languageIds = languages.map { it.key }
+ val languageNames = languages.map {
+ activity.getString(it.value)
+ }
+
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.app_language_dialog_title)
+ //.setMessage(R.string.settings_about_language_dialog_text)
+ .setSingleChoiceItems(
+ languageNames.toTypedArray(),
+ languageIds.indexOf(app.config.ui.language),
+ null
+ )
+ .setPositiveButton(R.string.ok) { _, _ ->
+ val which = dialog.listView.checkedItemPosition
+
+ app.config.ui.language = languageIds[which]
+ activity.recreate()
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt
new file mode 100644
index 00000000..61e95a8b
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-18.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.settings
+
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.MainActivity
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_NOTIFICATIONS
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_SETTINGS
+import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
+import pl.szczodrzynski.edziennik.R
+import kotlin.coroutines.CoroutineContext
+
+class MiniMenuConfigDialog(
+ val activity: AppCompatActivity,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "MiniMenuConfigDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ onShowListener?.invoke(TAG)
+ app = activity.applicationContext as App
+
+ val buttons = mapOf(
+ DRAWER_ITEM_HOME to R.string.menu_home_page,
+ DRAWER_ITEM_TIMETABLE to R.string.menu_timetable,
+ DRAWER_ITEM_AGENDA to R.string.menu_agenda,
+ DRAWER_ITEM_GRADES to R.string.menu_grades,
+ DRAWER_ITEM_MESSAGES to R.string.menu_messages,
+ DRAWER_ITEM_HOMEWORK to R.string.menu_homework,
+ DRAWER_ITEM_BEHAVIOUR to R.string.menu_notices,
+ DRAWER_ITEM_ATTENDANCE to R.string.menu_attendance,
+ DRAWER_ITEM_ANNOUNCEMENTS to R.string.menu_announcements,
+ DRAWER_ITEM_NOTIFICATIONS to R.string.menu_notifications,
+ DRAWER_ITEM_SETTINGS to R.string.menu_settings
+ )
+ val miniMenuButtons = app.config.ui.miniMenuButtons
+
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.settings_theme_mini_drawer_buttons_dialog_title)
+ //.setMessage(R.string.settings_theme_mini_drawer_buttons_dialog_text)
+ .setMultiChoiceItems(
+ buttons.map { activity.getString(it.value) }.toTypedArray(),
+ buttons.map { it.key in miniMenuButtons }.toBooleanArray(),
+ null
+ )
+ .setPositiveButton(R.string.ok) { _, _ ->
+ app.config.ui.miniMenuButtons =
+ buttons.keys.mapIndexedNotNull { index, id ->
+ if (dialog.listView.checkedItemPositions[index])
+ id
+ else
+ null
+ }
+
+ if (activity is MainActivity) {
+ activity.setDrawerItems()
+ activity.drawer.updateBadges()
+ }
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt
new file mode 100644
index 00000000..ca9b2f11
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-18.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.settings
+
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.utils.Themes
+import kotlin.coroutines.CoroutineContext
+
+class ThemeChooserDialog(
+ val activity: AppCompatActivity,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "ThemeChooserDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ onShowListener?.invoke(TAG)
+ app = activity.applicationContext as App
+
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.settings_theme_theme_text)
+ .setSingleChoiceItems(
+ Themes.getThemeNames(activity).toTypedArray(),
+ Themes.themeIndex,
+ null
+ )
+ .setPositiveButton(R.string.ok) { _, _ ->
+ val which = dialog.listView.checkedItemPosition
+
+ val theme = Themes.themeList[which]
+ if (app.config.ui.theme == theme.id)
+ return@setPositiveButton
+ app.config.ui.theme = theme.id
+ Themes.themeIndex = which
+ activity.recreate()
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt
new file mode 100644
index 00000000..5c933e20
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-20.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.sync
+
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.timepicker.MaterialTimePicker
+import com.google.android.material.timepicker.TimeFormat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.utils.models.Time
+import kotlin.coroutines.CoroutineContext
+
+class QuietHoursConfigDialog(
+ val activity: AppCompatActivity,
+ val onChangeListener: (() -> Unit)? = null,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "QuietHoursConfigDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ onShowListener?.invoke(TAG)
+ app = activity.applicationContext as App
+
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.settings_sync_quiet_hours_dialog_title)
+ .setItems(arrayOf(
+ activity.getString(R.string.settings_sync_quiet_hours_set_beginning),
+ activity.getString(R.string.settings_sync_quiet_hours_set_end)
+ )) { dialog, which ->
+ when (which) {
+ 0 -> configStartTime()
+ 1 -> configEndTime()
+ }
+ dialog.dismiss()
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
+ }}
+
+ private fun configStartTime() {
+ onShowListener?.invoke(TAG + "Start")
+
+ val time = app.config.sync.quietHoursStart ?: return
+ val picker = MaterialTimePicker.Builder()
+ .setTitleText(R.string.settings_sync_quiet_hours_set_beginning)
+ .setTimeFormat(TimeFormat.CLOCK_24H)
+ .setHour(time.hour)
+ .setMinute(time.minute)
+ .build()
+
+ picker.show(activity.supportFragmentManager, TAG)
+ picker.addOnPositiveButtonClickListener {
+ app.config.sync.quietHoursEnabled = true
+ app.config.sync.quietHoursStart = Time(picker.hour, picker.minute, 0)
+ onChangeListener?.invoke()
+ }
+ picker.addOnDismissListener {
+ onDismissListener?.invoke(TAG + "Start")
+ }
+ }
+
+ private fun configEndTime() {
+ onShowListener?.invoke(TAG + "End")
+
+ val time = app.config.sync.quietHoursEnd ?: return
+ val picker = MaterialTimePicker.Builder()
+ .setTitleText(R.string.settings_sync_quiet_hours_set_end)
+ .setTimeFormat(TimeFormat.CLOCK_24H)
+ .setHour(time.hour)
+ .setMinute(time.minute)
+ .build()
+
+ picker.show(activity.supportFragmentManager, TAG)
+ picker.addOnPositiveButtonClickListener {
+ app.config.sync.quietHoursEnabled = true
+ app.config.sync.quietHoursEnd = Time(picker.hour, picker.minute, 0)
+ onChangeListener?.invoke()
+ }
+ picker.addOnDismissListener {
+ onDismissListener?.invoke(TAG + "End")
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt
new file mode 100644
index 00000000..fff65b43
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2020-3-15.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.sync
+
+import android.text.Html
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.*
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
+import pl.szczodrzynski.edziennik.data.api.task.AppSync
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import kotlin.coroutines.CoroutineContext
+
+class RegistrationConfigDialog(
+ val activity: AppCompatActivity,
+ val profile: Profile,
+ val onChangeListener: ((enabled: Boolean) -> Unit)? = null,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "RegistrationEnableDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ app = activity.applicationContext as App
+ }}
+
+ fun showEventShareDialog() {
+ onShowListener?.invoke(TAG + "EventShare")
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.registration_config_event_sharing_title)
+ .setMessage(R.string.registration_config_event_sharing_text)
+ .setPositiveButton(R.string.i_agree) { _, _ ->
+ enableRegistration()
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG + "EventShare")
+ }
+ .show()
+ }
+
+ fun showEnableDialog() {
+ onShowListener?.invoke(TAG + "Enable")
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.registration_config_title)
+ .setMessage(Html.fromHtml(app.getString(R.string.registration_config_enable_text)))
+ .setPositiveButton(R.string.i_agree) { _, _ ->
+ enableRegistration()
+ }
+ .setNegativeButton(R.string.i_disagree, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG + "Enable")
+ }
+ .show()
+ }
+
+ fun showDisableDialog() {
+ onShowListener?.invoke(TAG + "Disable")
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.registration_config_title)
+ .setMessage(Html.fromHtml(app.getString(R.string.registration_config_disable_text)))
+ .setPositiveButton(R.string.ok) { _, _ ->
+ disableRegistration()
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG + "Disable")
+ }
+ .show()
+ }
+
+ private fun enableRegistration() = launch {
+ onShowListener?.invoke(TAG + "Enabling")
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.please_wait)
+ .setMessage(R.string.registration_config_enable_progress_text)
+ .setCancelable(false)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG + "Enabling")
+ }
+ .show()
+
+ withContext(Dispatchers.Default) {
+ profile.registration = Profile.REGISTRATION_ENABLED
+
+ // force full registration of the user
+ App.config.getFor(profile.id).hash = ""
+
+ SzkolnyApi(app).runCatching(activity) {
+ AppSync(app, mutableListOf(), listOf(profile), this).run(
+ 0L,
+ markAsSeen = true
+ )
+ }
+ app.db.profileDao().add(profile)
+ if (profile.id == App.profileId) {
+ App.profile.registration = profile.registration
+ }
+ }
+
+ dialog.dismiss()
+ onChangeListener?.invoke(true)
+ }
+
+ private fun disableRegistration() = launch {
+ onShowListener?.invoke(TAG + "Disabling")
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.please_wait)
+ .setMessage(R.string.registration_config_disable_progress_text)
+ .setCancelable(false)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG + "Disabling")
+ }
+ .show()
+
+ withContext(Dispatchers.Default) {
+ profile.registration = Profile.REGISTRATION_DISABLED
+
+ SzkolnyApi(app).runCatching(activity) {
+ unregisterAppUser(profile.userCode)
+ }
+ app.db.profileDao().add(profile)
+ if (profile.id == App.profileId) {
+ App.profile.registration = profile.registration
+ }
+ }
+
+ dialog.dismiss()
+ onChangeListener?.invoke(false)
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt
deleted file mode 100644
index 7fc0caf3..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-3-15.
- */
-
-package pl.szczodrzynski.edziennik.ui.dialogs.sync
-
-import android.text.Html
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.app.AppCompatActivity
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.coroutines.*
-import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.R
-import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
-import pl.szczodrzynski.edziennik.data.api.task.AppSync
-import pl.szczodrzynski.edziennik.data.db.entity.Profile
-import kotlin.coroutines.CoroutineContext
-
-class RegistrationEnableDialog(
- val activity: AppCompatActivity,
- val profileId: Int
-) : CoroutineScope {
- companion object {
- private const val TAG = "RegistrationEnableDialog"
- }
-
- private lateinit var app: App
-
- private val job = Job()
- override val coroutineContext: CoroutineContext
- get() = job + Dispatchers.Main
-
- // local variables go here
- private var progressDialog: AlertDialog? = null
-
- init { run {
- if (activity.isFinishing)
- return@run
- app = activity.applicationContext as App
- }}
-
- fun showEventShareDialog(onSuccess: (profile: Profile?) -> Unit) {
- MaterialAlertDialogBuilder(activity)
- .setTitle(R.string.event_manual_need_registration_title)
- .setMessage(R.string.event_manual_need_registration_text)
- .setPositiveButton(R.string.ok) { dialog, which ->
- enableRegistration(onSuccess)
- }
- .setNegativeButton(R.string.cancel, null)
- .show()
- }
-
- fun showEnableDialog(onSuccess: (profile: Profile?) -> Unit) {
- MaterialAlertDialogBuilder(activity)
- .setTitle(R.string.registration_enable_dialog_title)
- .setMessage(Html.fromHtml(app.getString(R.string.registration_enable_dialog_text)))
- .setPositiveButton(R.string.ok) { dialog, which ->
- enableRegistration(onSuccess)
- }
- .setNegativeButton(R.string.cancel, null)
- .show()
- }
-
- private fun enableRegistration(onSuccess: (profile: Profile?) -> Unit) { launch {
- progressDialog = MaterialAlertDialogBuilder(activity)
- .setTitle(R.string.please_wait)
- .setMessage(R.string.registration_enable_progress_text)
- .setCancelable(false)
- .show()
-
- val profile = withContext(Dispatchers.Default) {
- val profile = app.db.profileDao().getByIdNow(profileId) ?: return@withContext null
- profile.registration = Profile.REGISTRATION_ENABLED
-
- // force full registration of the user
- App.config.getFor(profile.id).hash = ""
-
- AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run(0L, markAsSeen = true)
- app.db.profileDao().add(profile)
- if (profile.id == App.profileId) {
- App.profile.registration = profile.registration
- }
- return@withContext profile
- }
-
- progressDialog?.dismiss()
- onSuccess(profile)
- }}
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt
new file mode 100644
index 00000000..6f4f027b
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-20.
+ */
+
+package pl.szczodrzynski.edziennik.ui.dialogs.sync
+
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.*
+import kotlin.coroutines.CoroutineContext
+
+class SyncIntervalDialog(
+ val activity: AppCompatActivity,
+ val onChangeListener: (() -> Unit)? = null,
+ val onShowListener: ((tag: String) -> Unit)? = null,
+ val onDismissListener: ((tag: String) -> Unit)? = null
+) : CoroutineScope {
+ companion object {
+ private const val TAG = "SyncIntervalDialog"
+ }
+
+ private lateinit var app: App
+ private lateinit var dialog: AlertDialog
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ // local variables go here
+
+ init { run {
+ if (activity.isFinishing)
+ return@run
+ onShowListener?.invoke(TAG)
+ app = activity.applicationContext as App
+
+ val intervals = listOf(
+ 30 * MINUTE,
+ 45 * MINUTE,
+ 60 * MINUTE,
+ 90 * MINUTE,
+ 2 * HOUR,
+ 3 * HOUR,
+ 4 * HOUR,
+ 6 * HOUR,
+ 10 * HOUR
+ )
+ val intervalNames = intervals.map {
+ activity.getSyncInterval(it.toInt())
+ }
+
+ dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.settings_sync_sync_interval_dialog_title)
+ //.setMessage(R.string.settings_sync_sync_interval_dialog_text)
+ .setSingleChoiceItems(
+ intervalNames.toTypedArray(),
+ intervals.indexOf(app.config.sync.interval.toLong()),
+ null
+ )
+ .setPositiveButton(R.string.ok) { _, _ ->
+ val which = dialog.listView.checkedItemPosition
+
+ val interval = intervals[which]
+ app.config.sync.interval = interval.toInt()
+ onChangeListener?.invoke()
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .setOnDismissListener {
+ onDismissListener?.invoke(TAG)
+ }
+ .show()
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/GenerateBlockTimetableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/GenerateBlockTimetableDialog.kt
index aefd16f9..c93d5a6e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/GenerateBlockTimetableDialog.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/GenerateBlockTimetableDialog.kt
@@ -18,8 +18,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView
import androidx.core.content.FileProvider
+import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@@ -107,25 +107,27 @@ class GenerateBlockTimetableDialog(
.show()
dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.onClick {
- when (b.weekSelectionRadioGroup.checkedRadioButtonId) {
- R.id.withChangesCurrentWeekRadio -> generateBlockTimetable(weekCurrentStart, weekCurrentEnd)
- R.id.withChangesNextWeekRadio -> generateBlockTimetable(weekNextStart, weekNextEnd)
- R.id.forSelectedWeekRadio -> selectDate()
+ app.permissionManager.requestStoragePermission(activity, permissionMessage = R.string.permissions_generate_timetable) {
+ when (b.weekSelectionRadioGroup.checkedRadioButtonId) {
+ R.id.withChangesCurrentWeekRadio -> generateBlockTimetable(weekCurrentStart, weekCurrentEnd)
+ R.id.withChangesNextWeekRadio -> generateBlockTimetable(weekNextStart, weekNextEnd)
+ R.id.forSelectedWeekRadio -> selectDate()
+ }
}
}
}}
private fun selectDate() {
- val date = Date.getToday()
- DatePickerDialog
- .newInstance({ _, year, monthOfYear, dayOfMonth ->
- val dateSelected = Date(year, monthOfYear, dayOfMonth)
+ MaterialDatePicker.Builder.datePicker()
+ .setCalendarConstraints(app.profile.getSchoolYearConstrains())
+ .build()
+ .apply {
+ addOnPositiveButtonClickListener { millis ->
+ val dateSelected = Date.fromMillisUtc(millis)
generateBlockTimetable(dateSelected.weekStart, dateSelected.weekEnd)
- }, date.year, date.month, date.day)
- .apply {
- accentColor = R.attr.colorPrimary.resolveAttr(this@GenerateBlockTimetableDialog.activity)
- show(this@GenerateBlockTimetableDialog.activity.supportFragmentManager, "DatePickerDialog")
}
+ }
+ .show(activity.supportFragmentManager, TAG)
}
@Subscribe(threadMode = ThreadMode.MAIN)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt
index ec212cea..367b00da 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/agenda/AgendaFragment.kt
@@ -16,12 +16,11 @@ import com.github.tibolte.agendacalendarview.CalendarPickerController
import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent
import com.github.tibolte.agendacalendarview.models.CalendarEvent
import com.github.tibolte.agendacalendarview.models.IDayItem
-import com.mikepenz.iconics.IconicsColor
import com.mikepenz.iconics.IconicsDrawable
-import com.mikepenz.iconics.IconicsSize
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
+import com.mikepenz.iconics.utils.colorInt
+import com.mikepenz.iconics.utils.sizeDp
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
@@ -89,7 +88,7 @@ class AgendaFragment : Fragment(), CoroutineScope {
}),
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_agenda_change_view)
- .withIcon(if (type == Profile.AGENDA_DEFAULT) CommunityMaterial.Icon.cmd_calendar_outline else CommunityMaterial.Icon.cmd_format_list_bulleted_square)
+ .withIcon(if (type == Profile.AGENDA_DEFAULT) CommunityMaterial.Icon.cmd_calendar_outline else CommunityMaterial.Icon2.cmd_format_list_bulleted_square)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
type = if (type == Profile.AGENDA_DEFAULT) Profile.AGENDA_CALENDAR else Profile.AGENDA_DEFAULT
@@ -111,7 +110,7 @@ class AgendaFragment : Fragment(), CoroutineScope {
activity.navView.bottomBar.fabEnable = true
activity.navView.bottomBar.fabExtendedText = getString(R.string.add)
- activity.navView.bottomBar.fabIcon = Icon2.cmd_plus
+ activity.navView.bottomBar.fabIcon = CommunityMaterial.Icon3.cmd_plus
activity.navView.setFabOnClickListener(View.OnClickListener {
EventManualDialog(activity, app.profileId, defaultDate = actualDate)
})
@@ -278,10 +277,11 @@ class AgendaFragment : Fragment(), CoroutineScope {
val unreadEventDates = mutableSetOf()
events.forEach { event ->
- val eventIcon = IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_checkbox_blank_circle)
- .size(IconicsSize.dp(10))
- .color(IconicsColor.colorInt(event.eventColor))
+ val eventIcon = IconicsDrawable(activity).apply {
+ icon = CommunityMaterial.Icon.cmd_checkbox_blank_circle
+ sizeDp = 10
+ colorInt = event.eventColor
+ }
dayList.add(EventDay(event.startTimeCalendar, eventIcon))
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/announcements/AnnouncementsFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/announcements/AnnouncementsFragment.java
index 9529f268..d8cdbc2c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/announcements/AnnouncementsFragment.java
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/announcements/AnnouncementsFragment.java
@@ -14,7 +14,7 @@ import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.afollestad.materialdialogs.MaterialDialog;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
import org.greenrobot.eventbus.EventBus;
@@ -120,7 +120,7 @@ public class AnnouncementsFragment extends Fragment {
return;
}*/
AnnouncementsAdapter announcementsAdapter = new AnnouncementsAdapter(activity, announcements, (v, announcement) -> {
- if (announcement.getText() == null || (app.getProfile().getLoginStoreType() == LOGIN_TYPE_LIBRUS && !announcement.getSeen() && app.getNetworkUtils().isOnline())) {
+ if (announcement.getText() == null || (app.getProfile().getLoginStoreType() == LOGIN_TYPE_LIBRUS && !announcement.getSeen())) {
EdziennikTask.Companion.announcementGet(App.Companion.getProfileId(), announcement).enqueue(requireContext());
} else {
showAnnouncementDetailsDialog(announcement);
@@ -161,12 +161,12 @@ public class AnnouncementsFragment extends Fragment {
}
private void showAnnouncementDetailsDialog(AnnouncementFull announcement) {
- MaterialDialog dialog = new MaterialDialog.Builder(activity)
- .title(announcement.getSubject())
- .customView(R.layout.dialog_announcement, true)
- .positiveText(R.string.ok)
+ DialogAnnouncementBinding b = DialogAnnouncementBinding.inflate(LayoutInflater.from(activity), null, false);
+ new MaterialAlertDialogBuilder(activity)
+ .setTitle(announcement.getSubject())
+ .setView(b.getRoot())
+ .setPositiveButton(R.string.ok, null)
.show();
- DialogAnnouncementBinding b = DialogAnnouncementBinding.bind(dialog.getCustomView());
b.text.setText(announcement.getTeacherName() +"\n\n"+ (announcement.getStartDate() != null ? announcement.getStartDate().getFormattedString() : "-") + (announcement.getEndDate() != null ? " do " + announcement.getEndDate().getFormattedString() : "")+"\n\n" +announcement.getText());
if (!announcement.getSeen() && app.getProfile().getLoginStoreType() != LOGIN_TYPE_LIBRUS) {
announcement.setSeen(true);
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt
index 0af177f9..194f36d2 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment.kt
@@ -60,7 +60,7 @@ class AttendanceFragment : Fragment(), CoroutineScope {
activity.bottomSheet.prependItems(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_attendance_config)
- .withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
+ .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
AttendanceConfigDialog(activity, true, null, null)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment_.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment_.java
deleted file mode 100644
index c46b3e09..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/attendance/AttendanceFragment_.java
+++ /dev/null
@@ -1,361 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.attendance;
-
-import android.graphics.Color;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.LongSparseArray;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.widget.PopupMenu;
-import androidx.core.graphics.ColorUtils;
-import androidx.databinding.DataBindingUtil;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
-
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import antonkozyriatskyi.circularprogressindicator.CircularProgressIndicator;
-import pl.szczodrzynski.edziennik.App;
-import pl.szczodrzynski.edziennik.MainActivity;
-import pl.szczodrzynski.edziennik.R;
-import pl.szczodrzynski.edziennik.data.db.entity.Subject;
-import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull;
-import pl.szczodrzynski.edziennik.databinding.FragmentAttendanceBinding;
-import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration;
-import pl.szczodrzynski.edziennik.utils.Themes;
-import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
-
-import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static pl.szczodrzynski.edziennik.data.db.entity.Attendance.TYPE_ABSENT;
-import static pl.szczodrzynski.edziennik.data.db.entity.Attendance.TYPE_ABSENT_EXCUSED;
-import static pl.szczodrzynski.edziennik.data.db.entity.Attendance.TYPE_BELATED;
-import static pl.szczodrzynski.edziennik.data.db.entity.Attendance.TYPE_BELATED_EXCUSED;
-import static pl.szczodrzynski.edziennik.data.db.entity.Attendance.TYPE_PRESENT;
-import static pl.szczodrzynski.edziennik.data.db.entity.Attendance.TYPE_RELEASED;
-import static pl.szczodrzynski.edziennik.data.db.entity.LoginStore.LOGIN_TYPE_VULCAN;
-import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ATTENDANCE;
-
-public class AttendanceFragment_ extends Fragment {
-
- private App app = null;
- private MainActivity activity = null;
- private FragmentAttendanceBinding b = null;
-
- private int displayMode = MODE_YEAR;
- private static final int MODE_YEAR = 0;
- private static final int MODE_SEMESTER_1 = 1;
- private static final int MODE_SEMESTER_2 = 2;
- private long subjectIdFilter = -1;
- private LongSparseArray subjectTotalCount;
- private LongSparseArray subjectAbsentCount;
- private LongSparseArray subjectAttendancePercentage;
-
- private List attendanceList = null;
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- activity = (MainActivity) getActivity();
- if (getActivity() == null || getContext() == null)
- return null;
- app = (App) activity.getApplication();
- getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
- // activity, context and profile is valid
- b = DataBindingUtil.inflate(inflater, R.layout.fragment_attendance, container, false);
- b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
- return b.getRoot();
- }
-
- @Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- if (app == null || activity == null || b == null || !isAdded())
- return;
-
- activity.getBottomSheet().prependItems(
- new BottomSheetPrimaryItem(true)
- .withTitle(R.string.menu_mark_as_read)
- .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
- .withOnClickListener(v3 -> {
- activity.getBottomSheet().close();
- AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_ATTENDANCE, true));
- Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
- })
- );
-
- /*b.refreshLayout.setOnRefreshListener(() -> {
- activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_ATTENDANCE, b.refreshLayout);
- });*/
-
- b.attendancePercentage.setProgressTextAdapter(PERCENTAGE_ADAPTER);
- b.attendancePercentage.setMaxProgress(100.0f);
-
- b.attendanceSummaryTitle.setOnClickListener((v -> {
- PopupMenu popupMenu = new PopupMenu(activity, b.attendanceSummaryTitle, Gravity.END);
- popupMenu.getMenu().add(0, 0, 0, R.string.summary_mode_year);
- popupMenu.getMenu().add(0, 1, 1, R.string.summary_mode_semester_1);
- popupMenu.getMenu().add(0, 2, 2, R.string.summary_mode_semester_2);
- popupMenu.setOnMenuItemClickListener((item -> {
- displayMode = item.getItemId();
- updateList();
- return true;
- }));
- popupMenu.show();
- }));
-
- /*if (app.profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK) {
- long attendanceLastSync = app.profile.getStudentData("attendanceLastSync", (long)0);
- if (attendanceLastSync == 0) {
- attendanceLastSync = app.profile.getSemesterStart(1).getInMillis();
- }
- Date lastSyncDate = Date.fromMillis(attendanceLastSync);
- if (lastSyncDate.getValue() < Week.getWeekStart().getValue()) {
- CafeBar.builder(activity)
- .to(activity.getNavView().getCoordinator())
- .content(R.string.sync_old_data_info)
- .icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_download_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
- .positiveText(R.string.refresh)
- .positiveColor(0xff4caf50)
- .negativeText(R.string.ok)
- .negativeColor(0x66ffffff)
- .onPositive((cafeBar -> {
- if (!activity.getSwipeRefreshLayout().isRefreshing()) {
- cafeBar.dismiss();
- activity.syncCurrentFeature();
- }
- else {
- Toast.makeText(app, R.string.please_wait, Toast.LENGTH_SHORT).show();
- }
- }))
- .onNegative(CafeBar::dismiss)
- .autoDismiss(false)
- .swipeToDismiss(true)
- .floating(true)
- .show();
- }
- }*/
-
- b.attendanceSummarySubject.setOnClickListener((v -> {
- AsyncTask.execute(() -> {
- List subjectList = App.db.subjectDao().getAllNow(App.Companion.getProfileId());
- PopupMenu popupMenu = new PopupMenu(activity, b.attendanceSummarySubject, Gravity.END);
- popupMenu.getMenu().add(0, -1, 0, R.string.subject_filter_disabled);
- int index = 0;
- DecimalFormat format = new DecimalFormat("0.00");
- for (Subject subject: subjectList) {
- int total = subjectTotalCount.get(subject.id, new int[3])[displayMode];
- int absent = subjectAbsentCount.get(subject.id, new int[3])[displayMode];
- if (total == 0)
- continue;
- int present = total - absent;
- float percentage = (float)present / (float)total * 100.0f;
- String percentageStr = format.format(percentage);
- popupMenu.getMenu().add(0, (int)subject.id, index++, getString(R.string.subject_filter_format, subject.longName, percentageStr));
- }
- popupMenu.setOnMenuItemClickListener((item -> {
- subjectIdFilter = item.getItemId();
- b.attendanceSummarySubject.setText(item.getTitle().toString().replaceAll("\\s-\\s[0-9]{1,2}\\.[0-9]{1,2}%", ""));
- updateList();
- return true;
- }));
- new Handler(activity.getMainLooper()).post(popupMenu::show);
- });
-
- }));
-
- LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
-
- b.attendanceView.setHasFixedSize(true);
- b.attendanceView.setLayoutManager(linearLayoutManager);
- b.attendanceView.addItemDecoration(new SimpleDividerItemDecoration(getContext()));
-
- b.attendanceView.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
- if (recyclerView.canScrollVertically(-1)) {
- b.refreshLayout.setEnabled(false);
- }
- if (!recyclerView.canScrollVertically(-1) && newState == SCROLL_STATE_IDLE) {
- b.refreshLayout.setEnabled(true);
- }
- }
- });
-
- App.db.attendanceDao().getAll(App.Companion.getProfileId()).observe(this, attendance -> {
- if (app == null || activity == null || b == null || !isAdded())
- return;
-
- if (attendance == null) {
- b.attendanceView.setVisibility(View.GONE);
- b.attendanceNoData.setVisibility(View.VISIBLE);
- return;
- }
-
- attendanceList = attendance;
-
- countSubjectStats();
-
- updateList();
- });
- }
-
- private void countSubjectStats() {
- subjectTotalCount = new LongSparseArray<>();
- subjectAbsentCount = new LongSparseArray<>();
- for (AttendanceFull attendance: attendanceList) {
- if (app.getProfile().getLoginStoreType() == LOGIN_TYPE_VULCAN && attendance.getBaseType() == TYPE_RELEASED)
- continue;
- int[] subjectTotal = subjectTotalCount.get(attendance.getSubjectId(), new int[3]);
- int[] subjectAbsent = subjectAbsentCount.get(attendance.getSubjectId(), new int[3]);
-
- subjectTotal[0]++;
- subjectTotal[attendance.getSemester()]++;
-
- if (attendance.getBaseType() == TYPE_ABSENT || attendance.getBaseType() == TYPE_ABSENT_EXCUSED) {
- subjectAbsent[0]++;
- subjectAbsent[attendance.getSemester()]++;
- }
-
- subjectTotalCount.put(attendance.getSubjectId(), subjectTotal);
- subjectAbsentCount.put(attendance.getSubjectId(), subjectAbsent);
- }
- }
-
- private void updateList() {
- if (app == null || activity == null || b == null || !isAdded())
- return;
-
- int presentCount = 0;
- int absentCount = 0;
- int absentUnexcusedCount = 0;
- int belatedCount = 0;
- int releasedCount = 0;
-
- List filteredList = new ArrayList<>();
- for (AttendanceFull attendance: attendanceList) {
- if (displayMode != MODE_YEAR && attendance.getSemester() != displayMode)
- continue;
- if (subjectIdFilter != -1 && attendance.getSubjectId() != subjectIdFilter)
- continue;
- if (attendance.getBaseType() != TYPE_PRESENT)
- filteredList.add(attendance);
- switch (attendance.getBaseType()) {
- case TYPE_PRESENT:
- presentCount++;
- break;
- case TYPE_ABSENT:
- absentCount++;
- absentUnexcusedCount++;
- break;
- case TYPE_ABSENT_EXCUSED:
- absentCount++;
- break;
- case TYPE_BELATED_EXCUSED:
- case TYPE_BELATED:
- belatedCount++;
- break;
- case TYPE_RELEASED:
- releasedCount++;
- break;
- }
- }
- if (filteredList.size() > 0) {
- AttendanceAdapter adapter;
- b.attendanceView.setVisibility(View.VISIBLE);
- b.attendanceNoData.setVisibility(View.GONE);
- if ((adapter = (AttendanceAdapter) b.attendanceView.getAdapter()) != null) {
- //adapter.setItems(filteredList);
- adapter.notifyDataSetChanged();
- }
- else {
- //adapter = new AttendanceAdapter(activity, true, null);
- //adapter.setItems(filteredList);
- b.attendanceView.setAdapter(adapter);
- }
- }
- else {
- b.attendanceView.setVisibility(View.GONE);
- b.attendanceNoData.setVisibility(View.VISIBLE);
- }
-
- // SUMMARY
- if (displayMode == MODE_YEAR) {
- b.attendanceSummaryTitle.setText(getString(R.string.attendance_summary_title_year));
- }
- else {
- b.attendanceSummaryTitle.setText(getString(R.string.attendance_summary_title_semester_format, displayMode));
- }
- b.presentCountContainer.setVisibility(presentCount == 0 ? View.GONE : View.VISIBLE);
- b.presentCount.setText(String.format(Locale.getDefault(), "%d", presentCount));
- b.absentCount.setText(String.format(Locale.getDefault(), "%d", absentCount));
- b.absentUnexcusedCount.setText(String.format(Locale.getDefault(), "%d", absentUnexcusedCount));
- b.belatedCount.setText(String.format(Locale.getDefault(), "%d", belatedCount));
- b.releasedCount.setText(String.format(Locale.getDefault(), "%d", releasedCount));
- if (absentUnexcusedCount >= 5) {
- b.absentUnexcusedCount.setTextColor(Color.RED);
- }
- else {
- b.absentUnexcusedCount.setTextColor(Themes.INSTANCE.getPrimaryTextColor(activity));
- }
-
- float attendancePercentage;
-
- // in Mobidziennik there are no TYPE_PRESENT records so we cannot calculate the percentage
- if (app.getProfile().getLoginStoreType() == LOGIN_TYPE_VULCAN) {
- float allCount = presentCount + absentCount + belatedCount; // do not count releases
- float present = allCount - absentCount;
- attendancePercentage = present / allCount * 100.0f;
- }
- else {
- float allCount = presentCount + absentCount + belatedCount + releasedCount;
- float present = allCount - absentCount;
- attendancePercentage = present / allCount * 100.0f;
- }
- // if it's still 0%, hide the indicator
- if (attendancePercentage <= 0.0f) {
- b.attendancePercentage.setVisibility(View.GONE);
- return;
- }
- animatePercentageIndicator(attendancePercentage);
- }
-
- private void animatePercentageIndicator(float percentage) {
- Animation a = new Animation() {
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- float progress = percentage *interpolatedTime;
- if (interpolatedTime == 1.0f) {
- progress = percentage;
- }
- int color = ColorUtils.blendARGB(Color.RED, Color.GREEN, progress/100.0f);
- b.attendancePercentage.setTextColor(color);
- b.attendancePercentage.setProgressColor(color);
- b.attendancePercentage.setCurrentProgress(progress);
- }
- public boolean willChangeBounds() {
- return true;
- }
- };
- a.setDuration(1300);
- a.setInterpolator(new AccelerateDecelerateInterpolator());
- b.attendancePercentage.postDelayed(() -> b.attendancePercentage.startAnimation(a), 500);
- }
-
- private static final CircularProgressIndicator.ProgressTextAdapter PERCENTAGE_ADAPTER = value -> {
- DecimalFormat df = new DecimalFormat("0.##");
- return df.format(value)+"%";
- };
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/BuildInvalidActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/BuildInvalidActivity.kt
new file mode 100644
index 00000000..766c79ad
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/BuildInvalidActivity.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-27.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.base
+
+import android.graphics.Color
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isVisible
+import com.mikepenz.iconics.utils.colorInt
+import pl.szczodrzynski.edziennik.databinding.ActivityBuildInvalidBinding
+import pl.szczodrzynski.edziennik.onClick
+import pl.szczodrzynski.edziennik.utils.Themes
+
+class BuildInvalidActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setTheme(Themes.themeInt)
+ val b = ActivityBuildInvalidBinding.inflate(layoutInflater, null, false)
+ setContentView(b.root)
+
+ setSupportActionBar(b.toolbar)
+
+ b.icon.icon?.colorInt = intent.getIntExtra("color", Color.GREEN)
+ b.message.text = intent.getStringExtra("message")
+ b.closeButton.isVisible = !intent.getBooleanExtra("isCritical", true)
+ b.closeButton.onClick {
+ finish()
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/CrashActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/CrashActivity.kt
index bf8eab06..0b39b913 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/CrashActivity.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/CrashActivity.kt
@@ -12,7 +12,7 @@ import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import cat.ereza.customactivityoncrash.CustomActivityOnCrash
-import com.afollestad.materialdialogs.MaterialDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.BuildConfig
@@ -69,47 +69,31 @@ class CrashActivity : AppCompatActivity(), CoroutineScope {
val restartButton = findViewById(R.id.crash_restart_btn)
restartButton.setOnClickListener { CustomActivityOnCrash.restartApplication(this@CrashActivity, config) }
- val devMessageButton = findViewById(R.id.crash_dev_message_btn)
- devMessageButton.setOnClickListener {
- val i = Intent(this@CrashActivity, CrashGtfoActivity::class.java)
- startActivity(i)
- }
-
val reportButton = findViewById(R.id.crash_report_btn)
reportButton.setOnClickListener {
- if (!app.networkUtils.isOnline) {
- MaterialDialog.Builder(this@CrashActivity)
- .title(R.string.network_you_are_offline_title)
- .content(R.string.network_you_are_offline_text)
- .positiveText(R.string.ok)
- .show()
- } else {
- launch {
- api.runCatching({
- withContext(Dispatchers.Default) {
- errorReport(listOf(getReportableError(intent)))
- }
- }, {
- Toast.makeText(app, getString(R.string.crash_report_cannot_send) + it, Toast.LENGTH_LONG).show()
- }) ?: return@launch
+ launch {
+ api.runCatching({
+ withContext(Dispatchers.Default) {
+ errorReport(listOf(getReportableError(intent)))
+ }
+ }, {
+ Toast.makeText(app, getString(R.string.crash_report_cannot_send) + it, Toast.LENGTH_LONG).show()
+ }) ?: return@launch
- Toast.makeText(app, getString(R.string.crash_report_sent), Toast.LENGTH_SHORT).show()
- reportButton.isEnabled = false
- reportButton.setTextColor(resources.getColor(android.R.color.darker_gray))
- }
+ Toast.makeText(app, getString(R.string.crash_report_sent), Toast.LENGTH_SHORT).show()
+ reportButton.isEnabled = false
+ reportButton.setTextColor(resources.getColor(android.R.color.darker_gray))
}
}
val moreInfoButton = findViewById(R.id.crash_details_btn)
- moreInfoButton.setOnClickListener { v: View? ->
- MaterialDialog.Builder(this@CrashActivity)
- .title(R.string.crash_details)
- .content(Html.fromHtml(getErrorString(intent, false)))
- .typeface(null, "RobotoMono-Regular.ttf")
- .positiveText(R.string.close)
- .neutralText(R.string.copy_to_clipboard)
- .onNeutral { _, _ -> copyErrorToClipboard() }
- .show()
+ moreInfoButton.setOnClickListener {
+ MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialogMonospace)
+ .setTitle(R.string.crash_details)
+ .setMessage(Html.fromHtml(getErrorString(intent, false)))
+ .setPositiveButton(R.string.close, null)
+ .setNeutralButton(R.string.copy_to_clipboard) { _, _ -> copyErrorToClipboard() }
+ .show()
}
val errorInformation = CustomActivityOnCrash.getAllErrorDetailsFromIntent(this@CrashActivity, intent)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/CrashGtfoActivity.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/CrashGtfoActivity.java
deleted file mode 100644
index b2aa0174..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/CrashGtfoActivity.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.base;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-import pl.szczodrzynski.edziennik.R;
-
-public class CrashGtfoActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setTheme((getApplication()
- .getSharedPreferences(getString(R.string.preference_file_global), Context.MODE_PRIVATE)
- .getBoolean("dark_theme", false) ? R.style.AppTheme_Dark : R.style.AppTheme));
- setContentView(R.layout.activity_gtfo);
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/LoadingFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/LoadingFragment.kt
deleted file mode 100644
index b5626fa4..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/LoadingFragment.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.base
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import pl.szczodrzynski.edziennik.databinding.FragmentLoadingBinding
-import pl.szczodrzynski.edziennik.utils.Themes
-
-class LoadingFragment : Fragment() {
-
- private lateinit var b: FragmentLoadingBinding
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- if (context == null)
- return null
- context!!.theme.applyStyle(Themes.appTheme, true)
- // activity, context and profile is valid
- b = FragmentLoadingBinding.inflate(inflater)
- return b.root
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt
index f495d61e..a3288da2 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/behaviour/NoticesAdapter.kt
@@ -13,9 +13,9 @@ import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
import com.mikepenz.iconics.utils.colorRes
import com.mikepenz.iconics.utils.sizeDp
+import eu.szkolny.font.SzkolnyFont
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK
@@ -49,17 +49,26 @@ class NoticesAdapter//getting the context and product list with constructor
holder.noticesItemAddedDate.text = Date.fromMillis(notice.addedDate).formattedString
if (notice.type == Notice.TYPE_POSITIVE) {
- holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle_outline)
- .colorRes(R.color.md_green_600)
- .sizeDp(36))
+ holder.noticesItemType.setImageDrawable(
+ IconicsDrawable(context, CommunityMaterial.Icon3.cmd_plus_circle_outline).apply {
+ colorRes = R.color.md_green_600
+ sizeDp = 36
+ }
+ )
} else if (notice.type == Notice.TYPE_NEGATIVE) {
- holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram_outline)
- .colorRes(R.color.md_red_600)
- .sizeDp(36))
+ holder.noticesItemType.setImageDrawable(
+ IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram_outline).apply {
+ colorRes = R.color.md_red_600
+ sizeDp = 36
+ }
+ )
} else {
- holder.noticesItemType.setImageDrawable(IconicsDrawable(context, SzkolnyFont.Icon.szf_message_processing_outline)
- .colorRes(R.color.md_blue_500)
- .sizeDp(36))
+ holder.noticesItemType.setImageDrawable(
+ IconicsDrawable(context, SzkolnyFont.Icon.szf_message_processing_outline).apply {
+ colorRes = R.color.md_blue_500
+ sizeDp = 36
+ }
+ )
}
if (!notice.seen) {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/DebugFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/DebugFragment.java
index 63ef7f51..62d5462b 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/DebugFragment.java
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/DebugFragment.java
@@ -14,7 +14,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
-import com.afollestad.materialdialogs.MaterialDialog;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
import com.google.gson.Gson;
import com.yuyh.jsonviewer.library.JsonRecyclerView;
@@ -211,10 +211,10 @@ public class DebugFragment extends Fragment {
mRecyclerView.bindJson(result);
}
catch (Exception e) {
- new MaterialDialog.Builder(getActivity())
- .title("Result")
- .content(result)
- .positiveText(R.string.ok)
+ new MaterialAlertDialogBuilder(getActivity(), R.style.AppTheme_MaterialAlertDialogMonospace)
+ .setTitle("Result")
+ .setMessage(result)
+ .setPositiveButton(R.string.ok, null)
.show();
}
mRecyclerView.setTextSize(20);
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt
index 29a0b2b3..b1b84f9d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabPageFragment.kt
@@ -16,7 +16,7 @@ import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
import pl.szczodrzynski.fslogin.decode
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabProfileFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabProfileFragment.kt
index 50c64762..ee3ea2c6 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabProfileFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/debug/LabProfileFragment.kt
@@ -10,7 +10,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
-import com.afollestad.materialdialogs.MaterialDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.gson.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -18,6 +18,7 @@ import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.databinding.TemplateListPageFragmentBinding
+import pl.szczodrzynski.edziennik.ui.dialogs.input
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
@@ -87,51 +88,55 @@ class LabProfileFragment : LazyFragment(), CoroutineScope {
else -> objVal.toString()
}
- MaterialDialog.Builder(activity)
- .input("value", value, false) { _, input ->
- val input = input.toString()
- when (parent) {
- is JsonObject -> {
- val v = objVal as JsonPrimitive
- when {
- v.isString -> (parent as JsonObject)[objName] = input
- v.isNumber -> (parent as JsonObject)[objName] = input.toLong()
- v.isBoolean -> (parent as JsonObject)[objName] = input.toBoolean()
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(item.key)
+ .input(
+ hint = "value",
+ value = value,
+ positiveButton = R.string.ok,
+ positiveListener = { _, input ->
+ when (parent) {
+ is JsonObject -> {
+ val v = objVal as JsonPrimitive
+ when {
+ v.isString -> (parent as JsonObject)[objName] = input
+ v.isNumber -> (parent as JsonObject)[objName] = input.toLong()
+ v.isBoolean -> (parent as JsonObject)[objName] = input.toBoolean()
+ }
+ }
+ is JsonArray -> {
+
+ }
+ is HashMap<*, *> -> app.config.set(objName, input)
+ else -> {
+ val field = parent::class.java.getDeclaredField(objName)
+ field.isAccessible = true
+ val newVal = when (objVal) {
+ is Int -> input.toInt()
+ is Boolean -> input.toBoolean()
+ is Float -> input.toFloat()
+ is Char -> input.toCharArray()[0]
+ is String -> input
+ is Long -> input.toLong()
+ is Double -> input.toDouble()
+ else -> input
+ }
+ field.set(parent, newVal)
}
}
- is JsonArray -> {
+ when (item.key.substringBefore(":")) {
+ "App.profile" -> app.profileSave()
+ "App.profile.studentData" -> app.profileSave()
+ "App.profile.loginStore" -> app.db.loginStoreDao().add(loginStore)
}
- is HashMap<*, *> -> app.config.set(objName, input)
- else -> {
- val field = parent::class.java.getDeclaredField(objName)
- field.isAccessible = true
- val newVal = when (objVal) {
- is Int -> input.toInt()
- is Boolean -> input.toBoolean()
- is Float -> input.toFloat()
- is Char -> input.toCharArray()[0]
- is String -> input
- is Long -> input.toLong()
- is Double -> input.toDouble()
- else -> input
- }
- field.set(parent, newVal)
- }
+
+ showJson()
+
+ return@input true
}
-
- when (item.key.substringBefore(":")) {
- "App.profile" -> app.profileSave()
- "App.profile.studentData" -> app.profileSave()
- "App.profile.loginStore" -> app.db.loginStoreDao().add(loginStore)
- }
-
- showJson()
-
- }
- .title(item.key)
- .positiveText(R.string.ok)
- .negativeText(R.string.cancel)
+ )
+ .setNegativeButton(R.string.cancel, null)
.show()
}
catch (e: Exception) {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt
index 63f7500f..3c33be8d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/FeedbackFragment.kt
@@ -14,8 +14,8 @@ import android.widget.PopupMenu
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
-import coil.Coil
-import coil.api.load
+import coil.imageLoader
+import coil.request.ImageRequest
import com.github.bassaer.chatmessageview.model.IChatUser
import com.github.bassaer.chatmessageview.model.Message
import com.github.bassaer.chatmessageview.view.ChatView
@@ -34,14 +34,6 @@ import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.Utils.openUrl
import java.util.*
-import kotlin.collections.List
-import kotlin.collections.any
-import kotlin.collections.filter
-import kotlin.collections.firstOrNull
-import kotlin.collections.forEach
-import kotlin.collections.forEachIndexed
-import kotlin.collections.isNotEmpty
-import kotlin.collections.mutableMapOf
import kotlin.collections.set
import kotlin.coroutines.CoroutineContext
@@ -221,13 +213,15 @@ class FeedbackFragment : Fragment(), CoroutineScope {
Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888).also { bmp ->
launch {
Log.d(TAG, "Created image for $userName")
- Coil.load(activity, image) {
- target {
+ val request = ImageRequest.Builder(activity)
+ .data(image)
+ .target {
val canvas = Canvas(bmp)
it.setBounds(0, 0, bmp.width, bmp.height)
it.draw(canvas)
}
- }
+ .build()
+ activity.imageLoader.enqueue(request)
}
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/HelpFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/HelpFragment.kt
deleted file mode 100644
index e7dfb5cc..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/feedback/HelpFragment.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.feedback
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.R
-import pl.szczodrzynski.edziennik.MainActivity
-import pl.szczodrzynski.edziennik.databinding.FragmentHelpBinding
-import pl.szczodrzynski.edziennik.utils.Themes
-
-class HelpFragment : Fragment() {
-
- private lateinit var app: App
- private lateinit var activity: MainActivity
- private lateinit var b: FragmentHelpBinding
-/*
- private val navController: NavController by lazy { Navigation.findNavController(b.root) }
-*/
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- activity = (getActivity() as MainActivity?) ?: return null
- if (context == null)
- return null
- app = activity.application as App
- context!!.theme.applyStyle(Themes.appTheme, true)
- if (app.profile == null)
- return inflater.inflate(R.layout.fragment_loading, container, false)
- // activity, context and profile is valid
- b = FragmentHelpBinding.inflate(inflater)
- return b.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- // TODO check if app, activity, b can be null
- if (app.profile == null || !isAdded)
- return
-
-
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt
index 33d69c60..63521e97 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt
@@ -15,7 +15,6 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.MainActivity.Companion.TARGET_GRADES_EDITOR
@@ -24,7 +23,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE
import pl.szczodrzynski.edziennik.data.db.full.GradeFull
import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSemester
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats
@@ -71,7 +70,7 @@ class GradesListFragment : Fragment(), CoroutineScope {
val adapter = GradesAdapter(activity)
var firstRun = true
- app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(this@GradesListFragment, Observer { grades -> this@GradesListFragment.launch {
+ app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(viewLifecycleOwner, Observer { grades -> this@GradesListFragment.launch {
if (!isAdded) return@launch
val items = when {
@@ -135,7 +134,7 @@ class GradesListFragment : Fragment(), CoroutineScope {
activity.bottomSheet.prependItems(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_grades_config)
- .withIcon(Icon2.cmd_settings_outline)
+ .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
GradesConfigDialog(activity, true, null, null)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt
index 6520ce54..2d90f4f9 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt
@@ -11,10 +11,11 @@ import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
-import com.afollestad.materialdialogs.MaterialDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.databinding.FragmentGradesEditorBinding
+import pl.szczodrzynski.edziennik.ui.dialogs.input
import pl.szczodrzynski.edziennik.utils.Colors
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_AVG_2_AVG
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_AVG_2_SEM
@@ -72,12 +73,11 @@ class GradesEditorFragment : Fragment() {
semester = arguments.getInt("semester", 1)
if (subjectId == -1L) {
- MaterialDialog.Builder(activity)
- .title(R.string.error_occured)
- .content(R.string.error_no_subject_id)
- .positiveText(R.string.ok)
- .onPositive { _, _ -> activity.navigateUp() }
- .show()
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.error_occured)
+ .setMessage(R.string.error_no_subject_id)
+ .setPositiveButton(R.string.ok) { _, _ -> activity.navigateUp() }
+ .show()
return
}
@@ -193,12 +193,11 @@ class GradesEditorFragment : Fragment() {
app.db.subjectDao().getById(App.profileId, subjectId).observe(this, Observer { subject ->
if (subject == null || subject.id == -1L) {
- MaterialDialog.Builder(activity)
- .title(R.string.error_occured)
- .content(R.string.error_no_subject_id)
- .positiveText(R.string.ok)
- .onPositive { _, _ -> activity.navigateUp() }
- .show()
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.error_occured)
+ .setMessage(R.string.error_no_subject_id)
+ .setPositiveButton(R.string.ok) { _, _ -> activity.navigateUp() }
+ .show()
return@Observer
}
@@ -329,21 +328,24 @@ class GradesEditorFragment : Fragment() {
popup.setOnMenuItemClickListener { item ->
if (item.itemId == 100) {
- MaterialDialog.Builder(v.context)
- .title(R.string.grades_editor_add_grade_title)
- .content(R.string.grades_editor_add_grade_weight)
- .inputType(InputType.TYPE_NUMBER_FLAG_SIGNED)
- .input(null, null) { _, input ->
+ MaterialAlertDialogBuilder(v.context)
+ .setTitle(R.string.grades_editor_add_grade_title)
+ .input(
+ message = v.context.getString(R.string.grades_editor_add_grade_weight),
+ type = InputType.TYPE_NUMBER_FLAG_SIGNED,
+ positiveButton = R.string.ok,
+ positiveListener = { _, input ->
try {
- editorGrade.weight = input.toString().toFloat()
+ editorGrade.weight = input.toFloat()
callback()
} catch (e: Exception) {
e.printStackTrace()
}
+ true
}
- .positiveText(R.string.ok)
- .negativeText(R.string.cancel)
- .show()
+ )
+ .setNegativeButton(R.string.cancel, null)
+ .show()
} else {
editorGrade.weight = item.itemId.toFloat()
callback()
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt
index de1b071f..532ade84 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt
@@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.GradesItemStatsBinding
import pl.szczodrzynski.edziennik.onClick
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats
import java.text.DecimalFormat
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt
index e337f720..868b330f 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/CounterActivity.kt
@@ -7,9 +7,9 @@ package pl.szczodrzynski.edziennik.ui.modules.home
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.mikepenz.iconics.IconicsDrawable
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
@@ -59,9 +59,12 @@ class CounterActivity : AppCompatActivity(), CoroutineScope {
}
}
- b.bellSync.setImageDrawable(IconicsDrawable(this@CounterActivity, SzkolnyFont.Icon.szf_alarm_bell_outline)
- .colorInt(0xff404040.toInt())
- .sizeDp(36))
+ b.bellSync.setImageDrawable(
+ IconicsDrawable(this@CounterActivity, SzkolnyFont.Icon.szf_alarm_bell_outline).apply {
+ colorInt = 0xff404040.toInt()
+ sizeDp = 36
+ }
+ )
b.bellSync.onClick {
BellSyncTimeChooseDialog(activity = this@CounterActivity)
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt
index 8afd7c04..944c60e8 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.kt
@@ -19,14 +19,13 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding
import pl.szczodrzynski.edziennik.ui.dialogs.home.StudentNumberDialog
import pl.szczodrzynski.edziennik.ui.modules.home.cards.*
-import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
import kotlin.coroutines.CoroutineContext
@@ -75,7 +74,7 @@ class HomeFragment : Fragment(), CoroutineScope {
private lateinit var activity: MainActivity
private lateinit var b: FragmentHomeBinding
- private lateinit var job: Job
+ private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
@@ -83,10 +82,8 @@ class HomeFragment : Fragment(), CoroutineScope {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
- context!!.theme.applyStyle(Themes.appTheme, true)
b = FragmentHomeBinding.inflate(inflater)
b.refreshLayout.setParent(activity.swipeRefreshLayout)
- job = Job()
return b.root
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt
index 957dff0c..fd54748e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeAvailabilityCard.kt
@@ -12,7 +12,7 @@ import androidx.core.text.HtmlCompat
import androidx.core.view.isVisible
import androidx.core.view.plusAssign
import androidx.core.view.setMargins
-import coil.api.load
+import coil.load
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt
index 68363ec6..d1a30053 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeTimetableCard.kt
@@ -15,8 +15,8 @@ import androidx.core.view.setMargins
import androidx.lifecycle.Observer
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
import com.mikepenz.iconics.utils.sizeDp
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@@ -87,17 +87,26 @@ class HomeTimetableCard(
}
holder.root += b.root
- b.settings.setImageDrawable(IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_settings_outline)
- .colorAttr(activity, R.attr.colorIcon)
- .sizeDp(20))
+ b.settings.setImageDrawable(
+ IconicsDrawable(activity, CommunityMaterial.Icon.cmd_cog_outline).apply {
+ colorAttr(activity, R.attr.colorIcon)
+ sizeDp = 24
+ }
+ )
- b.bellSync.setImageDrawable(IconicsDrawable(activity, SzkolnyFont.Icon.szf_alarm_bell_outline)
- .colorAttr(activity, R.attr.colorIcon)
- .sizeDp(20))
+ b.bellSync.setImageDrawable(
+ IconicsDrawable(activity, SzkolnyFont.Icon.szf_alarm_bell_outline).apply {
+ colorAttr(activity, R.attr.colorIcon)
+ sizeDp = 24
+ }
+ )
- b.showCounter.setImageDrawable(IconicsDrawable(activity, CommunityMaterial.Icon.cmd_fullscreen)
- .colorAttr(activity, R.attr.colorIcon)
- .sizeDp(20))
+ b.showCounter.setImageDrawable(
+ IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_fullscreen).apply {
+ colorAttr(activity, R.attr.colorIcon)
+ sizeDp = 24
+ }
+ )
b.bellSync.setOnClickListener {
BellSyncTimeChooseDialog(
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkAdapter.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkAdapter.java
deleted file mode 100644
index 0a568464..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkAdapter.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.homework;
-
-import android.content.Context;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.os.AsyncTask;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.cardview.widget.CardView;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.List;
-
-import pl.szczodrzynski.edziennik.App;
-import pl.szczodrzynski.edziennik.MainActivity;
-import pl.szczodrzynski.edziennik.R;
-import pl.szczodrzynski.edziennik.data.db.full.EventFull;
-import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
-import pl.szczodrzynski.edziennik.utils.models.Date;
-
-import static pl.szczodrzynski.edziennik.utils.Utils.bs;
-
-public class HomeworkAdapter extends RecyclerView.Adapter {
- private Context context;
- private List homeworkList;
-
- //getting the context and product list with constructor
- public HomeworkAdapter(Context mCtx, List homeworkList) {
- this.context = mCtx;
- this.homeworkList = homeworkList;
- }
-
- @NonNull
- @Override
- public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- //inflating and returning our view holder
- LayoutInflater inflater = LayoutInflater.from(context);
- View view = inflater.inflate(R.layout.row_homework_item, parent, false);
- return new ViewHolder(view);
- }
-
- @Override
- public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
- App app = (App) context.getApplicationContext();
-
- EventFull homework = homeworkList.get(position);
-
- int diffDays = Date.diffDays(homework.getDate(), Date.getToday());
-
- holder.homeworkItemHomeworkDate.setText(app.getString(R.string.date_relative_format, homework.getDate().getFormattedString(), Date.dayDiffString(context, diffDays)));
- holder.homeworkItemTopic.setText(homework.getTopic());
- holder.homeworkItemSubjectTeacher.setText(context.getString(R.string.homework_subject_teacher_format, bs(homework.getSubjectLongName()), bs(homework.getTeacherName())));
- holder.homeworkItemTeamDate.setText(context.getString(R.string.homework_team_date_format, bs(homework.getTeamName()), Date.fromMillis(homework.getAddedDate()).getFormattedStringShort()));
-
- if (!homework.getSeen()) {
- holder.homeworkItemTopic.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_8dp));
- holder.homeworkItemTopic.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
- homework.setSeen(true);
- AsyncTask.execute(() -> {
- App.db.metadataDao().setSeen(App.Companion.getProfileId(), homework, true);
- });
- }
- else {
- holder.homeworkItemTopic.setBackground(null);
- }
-
- holder.homeworkItemEdit.setVisibility((homework.getAddedManually() ? View.VISIBLE : View.GONE));
- holder.homeworkItemEdit.setOnClickListener(v -> {
- new EventManualDialog(
- (MainActivity) context,
- homework.getProfileId(),
- null,
- null,
- null,
- null,
- homework,
- null,
- null);
- });
-
- if (homework.getSharedBy() == null) {
- holder.homeworkItemSharedBy.setVisibility(View.GONE);
- }
- else if (homework.getSharedByName() != null) {
- holder.homeworkItemSharedBy.setText(app.getString(R.string.event_shared_by_format, (homework.getSharedBy().equals("self") ? app.getString(R.string.event_shared_by_self) : homework.getSharedByName())));
- }
- }
-
- @Override
- public int getItemCount() {
- return homeworkList.size();
- }
-
- class ViewHolder extends RecyclerView.ViewHolder {
-
- CardView homeworkItemCard;
- TextView homeworkItemTopic;
- TextView homeworkItemHomeworkDate;
- TextView homeworkItemSharedBy;
- TextView homeworkItemSubjectTeacher;
- TextView homeworkItemTeamDate;
- Button homeworkItemEdit;
-
- ViewHolder(View itemView) {
- super(itemView);
- homeworkItemCard = itemView.findViewById(R.id.homeworkItemCard);
- homeworkItemTopic = itemView.findViewById(R.id.homeworkItemTopic);
- homeworkItemHomeworkDate = itemView.findViewById(R.id.homeworkItemHomeworkDate);
- homeworkItemSharedBy = itemView.findViewById(R.id.homeworkItemSharedBy);
- homeworkItemSubjectTeacher = itemView.findViewById(R.id.homeworkItemSubjectTeacher);
- homeworkItemTeamDate = itemView.findViewById(R.id.homeworkItemTeamDate);
- homeworkItemEdit = itemView.findViewById(R.id.homeworkItemEdit);
- }
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt
index 30abcd02..c8a62def 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/homework/HomeworkFragment.kt
@@ -12,7 +12,7 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -100,7 +100,7 @@ class HomeworkFragment : Fragment(), CoroutineScope {
bottomBar.apply {
fabEnable = true
fabExtendedText = getString(R.string.add)
- fabIcon = CommunityMaterial.Icon2.cmd_plus
+ fabIcon = CommunityMaterial.Icon3.cmd_plus
}
setFabOnClickListener(View.OnClickListener {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginActivity.kt
index 925b2a98..32446605 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginActivity.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginActivity.kt
@@ -96,6 +96,8 @@ class LoginActivity : AppCompatActivity(), CoroutineScope {
setContentView(b.root)
errorSnackbar.setCoordinator(b.coordinator, b.snackbarAnchor)
+ app.buildManager.validateBuild(this)
+
launch {
app.config.loginFinished = app.db.profileDao().count > 0
if (!app.config.loginFinished) {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt
index 4b88b4e6..8d1a2a19 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginChooserFragment.kt
@@ -16,15 +16,16 @@ import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.Animation
import android.view.animation.RotateAnimation
+import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.google.firebase.analytics.FirebaseAnalytics
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
+import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity
@@ -202,12 +203,6 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
return
}
- if (loginType.loginType == LOGIN_TYPE_LIBRUS) {
- FirebaseAnalytics.getInstance(activity).logEvent("librus_hacked", Bundle())
- nav.navigate(R.id.loginLibrusFragment, null, activity.navOptions)
- return
- }
-
launch {
if (!checkAvailability(loginType.loginType))
return@launch
@@ -255,19 +250,38 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
}?.let { registerName ->
var status = app.config.sync.registerAvailability[registerName]
if (status == null || status.nextCheckAt < currentTimeUnix()) {
- withContext(Dispatchers.IO) {
- val api = SzkolnyApi(app)
- api.runCatching(activity) {
+ val api = SzkolnyApi(app)
+ val result = withContext(Dispatchers.IO) {
+ return@withContext api.runCatching({
val availability = getRegisterAvailability()
app.config.sync.registerAvailability = availability
- status = availability[registerName]
+ availability[registerName]
+ }, onError = {
+ if (it.toErrorCode() == ERROR_API_INVALID_SIGNATURE) {
+ return@withContext false
+ }
+ return@withContext it
+ })
+ }
+
+ when (result) {
+ false -> {
+ Toast.makeText(activity, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
+ return@let
+ }
+ is Throwable -> {
+ activity.errorSnackbar.addError(result.toApiError(TAG)).show()
+ return false
+ }
+ is RegisterAvailabilityStatus -> {
+ status = result
}
}
}
- if (status?.available != true) {
+ if (status?.available != true || status.minVersionCode > BuildConfig.VERSION_CODE) {
if (status != null)
- RegisterUnavailableDialog(activity, status!!)
+ RegisterUnavailableDialog(activity, status)
return false
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt
index 8776f355..ea6bbe4d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginFormFragment.kt
@@ -15,7 +15,6 @@ import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import com.google.android.material.textfield.TextInputLayout
import com.mikepenz.iconics.IconicsDrawable
-import com.mikepenz.iconics.utils.paddingDp
import com.mikepenz.iconics.utils.sizeDp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -97,11 +96,11 @@ class LoginFormFragment : Fragment(), CoroutineScope {
b.textEdit.id = credential.name
b.textEdit.setText(arguments?.getString(credential.keyName) ?: "")
- b.textLayout.startIconDrawable = IconicsDrawable(activity)
- .icon(credential.icon)
- .sizeDp(24)
- .paddingDp(2)
- .colorAttr(activity, R.attr.colorOnBackground)
+ b.textLayout.startIconDrawable = IconicsDrawable(activity).apply {
+ icon = credential.icon
+ sizeDp = 24
+ colorAttr(activity, R.attr.colorOnBackground)
+ }
this.b.formContainer.addView(b.root)
credentials[credential] = b
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt
index 949848a5..77036f19 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt
@@ -110,7 +110,7 @@ object LoginInfo {
FormField(
keyName = "accountPin",
name = R.string.login_hint_pin,
- icon = CommunityMaterial.Icon2.cmd_lock,
+ icon = CommunityMaterial.Icon2.cmd_lock_outline,
emptyText = R.string.login_error_no_pin,
invalidText = R.string.login_error_incorrect_pin,
errorCodes = mapOf(),
@@ -157,7 +157,7 @@ object LoginInfo {
FormField(
keyName = "symbol",
name = R.string.login_hint_symbol,
- icon = CommunityMaterial.Icon2.cmd_school,
+ icon = CommunityMaterial.Icon3.cmd_school_outline,
emptyText = R.string.login_error_no_symbol,
invalidText = R.string.login_error_incorrect_symbol,
errorCodes = mapOf(
@@ -170,7 +170,7 @@ object LoginInfo {
FormField(
keyName = "devicePin",
name = R.string.login_hint_pin,
- icon = CommunityMaterial.Icon2.cmd_lock,
+ icon = CommunityMaterial.Icon2.cmd_lock_outline,
emptyText = R.string.login_error_no_pin,
invalidText = R.string.login_error_incorrect_pin,
errorCodes = mapOf(
@@ -252,7 +252,7 @@ object LoginInfo {
FormField(
keyName = "serverName",
name = R.string.login_hint_address,
- icon = CommunityMaterial.Icon2.cmd_web,
+ icon = CommunityMaterial.Icon3.cmd_web,
emptyText = R.string.login_error_no_address,
invalidText = R.string.login_error_incorrect_address,
errorCodes = mapOf(
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginLibrusFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginLibrusFragment.kt
deleted file mode 100644
index 46b345e6..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginLibrusFragment.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) Kacper Ziubryniewicz 2021-3-1
- */
-
-package pl.szczodrzynski.edziennik.ui.modules.login
-
-import android.net.Uri
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.databinding.LoginLibrusFragmentBinding
-import kotlin.coroutines.CoroutineContext
-
-class LoginLibrusFragment : Fragment(), CoroutineScope {
- companion object {
- private const val TAG = "LoginLibrusFragment"
- }
-
- private lateinit var app: App
- private lateinit var activity: LoginActivity
- private lateinit var b: LoginLibrusFragmentBinding
-
- private val job: Job = Job()
- override val coroutineContext: CoroutineContext
- get() = job + Dispatchers.Main
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- activity = (getActivity() as LoginActivity?) ?: return null
- context ?: return null
- app = activity.application as App
- b = LoginLibrusFragmentBinding.inflate(inflater)
- return b.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- b.librus2021HackWorking100PercentLegit.apply {
- setVideoURI(Uri.parse("https://szkolny.eu/librus.mp4"))
- setMediaController(null)
- requestFocus()
- start()
- }
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt
index b9fdf43a..1c9634fc 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginPrizeFragment.kt
@@ -10,7 +10,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
-import coil.api.load
+import coil.load
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt
index ea8a063d..2c08c27e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/viewholder/PlatformViewHolder.kt
@@ -9,7 +9,7 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
-import coil.api.load
+import coil.load
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.databinding.LoginPlatformItemBinding
import pl.szczodrzynski.edziennik.ui.modules.grades.viewholder.BindableViewHolder
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt
index b2623b64..30f40c30 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessageFragment.kt
@@ -65,9 +65,10 @@ class MessageFragment : Fragment(), CoroutineScope {
if (!isAdded) return
b.closeButton.setImageDrawable(
- IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_window_close)
- .colorAttr(activity, android.R.attr.textColorSecondary)
- .sizeDp(12)
+ IconicsDrawable(activity, CommunityMaterial.Icon3.cmd_window_close).apply {
+ colorAttr(activity, android.R.attr.textColorSecondary)
+ sizeDp = 16
+ }
)
b.closeButton.setOnClickListener { activity.navigateUp() }
@@ -230,7 +231,7 @@ class MessageFragment : Fragment(), CoroutineScope {
bottomBar.apply {
fabEnable = true
fabExtendedText = getString(R.string.messages_reply)
- fabIcon = CommunityMaterial.Icon2.cmd_reply
+ fabIcon = CommunityMaterial.Icon3.cmd_reply_outline
}
setFabOnClickListener(View.OnClickListener {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt
index 043cce7d..add36a3c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesFragment.kt
@@ -97,7 +97,7 @@ class MessagesFragment : Fragment(), CoroutineScope {
bottomBar.apply {
fabEnable = true
fabExtendedText = getString(R.string.compose)
- fabIcon = CommunityMaterial.Icon2.cmd_pencil_outline
+ fabIcon = CommunityMaterial.Icon3.cmd_pencil_outline
}
setFabOnClickListener(View.OnClickListener {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesListFragmentOld.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesListFragmentOld.java
deleted file mode 100644
index c9574de7..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/MessagesListFragmentOld.java
+++ /dev/null
@@ -1,295 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.messages;
-
-
-import android.graphics.Rect;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-
-import androidx.annotation.NonNull;
-import androidx.databinding.DataBindingUtil;
-import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import pl.szczodrzynski.edziennik.App;
-import pl.szczodrzynski.edziennik.MainActivity;
-import pl.szczodrzynski.edziennik.R;
-import pl.szczodrzynski.edziennik.data.db.entity.Message;
-import pl.szczodrzynski.edziennik.data.db.full.MessageFull;
-import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull;
-import pl.szczodrzynski.edziennik.databinding.MessagesListBinding;
-import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment;
-import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration;
-import pl.szczodrzynski.edziennik.utils.Themes;
-
-import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
-import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static pl.szczodrzynski.edziennik.utils.Utils.d;
-
-public class MessagesListFragmentOld extends LazyFragment {
-
- private App app = null;
- private MainActivity activity = null;
- private MessagesListBinding b = null;
-
- private Rect viewRect = new Rect();
- private MessagesAdapter messagesAdapter = null;
- private ViewGroup viewParent = null;
-
- static final Interpolator transitionInterpolator = new FastOutSlowInInterpolator();
- static final long TRANSITION_DURATION = 300L;
- static final String TAP_POSITION = "tap_position";
-
- public static int[] tapPositions = {NO_POSITION, NO_POSITION};
- public static int[] topPositions = {NO_POSITION, NO_POSITION};
- public static int[] bottomPositions = {NO_POSITION, NO_POSITION};
-
- private int messageType = Message.TYPE_RECEIVED;
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- activity = (MainActivity) getActivity();
- if (getActivity() == null || getContext() == null)
- return null;
- app = (App) activity.getApplication();
- getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
- // activity, context and profile is valid
- b = DataBindingUtil.inflate(inflater, R.layout.messages_list, container, false);
- return b.getRoot();
- }
-
- @Override
- public boolean onPageCreated() {
- if (app == null || activity == null || b == null || !isAdded())
- return false;
-
- long messageId = -1;
- if (getArguments() != null) {
- messageId = getArguments().getLong("messageId", -1);
- }
- if (messageId != -1) {
- Bundle args = new Bundle();
- args.putLong("messageId", messageId);
- getArguments().remove("messageId");
- activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args);
- return false;
- }
-
- if (getArguments() != null) {
- messageType = getArguments().getInt("messageType", Message.TYPE_RECEIVED);
- }
-
- /*b.refreshLayout.setOnRefreshListener(() -> {
- activity.syncCurrentFeature(messageType, b.refreshLayout);
- });*/
-
- /*messagesAdapter = new MessagesAdapter(app, ((parent, view1, position, id) -> {
- // TODO ANIMATION
- tapPositions[messageType] = position;
- topPositions[messageType] = ((LinearLayoutManager) b.emailList.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
- bottomPositions[messageType] = ((LinearLayoutManager) b.emailList.getLayoutManager()).findLastCompletelyVisibleItemPosition();
-
- *//*view1.getGlobalVisibleRect(viewRect);
- ((Transition) MessagesListFragment.this.getExitTransition()).setEpicenterCallback(new Transition.EpicenterCallback() {
- @Override
- public Rect onGetEpicenter(@NonNull Transition transition) {
- return viewRect;
- }
- });*//*
-
- Bundle args = new Bundle();
- args.putLong("messageId", messagesAdapter.getMessageList().get(position).id);
- activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args);
-
- // KOD W WERSJI 2.7
- // TODO ANIMATION
- *//*TransitionSet sharedElementTransition = new TransitionSet()
- .addTransition(new Fade())
- .addTransition(new ChangeBounds())
- .addTransition(new ChangeTransform())
- .addTransition(new ChangeImageTransform())
- .setDuration(TRANSITION_DURATION)
- .setInterpolator(transitionInterpolator);
-
- MessagesDetailsFragment fragment = new MessagesDetailsFragment();
- Bundle args = new Bundle();
- args.putLong("messageId", messagesAdapter.messageList.get(position).id);
- fragment.setArguments(args);
- fragment.setSharedElementEnterTransition(sharedElementTransition);
- fragment.setSharedElementReturnTransition(sharedElementTransition);*//*
-
- // JAKIS STARSZY KOD
- *//*Intent intent = new Intent(activity, MessagesDetailsActivity.class);
- intent.putExtra("item_id", 1);
- intent.putExtra("transition_name", ViewCompat.getTransitionName(view1));
-
-
- ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
- activity,
- view1,
- getString(R.string.transition_name)
- );
-
- TransitionManager.beginDelayedTransition((ViewGroup) view1, sharedElementTransition);
- setEnterTransition(sharedElementTransition);
- setReturnTransition(sharedElementTransition);
- setExitTransition(sharedElementTransition);
- setSharedElementEnterTransition(sharedElementTransition);
- setSharedElementReturnTransition(sharedElementTransition);
- startActivity(intent, options.toBundle());*//*
-
- *//*activity.getSupportFragmentManager()
- .beginTransaction()
- .setReorderingAllowed(true)
- .replace(R.id.fragment_container, fragment)
- .addToBackStack(null)
- .addSharedElement(view1, getString(R.string.transition_name))
- .commit();*//*
-
- }));*/
-
-
- //tapPosition = savedInstanceState != null ? savedInstanceState.getInt(TAP_POSITION, tapPosition) : tapPosition;
-
- // May not be the best place to postpone transition. Just an example to demo how reenter transition works.
- // TODO ANIMATION
- //postponeEnterTransition();
-
- viewParent = (ViewGroup) getView().getParent();
-
- b.emailList.setLayoutManager(new LinearLayoutManager(getView().getContext()));
- b.emailList.addItemDecoration(new SimpleDividerItemDecoration(getView().getContext()));
- b.emailList.setAdapter(messagesAdapter);
- b.emailList.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
- if (b.emailList.canScrollVertically(-1)) {
- setSwipeToRefresh(false);
- }
- if (!b.emailList.canScrollVertically(-1) && newState == SCROLL_STATE_IDLE) {
- setSwipeToRefresh(true);
- }
- }
- });
-
- if (messageType == Message.TYPE_RECEIVED) {
- App.db.messageDao().getReceived(App.Companion.getProfileId()).observe(this, messageFulls -> {
- createMessageList(messageFulls);
- });
- }
- else if (messageType == Message.TYPE_DELETED) {
- App.db.messageDao().getDeleted(App.Companion.getProfileId()).observe(this, messageFulls -> {
- createMessageList(messageFulls);
- });
- }
- else if (messageType == Message.TYPE_SENT) {
- App.db.messageDao().getSent(App.Companion.getProfileId()).observe(this, messageFulls -> {
- AsyncTask.execute(() -> {
- List messageRecipients = App.db.messageRecipientDao().getAll(App.Companion.getProfileId());
- List messageIds = new ArrayList<>();
- for (MessageFull messageFull: messageFulls) {
- messageIds.add(messageFull.getId());
- }
- for (MessageRecipientFull messageRecipientFull: messageRecipients) {
- if (messageRecipientFull.id == -1)
- continue;
-
- int index = -1;
-
- int i = -1;
- for (long id: messageIds) {
- //index++;
- i++;
- if (id == messageRecipientFull.messageId) {
- index = i;
- break;
- }
- }
-
- if (index >= 0) {
- MessageFull messageFull = messageFulls.get(index);
- if (messageFull != null) {
- messageFull.addRecipient(messageRecipientFull);
- }
- }
- }
- activity.runOnUiThread(() -> {
- createMessageList(messageFulls);
- });
- });
- });
- }
-
- return true;
- }
-
- private void createMessageList(List messageFulls) {
- b.progressBar.setVisibility(View.GONE);
- b.emailList.setVisibility(View.VISIBLE);
- //messagesAdapter.setData(messageFulls);
-
- LinearLayoutManager layoutManager = (LinearLayoutManager) b.emailList.getLayoutManager();
- if (tapPositions[messageType] != NO_POSITION && layoutManager != null) {
- //d("MessageList", "Scrolling");
-
- if (topPositions[messageType] > layoutManager.findLastCompletelyVisibleItemPosition()) {
- b.emailList.scrollToPosition(topPositions[messageType]);
- }
- else if (bottomPositions[messageType] < layoutManager.findFirstCompletelyVisibleItemPosition()) {
- b.emailList.scrollToPosition(bottomPositions[messageType]);
- }
- else {
- b.emailList.scrollToPosition(tapPositions[messageType]);
- }
-
- //tapPositions[messageType] = NO_POSITION;
- //topPositions[messageType] = NO_POSITION;
- //bottomPositions[messageType] = NO_POSITION;
- }
- // TODO ANIMATION
- /*final ViewTreeObserver observer = viewParent.getViewTreeObserver();
- observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
-
- *//*viewParent.getViewTreeObserver().removeOnPreDrawListener(this);
- if (getExitTransition() == null) {
- setExitTransition(new SlideExplode().setDuration(TRANSITION_DURATION).setInterpolator(transitionInterpolator));
- }
-
- View view2 = layoutManager != null ? layoutManager.findViewByPosition(tapPosition) : null;
- if (view2 != null) {
- view2.getGlobalVisibleRect(viewRect);
- ((Transition) getExitTransition()).setEpicenterCallback(new Transition.EpicenterCallback() {
- @Override
- public Rect onGetEpicenter(@NonNull Transition transition) {
- return viewRect;
- }
- });
- }
-
- d("MessagesList", "topPosition "+topPosition);
- d("MessagesList", "tapPosition "+tapPosition);
- d("MessagesList", "bottomPosition "+bottomPosition);*//*
-
-
- startPostponedEnterTransition();
- return true;
- }
- });*/
- }
-
- @Override
- public void onSaveInstanceState(@NonNull Bundle outState) {
- super.onSaveInstanceState(outState);
- d("MessagesList", "onSaveInstanceState position "+tapPositions[messageType]);
- outState.putInt(TAP_POSITION, tapPositions[messageType]);
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt
index 96898871..942876f2 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/messages/compose/MessagesComposeFragment.kt
@@ -316,7 +316,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
activity.navView.bottomBar.apply {
fabEnable = true
fabExtendedText = getString(R.string.messages_compose_send)
- fabIcon = CommunityMaterial.Icon2.cmd_send
+ fabIcon = CommunityMaterial.Icon3.cmd_send_outline
setFabOnClickListener(View.OnClickListener {
sendMessage()
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt
new file mode 100644
index 00000000..dfff3246
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-17.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings
+
+import android.content.Context
+import android.view.View
+import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder
+import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem
+
+class MaterialAboutProfileItem(item: MaterialAboutTitleItem) : MaterialAboutTitleItem(item) {
+ companion object {
+ fun getViewHolder(view: View): MaterialAboutItemViewHolder =
+ MaterialAboutTitleItem.getViewHolder(view)
+
+ fun setupItem(
+ holder: MaterialAboutTitleItemViewHolder,
+ item: MaterialAboutProfileItem,
+ context: Context
+ ) = MaterialAboutTitleItem.setupItem(holder, item, context)
+ }
+
+ override fun getType(): Int {
+ return SettingsViewTypeManager.ItemType.PROFILE_ITEM
+ }
+
+ override fun getDetailString() = "MaterialAboutProfileItem{" +
+ "text=" + text +
+ ", textRes=" + textRes +
+ ", desc=" + desc +
+ ", descRes=" + descRes +
+ ", icon=" + icon +
+ ", iconRes=" + iconRes +
+ ", onClickAction=" + onClickAction +
+ ", onLongClickAction=" + onLongClickAction +
+ '}'
+
+ override fun clone() = MaterialAboutProfileItem(this)
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/ProfileManagerFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/ProfileManagerFragment.kt
index 06952328..2ab29917 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/ProfileManagerFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/ProfileManagerFragment.kt
@@ -1,12 +1,11 @@
package pl.szczodrzynski.edziennik.ui.modules.settings
import android.os.Bundle
-import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.fragment.app.Fragment
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.databinding.FragmentProfileManagerBinding
import pl.szczodrzynski.edziennik.utils.Themes
@@ -26,8 +25,6 @@ class ProfileManagerFragment : Fragment() {
return null
app = activity.application as App
context!!.theme.applyStyle(Themes.appTheme, true)
- if (app.profile == null)
- return inflater.inflate(R.layout.fragment_loading, container, false)
// activity, context and profile is valid
b = FragmentProfileManagerBinding.inflate(inflater)
b.refreshLayout.setParent(activity.swipeRefreshLayout)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt
new file mode 100644
index 00000000..36ce3777
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-17.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings
+
+import com.danielstone.materialaboutlibrary.items.MaterialAboutItem
+import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.MainActivity
+
+abstract class SettingsCard(
+ protected val util: SettingsUtil,
+) {
+ protected val app: App = util.activity.application as App
+ protected val activity: MainActivity = util.activity
+
+ protected val configGlobal by lazy { app.config }
+ protected val configProfile by lazy { app.config.forProfile() }
+
+ val card by lazy {
+ buildCard()
+ }
+
+ protected abstract fun buildCard(): MaterialAboutCard
+ protected abstract fun getItems(): List
+ protected open fun getItemsMore(): List = listOf()
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt
new file mode 100644
index 00000000..cf7fa625
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-16.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.danielstone.materialaboutlibrary.MaterialAboutFragment
+import com.danielstone.materialaboutlibrary.model.MaterialAboutList
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.MainActivity
+import pl.szczodrzynski.edziennik.ui.modules.settings.cards.*
+import kotlin.coroutines.CoroutineContext
+
+class SettingsFragment : MaterialAboutFragment(), CoroutineScope {
+ companion object {
+ private const val TAG = "SettingsFragment"
+ }
+
+ private lateinit var app: App
+ private lateinit var activity: MainActivity
+
+ private val job: Job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ private val util by lazy {
+ SettingsUtil(activity) {
+ refreshMaterialAboutList()
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ activity = (getActivity() as MainActivity?) ?: return null
+ app = activity.application as App
+ return super.onCreateView(inflater, container, savedInstanceState)
+ }
+
+ override fun getViewTypeManager() =
+ SettingsViewTypeManager()
+
+ override fun getMaterialAboutList(activityContext: Context?): MaterialAboutList {
+ return MaterialAboutList(
+ SettingsProfileCard(util).card,
+ SettingsThemeCard(util).card,
+ SettingsSyncCard(util).card,
+ SettingsRegisterCard(util).card,
+ SettingsAboutCard(util).card,
+ )
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt
index eb1a23e1..de829d8d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsLicenseActivity.kt
@@ -3,8 +3,8 @@ package pl.szczodrzynski.edziennik.ui.modules.settings
import android.content.Context
import android.net.Uri
import android.os.Bundle
-
import com.danielstone.materialaboutlibrary.ConvenienceBuilder
+import com.danielstone.materialaboutlibrary.ConvenienceBuilder.createLicenseCard
import com.danielstone.materialaboutlibrary.MaterialAboutActivity
import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
@@ -14,180 +14,366 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
-
-import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.resolveColor
import pl.szczodrzynski.edziennik.utils.Themes
class SettingsLicenseActivity : MaterialAboutActivity() {
var foregroundColor: Int = 0
+ private val icon
+ get() = IconicsDrawable(this).apply {
+ icon = CommunityMaterial.Icon.cmd_book_outline
+ colorInt = foregroundColor
+ sizeDp = 24
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
- val app = application as App
- setTheme(Themes.appTheme)
- foregroundColor = Themes.getPrimaryTextColor(this)
+ setTheme(
+ if (Themes.isDark)
+ R.style.Theme_MaterialComponents
+ else
+ R.style.Theme_MaterialComponents_Light
+ )
+ foregroundColor = if (Themes.isDark)
+ R.color.primaryTextDark.resolveColor(this)
+ else
+ R.color.primaryTextLight.resolveColor(this)
super.onCreate(savedInstanceState)
}
- private fun createLicenseCard(
- context: Context,
- libraryTitle: CharSequence,
- copyrightYear: CharSequence,
- copyrightName: CharSequence,
- license: OpenSourceLicense,
- libraryUrl: String): MaterialAboutCard {
- val licenseItem = MaterialAboutActionItem.Builder()
- .icon(IconicsDrawable(this)
- .icon(CommunityMaterial.Icon.cmd_book_outline)
- .colorInt(foregroundColor)
- .sizeDp(18))
- .setIconGravity(MaterialAboutActionItem.GRAVITY_TOP)
- .text(libraryTitle)
- .subText(String.format(getString(license.resourceId), copyrightYear, copyrightName))
- .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(context, Uri.parse(libraryUrl)))
- .build()
-
- return MaterialAboutCard.Builder().addItem(licenseItem).build()
+ private fun license(
+ title: String,
+ year: String,
+ copyright: String,
+ license: OpenSourceLicense,
+ url: String
+ ): MaterialAboutCard {
+ return createLicenseCard(this, icon, title, year, copyright, license).also {
+ (it.items[0] as MaterialAboutActionItem).onClickAction =
+ ConvenienceBuilder.createWebsiteOnClickAction(
+ this,
+ Uri.parse(url)
+ )
+ }
}
- override fun getMaterialAboutList(context: Context): MaterialAboutList {
+ override fun getMaterialAboutList(context: Context) = MaterialAboutList(
+ license(
+ "Kotlin",
+ "2000-2020",
+ "JetBrains s.r.o. and Kotlin Programming Language contributors.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/JetBrains/kotlin"
+ ),
- return MaterialAboutList(
- createLicenseCard(this,
- "OkHttp",
- "",
- "square",
- OpenSourceLicense.APACHE_2,
- "https://github.com/square/okhttp/"),
- createLicenseCard(this,
- "MHttp",
- "2018",
- "Mot.",
- OpenSourceLicense.APACHE_2,
- "https://github.com/motcwang/MHttp/"),
- createLicenseCard(this,
- "AgendaCalendarView",
- "2015",
- "Thibault Guégan",
- OpenSourceLicense.APACHE_2,
- "https://github.com/Tibolte/AgendaCalendarView/"),
- createLicenseCard(this,
- "Material Calendar View",
- "2017",
- "Applandeo sp. z o.o.",
- OpenSourceLicense.APACHE_2,
- "https://github.com/Applandeo/Material-Calendar-View/"),
- createLicenseCard(this,
- "Android-Job",
- "2007-2017",
- "Evernote Corporation",
- OpenSourceLicense.APACHE_2,
- "https://github.com/evernote/android-job/"),
- createLicenseCard(this,
- "Custom Activity On Crash",
- "",
- "Eduard Ereza MartĂnez (Ereza)",
- OpenSourceLicense.APACHE_2,
- "https://github.com/Ereza/CustomActivityOnCrash/"),
- createLicenseCard(this,
- "Android-Iconics",
- "2018",
- "Mike Penz",
- OpenSourceLicense.APACHE_2,
- "https://github.com/mikepenz/Android-Iconics/"),
- createLicenseCard(this,
- "MaterialDrawer",
- "2016",
- "Mike Penz",
- OpenSourceLicense.APACHE_2,
- "https://github.com/mikepenz/MaterialDrawer/"),
- createLicenseCard(this,
- "Material Dialogs",
- "2014-2016",
- "Aidan Michael Follestad",
- OpenSourceLicense.MIT,
- "https://github.com/afollestad/material-dialogs/"),
- createLicenseCard(this,
- "MaterialDateTimePicker",
- "2014",
- "Wouter Dullaert",
- OpenSourceLicense.APACHE_2,
- "https://github.com/wdullaer/MaterialDateTimePicker/"),
- createLicenseCard(this,
- "ColorPicker",
- "2016",
- "Jared Rummler, 2015 Daniel Nilsson",
- OpenSourceLicense.APACHE_2,
- "https://github.com/jaredrummler/ColorPicker/"),
- createLicenseCard(this,
- "material-about-library",
- "2016-2018",
- "Daniel Stone",
- OpenSourceLicense.APACHE_2,
- "https://github.com/daniel-stoneuk/material-about-library/"),
- createLicenseCard(this,
- "material-intro",
- "2017",
- "Jan Heinrich Reimer",
- OpenSourceLicense.MIT,
- "https://github.com/heinrichreimer/material-intro/"),
- createLicenseCard(this,
- "JsonViewer",
- "2017",
- "smuyyh",
- OpenSourceLicense.APACHE_2,
- "https://github.com/smuyyh/JsonViewer/"),
- createLicenseCard(this,
- "ShortcutBadger",
- "2014",
- "Leo Lin",
- OpenSourceLicense.APACHE_2,
- "https://github.com/leolin310148/ShortcutBadger/"),
- createLicenseCard(this,
- "Android Image Cropper",
- "2016",
- "Arthur Teplitzki, 2013 Edmodo, Inc.",
- OpenSourceLicense.APACHE_2,
- "https://github.com/ArthurHub/Android-Image-Cropper/"),
- createLicenseCard(this,
- "Material Tap Target Prompt",
- "2016-2018",
- "Samuel Wall",
- OpenSourceLicense.APACHE_2,
- "https://github.com/sjwall/MaterialTapTargetPrompt/"),
- createLicenseCard(this,
- "Android Swipe Layout",
- "2014",
- "代码家 (daimajia)",
- OpenSourceLicense.MIT,
- "https://github.com/daimajia/AndroidSwipeLayout/"),
- createLicenseCard(this,
- "barcodescanner (ZXing)",
- "2014",
- "Dushyanth Maguluru",
- OpenSourceLicense.APACHE_2,
- "https://github.com/dm77/barcodescanner/"),
- createLicenseCard(this,
- "CircularProgressIndicator",
- "2018",
- "Anton Kozyriatskyi",
- OpenSourceLicense.APACHE_2,
- "https://github.com/antonKozyriatskyi/CircularProgressIndicator/")
+ license(
+ "Android Jetpack",
+ "",
+ "The Android Open Source Project",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/androidx/androidx"
+ ),
+ license(
+ "Material Components for Android",
+ "2014-2020",
+ "Google, Inc.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/material-components/material-components-android"
+ ),
- /*createLicenseCard(this,
- "NoNonsense-FilePicker",
- "",
- "Jonas Kalderstam (spacecowboy)",
- OpenSourceLicense.GNU_GPL_3,
- "https://github.com/spacecowboy/NoNonsense-FilePicker/")*/
+ license(
+ "OkHttp",
+ "2019",
+ "Square, Inc.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/square/okhttp"
+ ),
+ license(
+ "Retrofit",
+ "2013",
+ "Square, Inc.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/square/retrofit"
+ ),
+
+ license(
+ "Gson",
+ "2008",
+ "Google Inc.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/google/gson"
+ ),
+
+ license(
+ "jsoup",
+ "2009-2021",
+ "Jonathan Hedley",
+ OpenSourceLicense.MIT,
+ "https://github.com/jhy/jsoup"
+ ),
+
+ license(
+ "jspoon",
+ "2017",
+ "Droids On Roids",
+ OpenSourceLicense.MIT,
+ "https://github.com/DroidsOnRoids/jspoon"
+ ),
+
+ license(
+ "AgendaCalendarView",
+ "2015",
+ "Thibault Guégan",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/szkolny-eu/agendacalendarview"
+ ),
+
+ license(
+ "CafeBar",
+ "2017",
+ "Dani Mahardhika",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/szkolny-eu/cafebar"
+ ),
+
+ license(
+ "FSLogin",
+ "2021",
+ "kuba2k2",
+ OpenSourceLicense.MIT,
+ "https://github.com/szkolny-eu/FSLogin"
+ ),
+
+ license(
+ "material-about-library",
+ "2016-2020",
+ "Daniel Stone",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/szkolny-eu/material-about-library"
+ ),
+
+ license(
+ "MHttp",
+ "2018",
+ "Mot.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/szkolny-eu/mhttp"
+ ),
+
+ license(
+ "Nachos for Android",
+ "2016",
+ "Hootsuite Media, Inc.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/szkolny-eu/nachos"
+ ),
+
+ license(
+ "Material Number Sliding Picker",
+ "2019",
+ "Alessandro Crugnola",
+ OpenSourceLicense.MIT,
+ "https://github.com/kuba2k2/NumberSlidingPicker"
+ ),
+
+ license(
+ "RecyclerTabLayout",
+ "2017",
+ "nshmura",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/kuba2k2/RecyclerTabLayout"
+ ),
+
+ license(
+ "Tachyon",
+ "2019",
+ "LinkedIn Corporation",
+ OpenSourceLicense.BSD,
+ "https://github.com/kuba2k2/Tachyon"
+ ),
+
+ license(
+ "Android-Iconics",
+ "2021",
+ "Mike Penz",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/mikepenz/Android-Iconics"
+ ),
+
+ license(
+ "Custom Activity On Crash library",
+ "2020",
+ "Eduard Ereza Martínez",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/Ereza/CustomActivityOnCrash"
+ ),
+
+ license(
+ "Material-Calendar-View",
+ "2017",
+ "Applandeo sp. z o.o.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/Applandeo/Material-Calendar-View"
+ ),
+
+ license(
+ "Android Swipe Layout",
+ "2014",
+ "代码家",
+ OpenSourceLicense.MIT,
+ "https://github.com/daimajia/AndroidSwipeLayout"
+ ),
+
+ license(
+ "CircularProgressIndicator",
+ "2018",
+ "Anton Kozyriatskyi",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/antonKozyriatskyi/CircularProgressIndicator"
+ ),
+
+ license(
+ "ChatMessageView",
+ "2019",
+ "Tsubasa Nakayama",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/bassaer/ChatMessageView"
+ ),
+
+ license(
+ "Android Image Cropper",
+ "2016 Arthur Teplitzki,",
+ "2013 Edmodo, Inc.",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/CanHub/Android-Image-Cropper"
+ ),
+
+ license(
+ "Chucker",
+ "2018-2020 Chucker Team,",
+ "2017 Jeff Gilfelt",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/ChuckerTeam/chucker"
+ ),
+
+ license(
+ "Android-Snowfall",
+ "2016",
+ "JetRadar",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/JetradarMobile/android-snowfall"
+ ),
+
+ license(
+ "UONET+ Request Signer",
+ "2019",
+ "Wulkanowy",
+ OpenSourceLicense.MIT,
+ "https://github.com/wulkanowy/uonet-request-signer"
+ ),
+
+ license(
+ "material-intro",
+ "2017",
+ "Jan Heinrich Reimer",
+ OpenSourceLicense.MIT,
+ "https://github.com/heinrichreimer/material-intro"
+ ),
+
+ license(
+ "HyperLog Android",
+ "2018",
+ "HyperTrack",
+ OpenSourceLicense.MIT,
+ "https://github.com/hypertrack/hyperlog-android"
+ ),
+
+ license(
+ "Color Picker",
+ "2016 Jared Rummler,",
+ "2015 Daniel Nilsson",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/jaredrummler/ColorPicker"
+ ),
+
+ license(
+ "PowerPermission",
+ "2020",
+ "Qifan Yang",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/underwindfall/PowerPermission"
+ ),
+
+ license(
+ "JsonViewer",
+ "2017",
+ "smuyyh",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/smuyyh/JsonViewer"
+ ),
+
+ license(
+ "Coil",
+ "2021",
+ "Coil Contributors",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/coil-kt/coil"
+ ),
+
+ license(
+ "Barcode Scanner (ZXing)",
+ "2014",
+ "Dushyanth Maguluru",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/dm77/barcodescanner"
+ ),
+
+ license(
+ "AutoFitTextView",
+ "2014",
+ "Grantland Chew",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/grantland/android-autofittextview"
+ ),
+
+ license(
+ "ShortcutBadger",
+ "2014",
+ "Leo Lin",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/leolin310148/ShortcutBadger"
+ ),
+
+ license(
+ "EventBus",
+ "2012-2020",
+ "Markus Junginger, greenrobot",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/greenrobot/EventBus"
+ ),
+
+ license(
+ "android-gif-drawable",
+ "2013 - present,",
+ "Karol Wrótniak, Droids on Roids LLC\n",
+ OpenSourceLicense.MIT,
+ "https://github.com/koral--/android-gif-drawable"
+ ),
+
+ license(
+ "Android Debug Database",
+ "2019 Amit Shekhar,",
+ "2011 Android Open Source Project",
+ OpenSourceLicense.APACHE_2,
+ "https://github.com/amitshekhariitbhu/Android-Debug-Database"
)
- }
+ )
- override fun getActivityTitle(): CharSequence? {
+ override fun getActivityTitle(): CharSequence {
return getString(R.string.settings_about_licenses_text)
}
-
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java
deleted file mode 100644
index 555bc3fd..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java
+++ /dev/null
@@ -1,1417 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.settings;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.provider.Settings;
-import android.widget.Toast;
-
-import com.afollestad.materialdialogs.MaterialDialog;
-import com.danielstone.materialaboutlibrary.ConvenienceBuilder;
-import com.danielstone.materialaboutlibrary.MaterialAboutFragment;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutActionSwitchItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutItemOnClickAction;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutProfileItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutSwitchItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem;
-import com.danielstone.materialaboutlibrary.model.MaterialAboutCard;
-import com.danielstone.materialaboutlibrary.model.MaterialAboutList;
-import com.mikepenz.iconics.IconicsColor;
-import com.mikepenz.iconics.IconicsDrawable;
-import com.mikepenz.iconics.IconicsSize;
-import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
-import com.theartofdev.edmodo.cropper.CropImage;
-import com.theartofdev.edmodo.cropper.CropImageView;
-import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import pl.szczodrzynski.edziennik.App;
-import pl.szczodrzynski.edziennik.BuildConfig;
-import pl.szczodrzynski.edziennik.ExtensionsKt;
-import pl.szczodrzynski.edziennik.MainActivity;
-import pl.szczodrzynski.edziennik.R;
-import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi;
-import pl.szczodrzynski.edziennik.data.db.entity.LoginStore;
-import pl.szczodrzynski.edziennik.network.NetworkUtils;
-import pl.szczodrzynski.edziennik.sync.SyncWorker;
-import pl.szczodrzynski.edziennik.sync.UpdateWorker;
-import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog;
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog;
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog;
-import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog;
-import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog;
-import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity;
-import pl.szczodrzynski.edziennik.utils.Themes;
-import pl.szczodrzynski.edziennik.utils.Utils;
-import pl.szczodrzynski.edziennik.utils.models.Date;
-import pl.szczodrzynski.edziennik.utils.models.Time;
-
-import static android.app.Activity.RESULT_OK;
-import static pl.szczodrzynski.edziennik.ExtensionsKt.initDefaultLocale;
-import static pl.szczodrzynski.edziennik.data.db.entity.Profile.REGISTRATION_DISABLED;
-import static pl.szczodrzynski.edziennik.data.db.entity.Profile.REGISTRATION_ENABLED;
-import static pl.szczodrzynski.edziennik.utils.Utils.d;
-import static pl.szczodrzynski.edziennik.utils.Utils.getRealPathFromURI;
-import static pl.szczodrzynski.edziennik.utils.Utils.getResizedBitmap;
-import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_AVG_2_AVG;
-import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_AVG_2_SEM;
-import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_SEM_2_AVG;
-import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_SEM_2_SEM;
-import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_ALL_GRADES;
-
-public class SettingsNewFragment extends MaterialAboutFragment {
-
- private static final String TAG = "Settings";
- private App app = null;
- private MainActivity activity;
-
- private static final int CARD_PROFILE = 0;
- private static final int CARD_THEME = 1;
- private static final int CARD_SYNC = 2;
- private static final int CARD_REGISTER = 3;
- private static final int CARD_ABOUT = 4;
- private int iconColor = Color.WHITE;
- private int primaryTextOnPrimaryBg = -1;
- private int secondaryTextOnPrimaryBg = -1;
- private int iconSizeDp = 20;
-
- private MaterialAboutCard getCardWithItems(CharSequence title, ArrayList items, boolean primaryColor) {
- MaterialAboutCard card = new MaterialAboutCard.Builder().title(title).cardColor(0xff1976D2).build();
- card.getItems().addAll(items);
- return card;
- }
- private MaterialAboutCard getCardWithItems(CharSequence title, ArrayList items) {
- MaterialAboutCard card = new MaterialAboutCard.Builder().title(title).cardColor(Utils.getAttr(activity, R.attr.mal_card_background)).build();
- card.getItems().addAll(items);
- return card;
- }
- private void addCardItems(int cardIndex, ArrayList itemsNew) {
- ArrayList items = getList().getCards().get(cardIndex).getItems();
- items.remove(items.size() - 1);
- items.addAll(itemsNew);
- refreshMaterialAboutList();
- }
- private void addCardItem(int cardIndex, int itemIndex, MaterialAboutItem item) {
- ArrayList items = getList().getCards().get(cardIndex).getItems();
- items.add(itemIndex, item);
- refreshMaterialAboutList();
- }
- private void removeCardItem(int cardIndex, int itemIndex) {
- ArrayList items = getList().getCards().get(cardIndex).getItems();
- items.remove(itemIndex);
- refreshMaterialAboutList();
- }
- private MaterialAboutActionItem getMoreItem(MaterialAboutItemOnClickAction onClickAction) {
- return new MaterialAboutActionItem(
- getString(R.string.settings_more_text),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_chevron_down)
- .size(IconicsSize.dp(14))
- .color(IconicsColor.colorInt(iconColor)),
- onClickAction
- );
- }
-
-
- /* _____ __ _ _
- | __ \ / _(_) |
- | |__) | __ ___ | |_ _| | ___
- | ___/ '__/ _ \| _| | |/ _ \
- | | | | | (_) | | | | | __/
- |_| |_| \___/|_| |_|_|\__*/
- private Drawable getProfileDrawable() {
- return app.getProfile().getImageDrawable(activity);
-
- /*Bitmap profileImage = null;
- if (app.getProfile().getImage() != null && !app.getProfile().getImage().equals("")) {
- profileImage = BitmapFactory.decodeFile(app.getProfile().getImage());
- RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(getResources(), profileImage);
- roundDrawable.setCircular(true);
- return roundDrawable;
- }
- return getDrawableFromRes(getContext(), R.drawable.profile);*/
-
- /*if (profileImage == null) {
- profileImage = BitmapFactory.decodeResource(getResources(), R.drawable.profile);
- }
- profileImage = ThumbnailUtils.extractThumbnail(profileImage, Math.min(profileImage.getWidth(), profileImage.getHeight()), Math.min(profileImage.getWidth(), profileImage.getHeight()));
- RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(getResources(), profileImage);
- roundDrawable.setCircular(true);
- return roundDrawable;*/
- }
- private MaterialAboutProfileItem profileCardTitleItem;
- private ArrayList getProfileCard(boolean expandedOnly) {
- ArrayList items = new ArrayList<>();
- if (!expandedOnly) {
-
- profileCardTitleItem = new MaterialAboutProfileItem(
- app.getProfile().getName(),
- app.getProfile().getSubname(),
- getProfileDrawable()
- );
- profileCardTitleItem.setOnClickAction(() -> {
- new MaterialDialog.Builder(activity)
- .title(R.string.settings_profile_change_title)
- .items(
- getString(R.string.settings_profile_change_name),
- getString(R.string.settings_profile_change_image),
- app.getProfile().getImage() == null ? null : getString(R.string.settings_profile_remove_image)
- )
- .itemsCallback((dialog, itemView, position, text) -> {
- switch (position) {
- case 0:
- new MaterialDialog.Builder(activity)
- .title(getString(R.string.settings_profile_change_name_dialog_title))
- .input(getString(R.string.settings_profile_change_name_dialog_text), app.getProfile().getName(), (dialog1, input) -> {
- app.getProfile().setName(input.toString());
- profileCardTitleItem.setText(input);
- profileCardTitleItem.setIcon(getProfileDrawable());
- refreshMaterialAboutList();
- app.profileSave();
- })
- .positiveText(R.string.ok)
- .negativeText(R.string.cancel)
- .show();
- break;
- case 1:
- startActivityForResult(CropImage.getPickImageChooserIntent(activity), 21);
- break;
- case 2:
- app.getProfile().setImage(null);
- profileCardTitleItem.setIcon(getProfileDrawable());
- refreshMaterialAboutList();
- app.profileSave();
- break;
- }
- })
- .negativeText(R.string.cancel)
- .show();
- });
- items.add(profileCardTitleItem);
-
- /*items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_profile_change_password_text),
- getString(R.string.settings_profile_change_password_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_key_variant)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
-
- })
- );*/
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_add_student_text),
- getString(R.string.settings_add_student_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_account_plus_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- startActivity(new Intent(activity, LoginActivity.class));
- })
- );
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_profile_notifications_text),
- getString(R.string.settings_profile_notifications_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_filter_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- new NotificationFilterDialog(activity, null, null);
- })
- );
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_profile_remove_text),
- getString(R.string.settings_profile_remove_subtext),
- new IconicsDrawable(activity)
- .icon(SzkolnyFont.Icon.szf_delete_empty_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName(), false);
- })
- );
-
- items.add(getMoreItem(() -> addCardItems(CARD_PROFILE, getProfileCard(true))));
- }
- else {
-
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_profile_sync_text),
- getString(R.string.settings_profile_sync_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_account_convert)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getProfile().getSyncEnabled())
- .setOnChangeAction(((isChecked, tag) -> {
- app.getProfile().setSyncEnabled(isChecked);
- app.profileSave();
- return true;
- }))
- );
-
- }
- return items;
- }
-
- /* _______ _
- |__ __| |
- | | | |__ ___ _ __ ___ ___
- | | | '_ \ / _ \ '_ ` _ \ / _ \
- | | | | | | __/ | | | | | __/
- |_| |_| |_|\___|_| |_| |_|\__*/
- private ArrayList getThemeCard(boolean expandedOnly) {
- ArrayList items = new ArrayList<>();
- if (!expandedOnly) {
-
- Date today = Date.getToday();
- if (today.month == 12 || today.month == 1) {
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_theme_snowfall_text),
- getString(R.string.settings_theme_snowfall_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_snowflake)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getConfig().getUi().getSnowfall())
- .setOnChangeAction((isChecked, tag) -> {
- app.getConfig().getUi().setSnowfall(isChecked);
- activity.recreate();
- return true;
- })
- );
- }
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_theme_theme_text),
- Themes.INSTANCE.getThemeName(activity),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_palette_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- new MaterialDialog.Builder(activity)
- .title(R.string.settings_theme_theme_text)
- .items(Themes.INSTANCE.getThemeNames(activity))
- .itemsCallbackSingleChoice(app.getConfig().getUi().getTheme(), (dialog, itemView, which, text) -> {
- if (app.getConfig().getUi().getTheme() == which)
- return true;
- app.getConfig().getUi().setTheme(which);
- Themes.INSTANCE.setThemeInt(app.getConfig().getUi().getTheme());
- activity.recreate();
- return true;
- })
- .show();
- })
- );
-
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_theme_mini_drawer_text),
- getString(R.string.settings_theme_mini_drawer_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_dots_vertical)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getConfig().getUi().getMiniMenuVisible())
- .setOnChangeAction((isChecked, tag) -> {
- // 0,1 1
- // 0,0 0
- // 1,1 0
- // 1,0 1
- app.getConfig().getUi().setMiniMenuVisible(isChecked);
- activity.getNavView().drawer.setMiniDrawerVisiblePortrait(isChecked);
- return true;
- })
- );
-
- items.add(getMoreItem(() -> addCardItems(CARD_THEME, getThemeCard(true))));
- }
- else {
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_theme_mini_drawer_buttons_text),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_format_list_checks)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- List buttonIds = new ArrayList<>();
- buttonIds.add(MainActivity.DRAWER_ITEM_HOME);
- buttonIds.add(MainActivity.DRAWER_ITEM_TIMETABLE);
- buttonIds.add(MainActivity.DRAWER_ITEM_AGENDA);
- buttonIds.add(MainActivity.DRAWER_ITEM_GRADES);
- buttonIds.add(MainActivity.DRAWER_ITEM_MESSAGES);
- buttonIds.add(MainActivity.DRAWER_ITEM_HOMEWORK);
- buttonIds.add(MainActivity.DRAWER_ITEM_BEHAVIOUR);
- buttonIds.add(MainActivity.DRAWER_ITEM_ATTENDANCE);
- buttonIds.add(MainActivity.DRAWER_ITEM_ANNOUNCEMENTS);
- buttonIds.add(MainActivity.DRAWER_ITEM_NOTIFICATIONS);
- buttonIds.add(MainActivity.DRAWER_ITEM_SETTINGS);
- //buttonIds.add(MainActivity.DRAWER_ITEM_DEBUG);
- List buttonCaptions = new ArrayList<>();
- buttonCaptions.add(getString(R.string.menu_home_page));
- buttonCaptions.add(getString(R.string.menu_timetable));
- buttonCaptions.add(getString(R.string.menu_agenda));
- buttonCaptions.add(getString(R.string.menu_grades));
- buttonCaptions.add(getString(R.string.menu_messages));
- buttonCaptions.add(getString(R.string.menu_homework));
- buttonCaptions.add(getString(R.string.menu_notices));
- buttonCaptions.add(getString(R.string.menu_attendance));
- buttonCaptions.add(getString(R.string.menu_announcements));
- buttonCaptions.add(getString(R.string.menu_notifications));
- buttonCaptions.add(getString(R.string.menu_settings));
- //buttonCaptions.add(getString(R.string.title_debugging));
- List selectedIds = new ArrayList<>();
- for (int id: app.getConfig().getUi().getMiniMenuButtons()) {
- selectedIds.add(buttonIds.indexOf(id));
- }
- new MaterialDialog.Builder(activity)
- .title(R.string.settings_theme_mini_drawer_buttons_dialog_title)
- .content(getString(R.string.settings_theme_mini_drawer_buttons_dialog_text))
- .items(buttonCaptions)
- .itemsCallbackMultiChoice(selectedIds.toArray(new Integer[0]), (dialog, which, text) -> {
- List list = new ArrayList<>();
- for (int index: which) {
- if (index == -1)
- continue;
- // wtf
-
- int id = buttonIds.get(index);
- list.add(id);
- }
- app.getConfig().getUi().setMiniMenuButtons(list);
- activity.setDrawerItems();
- activity.getDrawer().updateBadges();
- return true;
- })
- .positiveText(R.string.ok)
- .show();
- })
- );
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_theme_drawer_header_text),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_image_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- if (app.getConfig().getUi().getHeaderBackground() != null) {
- new MaterialDialog.Builder(activity)
- .title(R.string.what_do_you_want_to_do)
- .items(getString(R.string.settings_theme_drawer_header_dialog_set), getString(R.string.settings_theme_drawer_header_dialog_restore))
- .itemsCallback((dialog, itemView, position, text) -> {
- if (position == 0) {
- startActivityForResult(CropImage.getPickImageChooserIntent(activity), 22);
- } else {
- MainActivity ac = (MainActivity) getActivity();
- app.getConfig().getUi().setHeaderBackground(null);
- if (ac != null) {
- ac.getDrawer().setAccountHeaderBackground(null);
- ac.getDrawer().open();
- }
- }
- })
- .show();
- }
- else {
- startActivityForResult(CropImage.getPickImageChooserIntent(activity), 22);
- }
- })
- );
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_theme_app_background_text),
- getString(R.string.settings_theme_app_background_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_image_filter_hdr)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- if (app.getConfig().getUi().getAppBackground() != null) {
- new MaterialDialog.Builder(activity)
- .title(R.string.what_do_you_want_to_do)
- .items(getString(R.string.settings_theme_app_background_dialog_set), getString(R.string.settings_theme_app_background_dialog_restore))
- .itemsCallback((dialog, itemView, position, text) -> {
- if (position == 0) {
- startActivityForResult(CropImage.getPickImageChooserIntent(activity), 23);
- } else {
- app.getConfig().getUi().setAppBackground(null);
- activity.recreate();
- }
- })
- .show();
- }
- else {
- startActivityForResult(CropImage.getPickImageChooserIntent(activity), 23);
- }
- })
- );
-
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_theme_open_drawer_on_back_pressed_text),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_menu_open)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getConfig().getUi().getOpenDrawerOnBackPressed())
- .setOnChangeAction((isChecked, tag) -> {
- app.getConfig().getUi().setOpenDrawerOnBackPressed(isChecked);
- return true;
- })
- );
- }
- return items;
- }
-
- /* _____
- / ____|
- | (___ _ _ _ __ ___
- \___ \| | | | '_ \ / __|
- ____) | |_| | | | | (__
- |_____/ \__, |_| |_|\___|
- __/ |
- |__*/
- private String getSyncCardIntervalSubText() {
-
- if (app.getConfig().getSync().getInterval() < 60 * 60)
- return getString(
- R.string.settings_sync_sync_interval_subtext_format,
- ExtensionsKt.plural(activity, R.plurals.time_till_minutes, app.getConfig().getSync().getInterval() / 60)
- );
- return getString(
- R.string.settings_sync_sync_interval_subtext_format,
- ExtensionsKt.plural(activity, R.plurals.time_till_hours, app.getConfig().getSync().getInterval() / 60 / 60) +
- (app.getConfig().getSync().getInterval() / 60 % 60 == 0 ?
- "" :
- " " + ExtensionsKt.plural(activity, R.plurals.time_till_minutes, app.getConfig().getSync().getInterval() / 60 % 60)
- )
- );
- }
- private String getSyncCardQuietHoursSubText() {
- if (app.getConfig().getSync().getQuietHoursStart() == null || app.getConfig().getSync().getQuietHoursEnd() == null)
- return "";
- return getString(
- app.getConfig().getSync().getQuietHoursStart().getValue() >= app.getConfig().getSync().getQuietHoursEnd().getValue() ? R.string.settings_sync_quiet_hours_subtext_next_day_format : R.string.settings_sync_quiet_hours_subtext_format,
- app.getConfig().getSync().getQuietHoursStart().getStringHM(),
- app.getConfig().getSync().getQuietHoursEnd().getStringHM()
- );
- }
- private MaterialAboutItem getSyncCardWifiItem() {
- return new MaterialAboutSwitchItem(
- getString(R.string.settings_sync_wifi_text),
- getString(R.string.settings_sync_wifi_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_wifi_strength_2)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getConfig().getSync().getOnlyWifi())
- .setOnChangeAction((isChecked, tag) -> {
- app.getConfig().getSync().setOnlyWifi(isChecked);
- SyncWorker.Companion.rescheduleNext(app);
- return true;
- });
- }
- private MaterialAboutActionSwitchItem syncCardIntervalItem;
- private MaterialAboutActionSwitchItem syncCardQuietHoursItem;
- private ArrayList getSyncCard(boolean expandedOnly) {
- ArrayList items = new ArrayList<>();
- if (!expandedOnly) {
-
- syncCardIntervalItem = new MaterialAboutActionSwitchItem(
- getString(R.string.settings_sync_sync_interval_text),
- getString(R.string.settings_sync_sync_interval_subtext_disabled),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_download_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- );
- syncCardIntervalItem.setSubTextChecked(getSyncCardIntervalSubText());
- syncCardIntervalItem.setChecked(app.getConfig().getSync().getEnabled());
- syncCardIntervalItem.setOnClickAction(() -> {
- List intervalNames = new ArrayList<>();
- if (App.Companion.getDebugMode() && false) {
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_seconds, 30));
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 2));
- }
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 30));
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 45));
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 1));
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 1)+" "+ ExtensionsKt.plural(activity, R.plurals.time_till_minutes, 30));
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 2));
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 3));
- intervalNames.add(ExtensionsKt.plural(activity, R.plurals.time_till_hours, 4));
- List intervals = new ArrayList<>();
- if (App.Companion.getDebugMode() && false) {
- intervals.add(30);
- intervals.add(2 * 60);
- }
- intervals.add(30 * 60);
- intervals.add(45 * 60);
- intervals.add(60 * 60);
- intervals.add(90 * 60);
- intervals.add(120 * 60);
- intervals.add(180 * 60);
- intervals.add(240 * 60);
- new MaterialDialog.Builder(activity)
- .title(getString(R.string.settings_sync_sync_interval_dialog_title))
- .content(getString(R.string.settings_sync_sync_interval_dialog_text))
- .items(intervalNames)
- .itemsCallbackSingleChoice(intervals.indexOf(app.getConfig().getSync().getInterval()), (dialog, itemView, which, text) -> {
- app.getConfig().getSync().setInterval(intervals.get(which));
- syncCardIntervalItem.setSubTextChecked(getSyncCardIntervalSubText());
- syncCardIntervalItem.setChecked(true);
- if (!app.getConfig().getSync().getEnabled()) {
- addCardItem(CARD_SYNC, 1, getSyncCardWifiItem());
- }
- else {
- refreshMaterialAboutList();
- }
- app.getConfig().getSync().setEnabled(true);
- // app.appConfig modifications have to surround syncCardIntervalItem and those ifs
- SyncWorker.Companion.rescheduleNext(app);
- return true;
- })
- .show();
- });
- syncCardIntervalItem.setOnChangeAction((isChecked, tag) -> {
- if (isChecked && !app.getConfig().getSync().getEnabled()) {
- addCardItem(CARD_SYNC, 1, getSyncCardWifiItem());
- }
- else if (!isChecked) {
- removeCardItem(CARD_SYNC, 1);
- }
- app.getConfig().getSync().setEnabled(isChecked);
- SyncWorker.Companion.rescheduleNext(app);
- return true;
- });
- items.add(syncCardIntervalItem);
-
- if (app.getConfig().getSync().getEnabled()) {
- items.add(getSyncCardWifiItem());
- }
-
- /* items.add(
- new MaterialAboutSwitchItem(
- "Cisza na lekcjach",
- "Nie odtwarzaj dźwięku powiadomień podczas lekcji",
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_volume_off)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.appConfig.quietDuringLessons)
- .setOnChangeAction((isChecked) -> {
- app.appConfig.quietDuringLessons = isChecked;
- app.saveConfig("quietDuringLessons");
- return true;
- })
- );*/
-
-
- syncCardQuietHoursItem = new MaterialAboutActionSwitchItem(
- getString(R.string.settings_sync_quiet_hours_text),
- getString(R.string.settings_sync_quiet_hours_subtext_disabled),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_bell_sleep_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- );
- syncCardQuietHoursItem.setChecked(app.getConfig().getSync().getQuietHoursEnabled());
- syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText());
- syncCardQuietHoursItem.setOnClickAction(() -> {
- new MaterialDialog.Builder(activity)
- .title(R.string.settings_sync_quiet_hours_dialog_title)
- .items(
- getString(R.string.settings_sync_quiet_hours_set_beginning),
- getString(R.string.settings_sync_quiet_hours_set_end)
- )
- .itemsCallback((dialog, itemView, position, text) -> {
- if (position == 0) {
- // set beginning
- Time time = app.getConfig().getSync().getQuietHoursStart();
- if (time == null)
- time = new Time(22, 30, 0);
- TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> {
- app.getConfig().getSync().setQuietHoursEnabled(true);
- app.getConfig().getSync().setQuietHoursStart(new Time(hourOfDay, minute, second));
- syncCardQuietHoursItem.setChecked(true);
- syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText());
- refreshMaterialAboutList();
- }, time.hour, time.minute, 0, true).show(activity.getSupportFragmentManager(), "TimePickerDialog");
- }
- else {
- // set end
- Time time = app.getConfig().getSync().getQuietHoursEnd();
- if (time == null)
- time = new Time(5, 30, 0);
- TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> {
- app.getConfig().getSync().setQuietHoursEnabled(true);
- app.getConfig().getSync().setQuietHoursEnd(new Time(hourOfDay, minute, second));
- syncCardQuietHoursItem.setChecked(true);
- syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText());
- refreshMaterialAboutList();
- }, time.hour, time.minute, 0, true).show(activity.getSupportFragmentManager(), "TimePickerDialog");
- }
- })
- .show();
- });
- syncCardQuietHoursItem.setOnChangeAction((isChecked, tag) -> {
- app.getConfig().getSync().setQuietHoursEnabled(isChecked);
- if (isChecked && app.getConfig().getSync().getQuietHoursStart() == null) {
- app.getConfig().getSync().setQuietHoursStart(new Time(22, 30, 0));
- app.getConfig().getSync().setQuietHoursEnd(new Time(5, 30, 0));
- syncCardQuietHoursItem.setSubTextChecked(getSyncCardQuietHoursSubText());
- refreshMaterialAboutList();
- }
- return true;
- });
- items.add(syncCardQuietHoursItem);
-
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_sync_web_push_text),
- getString(R.string.settings_sync_web_push_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_laptop)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- activity.loadTarget(MainActivity.TARGET_WEB_PUSH, null);
- })
- );
-
- items.add(getMoreItem(() -> addCardItems(CARD_SYNC, getSyncCard(true))));
- }
- else {
- // TODO: 2019-04-27 add notification sound options: szkolny.eu, system default, custom
- /*items.add(
- new MaterialAboutActionItem(
- "Dźwięk powiadomień",
- "Szkolny.eu",
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_volume_high)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
-
- })
- );*/
-
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_sync_updates_text),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_cellphone_arrow_down)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getConfig().getSync().getNotifyAboutUpdates())
- .setOnChangeAction((isChecked, tag) -> {
- app.getConfig().getSync().setNotifyAboutUpdates(isChecked);
- UpdateWorker.Companion.rescheduleNext(app);
- return true;
- })
- );
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- items.add(
- new MaterialAboutActionItem(
- getString(R.string.settings_sync_notifications_settings_text),
- getString(R.string.settings_sync_notifications_settings_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_settings_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setOnClickAction(() -> {
- String channel = app.getNotificationChannelsManager().getData().getKey();
- Intent intent = new Intent();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
- intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel);
- intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName());
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- if (channel != null) {
- intent.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
- intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel);
- } else {
- intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
- }
- intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName());
- } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
- intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
- intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName());
- } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
- intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
- intent.putExtra("app_package", activity.getPackageName());
- intent.putExtra("app_uid", activity.getApplicationInfo().uid);
- } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
- intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.setData(Uri.parse("package:" + activity.getPackageName()));
- }
- activity.startActivity(intent);
- })
- );
- }
- }
- return items;
- }
-
- /* _____ _ _
- | __ \ (_) | |
- | |__) |___ __ _ _ ___| |_ ___ _ __
- | _ // _ \/ _` | / __| __/ _ \ '__|
- | | \ \ __/ (_| | \__ \ || __/ |
- |_| \_\___|\__, |_|___/\__\___|_|
- __/ |
- |__*/
- private String getRegisterCardAverageModeSubText() {
- switch (app.getConfig().forProfile().getGrades().getYearAverageMode()) {
- default:
- case YEAR_1_AVG_2_AVG:
- return getString(R.string.settings_register_avg_mode_0_short);
- case YEAR_1_SEM_2_AVG:
- return getString(R.string.settings_register_avg_mode_1_short);
- case YEAR_1_AVG_2_SEM:
- return getString(R.string.settings_register_avg_mode_2_short);
- case YEAR_1_SEM_2_SEM:
- return getString(R.string.settings_register_avg_mode_3_short);
- case YEAR_ALL_GRADES:
- return getString(R.string.settings_register_avg_mode_4_short);
- }
- }
- private String getRegisterCardBellSyncSubText() {
- if (app.getConfig().getTimetable().getBellSyncDiff() == null)
- return getString(R.string.settings_register_bell_sync_subtext_disabled);
- return getString(
- R.string.settings_register_bell_sync_subtext_format,
- (app.getConfig().getTimetable().getBellSyncMultiplier() == -1 ? "-" : "+") + app.getConfig().getTimetable().getBellSyncDiff().getStringHMS()
- );
- }
- private MaterialAboutItem getRegisterCardSharedEventsItem() {
- return new MaterialAboutSwitchItem(
- getString(R.string.settings_register_shared_events_text),
- getString(R.string.settings_register_shared_events_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_share_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getProfile().getEnableSharedEvents())
- .setOnChangeAction((isChecked, tag) -> {
- app.getProfile().setEnableSharedEvents(isChecked);
- app.profileSave();
- if (isChecked) new MaterialDialog.Builder(activity)
- .title(R.string.event_sharing)
- .content(getString(R.string.settings_register_shared_events_dialog_enabled_text))
- .positiveText(R.string.ok)
- .show();
- else new MaterialDialog.Builder(activity)
- .title(R.string.event_sharing)
- .content(getString(R.string.settings_register_shared_events_dialog_disabled_text))
- .positiveText(R.string.ok)
- .show();
- return true;
- });
- }
-
- private MaterialAboutSwitchItem registerCardAllowRegistrationItem;
- private MaterialAboutActionItem registerCardBellSyncItem;
- private ArrayList getRegisterCard(boolean expandedOnly) {
- ArrayList items = new ArrayList<>();
- if (!expandedOnly) {
- items.add(new MaterialAboutActionItem(
- getString(R.string.menu_grades_config),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- ).setOnClickAction(() -> new GradesConfigDialog(activity, false, null, null)));
-
- items.add(new MaterialAboutActionItem(
- getString(R.string.menu_attendance_config),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- ).setOnClickAction(() -> new AttendanceConfigDialog(activity, false, null, null)));
-
- registerCardAllowRegistrationItem = new MaterialAboutSwitchItem(
- getString(R.string.settings_register_allow_registration_text),
- getString(R.string.settings_register_allow_registration_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_account_circle_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- );
- registerCardAllowRegistrationItem.setChecked(app.getProfile().getRegistration() == REGISTRATION_ENABLED);
- registerCardAllowRegistrationItem.setOnChangeAction((isChecked, tag) -> {
- if (isChecked) new MaterialDialog.Builder(activity)
- .title(getString(R.string.settings_register_allow_registration_dialog_enabled_title))
- .content(getString(R.string.settings_register_allow_registration_dialog_enabled_text))
- .positiveText(R.string.i_agree)
- .negativeText(R.string.not_now)
- .onPositive(((dialog, which) -> {
- registerCardAllowRegistrationItem.setChecked(true);
- app.getProfile().setRegistration(REGISTRATION_ENABLED);
- app.profileSave();
- addCardItem(CARD_REGISTER, 2, getRegisterCardSharedEventsItem());
- refreshMaterialAboutList();
- }))
- .show();
- else new MaterialDialog.Builder(activity)
- .title(getString(R.string.settings_register_allow_registration_dialog_disabled_title))
- .content(getString(R.string.settings_register_allow_registration_dialog_disabled_text))
- .positiveText(R.string.ok)
- .negativeText(R.string.cancel)
- .onPositive(((dialog, which) -> {
- registerCardAllowRegistrationItem.setChecked(false);
- app.getProfile().setRegistration(REGISTRATION_DISABLED);
- app.profileSave();
- removeCardItem(CARD_REGISTER, 2);
- refreshMaterialAboutList();
- MaterialDialog progressDialog = new MaterialDialog.Builder(activity)
- .title(getString(R.string.settings_register_allow_registration_dialog_disabling_title))
- .content(getString(R.string.settings_register_allow_registration_dialog_disabling_text))
- .positiveText(R.string.ok)
- .negativeText(R.string.abort)
- .show();
- AsyncTask.execute(() -> {
- new SzkolnyApi(app).runCatching(szkolnyApi -> null, szkolnyApi -> null);
- activity.runOnUiThread(() -> {
- progressDialog.dismiss();
- Toast.makeText(activity, getString(R.string.settings_register_allow_registration_dialog_disabling_finished), Toast.LENGTH_SHORT).show();
- });
- });
- }))
- .show();
- return false;
- });
- items.add(registerCardAllowRegistrationItem);
-
- if (app.getProfile().getRegistration() == REGISTRATION_ENABLED) {
- items.add(getRegisterCardSharedEventsItem());
- }
-
- items.add(getMoreItem(() -> addCardItems(CARD_REGISTER, getRegisterCard(true))));
- }
- else {
- registerCardBellSyncItem = new MaterialAboutActionItem(
- getString(R.string.settings_register_bell_sync_text),
- getRegisterCardBellSyncSubText(),
- new IconicsDrawable(activity)
- .icon(SzkolnyFont.Icon.szf_alarm_bell_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- );
- registerCardBellSyncItem.setOnClickAction(() -> {
- new MaterialDialog.Builder(activity)
- .title(R.string.bell_sync_title)
- .content(R.string.bell_sync_adjust_content)
- .positiveText(R.string.ok)
- .negativeText(R.string.cancel)
- .neutralText(R.string.reset)
- .inputRangeRes(8, 8, R.color.md_red_500)
- .input("±H:MM:SS",
- (app.getConfig().getTimetable().getBellSyncDiff() != null
- ? (app.getConfig().getTimetable().getBellSyncMultiplier() == -1 ? "-" : "+") + app.getConfig().getTimetable().getBellSyncDiff().getStringHMS()
- : ""), (dialog, input) -> {
- if (input == null)
- return;
- if (input.length() < 8) {
- Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show();
- return;
- }
- if (input.charAt(2) != ':' || input.charAt(5) != ':') {
- Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show();
- return;
- }
- if (input.charAt(0) == '+') {
- app.getConfig().getTimetable().setBellSyncMultiplier(1);
- }
- else if (input.charAt(0) == '-') {
- app.getConfig().getTimetable().setBellSyncMultiplier(-1);
- }
- else {
- Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show();
- return;
- }
-
- int hour;
- int minute;
- int second;
- try {
- hour = Integer.parseInt(input.charAt(1) + "");
- minute = Integer.parseInt(input.charAt(3) + "" + input.charAt(4));
- second = Integer.parseInt(input.charAt(6) + "" + input.charAt(7));
- }
- catch (Exception e) {
- e.printStackTrace();
- Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show();
- return;
- }
-
- app.getConfig().getTimetable().setBellSyncDiff(new Time(hour, minute, second));
- registerCardBellSyncItem.setSubText(getRegisterCardBellSyncSubText());
- refreshMaterialAboutList();
- })
- .onNeutral(((dialog, which) -> {
- app.getConfig().getTimetable().setBellSyncDiff(null);
- app.getConfig().getTimetable().setBellSyncMultiplier(0);
- registerCardBellSyncItem.setSubText(getRegisterCardBellSyncSubText());
- refreshMaterialAboutList();
- }))
- .show();
- });
- items.add(registerCardBellSyncItem);
-
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_register_count_in_seconds_text),
- getString(R.string.settings_register_count_in_seconds_subtext),
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_timer)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getConfig().getTimetable().getCountInSeconds())
- .setOnChangeAction((isChecked, tag) -> {
- app.getConfig().getTimetable().setCountInSeconds(isChecked);
- return true;
- })
- );
-
- if (app.getProfile().getLoginStoreType() == LoginStore.LOGIN_TYPE_LIBRUS) {
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_register_show_teacher_absences_text),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_account_arrow_right_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getProfile().getStudentData("showTeacherAbsences", true))
- .setOnChangeAction((isChecked, tag) -> {
- app.getProfile().putStudentData("showTeacherAbsences", isChecked);
- app.profileSave();
- return true;
- })
- );
- }
-
- if (App.Companion.getDevMode()) {
- items.add(
- new MaterialAboutSwitchItem(
- getString(R.string.settings_register_hide_sticks_from_old),
- null,
- new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_numeric_1_box_outline)
- .size(IconicsSize.dp(iconSizeDp))
- .color(IconicsColor.colorInt(iconColor))
- )
- .setChecked(app.getConfig().forProfile().getGrades().getHideSticksFromOld())
- .setOnChangeAction((isChecked, tag) -> {
- app.getConfig().forProfile().getGrades().setHideSticksFromOld(isChecked);
- return true;
- })
- );
- }
-
- }
- return items;
- }
-
- /* _ _
- /\ | | | |
- / \ | |__ ___ _ _| |_
- / /\ \ | '_ \ / _ \| | | | __|
- / ____ \| |_) | (_) | |_| | |_
- /_/ \_\_.__/ \___/ \__,_|\_*/
- private MaterialAboutActionItem pref_about_version;
- private ArrayList getAboutCard(boolean expandedOnly) {
- primaryTextOnPrimaryBg = 0xffffffff;//getColorFromAttr(activity, R.attr.colorOnPrimary);
- secondaryTextOnPrimaryBg = 0xd0ffffff;//activity.getResources().getColor(R.color.secondaryTextLight);
-
- ArrayList items = new ArrayList<>();
- if (!expandedOnly) {
- items.add(new MaterialAboutTitleItem.Builder()
- .text(R.string.app_name)
- .desc(R.string.settings_about_title_subtext)
- .textColor(primaryTextOnPrimaryBg)
- .descColor(secondaryTextOnPrimaryBg)
- .icon(R.mipmap.ic_splash)
- .build());
-
- pref_about_version = new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_version_text)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .subText(BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_information_outline)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .build();
- final int[] clickCounter = {0};
- pref_about_version.setOnClickAction(() -> {
- if (6 - clickCounter[0] != 0) {
- Toast.makeText(activity, ("\ud83d\ude02"), Toast.LENGTH_SHORT).show();
- }
- refreshMaterialAboutList();
- clickCounter[0] = clickCounter[0] + 1;
- if (clickCounter[0] > 6) {
- final MediaPlayer mp = MediaPlayer.create(activity, R.raw.ogarnij_sie);
- mp.start();
- clickCounter[0] = 0;
- }
- });
- items.add(pref_about_version);
-
- items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_privacy_policy_text)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_shield_outline)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/privacy-policy")))
- .build());
-
- items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_discord_text)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .subText(R.string.settings_about_discord_subtext)
- .icon(new IconicsDrawable(activity)
- .icon(SzkolnyFont.Icon.szf_discord_outline)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/discord")))
- .build());
-
- items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_language_text)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .subText(R.string.settings_about_language_subtext)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_translate)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(() -> {
- new MaterialDialog.Builder(activity)
- .title(getString(R.string.settings_about_language_dialog_title))
- .content(getString(R.string.settings_about_language_dialog_text))
- .items(getString(R.string.language_system), getString(R.string.language_polish), getString(R.string.language_english), getString(R.string.language_german))
- .itemsCallbackSingleChoice(app.getConfig().getUi().getLanguage() == null ? 0 : app.getConfig().getUi().getLanguage().equals("pl") ? 1 : app.getConfig().getUi().getLanguage().equals("en") ? 2 : 3, (dialog, itemView, which, text) -> {
- switch (which) {
- case 0:
- app.getConfig().getUi().setLanguage(null);
- initDefaultLocale();
- break;
- case 1:
- app.getConfig().getUi().setLanguage("pl");
- break;
- case 2:
- app.getConfig().getUi().setLanguage("en");
- break;
- case 3:
- app.getConfig().getUi().setLanguage("de");
- break;
- }
- activity.recreate(MainActivity.DRAWER_ITEM_SETTINGS);
- return true;
- })
- .show();
- })
- .build());
-
- items.add(getMoreItem(() -> addCardItems(CARD_ABOUT, getAboutCard(true))));
- }
- else {
- items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_update_text)
- .subText(R.string.settings_about_update_subtext)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_update)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(() -> {
- //open browser or intent here
- NetworkUtils net = new NetworkUtils(app);
- if (!net.isOnline()) {
- new MaterialDialog.Builder(activity)
- .title(R.string.you_are_offline_title)
- .content(R.string.you_are_offline_text)
- .positiveText(R.string.ok)
- .show();
- } else {
- AsyncTask.execute(() -> {
- new UpdateWorker.JavaWrapper(app);
- });
- }
- })
- .build());
-
- items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_changelog_text)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_radar)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(() -> new ChangelogDialog(activity, null, null))
- .build());
-
- items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_licenses_text)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_code_braces)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(() -> {
- Intent intent = new Intent(activity, SettingsLicenseActivity.class);
- startActivity(intent);
- })
- .build());
-
- /*items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_intro_text)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon2.cmd_projector_screen)
- .color(IconicsColor.colorInt(iconColor))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(() -> {
- if (tryingToDevMode[0]) {
- if (getParentFragment() instanceof SettingsGeneralFragment) {
- ((SettingsGeneralFragment) getParentFragment()).showDevSettings();
- }
- tryingToDevMode[0] = false;
- return;
- }
- IntroConnectionFragment.connectionOk = true;
- IntroConnectionFragment.httpsOk = (app.requestScheme.equals("https"));
- Intent intent = new Intent(activity, MainIntroActivity.class);
- IntroSplashFragment.skipAnimation = false;
- startActivity(intent);
- })
- .build());*/
-
- if (App.Companion.getDevMode()) {
- items.add(new MaterialAboutActionItem.Builder()
- .text(R.string.settings_about_crash_text)
- .subText(R.string.settings_about_crash_subtext)
- .textColor(primaryTextOnPrimaryBg)
- .subTextColor(secondaryTextOnPrimaryBg)
- .icon(new IconicsDrawable(activity)
- .icon(CommunityMaterial.Icon.cmd_bug_outline)
- .color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
- .size(IconicsSize.dp(iconSizeDp)))
- .setOnClickAction(() -> {
- throw new RuntimeException("MANUAL CRASH");
- })
- .build());
- }
- }
- return items;
- }
-
- @Override
- protected MaterialAboutList getMaterialAboutList(Context activityContext) {
- if (getActivity() == null || getContext() == null || !isAdded())
- return null;
- this.activity = (MainActivity) activityContext;
- this.app = (App) activity.getApplication();
- iconColor = Themes.INSTANCE.getPrimaryTextColor(activityContext);
- if (app.getProfile() == null)
- return new MaterialAboutList.Builder().build();
-
- MaterialAboutList materialAboutList = new MaterialAboutList();
- materialAboutList.addCard(getCardWithItems(null, getProfileCard(false)));
- materialAboutList.addCard(getCardWithItems(getString(R.string.settings_theme_title_text), getThemeCard(false)));
- materialAboutList.addCard(getCardWithItems(getString(R.string.settings_sync_title_text), getSyncCard(false)));
- materialAboutList.addCard(getCardWithItems(getString(R.string.settings_about_register_title_text), getRegisterCard(false)));
- //if (configurableEndpoints != null)
- // materialAboutList.addCard(getCardWithItems(getString(R.string.settings_sync_customize_title_text), getSyncCustomizeCard(false)));
- materialAboutList.addCard(getCardWithItems(null, getAboutCard(false), true));
-
- return materialAboutList;
- }
-
- @Override
- protected int getTheme() {
- return Themes.INSTANCE.getAppTheme();
- }
-
- /* _____ _ ____ _ _
- / ____| | | | _ \ | | | |
- | | _ _ ___| |_ ___ _ __ ___ | |_) | __ _ ___| | ____ _ _ __ ___ _ _ _ __ __| |___
- | | | | | / __| __/ _ \| '_ ` _ \ | _ < / _` |/ __| |/ / _` | '__/ _ \| | | | '_ \ / _` / __|
- | |___| |_| \__ \ || (_) | | | | | | | |_) | (_| | (__| < (_| | | | (_) | |_| | | | | (_| \__ \
- \_____\__,_|___/\__\___/|_| |_| |_| |____/ \__,_|\___|_|\_\__, |_| \___/ \__,_|_| |_|\__,_|___/
- __/ |
- |__*/
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (data == null) {
- Toast.makeText(app, "Wystąpił błąd. Spróbuj ponownie", Toast.LENGTH_SHORT).show();
- return;
- }
- if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
- CropImage.ActivityResult result = CropImage.getActivityResult(data);
-
- Uri uri = result.getUri();
-
- File photoFile = new File(uri.getPath());
- File destFile = new File(getContext().getFilesDir(),"profile"+ app.getProfile().getId() +".jpg");
- if (destFile.exists()) {
- destFile.delete();
- destFile = new File(getContext().getFilesDir(),"profile"+ app.getProfile().getId() +".jpg");
- }
-
- d(TAG, "Source file: "+photoFile.getAbsolutePath());
- d(TAG, "Dest file: "+destFile.getAbsolutePath());
-
- if (result.getCropRect().width() > 512 || true) {
- Bitmap bigImage = BitmapFactory.decodeFile(uri.getPath());
- Bitmap smallImage = getResizedBitmap(bigImage, 512, 512);
- try (FileOutputStream out = new FileOutputStream(destFile)) {
- smallImage.compress(Bitmap.CompressFormat.JPEG, 80, out); // bmp is your Bitmap instance
- // PNG is a lossless format, the compression factor (100) is ignored
- app.getProfile().setImage(destFile.getAbsolutePath());
- app.profileSave();
- profileCardTitleItem.setIcon(getProfileDrawable());
- refreshMaterialAboutList();
- if (photoFile.exists()) {
- photoFile.delete();
- }
- //((MainActivity)getActivity()).recreateWithTransition(); // TODO somehow update miniDrawer profile picture
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- else {
- if (photoFile.renameTo(destFile)) {
- // success
- app.getProfile().setImage(destFile.getAbsolutePath());
- app.profileSave();
- profileCardTitleItem.setIcon(getProfileDrawable());
- refreshMaterialAboutList();
- //((MainActivity)getActivity()).recreateWithTransition(); // TODO somehow update miniDrawer profile picture
- }
- else {
- // not this time
- Toast.makeText(app, R.string.error_occured, Toast.LENGTH_LONG).show();
- }
- }
- }
- else if (requestCode == 21 && resultCode == Activity.RESULT_OK) {
- Uri uri = data.getData();
- if (uri != null) {
- String path = getRealPathFromURI(activity, uri);
- if (path.toLowerCase().endsWith(".gif")) {
- app.getProfile().setImage(path);
- app.profileSave();
- profileCardTitleItem.setIcon(getProfileDrawable());
- refreshMaterialAboutList();
- }
- else {
- CropImage.activity(data.getData())
- .setAspectRatio(1, 1)
- //.setMaxCropResultSize(512, 512)
- .setCropShape(CropImageView.CropShape.OVAL)
- .setGuidelines(CropImageView.Guidelines.ON)
- .start(activity, this);
- }
- }
-
- }
- else if (requestCode == 22 && resultCode == Activity.RESULT_OK) {
- Uri uri = data.getData();
- if (uri != null) {
- app.getConfig().getUi().setHeaderBackground(getRealPathFromURI(getContext(), uri));
- if (activity != null) {
- activity.getDrawer().setAccountHeaderBackground(app.getConfig().getUi().getHeaderBackground());
- activity.getDrawer().open();
- }
- }
- }
- else if (requestCode == 23 && resultCode == Activity.RESULT_OK) {
- Uri uri = data.getData();
- if (uri != null) {
- app.getConfig().getUi().setAppBackground(getRealPathFromURI(getContext(), uri));
- if (activity != null) {
- activity.recreate();
- }
- }
- }
-
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt
new file mode 100644
index 00000000..a86fe2e3
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-17.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings
+
+import com.danielstone.materialaboutlibrary.items.*
+import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
+import com.mikepenz.iconics.IconicsDrawable
+import com.mikepenz.iconics.typeface.IIcon
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
+import com.mikepenz.iconics.utils.colorInt
+import com.mikepenz.iconics.utils.sizeDp
+import pl.szczodrzynski.edziennik.MainActivity
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.after
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.utils.Colors
+import pl.szczodrzynski.edziennik.utils.Themes
+
+class SettingsUtil(
+ val activity: MainActivity,
+ private val onRefresh: () -> Unit
+) {
+
+ fun refresh() = onRefresh()
+
+ private fun IIcon.asDrawable(color: Int? = null, size: Int = 24) =
+ IconicsDrawable(activity).apply {
+ icon = this@asDrawable
+ sizeDp = size
+ colorInt = color ?: Themes.getPrimaryTextColor(activity)
+ }
+
+ fun createCard(
+ titleRes: Int?,
+ items: List,
+ itemsMore: List,
+ backgroundColor: Int? = null,
+ theme: Int? = null
+ ): MaterialAboutCard {
+ val card = MaterialAboutCard.Builder()
+ .title(titleRes ?: 0)
+ .cardColor(backgroundColor ?: 0)
+ .theme(theme ?: 0)
+ .build()
+ card.items.addAll(items)
+
+ if (itemsMore.isNotEmpty()) {
+ card.items.add(createMoreItem(card, itemsMore))
+ }
+
+ return card
+ }
+
+ fun createMoreItem(
+ card: MaterialAboutCard,
+ items: List
+ ): MaterialAboutActionItem {
+ val iconColor = card.cardColor.let {
+ if (it == 0)
+ null
+ else
+ Colors.legibleTextColor(it)
+ }
+
+ val moreItem = MaterialAboutActionItem.Builder()
+ .text(R.string.settings_more_text)
+ .icon(CommunityMaterial.Icon.cmd_chevron_down.asDrawable(iconColor, size = 24))
+ .build()
+
+ moreItem.setOnClickAction {
+ card.items.after(moreItem, items)
+ card.items.remove(moreItem)
+ onRefresh()
+ }
+
+ return moreItem
+ }
+
+ fun createSectionItem(text: Int) = MaterialAboutSectionItem(text)
+
+ fun createActionItem(
+ text: Int,
+ subText: Int? = null,
+ icon: IIcon,
+ backgroundColor: Int? = null,
+ onClick: (item: MaterialAboutActionItem) -> Unit
+ ): MaterialAboutActionItem {
+ val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) }
+
+ val item = MaterialAboutActionItem.Builder()
+ .text(text)
+ .subText(subText ?: 0)
+ .icon(icon.asDrawable(iconColor))
+ .build()
+
+ item.setOnClickAction {
+ onClick(item)
+ }
+
+ return item
+ }
+
+ fun createPropertyItem(
+ text: Int,
+ subText: Int? = null,
+ subTextChecked: Int? = null,
+ icon: IIcon,
+ backgroundColor: Int? = null,
+ value: Boolean,
+ beforeChange: ((item: MaterialAboutSwitchItem, value: Boolean) -> Boolean)? = null,
+ onChange: (item: MaterialAboutSwitchItem, value: Boolean) -> Unit
+ ): MaterialAboutSwitchItem {
+ val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) }
+
+ val item = MaterialAboutSwitchItem.Builder()
+ .text(text)
+ .subText(subText ?: 0)
+ .subTextChecked(subTextChecked ?: 0)
+ .icon(icon.asDrawable(iconColor))
+ .setChecked(value)
+ .build()
+
+ item.setOnCheckedChangedAction { item, isChecked ->
+ if (beforeChange?.invoke(item as MaterialAboutSwitchItem, isChecked) == false)
+ return@setOnCheckedChangedAction false
+ onChange(item as MaterialAboutSwitchItem, isChecked)
+ true
+ }
+
+ return item
+ }
+
+ fun createPropertyActionItem(
+ text: Int,
+ subText: Int? = null,
+ subTextChecked: Int? = null,
+ icon: IIcon,
+ backgroundColor: Int? = null,
+ value: Boolean,
+ onChange: (item: MaterialAboutActionSwitchItem, value: Boolean) -> Unit,
+ onClick: (item: MaterialAboutActionSwitchItem) -> Unit
+ ): MaterialAboutSwitchItem {
+ val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) }
+
+ val item = MaterialAboutActionSwitchItem.Builder()
+ .text(text)
+ .subText(subText ?: 0)
+ .subTextChecked(subTextChecked ?: 0)
+ .icon(icon.asDrawable(iconColor))
+ .setChecked(value)
+ .build()
+
+ item.setOnClickAction {
+ onClick(item)
+ }
+ item.setOnCheckedChangedAction { item, isChecked ->
+ onChange(item as MaterialAboutActionSwitchItem, isChecked)
+ true
+ }
+
+ return item
+ }
+
+ fun createTitleItem(): MaterialAboutTitleItem =
+ MaterialAboutTitleItem.Builder()
+ .text(R.string.app_name)
+ .desc(R.string.settings_about_title_subtext)
+ .icon(R.mipmap.ic_splash)
+ .build()
+
+ fun createProfileItem(
+ profile: Profile,
+ onClick: (item: MaterialAboutProfileItem, profile: Profile) -> Unit
+ ): MaterialAboutProfileItem {
+ val item = MaterialAboutProfileItem(
+ MaterialAboutTitleItem.Builder()
+ .text(profile.name)
+ .desc(profile.subname)
+ .icon(profile.getImageDrawable(activity))
+ .build()
+ )
+ item.setOnClickAction {
+ onClick(item, profile)
+ }
+ return item
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt
new file mode 100644
index 00000000..1fb14fcd
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-17.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings
+
+import android.content.Context
+import android.view.View
+import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder
+import com.danielstone.materialaboutlibrary.items.MaterialAboutItem
+import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder
+import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsViewTypeManager.ItemType.Companion.PROFILE_ITEM
+
+class SettingsViewTypeManager : DefaultViewTypeManager() {
+ class ItemType {
+ companion object {
+ const val PROFILE_ITEM = 10
+ }
+ }
+
+ override fun getLayout(itemType: Int) = when (itemType) {
+ PROFILE_ITEM -> R.layout.mal_material_about_profile_item
+ else -> super.getLayout(itemType)
+ }
+
+ override fun getViewHolder(itemType: Int, view: View): MaterialAboutItemViewHolder =
+ when (itemType) {
+ PROFILE_ITEM -> MaterialAboutProfileItem.getViewHolder(view)
+ else -> super.getViewHolder(itemType, view)
+ }
+
+ override fun setupItem(
+ itemType: Int,
+ holder: MaterialAboutItemViewHolder,
+ item: MaterialAboutItem,
+ context: Context
+ ) = when (itemType) {
+ PROFILE_ITEM -> MaterialAboutProfileItem.setupItem(
+ holder as MaterialAboutTitleItemViewHolder,
+ item as MaterialAboutProfileItem, context
+ )
+ else -> super.setupItem(itemType, holder, item, context)
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt
new file mode 100644
index 00000000..5f55ec70
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-18.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings.cards
+
+import android.content.Intent
+import android.media.MediaPlayer
+import android.widget.Toast
+import com.danielstone.materialaboutlibrary.items.MaterialAboutItem
+import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
+import eu.szkolny.font.SzkolnyFont
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.BuildConfig
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.after
+import pl.szczodrzynski.edziennik.sync.UpdateWorker
+import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsLicenseActivity
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
+import pl.szczodrzynski.edziennik.utils.Utils
+import kotlin.coroutines.CoroutineContext
+
+class SettingsAboutCard(util: SettingsUtil) : SettingsCard(util), CoroutineScope {
+
+ private val job: Job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ private var clickCounter = 0
+ private val mediaPlayer by lazy {
+ MediaPlayer.create(activity, R.raw.ogarnij_sie)
+ }
+
+ override fun buildCard(): MaterialAboutCard =
+ util.createCard(
+ null,
+ items = listOf(),
+ itemsMore = listOf(),
+ backgroundColor = 0xff1976d2.toInt(),
+ theme = R.style.AppTheme_Dark
+ ).also {
+ it.items.addAll(getItems(it))
+ }
+
+ override fun getItems() = listOf()
+ override fun getItemsMore() = listOf()
+
+ private val versionDetailsItem by lazy {
+ util.createActionItem(
+ text = R.string.settings_about_version_details_text,
+ subText = R.string.settings_about_version_details_subtext,
+ icon = CommunityMaterial.Icon.cmd_cellphone_information,
+ onClick = { _ ->
+ app.buildManager.showVersionDialog(activity)
+ }
+ )
+ }
+
+ private fun getItems(card: MaterialAboutCard) = listOf(
+ util.createTitleItem(),
+
+ util.createActionItem(
+ text = R.string.settings_about_version_text,
+ icon = CommunityMaterial.Icon2.cmd_information_outline,
+ onClick = { item ->
+ if (!card.items.contains(versionDetailsItem)) {
+ card.items.after(item, versionDetailsItem)
+ util.refresh()
+ }
+
+ clickCounter++
+ if (clickCounter < 7)
+ Toast.makeText(activity, "\uD83D\uDE02", Toast.LENGTH_SHORT).show()
+ item.subText =
+ BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + " \uD83D\uDCA3"
+ util.refresh()
+ if (clickCounter >= 7) {
+ mediaPlayer.start()
+ clickCounter = 0
+ }
+ }
+ ).also {
+ it.subText = BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE
+ },
+
+ util.createMoreItem(card, items = listOf(
+ util.createActionItem(
+ text = R.string.settings_about_changelog_text,
+ icon = CommunityMaterial.Icon3.cmd_radar
+ ) {
+ ChangelogDialog(activity)
+ },
+
+ util.createActionItem(
+ text = R.string.settings_about_update_text,
+ subText = R.string.settings_about_update_subtext,
+ icon = CommunityMaterial.Icon3.cmd_update
+ ) {
+ launch {
+ UpdateWorker.runNow(app)
+ }
+ }
+ )),
+
+ util.createSectionItem(
+ text = R.string.see_also
+ ),
+
+ util.createActionItem(
+ text = R.string.settings_about_privacy_policy_text,
+ icon = CommunityMaterial.Icon3.cmd_shield_outline
+ ) {
+ Utils.openUrl(activity, "https://szkolny.eu/privacy-policy")
+ },
+
+ util.createActionItem(
+ text = R.string.settings_about_discord_text,
+ subText = R.string.settings_about_discord_subtext,
+ icon = SzkolnyFont.Icon.szf_discord_outline
+ ) {
+ Utils.openUrl(activity, "https://szkolny.eu/discord")
+ },
+
+ util.createActionItem(
+ text = R.string.settings_about_github_text,
+ subText = R.string.settings_about_github_subtext,
+ icon = SzkolnyFont.Icon.szf_github_face
+ ) {
+ Utils.openUrl(activity, "https://szkolny.eu/github/android")
+ },
+
+ util.createMoreItem(card, items = listOfNotNull(
+ util.createActionItem(
+ text = R.string.settings_about_homepage_text,
+ subText = R.string.settings_about_homepage_subtext,
+ icon = CommunityMaterial.Icon.cmd_earth
+ ) {
+ Utils.openUrl(activity, "https://szkolny.eu/")
+ },
+
+ util.createActionItem(
+ text = R.string.settings_about_licenses_text,
+ icon = CommunityMaterial.Icon.cmd_code_braces
+ ) {
+ activity.startActivity(Intent(activity, SettingsLicenseActivity::class.java))
+ },
+
+ if (App.devMode)
+ util.createActionItem(
+ text = R.string.settings_about_crash_text,
+ subText = R.string.settings_about_crash_subtext,
+ icon = CommunityMaterial.Icon.cmd_bug_outline
+ ) {
+ throw RuntimeException("MANUAL CRASH")
+ }
+ else
+ null
+ ))
+ )
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt
new file mode 100644
index 00000000..f88a0242
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-18.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings.cards
+
+import android.content.Intent
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog
+import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
+import pl.szczodrzynski.edziennik.ui.modules.settings.MaterialAboutProfileItem
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
+
+class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) {
+
+ override fun buildCard() = util.createCard(
+ null,
+ items = getItems(),
+ itemsMore = listOf()
+ )
+
+ private fun getProfileItem(): MaterialAboutProfileItem = util.createProfileItem(
+ profile = app.profile
+ ) { item, profile ->
+ ProfileConfigDialog(activity, profile, onProfileSaved = {
+ val index = card.items.indexOf(item)
+ if (index == -1)
+ return@ProfileConfigDialog
+ card.items.remove(item)
+ card.items.add(index, getProfileItem())
+ util.refresh()
+ })
+ }
+
+ override fun getItems() = listOf(
+ getProfileItem(),
+
+ util.createActionItem(
+ text = R.string.settings_add_student_text,
+ subText = R.string.settings_add_student_subtext,
+ icon = CommunityMaterial.Icon.cmd_account_plus_outline
+ ) {
+ activity.startActivity(Intent(activity, LoginActivity::class.java))
+ }
+ )
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt
new file mode 100644
index 00000000..14afd0cb
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-18.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings.cards
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
+import eu.szkolny.font.SzkolnyFont
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.after
+import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
+import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED
+import pl.szczodrzynski.edziennik.ui.dialogs.bell.BellSyncConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
+
+class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
+
+ override fun buildCard() = util.createCard(
+ R.string.settings_card_register_title,
+ items = getItems(),
+ itemsMore = getItemsMore()
+ )
+
+ private fun getBellSync() =
+ configGlobal.timetable.bellSyncDiff?.let {
+ activity.getString(
+ R.string.settings_register_bell_sync_subtext_format,
+ (if (configGlobal.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS
+ )
+ } ?: activity.getString(R.string.settings_register_bell_sync_subtext_disabled)
+
+ private val sharedEventsItem by lazy {
+ util.createPropertyItem(
+ text = R.string.settings_register_shared_events_text,
+ subText = R.string.settings_register_shared_events_subtext,
+ icon = CommunityMaterial.Icon3.cmd_share_outline,
+ value = app.profile.enableSharedEvents
+ ) { _, value ->
+ app.profile.enableSharedEvents = value
+ app.profileSave()
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.event_sharing)
+ .setMessage(
+ if (value)
+ R.string.settings_register_shared_events_dialog_enabled_text
+ else
+ R.string.settings_register_shared_events_dialog_disabled_text
+ )
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ }
+ }
+
+ override fun getItems() = listOfNotNull(
+ util.createActionItem(
+ text = R.string.menu_grades_config,
+ icon = CommunityMaterial.Icon3.cmd_numeric_5_box_outline
+ ) {
+ GradesConfigDialog(activity, reloadOnDismiss = false)
+ },
+
+ util.createActionItem(
+ text = R.string.menu_attendance_config,
+ icon = CommunityMaterial.Icon.cmd_calendar_remove_outline
+ ) {
+ AttendanceConfigDialog(activity, reloadOnDismiss = false)
+ },
+
+ util.createPropertyItem(
+ text = R.string.settings_register_allow_registration_text,
+ subText = R.string.settings_register_allow_registration_subtext,
+ icon = CommunityMaterial.Icon.cmd_account_circle_outline,
+ value = app.profile.registration == REGISTRATION_ENABLED,
+ beforeChange = { item, value ->
+ if (app.profile.registration == REGISTRATION_ENABLED == value)
+ // allow the switch to change - needed for util.refresh() to change the visual state
+ return@createPropertyItem true
+ val dialog =
+ RegistrationConfigDialog(activity, app.profile, onChangeListener = { enabled ->
+ if (item.isChecked == enabled)
+ return@RegistrationConfigDialog
+ item.isChecked = enabled
+ if (value) {
+ card.items.after(item, sharedEventsItem)
+ } else {
+ card.items.remove(sharedEventsItem)
+ }
+ util.refresh()
+ })
+ if (value)
+ dialog.showEnableDialog()
+ else
+ dialog.showDisableDialog()
+ false
+ }
+ ) { _, _ -> },
+
+ if (app.profile.registration == REGISTRATION_ENABLED)
+ sharedEventsItem
+ else
+ null
+ )
+
+ override fun getItemsMore() = listOfNotNull(
+ util.createActionItem(
+ text = R.string.settings_register_bell_sync_text,
+ icon = SzkolnyFont.Icon.szf_alarm_bell_outline,
+ onClick = {
+ BellSyncConfigDialog(activity, onChangeListener = {
+ it.subText = getBellSync()
+ util.refresh()
+ })
+ }
+ ).also {
+ it.subText = getBellSync()
+ },
+
+ util.createPropertyItem(
+ text = R.string.settings_register_count_in_seconds_text,
+ subText = R.string.settings_register_count_in_seconds_subtext,
+ icon = CommunityMaterial.Icon3.cmd_timer_outline,
+ value = configGlobal.timetable.countInSeconds
+ ) { _, it ->
+ configGlobal.timetable.countInSeconds = it
+ },
+
+ if (app.profile.loginStoreType == LOGIN_TYPE_LIBRUS)
+ util.createPropertyItem(
+ text = R.string.settings_register_show_teacher_absences_text,
+ icon = CommunityMaterial.Icon.cmd_account_arrow_right_outline,
+ value = app.profile.getStudentData("showTeacherAbsences", true)
+ ) { _, it ->
+ app.profile.putStudentData("showTeacherAbsences", it)
+ app.profileSave()
+ }
+ else
+ null,
+
+ util.createPropertyItem(
+ text = R.string.settings_register_hide_sticks_from_old,
+ icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline,
+ value = configProfile.grades.hideSticksFromOld
+ ) { _, it ->
+ configProfile.grades.hideSticksFromOld = it
+ }
+ )
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt
new file mode 100644
index 00000000..1d42b86b
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-18.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings.cards
+
+import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.net.Uri
+import android.os.Build.VERSION.SDK_INT
+import android.os.Build.VERSION_CODES
+import android.provider.Settings
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
+import pl.szczodrzynski.edziennik.MainActivity
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.after
+import pl.szczodrzynski.edziennik.getSyncInterval
+import pl.szczodrzynski.edziennik.sync.SyncWorker
+import pl.szczodrzynski.edziennik.sync.UpdateWorker
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.QuietHoursConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncIntervalDialog
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
+import pl.szczodrzynski.edziennik.utils.models.Time
+
+class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) {
+
+ override fun buildCard() = util.createCard(
+ R.string.settings_card_sync_title,
+ items = getItems(),
+ itemsMore = getItemsMore()
+ )
+
+ private fun getQuietHours(): String {
+ if (configGlobal.sync.quietHoursStart == null) {
+ configGlobal.sync.quietHoursStart = Time(22, 30, 0)
+ }
+ if (configGlobal.sync.quietHoursEnd == null) {
+ configGlobal.sync.quietHoursEnd = Time(6, 30, 0)
+ }
+
+ return activity.getString(
+ if (configGlobal.sync.quietHoursStart!! > configGlobal.sync.quietHoursEnd!!)
+ R.string.settings_sync_quiet_hours_subtext_next_day_format
+ else
+ R.string.settings_sync_quiet_hours_subtext_format,
+ configGlobal.sync.quietHoursStart?.stringHM,
+ configGlobal.sync.quietHoursEnd?.stringHM
+ )
+ }
+
+ private val syncWifiItem by lazy {
+ util.createPropertyItem(
+ text = R.string.settings_sync_wifi_text,
+ subText = R.string.settings_sync_wifi_subtext,
+ icon = CommunityMaterial.Icon3.cmd_wifi_strength_2,
+ value = configGlobal.sync.onlyWifi
+ ) { _, it ->
+ configGlobal.sync.onlyWifi = it
+ SyncWorker.rescheduleNext(app)
+ }
+ }
+
+ override fun getItems() = listOfNotNull(
+ util.createPropertyActionItem(
+ text = R.string.settings_sync_sync_interval_text,
+ subText = R.string.settings_sync_sync_interval_subtext_disabled,
+ icon = CommunityMaterial.Icon.cmd_download_outline,
+ value = configGlobal.sync.enabled,
+ onChange = { item, value ->
+ // When calling onChange from the onClick listener below
+ // a list refresh is requested, the adapter refreshes
+ // all view holders, changing the state of the switch
+ // view, thus calling onChange again, causing it to
+ // try to recursively refresh the list, therefore
+ // crashing the app. To avoid this, the method will
+ // continue only if the checked state is different
+ // from the saved value, which should only happen
+ // when clicking the switch manually or when called
+ // by onClick, **once** (because onClick doesn't
+ // update the config value - we let the switch
+ // listener do it). Then there comes a different problem,
+ // when onClick changes the subText and the onChange
+ // listener returns because the boolean value
+ // is unchanged, leaving the list not refreshed.
+ // To solve this, a list refresh is also requested
+ // in onClick, when the config value is the same
+ // as the new switch value, which would normally
+ // cause the onChange method to exit here.
+ if (value == configGlobal.sync.enabled)
+ return@createPropertyActionItem
+
+ if (value) {
+ card.items.after(item, syncWifiItem)
+ } else {
+ card.items.remove(syncWifiItem)
+ }
+ util.refresh()
+
+ configGlobal.sync.enabled = value
+ SyncWorker.rescheduleNext(app)
+ },
+ onClick = { item ->
+ SyncIntervalDialog(activity, onChangeListener = {
+ item.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval)
+ item.isChecked = true
+ item.onCheckedChangedAction.onCheckedChanged(item, true)
+ if (configGlobal.sync.enabled)
+ util.refresh()
+ })
+ }
+ ).also {
+ it.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval)
+ },
+
+ if (configGlobal.sync.enabled)
+ syncWifiItem
+ else
+ null,
+
+ util.createActionItem(
+ text = R.string.settings_profile_notifications_text,
+ subText = R.string.settings_profile_notifications_subtext,
+ icon = CommunityMaterial.Icon2.cmd_filter_outline
+ ) {
+ NotificationFilterDialog(activity)
+ },
+
+ util.createPropertyActionItem(
+ text = R.string.settings_sync_quiet_hours_text,
+ subText = R.string.settings_sync_quiet_hours_subtext_disabled,
+ icon = CommunityMaterial.Icon.cmd_bell_sleep_outline,
+ value = configGlobal.sync.quietHoursEnabled,
+ onChange = { _, value ->
+ configGlobal.sync.quietHoursEnabled = value
+ },
+ onClick = { item ->
+ QuietHoursConfigDialog(activity, onChangeListener = {
+ item.subTextChecked = getQuietHours()
+ item.isChecked = configGlobal.sync.quietHoursEnabled
+ util.refresh()
+ })
+ }
+ ).also {
+ it.subTextChecked = getQuietHours()
+ },
+
+ util.createActionItem(
+ text = R.string.settings_sync_web_push_text,
+ subText = R.string.settings_sync_web_push_subtext,
+ icon = CommunityMaterial.Icon2.cmd_laptop
+ ) {
+ activity.loadTarget(MainActivity.TARGET_WEB_PUSH)
+ }
+ )
+
+ override fun getItemsMore() = listOfNotNull(
+ util.createPropertyItem(
+ text = R.string.settings_sync_updates_text,
+ icon = CommunityMaterial.Icon.cmd_cellphone_arrow_down,
+ value = configGlobal.sync.notifyAboutUpdates
+ ) { _, it ->
+ configGlobal.sync.notifyAboutUpdates = it
+ UpdateWorker.rescheduleNext(app)
+ },
+
+ if (SDK_INT >= VERSION_CODES.KITKAT)
+ util.createActionItem(
+ text = R.string.settings_sync_notifications_settings_text,
+ subText = R.string.settings_sync_notifications_settings_subtext,
+ icon = CommunityMaterial.Icon.cmd_cog_outline
+ ) {
+ val channel = app.notificationChannelsManager.data.key
+ val intent = Intent().apply {
+ when {
+ SDK_INT >= VERSION_CODES.O -> {
+ action = Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS
+ putExtra(Settings.EXTRA_APP_PACKAGE, app.packageName)
+ putExtra(Settings.EXTRA_CHANNEL_ID, channel)
+ addFlags(FLAG_ACTIVITY_NEW_TASK)
+ }
+ SDK_INT >= VERSION_CODES.LOLLIPOP -> {
+ action = "android.settings.APP_NOTIFICATION_SETTINGS"
+ putExtra("app_package", app.packageName)
+ putExtra("app_uid", app.applicationInfo.uid)
+ }
+ else -> {
+ action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+ addCategory(Intent.CATEGORY_DEFAULT)
+ data = Uri.parse("package:" + app.packageName)
+ }
+ }
+ }
+ activity.startActivity(intent)
+ }
+ else
+ null
+ )
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt
new file mode 100644
index 00000000..17b108e5
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-18.
+ */
+
+package pl.szczodrzynski.edziennik.ui.modules.settings.cards
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.ui.dialogs.settings.AppLanguageDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.settings.MiniMenuConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.settings.ThemeChooserDialog
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard
+import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil
+import pl.szczodrzynski.edziennik.utils.Themes
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
+
+ override fun buildCard() = util.createCard(
+ R.string.settings_card_theme_title,
+ items = getItems(),
+ itemsMore = getItemsMore()
+ )
+
+ override fun getItems() = listOfNotNull(
+ if (Date.getToday().month % 11 == 1) // cool math games
+ util.createPropertyItem(
+ text = R.string.settings_theme_snowfall_text,
+ subText = R.string.settings_theme_snowfall_subtext,
+ icon = CommunityMaterial.Icon3.cmd_snowflake,
+ value = configGlobal.ui.snowfall
+ ) { _, it ->
+ configGlobal.ui.snowfall = it
+ activity.recreate()
+ }
+ else null,
+
+ util.createActionItem(
+ text = R.string.settings_theme_theme_text,
+ subText = Themes.getThemeNameRes(),
+ icon = CommunityMaterial.Icon3.cmd_palette_outline
+ ) {
+ ThemeChooserDialog(activity)
+ },
+
+ util.createActionItem(
+ text = R.string.settings_about_language_text,
+ subText = R.string.settings_about_language_subtext,
+ icon = CommunityMaterial.Icon3.cmd_translate
+ ) {
+ AppLanguageDialog(activity)
+ },
+
+ util.createPropertyItem(
+ text = R.string.settings_theme_mini_drawer_text,
+ subText = R.string.settings_theme_mini_drawer_subtext,
+ icon = CommunityMaterial.Icon.cmd_dots_vertical,
+ value = configGlobal.ui.miniMenuVisible
+ ) { _, it ->
+ configGlobal.ui.miniMenuVisible = it
+ activity.navView.drawer.miniDrawerVisiblePortrait = it
+ }
+ )
+
+ override fun getItemsMore() = listOf(
+ util.createActionItem(
+ text = R.string.settings_theme_mini_drawer_buttons_text,
+ icon = CommunityMaterial.Icon2.cmd_format_list_checks
+ ) {
+ MiniMenuConfigDialog(activity)
+ },
+
+ util.createActionItem(
+ text = R.string.settings_theme_drawer_header_text,
+ icon = CommunityMaterial.Icon2.cmd_image_outline
+ ) {
+ if (app.config.ui.appBackground == null) {
+ setHeaderBackground()
+ return@createActionItem
+ }
+ MaterialAlertDialogBuilder(activity)
+ .setItems(
+ arrayOf(
+ activity.getString(R.string.settings_theme_drawer_header_dialog_set),
+ activity.getString(R.string.settings_theme_drawer_header_dialog_restore)
+ )
+ ) { _, which ->
+ when (which) {
+ 0 -> setHeaderBackground()
+ 1 -> {
+ app.config.ui.headerBackground = null
+ activity.drawer.setAccountHeaderBackground(null)
+ activity.drawer.open()
+ }
+ }
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .show()
+ },
+
+ util.createActionItem(
+ text = R.string.settings_theme_app_background_text,
+ subText = R.string.settings_theme_app_background_subtext,
+ icon = CommunityMaterial.Icon2.cmd_image_filter_hdr
+ ) {
+ if (app.config.ui.appBackground == null) {
+ setAppBackground()
+ return@createActionItem
+ }
+ MaterialAlertDialogBuilder(activity)
+ .setItems(
+ arrayOf(
+ activity.getString(R.string.settings_theme_app_background_dialog_set),
+ activity.getString(R.string.settings_theme_app_background_dialog_restore)
+ )
+ ) { _, which ->
+ when (which) {
+ 0 -> setAppBackground()
+ 1 -> {
+ app.config.ui.appBackground = null
+ activity.setAppBackground()
+ }
+ }
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .show()
+ },
+
+ util.createPropertyItem(
+ text = R.string.settings_theme_open_drawer_on_back_pressed_text,
+ icon = CommunityMaterial.Icon3.cmd_menu_open,
+ value = configGlobal.ui.openDrawerOnBackPressed
+ ) { _, it ->
+ configGlobal.ui.openDrawerOnBackPressed = it
+ }
+ )
+
+ private fun setHeaderBackground() = activity.requestHandler.requestHeaderBackground {
+ activity.drawer.setAccountHeaderBackground(null)
+ activity.drawer.setAccountHeaderBackground(app.config.ui.headerBackground)
+ activity.drawer.open()
+ }
+
+ private fun setAppBackground() = activity.requestHandler.requestAppBackground {
+ activity.setAppBackground()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt
index 52441e25..970daeec 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableFragment.kt
@@ -16,17 +16,16 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
+import com.google.android.material.datepicker.MaterialDatePicker
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
-import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding
-import pl.szczodrzynski.edziennik.resolveAttr
+import pl.szczodrzynski.edziennik.getSchoolYearConstrains
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.dialogs.timetable.GenerateBlockTimetableDialog
import pl.szczodrzynski.edziennik.utils.models.Date
@@ -168,19 +167,23 @@ class TimetableFragment : Fragment(), CoroutineScope {
BottomSheetPrimaryItem(true)
.withTitle(R.string.timetable_select_day)
.withIcon(SzkolnyFont.Icon.szf_calendar_today_outline)
- .withOnClickListener(View.OnClickListener {
+ .withOnClickListener { _ ->
activity.bottomSheet.close()
- val date = Date.getToday()
- DatePickerDialog
- .newInstance({ _, year, monthOfYear, dayOfMonth ->
- val dateSelected = Date(year, monthOfYear, dayOfMonth)
- b.tabLayout.setCurrentItem(items.indexOfFirst { it == dateSelected }, true)
- }, date.year, date.month, date.day)
- .apply {
- accentColor = R.attr.colorPrimary.resolveAttr(this@TimetableFragment.activity)
- show(this@TimetableFragment.activity.supportFragmentManager, "DatePickerDialog")
+ val date = pageSelection ?: Date.getToday()
+ MaterialDatePicker.Builder.datePicker()
+ .setSelection(date.inMillisUtc)
+ .setCalendarConstraints(app.profile.getSchoolYearConstrains())
+ .build()
+ .apply {
+ addOnPositiveButtonClickListener { millis ->
+ val dateSelected = Date.fromMillisUtc(millis)
+ val index = items.indexOfFirst { it == dateSelected }
+ if (index != -1)
+ b.tabLayout.setCurrentItem(index, true)
}
- }),
+ }
+ .show(activity.supportFragmentManager, TAG)
+ },
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_add_event)
.withDescription(R.string.menu_add_event_desc)
@@ -192,7 +195,7 @@ class TimetableFragment : Fragment(), CoroutineScope {
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_generate_block_timetable)
.withDescription(R.string.menu_generate_block_timetable_desc)
- .withIcon(Icon2.cmd_table_large)
+ .withIcon(CommunityMaterial.Icon3.cmd_table_large)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
GenerateBlockTimetableDialog(activity)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt
index 1975f39e..5712207c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/AttachmentAdapter.kt
@@ -11,11 +11,9 @@ import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import com.mikepenz.iconics.IconicsDrawable
-import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
-import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
-import com.mikepenz.iconics.utils.paddingDp
import com.mikepenz.iconics.utils.sizeDp
+import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -60,7 +58,7 @@ class AttachmentAdapter(
val fileName = item.name.substringBefore(":http")
// create an icon for the attachment
- val icon: IIcon = when (Utils.getExtensionFromFileName(fileName)) {
+ val attachmentIcon = when (Utils.getExtensionFromFileName(fileName)) {
"doc", "docx", "odt", "rtf" -> SzkolnyFont.Icon.szf_file_word_outline
"xls", "xlsx", "ods" -> SzkolnyFont.Icon.szf_file_excel_outline
"ppt", "pptx", "odp" -> SzkolnyFont.Icon.szf_file_powerpoint_outline
@@ -70,7 +68,7 @@ class AttachmentAdapter(
"jpg", "jpeg", "png", "bmp", "gif" -> SzkolnyFont.Icon.szf_file_image_outline
"zip", "rar", "tar", "7z" -> SzkolnyFont.Icon.szf_zip_box_outline
"html", "cpp", "c", "h", "css", "java", "py" -> SzkolnyFont.Icon.szf_file_code_outline
- else -> CommunityMaterial.Icon.cmd_file_document_outline
+ else -> CommunityMaterial.Icon2.cmd_file_document_outline
}
b.chip.text = if (item.isDownloading) {
@@ -82,15 +80,16 @@ class AttachmentAdapter(
} ?: fileName
}
- b.chip.chipIcon = IconicsDrawable(context)
- .icon(icon)
- .colorAttr(context, R.attr.colorOnSurface)
- .sizeDp(24)
- .paddingDp(2)
- b.chip.closeIcon = IconicsDrawable(context)
- .icon(CommunityMaterial.Icon.cmd_check)
- .colorAttr(context, R.attr.colorOnSurface)
- .sizeDp(18)
+ b.chip.chipIcon = IconicsDrawable(context).apply {
+ icon = attachmentIcon
+ colorAttr(context, R.attr.colorOnSurface)
+ sizeDp = 24
+ }
+ b.chip.closeIcon = IconicsDrawable(context).apply {
+ icon = CommunityMaterial.Icon.cmd_check
+ colorAttr(context, R.attr.colorOnSurface)
+ sizeDp = 24
+ }
b.chip.isCloseIconVisible = item.isDownloaded && !item.isDownloading
// prevent progress bar flickering
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/DateDropdown.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/DateDropdown.kt
index 3d3ef4c7..92bf0515 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/DateDropdown.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/DateDropdown.kt
@@ -10,14 +10,13 @@ import android.util.AttributeSet
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
-import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
+import com.google.android.material.datepicker.MaterialDatePicker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
import pl.szczodrzynski.edziennik.observeOnce
-import pl.szczodrzynski.edziennik.resolveAttr
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Week
@@ -179,17 +178,17 @@ class DateDropdown : TextInputDropDown {
fun pickerDialog() {
val date = getSelected() as? Date ?: Date.getToday()
- DatePickerDialog
- .newInstance({ _, year, monthOfYear, dayOfMonth ->
- val dateSelected = Date(year, monthOfYear+1, dayOfMonth)
+ MaterialDatePicker.Builder.datePicker()
+ .setSelection(date.inMillisUtc)
+ .build()
+ .apply {
+ addOnPositiveButtonClickListener { millis ->
+ val dateSelected = Date.fromMillisUtc(millis)
selectDate(dateSelected)
onDateSelected?.invoke(dateSelected, null)
- }, date.year, date.month-1, date.day)
- .apply {
- this@DateDropdown.activity ?: return@apply
- accentColor = R.attr.colorPrimary.resolveAttr(this@DateDropdown.activity)
- show(this@DateDropdown.activity!!.supportFragmentManager, "DatePickerDialog")
}
+ }
+ .show(activity!!.supportFragmentManager, "DateDropdown")
}
fun selectDate(date: Date) {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/SubjectDropdown.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/SubjectDropdown.kt
index 73dbf795..06e01225 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/SubjectDropdown.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/SubjectDropdown.kt
@@ -9,12 +9,13 @@ import android.content.ContextWrapper
import android.text.InputType
import android.util.AttributeSet
import androidx.appcompat.app.AppCompatActivity
-import com.afollestad.materialdialogs.MaterialDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.crc16
import pl.szczodrzynski.edziennik.data.db.AppDb
+import pl.szczodrzynski.edziennik.ui.dialogs.input
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
class SubjectDropdown : TextInputDropDown {
@@ -105,19 +106,25 @@ class SubjectDropdown : TextInputDropDown {
fun customNameDialog() {
activity ?: return
- MaterialDialog.Builder(activity!!)
- .title("Własny przedmiot")
- .inputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)
- .input("Nazwa", "") { _: MaterialDialog?, input: CharSequence ->
- customSubjectName = input.toString()
+ MaterialAlertDialogBuilder(activity!!)
+ .setTitle("Własny przedmiot")
+ .input(
+ hint = "Nazwa",
+ type = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE,
+ positiveButton = R.string.ok,
+ positiveListener = { _, input ->
+ customSubjectName = input
select(Item(
- -1L * customSubjectName.crc16(),
- customSubjectName,
- tag = customSubjectName
+ -1L * customSubjectName.crc16(),
+ customSubjectName,
+ tag = customSubjectName
))
onCustomSubjectSelected?.invoke(customSubjectName)
+ true
}
- .show()
+ )
+ .setNegativeButton(R.string.cancel, null)
+ .show()
}
fun selectSubject(subjectId: Long) {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/TimeDropdown.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/TimeDropdown.kt
index e60f24f8..989184af 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/TimeDropdown.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/TimeDropdown.kt
@@ -8,7 +8,8 @@ import android.content.Context
import android.content.ContextWrapper
import android.util.AttributeSet
import androidx.appcompat.app.AppCompatActivity
-import com.wdullaer.materialdatetimepicker.time.TimePickerDialog
+import com.google.android.material.timepicker.MaterialTimePicker
+import com.google.android.material.timepicker.TimeFormat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.*
@@ -177,17 +178,19 @@ class TimeDropdown : TextInputDropDown {
fun pickerDialog() {
val time = (getSelected() as? Pair<*, *>)?.first as? Time ?: Time.getNow()
- TimePickerDialog
- .newInstance({ _, hourOfDay, minute, second ->
- val timeSelected = Time(hourOfDay, minute, second)
+ MaterialTimePicker.Builder()
+ .setTimeFormat(TimeFormat.CLOCK_24H)
+ .setHour(time.hour)
+ .setMinute(time.minute)
+ .build()
+ .also { dialog ->
+ dialog.addOnPositiveButtonClickListener {
+ val timeSelected = Time(dialog.hour, dialog.minute, 0)
selectTime(timeSelected)
onTimeSelected?.invoke(timeSelected, null, null)
- }, time.hour, time.minute, 0, true)
- .apply {
- this@TimeDropdown.activity ?: return@apply
- accentColor = R.attr.colorPrimary.resolveAttr(this@TimeDropdown.activity)
- show(this@TimeDropdown.activity!!.supportFragmentManager, "TimePickerDialog")
}
+ }
+ .show(activity!!.supportFragmentManager, "TimeDropdown")
}
fun selectTime(time: Time) {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/QrScannerActivity.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/QrScannerActivity.java
deleted file mode 100644
index b9028ac5..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/QrScannerActivity.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package pl.szczodrzynski.edziennik.ui.modules.webpush;
-
-import android.Manifest;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-
-import com.google.zxing.Result;
-
-import me.dm7.barcodescanner.zxing.ZXingScannerView;
-import pl.szczodrzynski.edziennik.R;
-
-public class QrScannerActivity extends AppCompatActivity implements ZXingScannerView.ResultHandler {
- private ZXingScannerView mScannerView;
- public static ZXingScannerView.ResultHandler resultHandler;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mScannerView = new ZXingScannerView(this); // Programmatically initialize the scanner view
- setContentView(mScannerView);
- int result = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
- if (result == PackageManager.PERMISSION_GRANTED) {
- mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
- mScannerView.startCamera(); // Start camera on resume
- } else {
- ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
- mScannerView.startCamera(); // Start camera on resume
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mScannerView.stopCamera(); // Stop camera on pause
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- switch (requestCode) {
- case 1: {
- // If request is cancelled, the result arrays are empty.
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- mScannerView.startCamera();
- } else {
- // permission denied, boo! Disable the
- // functionality that depends on this permission.
- Toast.makeText(this, R.string.no_permissions, Toast.LENGTH_SHORT).show();
- }
- }
- // other 'case' lines to check for other
- // permissions this app might request
- }
- }
-
- @Override
- public void handleResult(Result rawResult) {
- if (resultHandler != null) {
- resultHandler.handleResult(rawResult);
- }
- finish();
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt
index 4c8c34cc..0996c518 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/webpush/WebPushFragment.kt
@@ -4,15 +4,11 @@
package pl.szczodrzynski.edziennik.ui.modules.webpush
-import android.Manifest
import android.annotation.SuppressLint
-import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.core.app.ActivityCompat
-import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.CoroutineScope
@@ -25,7 +21,6 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
import pl.szczodrzynski.edziennik.databinding.WebPushFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.QrScannerDialog
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
-import pl.szczodrzynski.edziennik.utils.Themes
import kotlin.coroutines.CoroutineContext
class WebPushFragment : Fragment(), CoroutineScope {
@@ -46,13 +41,13 @@ class WebPushFragment : Fragment(), CoroutineScope {
SzkolnyApi(app)
}
+ private val manager
+ get() = app.permissionManager
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
- context!!.theme.applyStyle(Themes.appTheme, true)
- if (app.profile == null)
- return inflater.inflate(R.layout.fragment_loading, container, false)
// activity, context and profile is valid
b = WebPushFragmentBinding.inflate(inflater)
return b.root
@@ -60,19 +55,15 @@ class WebPushFragment : Fragment(), CoroutineScope {
@SuppressLint("DefaultLocale")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- // TODO check if app, activity, b can be null
- if (app.profile == null || !isAdded)
+ if (!isAdded)
return
b.scanQrCode.onClick {
- val result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
- if (result == PackageManager.PERMISSION_GRANTED) {
+ manager.requestCameraPermission(activity, R.string.permissions_qr_scanner) {
QrScannerDialog(activity, {
b.tokenEditText.setText(it.crc32().toString(36).toUpperCase())
pairBrowser(browserId = it)
})
- } else {
- ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), 1)
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java
index 2a35b1b2..5902f22e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java
@@ -8,17 +8,18 @@ import android.app.Activity;
import android.app.WallpaperManager;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
-import android.graphics.Color;
+import android.database.DataSetObserver;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListAdapter;
import android.widget.SeekBar;
-import com.afollestad.materialdialogs.MaterialDialog;
-import com.afollestad.materialdialogs.simplelist.MaterialSimpleListAdapter;
-import com.afollestad.materialdialogs.simplelist.MaterialSimpleListItem;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.gson.JsonObject;
import java.util.List;
@@ -27,6 +28,7 @@ import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.data.db.entity.Profile;
import pl.szczodrzynski.edziennik.databinding.DialogWidgetConfigBinding;
+import pl.szczodrzynski.edziennik.databinding.WidgetProfileDialogItemBinding;
import pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider;
import pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider;
import pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider;
@@ -96,45 +98,84 @@ public class WidgetConfigActivity extends Activity {
}
private void selectProfile() {
- MaterialSimpleListAdapter adapter =
- new MaterialSimpleListAdapter((dialog, index1, item) -> {
- profileId = (int) item.getId();
- profileName = item.toString();
+ if (profileList.size() > 1 && widgetType != WIDGET_LUCKY_NUMBER) {
+ profileList.add(
+ new Profile(-1,
+ 0,
+ 0,
+ getString(R.string.widget_config_all_profiles),
+ null,
+ "",
+ "",
+ null,
+ new JsonObject()
+ )
+ );
+ }
+
+ ListAdapter adapter = new ListAdapter() {
+ @Override public boolean areAllItemsEnabled() { return true; }
+ @Override public boolean isEnabled(int position) { return true; }
+ @Override public void registerDataSetObserver(DataSetObserver observer) { }
+ @Override public void unregisterDataSetObserver(DataSetObserver observer) { }
+ @Override public boolean hasStableIds() { return true; }
+ @Override public int getItemViewType(int position) { return 0; }
+ @Override public int getViewTypeCount() { return 1; }
+ @Override public boolean isEmpty() { return false; }
+
+ @Override public int getCount() { return profileList.size(); }
+ @Override public Object getItem(int position) { return profileList.get(position); }
+
+ @Override
+ public long getItemId(int position) {
+ return profileList.get(position).getId();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ WidgetProfileDialogItemBinding b;
+ if (convertView == null) {
+ b = WidgetProfileDialogItemBinding.inflate(getLayoutInflater(), null, false);
+ }
+ else {
+ b = WidgetProfileDialogItemBinding.bind(convertView);
+ }
+ Profile profile = profileList.get(position);
+
+ b.name.setText(profile.getName());
+ b.subname.setText(profile.getSubname());
+ b.subname.setVisibility(profile.getSubname() == null ? View.GONE : View.VISIBLE);
+ b.image.setVisibility(profile.getId() == -1 ? View.GONE : View.VISIBLE);
+ if (profile.getId() == -1)
+ b.image.setImageDrawable(null);
+ else
+ b.image.setImageDrawable(profile.getImageDrawable(WidgetConfigActivity.this));
+
+ b.getRoot().setOnClickListener(v -> {
+ profileId = profile.getId();
+ profileName = profile.getName();
configure();
});
- for (Profile profile : profileList) {
- adapter.add(
- new MaterialSimpleListItem.Builder(this)
- .id(profile.getId())
- .content(profile.getName())
- .icon(profile.getImageDrawable(this))
- .backgroundColor(Color.WHITE)
- .build());
- }
- if (profileList.size() > 1 && widgetType != WIDGET_LUCKY_NUMBER) {
- adapter.add(
- new MaterialSimpleListItem.Builder(this)
- .id(-1)
- .content(R.string.widget_config_all_profiles)
- .backgroundColor(Color.WHITE)
- .build());
- }
- new MaterialDialog.Builder(this)
- .title(R.string.choose_profile)
- .adapter(adapter, null)
- .dismissListener(dialog -> finish())
+ return b.getRoot();
+ }
+ };
+
+ new MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.choose_profile)
+ .setAdapter(adapter, null)
+ .setOnDismissListener(dialog -> finish())
.show();
}
private void configure() {
- MaterialDialog dialog = new MaterialDialog.Builder(this)
- .title(R.string.widget_config_activity_customize)
- .customView(R.layout.dialog_widget_config, true)
- .dismissListener(dialog1 -> finish())
- .positiveText(R.string.ok)
- .negativeText(R.string.cancel)
- .onPositive(((dialog1, which) -> {
+ b = DialogWidgetConfigBinding.inflate(getLayoutInflater(), null, false);
+
+ new MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.widget_config_activity_customize)
+ .setView(b.getRoot())
+ .setOnDismissListener(dialog -> finish())
+ .setPositiveButton(R.string.ok, ((dialog, which) -> {
WidgetConfig config = new WidgetConfig(profileId, bigStyle, darkTheme, opacity);
JsonObject configs = app.getConfig().getWidgetConfigs();
configs.add(Integer.toString(mAppWidgetId), app.getGson().toJsonTree(config));
@@ -165,10 +206,9 @@ public class WidgetConfigActivity extends Activity {
setResult(RESULT_OK, resultValue);
finish();
}))
+ .setNegativeButton(R.string.cancel, null)
.show();
- b = DialogWidgetConfigBinding.bind(dialog.getCustomView());
-
b.setProfileName(profileName);
WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt
index aec64aef..a0bf3b00 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt
@@ -32,7 +32,7 @@ class WidgetNotificationsProvider : AppWidgetProvider() {
for (appWidgetId in appWidgetIds) {
val config = widgetConfigs.getJsonObject(appWidgetId.toString())?.let { app.gson.fromJson(it, WidgetConfig::class.java) } ?: continue
- val iconSize = if (config.bigStyle) 24 else 16
+ val iconSize = if (config.bigStyle) 28 else 20
val views: RemoteViews = if (config.bigStyle) {
RemoteViews(app.packageName, if (config.darkTheme) R.layout.widget_notifications_dark_big else R.layout.widget_notifications_big)
@@ -48,10 +48,10 @@ class WidgetNotificationsProvider : AppWidgetProvider() {
views.setImageViewBitmap(
R.id.widgetNotificationsSync,
- IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
- .colorInt(Color.WHITE)
- .sizeDp(iconSize)
- .toBitmap()
+ IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline).apply {
+ colorInt = Color.WHITE
+ sizeDp = iconSize
+ }.toBitmap()
)
views.setViewVisibility(R.id.widgetNotificationsLoading, View.GONE)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java
index 6f81bf2c..369f6783 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableFactory.java
@@ -24,13 +24,14 @@ import android.widget.RemoteViewsService;
import androidx.annotation.DrawableRes;
-import com.mikepenz.iconics.IconicsColor;
import com.mikepenz.iconics.IconicsDrawable;
-import com.mikepenz.iconics.IconicsSize;
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
+import com.mikepenz.iconics.utils.IconicsConvertersKt;
+import com.mikepenz.iconics.utils.IconicsDrawableExtensionsKt;
import java.util.List;
+import kotlin.Unit;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.utils.models.Date;
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
@@ -126,6 +127,15 @@ public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFac
return resultBitmap;
}
+ private Bitmap homeIconBitmap() {
+ return new IconicsDrawable(context).apply((drawable) -> {
+ IconicsConvertersKt.setColorRes(drawable, R.color.md_red_500);
+ IconicsConvertersKt.setSizeDp(drawable, 14);
+ IconicsDrawableExtensionsKt.icon(drawable, CommunityMaterial.Icon2.cmd_home);
+ return Unit.INSTANCE;
+ }).toBitmap();
+ }
+
@Override
public RemoteViews getViewAt(int i) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.row_widget_timetable_item);
@@ -270,19 +280,19 @@ public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFac
if (lesson.eventColors.size() >= 1) {
views.setViewVisibility(R.id.widgetTimetableEvent1, View.VISIBLE);
if (lesson.eventColors.get(0) == -1)
- views.setBitmap(R.id.widgetTimetableEvent1, "setImageBitmap", new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home).toBitmap());
+ views.setBitmap(R.id.widgetTimetableEvent1, "setImageBitmap", homeIconBitmap());
else
views.setBitmap(R.id.widgetTimetableEvent1, "setImageBitmap", getColoredBitmap(context, R.drawable.event_color_circle, lesson.eventColors.get(0), eventIndicatorSize, eventIndicatorSize));
if (lesson.eventColors.size() >= 2) {
views.setViewVisibility(R.id.widgetTimetableEvent2, View.VISIBLE);
if (lesson.eventColors.get(1) == -1)
- views.setBitmap(R.id.widgetTimetableEvent2, "setImageBitmap", new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home).toBitmap());
+ views.setBitmap(R.id.widgetTimetableEvent2, "setImageBitmap", homeIconBitmap());
else
views.setBitmap(R.id.widgetTimetableEvent2, "setImageBitmap", getColoredBitmap(context, R.drawable.event_color_circle, lesson.eventColors.get(1), eventIndicatorSize, eventIndicatorSize));
if (lesson.eventColors.size() >= 3) {
views.setViewVisibility(R.id.widgetTimetableEvent3, View.VISIBLE);
if (lesson.eventColors.get(2) == -1)
- views.setBitmap(R.id.widgetTimetableEvent3, "setImageBitmap", new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home).toBitmap());
+ views.setBitmap(R.id.widgetTimetableEvent3, "setImageBitmap", homeIconBitmap());
else
views.setBitmap(R.id.widgetTimetableEvent3, "setImageBitmap", getColoredBitmap(context, R.drawable.event_color_circle, lesson.eventColors.get(2), eventIndicatorSize, eventIndicatorSize));
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt
index bc284ba2..6d5badf5 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt
@@ -115,13 +115,21 @@ class WidgetTimetableProvider : AppWidgetProvider() {
views.setOnClickPendingIntent(R.id.widgetTimetableSync, getPendingSelfIntent(context, ACTION_SYNC_DATA))
- views.setImageViewBitmap(R.id.widgetTimetableRefresh, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
- .colorInt(Color.WHITE)
- .sizeDp(if (config.bigStyle) 24 else 16).toBitmap())
+ views.setImageViewBitmap(
+ R.id.widgetTimetableRefresh,
+ IconicsDrawable(context, CommunityMaterial.Icon3.cmd_refresh).apply {
+ colorInt = Color.WHITE
+ sizeDp = if (config.bigStyle) 28 else 20
+ }.toBitmap()
+ )
- views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
- .colorInt(Color.WHITE)
- .sizeDp(if (config.bigStyle) 24 else 16).toBitmap())
+ views.setImageViewBitmap(
+ R.id.widgetTimetableSync,
+ IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline).apply {
+ colorInt = Color.WHITE
+ sizeDp = if (config.bigStyle) 28 else 20
+ }.toBitmap()
+ )
prepareAppWidget(app, appWidgetId, views, config, bellSyncDiffMillis)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/BadgeDrawable.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/BadgeDrawable.java
deleted file mode 100644
index b3cecc02..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/BadgeDrawable.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package pl.szczodrzynski.edziennik.utils;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.util.TypedValue;
-
-public class BadgeDrawable extends Drawable {
-
- private float mTextSize;
- private Paint mBadgePaint;
- private Paint mTextPaint;
- private Rect mTxtRect = new Rect();
-
- private String mCount = "";
- private boolean mTextEnabled = true;
- private boolean mWillDraw = false;
-
-
- public BadgeDrawable(Context context) {
- mTextSize = dpToPx(context, 11); //text size
- mBadgePaint = new Paint();
- mBadgePaint.setColor(Color.RED);
- mBadgePaint.setAntiAlias(true);
- mBadgePaint.setStyle(Paint.Style.FILL);
-
- mTextPaint = new Paint();
- mTextPaint.setColor(Color.WHITE);
- mTextPaint.setTypeface(Typeface.DEFAULT);
- mTextPaint.setTextSize(mTextSize);
- mTextPaint.setAntiAlias(true);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
- }
-
- private float dpToPx(Context context, float value) {
- Resources r = context.getResources();
- float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, r.getDisplayMetrics());
- return px;
- }
-
-
- @Override
- public void draw(Canvas canvas) {
- if (!mWillDraw) {
- return;
- }
- Rect bounds = getBounds();
- float width = bounds.right - bounds.left;
- float height = bounds.bottom - bounds.top;
- // Position the badge in the top-right quadrant of the icon.
-
- /*Using Math.max rather than Math.min */
-// float radius = ((Math.max(width, height) / 2)) / 2;
- float radius = width * 0.15f;
- float centerX = (width - radius - 1) +10;
- float centerY = radius -5;
- if (mTextEnabled) {
- if(mCount.length() <= 2){
- // Draw badge circle.
- canvas.drawCircle(centerX, centerY, radius+13, mBadgePaint);
- }
- else{
- canvas.drawCircle(centerX, centerY, radius+16, mBadgePaint);
- }
- // Draw badge count text inside the circle.
- mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect);
- float textHeight = mTxtRect.bottom - mTxtRect.top;
- float textY = centerY + (textHeight / 2f);
- if (mCount.length() > 2)
- canvas.drawText("99+", centerX, textY, mTextPaint);
- else
- canvas.drawText(mCount, centerX, textY, mTextPaint);
- }
- else {
- canvas.drawCircle(centerX, centerY, radius+5, mBadgePaint);
- }
- }
-
- /*
- Sets the count (i.e notifications) to display.
- */
- public void setCount(String count) {
- mCount = count;
- // Only draw a badge if there are notifications.
- mWillDraw = !count.equalsIgnoreCase("0");
- invalidateSelf();
- }
-
- @Override
- public void setAlpha(int alpha) {
- // do nothing
- }
-
- public void setTextEnabled(boolean mTextEnabled) {
- this.mTextEnabled = mTextEnabled;
- }
-
- @Override
- public void setColorFilter(ColorFilter cf) {
- // do nothing
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.UNKNOWN;
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SnackbarHelper.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SnackbarHelper.java
deleted file mode 100644
index 3fe2648b..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SnackbarHelper.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package pl.szczodrzynski.edziennik.utils;
-
-import android.content.Context;
-import android.view.ViewGroup;
-
-import com.google.android.material.snackbar.Snackbar;
-
-import androidx.core.view.ViewCompat;
-import pl.szczodrzynski.edziennik.R;
-
-public class SnackbarHelper {
-
- public static void configSnackbar(Context context, Snackbar snack) {
- addMargins(snack);
- setRoundBordersBg(context, snack);
- ViewCompat.setElevation(snack.getView(), 6f);
- }
-
- private static void addMargins(Snackbar snack) {
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) snack.getView().getLayoutParams();
- params.setMargins(12, 12, 12, 12);
- snack.getView().setLayoutParams(params);
- }
-
- private static void setRoundBordersBg(Context context, Snackbar snackbar) {
- snackbar.getView().setBackground(context.getResources().getDrawable(R.drawable.bg_snackbar));
- }
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SpannableHtmlTagHandler.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SpannableHtmlTagHandler.java
deleted file mode 100644
index 7a0f5cad..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SpannableHtmlTagHandler.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package pl.szczodrzynski.edziennik.utils;
-
-import android.text.Editable;
-import android.text.Html;
-import android.text.Spannable;
-import android.text.style.StrikethroughSpan;
-
-import org.xml.sax.XMLReader;
-
-public class SpannableHtmlTagHandler implements Html.TagHandler {
-
- public void handleTag(boolean opening, String tag, Editable output,
- XMLReader xmlReader) {
- if(tag.equalsIgnoreCase("strike") || tag.equals("s") || tag.equals("del")) {
- processStrike(opening, output);
- }
- }
-
- private void processStrike(boolean opening, Editable output) {
- int len = output.length();
- if(opening) {
- output.setSpan(new StrikethroughSpan(), len, len, Spannable.SPAN_MARK_MARK);
- } else {
- Object obj = getLast(output, StrikethroughSpan.class);
- int where = output.getSpanStart(obj);
-
- output.removeSpan(obj);
-
- if (where != len) {
- output.setSpan(new StrikethroughSpan(), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- }
-
- private Object getLast(Editable text, Class kind) {
- Object[] objs = text.getSpans(0, text.length(), kind);
-
- if (objs.length == 0) {
- return null;
- } else {
- for(int i = objs.length;i>0;i--) {
- if(text.getSpanFlags(objs[i-1]) == Spannable.SPAN_MARK_MARK) {
- return objs[i-1];
- }
- }
- return null;
- }
- }
-
-
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoIndicator.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoIndicator.java
new file mode 100644
index 00000000..75192eec
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoIndicator.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pl.szczodrzynski.edziennik.utils;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+/**
+ * The SwipeRefreshLayout should be used whenever the user can refresh the
+ * contents of a view via a vertical swipe gesture. The activity that
+ * instantiates this view should add an OnRefreshListener to be notified
+ * whenever the swipe to refresh gesture is completed. The SwipeRefreshLayout
+ * will notify the listener each and every time the gesture is completed again;
+ * the listener is responsible for correctly determining when to actually
+ * initiate a refresh of its content. If the listener determines there should
+ * not be a refresh, it must call setRefreshing(false) to cancel any visual
+ * indication of a refresh. If an activity wishes to show just the progress
+ * animation, it should call setRefreshing(true). To disable the gesture and
+ * progress animation, call setEnabled(false) on the view.
+ *
+ * This layout should be made the parent of the view that will be refreshed as a
+ * result of the gesture and can only support one direct child. This view will
+ * also be made the target of the gesture and will be forced to match both the
+ * width and the height supplied in this layout. The SwipeRefreshLayout does not
+ * provide accessibility events; instead, a menu item must be provided to allow
+ * refresh of the content wherever this gesture is used.
+ *
+ */
+public class SwipeRefreshLayoutNoIndicator extends SwipeRefreshLayout {
+
+ private SwipeRefreshLayoutNoTouch parent;
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (parent == null)
+ return;
+ parent.setEnabled(enabled);
+ super.setEnabled(enabled);
+ }
+
+ public void setParent(SwipeRefreshLayoutNoTouch parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Simple constructor to use when creating a SwipeRefreshLayout from code.
+ *
+ * @param context
+ */
+ public SwipeRefreshLayoutNoIndicator(@NonNull Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Constructor that is called when inflating SwipeRefreshLayout from XML.
+ *
+ * @param context
+ * @param attrs
+ */
+ public SwipeRefreshLayoutNoIndicator(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ ev.setSource(0x10000000);
+ boolean parentConsumed = parent.onInterceptTouchEvent(ev);
+ boolean superConsumed = super.onInterceptTouchEvent(ev);
+ return parentConsumed && superConsumed;
+ /*if (super.onInterceptTouchEvent(ev))
+ return parent.onInterceptTouchEvent(ev);
+ return false;*/
+ }
+
+ @Override
+ public void requestDisallowInterceptTouchEvent(boolean b) {
+ parent.requestDisallowInterceptTouchEvent(b);
+ }
+
+ // NestedScrollingParent
+
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ parent.onStartNestedScroll(child, target, nestedScrollAxes);
+ return !parent.isRefreshing() && super.onStartNestedScroll(child, target, nestedScrollAxes);
+ }
+
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int axes) {
+ parent.onNestedScrollAccepted(child, target, axes);
+ }
+
+ @Override
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+ parent.onNestedPreScroll(target, dx, dy, consumed);
+ }
+
+ @Override
+ public int getNestedScrollAxes() {
+ return parent.getNestedScrollAxes();
+ }
+
+ @Override
+ public void onStopNestedScroll(View target) {
+ parent.onStopNestedScroll(target);
+ }
+
+ @Override
+ public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed,
+ final int dxUnconsumed, final int dyUnconsumed) {
+ parent.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
+ }
+
+ // NestedScrollingChild
+
+ @Override
+ public void setNestedScrollingEnabled(boolean enabled) {
+ if (parent == null)
+ return;
+ //parent.setNestedScrollingEnabled(enabled);
+ super.setNestedScrollingEnabled(enabled);
+ }
+
+ @Override
+ public boolean isNestedScrollingEnabled() {
+ return parent.isNestedScrollingEnabled();
+ }
+
+ @Override
+ public boolean startNestedScroll(int axes) {
+ return parent.startNestedScroll(axes);
+ }
+
+ @Override
+ public void stopNestedScroll() {
+ parent.stopNestedScroll();
+ }
+
+ @Override
+ public boolean hasNestedScrollingParent() {
+ return parent.hasNestedScrollingParent();
+ }
+
+ @Override
+ public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
+ int dyUnconsumed, int[] offsetInWindow) {
+ return super.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+ return super.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean onNestedPreFling(View target, float velocityX,
+ float velocityY) {
+ return parent.onNestedPreFling(target, velocityX, velocityY);
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY,
+ boolean consumed) {
+ return parent.onNestedFling(target, velocityX, velocityY, consumed);
+ }
+
+ @Override
+ public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
+ return parent.dispatchNestedFling(velocityX, velocityY, consumed);
+ }
+
+ @Override
+ public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
+ return parent.dispatchNestedPreFling(velocityX, velocityY);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ ev.setSource(0x10000000);
+ /*boolean consumed = super.onTouchEvent(ev);
+ if (consumed) {
+ return false;
+ }*/
+ return parent.onTouchEvent(ev);
+ }
+
+
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoTouch.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoTouch.java
new file mode 100644
index 00000000..0b2daf51
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/SwipeRefreshLayoutNoTouch.java
@@ -0,0 +1,51 @@
+package pl.szczodrzynski.edziennik.utils;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+
+public class SwipeRefreshLayoutNoTouch extends SwipeRefreshLayout {
+ public SwipeRefreshLayoutNoTouch(@NonNull Context context) {
+ super(context);
+ }
+
+ public SwipeRefreshLayoutNoTouch(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return false;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getSource() == 0x10000000) {
+ // forward the event to super
+ return super.onInterceptTouchEvent(ev);
+ }
+ // discard all the other events
+ return false;
+
+ /*if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL)
+ return false;
+ super.onInterceptTouchEvent(ev);
+ return false;*/
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getSource() == 0x10000000) {
+ // forward the event to super
+ return super.onTouchEvent(ev);
+ }
+ // discard all the other events
+ return false;
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/TextInputDropDown.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/TextInputDropDown.kt
index b809f524..f8836374 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/TextInputDropDown.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/TextInputDropDown.kt
@@ -3,9 +3,11 @@ package pl.szczodrzynski.edziennik.utils
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.PopupMenu
-import androidx.core.graphics.drawable.DrawableCompat
import com.google.android.material.textfield.TextInputEditText
-import pl.szczodrzynski.edziennik.R
+import com.mikepenz.iconics.IconicsDrawable
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
+import com.mikepenz.iconics.utils.colorInt
+import com.mikepenz.iconics.utils.sizeDp
open class TextInputDropDown : TextInputEditText {
constructor(context: Context) : super(context) {
@@ -32,11 +34,12 @@ open class TextInputDropDown : TextInputEditText {
}
open fun create(context: Context) {
- val drawable = context.resources.getDrawable(R.drawable.dropdown_arrow)
- val wrappedDrawable = DrawableCompat.wrap(drawable)
- DrawableCompat.setTint(wrappedDrawable, Themes.getPrimaryTextColor(context))
+ val drawable = IconicsDrawable(context, CommunityMaterial.Icon.cmd_chevron_down).apply {
+ colorInt = Themes.getPrimaryTextColor(context)
+ sizeDp = 24
+ }
- setCompoundDrawablesWithIntrinsicBounds(null, null, wrappedDrawable, null)
+ setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null)
isFocusableInTouchMode = false
isCursorVisible = false
isLongClickable = false
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt
index e2189f71..5f62b794 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt
@@ -42,6 +42,12 @@ object Themes {
theme = themeList[value]
}
+ var themeIndex
+ get() = themeList.indexOf(theme)
+ set(value) {
+ theme = themeList[value]
+ }
+
val appThemeNoDisplay: Int
get() = if (theme.isDark) R.style.AppTheme_Dark_NoDisplay else R.style.AppTheme_Light_NoDisplay
@@ -61,38 +67,15 @@ object Themes {
return getColorFromAttr(context, android.R.attr.textColorSecondary)
}
- /*public static int getChipColorRes() {
- switch (themeInt) {
- case THEME_LIGHT:
- return R.color.chipBackgroundLight;
- default:
- case THEME_DARK:
- return R.color.chipBackgroundDark;
- case THEME_BLACK:
- return R.color.chipBackgroundBlack;
- case THEME_CHOCOLATE:
- return R.color.chipBackgroundChocolate;
- case THEME_BLUE:
- return R.color.chipBackgroundBlue;
- case THEME_PURPLE:
- return R.color.chipBackgroundPurple;
- case THEME_GREEN:
- return R.color.chipBackgroundGreen;
- case THEME_AMBER:
- return R.color.chipBackgroundAmber;
- case THEME_RED:
- return R.color.chipBackgroundRed;
- }
- }*/
fun getThemeName(context: Context): String {
return context.getString(theme.name)
}
- fun getThemeNames(context: Context): List {
- val list = mutableListOf()
- for (theme in themeList) {
- list += context.getString(theme.name)
+ @StringRes
+ fun getThemeNameRes() = theme.name
+
+ fun getThemeNames(context: Context) =
+ themeList.map {
+ context.getString(it.name)
}
- return list
- }
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt
new file mode 100644
index 00000000..8608d35a
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-3-27.
+ */
+
+package pl.szczodrzynski.edziennik.utils.managers
+
+import android.text.TextUtils
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.*
+import okhttp3.Request
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
+import pl.szczodrzynski.edziennik.ui.modules.base.BuildInvalidActivity
+import pl.szczodrzynski.edziennik.utils.Utils
+import pl.szczodrzynski.edziennik.utils.Utils.d
+import java.time.Instant
+import java.time.ZoneId
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+
+class BuildManager(val app: App) : CoroutineScope {
+
+ override val coroutineContext = Job() + Dispatchers.Main
+
+ val buildFlavor = BuildConfig.FLAVOR
+ val buildType = BuildConfig.BUILD_TYPE
+ val buildTimestamp = BuildConfig.BUILD_TIMESTAMP
+ val isRelease = !BuildConfig.DEBUG
+ val isDebug = BuildConfig.DEBUG
+ val isNightly = BuildConfig.VERSION_NAME.contains("nightly")
+ val isDaily = BuildConfig.VERSION_NAME.contains("daily")
+
+ val gitHash = BuildConfig.GIT_INFO["hash"]
+ val gitVersion = BuildConfig.GIT_INFO["version"]
+ val gitBranch = BuildConfig.GIT_INFO["branch"]
+ val gitUnstaged = BuildConfig.GIT_INFO["unstaged"]?.split("; ")
+ val gitRevCount = BuildConfig.GIT_INFO["revCount"]
+ val gitTag = BuildConfig.GIT_INFO["tag"]
+ val gitIsDirty = BuildConfig.GIT_INFO["dirty"] !== "false"
+ val gitRemotes = BuildConfig.GIT_INFO["remotes"]?.split("; ")
+ var gitRemote: String? = ""
+ var gitAuthor: String? = ""
+
+ val isSigned = Signing.appCertificate.md5() == "f98c600d6ea0cb5bc40ffc8e6f7824ac"
+
+ val isPlayRelease = isRelease && buildFlavor == "play"
+ val isApkRelease = isRelease && buildFlavor == "official"
+ val isOfficial = isSigned && (isPlayRelease || isApkRelease)
+
+ val versionName = when {
+ isOfficial -> BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE
+ isRelease -> "$gitVersion\n$gitBranch"
+ else -> BuildConfig.VERSION_NAME
+ }
+
+ val versionBadge = when {
+ isOfficial && isNightly ->
+ "Nightly\n" + BuildConfig.VERSION_NAME.substringAfterLast('.')
+ isOfficial && isDaily ->
+ "Daily\n" + BuildConfig.VERSION_NAME.substringAfterLast('.')
+ isDebug ->
+ "Debug\n" + BuildConfig.VERSION_BASE
+ !isOfficial ->
+ "Unofficial\n" + BuildConfig.VERSION_BASE
+ else -> null
+ }
+
+ fun showVersionDialog(activity: AppCompatActivity) {
+ val yes = activity.getString(R.string.yes)
+ val no = activity.getString(R.string.no)
+
+ val colorOnBackground = R.attr.colorOnBackground.resolveAttr(activity)
+ val mtrlGreen = R.color.md_green_500.resolveColor(activity)
+ val mtrlYellow = R.color.md_yellow_700.resolveColor(activity)
+ val mtrlRed = R.color.md_red_500.resolveColor(activity)
+
+ val fields = mapOf(
+ R.string.build_version to BuildConfig.VERSION_BASE,
+ R.string.build_official to if (isOfficial)
+ yes.asColoredSpannable(mtrlGreen)
+ else
+ no.asColoredSpannable(mtrlRed),
+ R.string.build_platform to when {
+ isPlayRelease -> activity.getString(R.string.build_platform_play)
+ isApkRelease -> activity.getString(R.string.build_platform_apk)
+ else -> activity
+ .getString(R.string.build_platform_unofficial)
+ .asColoredSpannable(mtrlYellow)
+ },
+ R.string.build_date to ZonedDateTime
+ .ofInstant(Instant.ofEpochMilli(buildTimestamp), ZoneId.systemDefault())
+ .format(DateTimeFormatter.RFC_1123_DATE_TIME),
+ R.string.build_branch to gitBranch,
+ R.string.build_commit to gitHash?.substring(0, 8),
+ R.string.build_dirty to if (gitUnstaged?.isEmpty() == true)
+ "-"
+ else
+ "\t" + gitUnstaged?.join("\n\t"),
+ R.string.build_tag to gitTag,
+ R.string.build_rev_count to gitRevCount,
+ R.string.build_remote to gitRemotes?.join("\n")
+ )
+
+ val message = fields.map { (key, value) ->
+ TextUtils.concat(
+ activity
+ .getString(key)
+ .asBoldSpannable()
+ .asColoredSpannable(colorOnBackground),
+ ":\n",
+ value
+ )
+ }.concat("\n\n")
+
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.build_details)
+ .setMessage(message)
+ .setPositiveButton(R.string.ok, null)
+ .setNeutralButton(R.string.build_dialog_open_repo) { _, _ ->
+ val url = if (gitRemote == null)
+ "https://szkolny.eu/github/android"
+ else
+ "https://github.com/$gitRemote/tree/$gitHash"
+ Utils.openUrl(activity, url)
+ }
+ .show()
+ }
+
+ enum class InvalidBuildReason(
+ val message: Int,
+ val color: Int,
+ val isCritical: Boolean = true
+ ) {
+ NO_REMOTE_REPO(R.string.build_invalid_no_remote_repo, R.color.md_orange_500),
+ NO_COMMIT_HASH(R.string.build_invalid_no_commit_hash, R.color.md_orange_500),
+ REMOTE_NO_COMMIT(R.string.build_invalid_remote_no_commit, R.color.md_red_500),
+ OFFICIAL_UNSIGNED(R.string.build_invalid_official_unsigned, R.color.md_red_500),
+ UNSTAGED_CHANGES(R.string.build_invalid_unstaged_changes, R.color.md_amber_800),
+ DEBUG(R.string.build_invalid_debug, R.color.md_yellow_500, false),
+ VALID(R.string.build_valid_unofficial, R.color.md_yellow_500, false)
+ }
+
+ private fun getRemoteRepo(): String? {
+ if (gitRemotes == null)
+ return null
+ return gitRemotes.map {
+ it.substringAfter("(").substringBefore(")")
+ }.firstOrNull {
+ it != "szkolny-eu/szkolny-android"
+ }
+ }
+
+ private suspend fun validateRepo(
+ repo: String,
+ commitHash: String
+ ) = withContext(Dispatchers.IO) {
+ val request = Request.Builder()
+ .url("https://api.github.com/repos/$repo/git/commits/$commitHash")
+ .header("Accept", "application/vnd.github.v3+json")
+ .build()
+
+ val call = app.http.newCall(request)
+
+ val response = runCatching {
+ call.execute()
+ }.getOrNull() ?: return@withContext false
+
+ if (response.code() != 200)
+ return@withContext false
+
+ val json = runCatching {
+ response.body()?.string()?.toJsonObject()
+ }.getOrNull() ?: return@withContext false
+
+ val sha = json.getString("sha")
+ if (sha != commitHash)
+ return@withContext false
+
+ val author = json.getJsonObject("author") ?: return@withContext false
+ val name = author.getString("name")
+ val email = author.getString("email")
+ gitAuthor = "$name <$email>"
+
+ return@withContext true
+ }
+
+ fun validateBuild(activity: AppCompatActivity) {
+ launch {
+ gitRemote = getRemoteRepo()
+ d("BuildManager", "isSigned = $isSigned, buildType = $buildType, buildFlavor = $buildFlavor, remote = $gitRemote")
+
+ // officially signed package
+ if (isSigned)
+ return@launch
+
+ // seems official, but unsigned
+ if (isPlayRelease || isApkRelease) {
+ invalidateBuild(activity, null, InvalidBuildReason.OFFICIAL_UNSIGNED)
+ return@launch
+ }
+
+ // probably no git repository, disabled on debug
+ if (gitRemote == null && !isDebug) {
+ invalidateBuild(activity, null, InvalidBuildReason.NO_REMOTE_REPO)
+ return@launch
+ }
+ if (gitHash == null) {
+ invalidateBuild(activity, null, InvalidBuildReason.NO_COMMIT_HASH)
+ return@launch
+ }
+
+ // debug build, invalidate once
+ if (isDebug) {
+ if (app.config.validation != "debug${Signing.appCertificate}".md5()) {
+ app.config.validation = "debug${Signing.appCertificate}".md5()
+ invalidateBuild(activity, null, InvalidBuildReason.DEBUG)
+ }
+ return@launch
+ }
+
+ // release version with unstaged changes
+ if (gitIsDirty) {
+ invalidateBuild(activity, null, InvalidBuildReason.UNSTAGED_CHANGES)
+ return@launch
+ }
+
+ val validation = Signing.appCertificate + gitHash + gitRemotes?.join(";")
+
+ // app already validated
+ if (app.config.validation == validation.md5())
+ return@launch
+
+ val dialog = MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.please_wait)
+ .setMessage(R.string.build_validate_progress)
+ .setCancelable(false)
+ .show()
+
+ val isRepoValid = if (app.config.validation == "invalid$gitRemote$gitHash".md5())
+ false
+ else
+ validateRepo(gitRemote!!, gitHash)
+
+ // release build with no public repository or not published changes
+ if (!isRepoValid) {
+ app.config.validation = "invalid$gitRemote$gitHash".md5()
+ invalidateBuild(activity, dialog, InvalidBuildReason.REMOTE_NO_COMMIT)
+ return@launch
+ }
+
+ // release, unofficial, published build
+ app.config.validation = validation.md5()
+ invalidateBuild(activity, dialog, InvalidBuildReason.VALID)
+ }
+ }
+
+ private fun invalidateBuild(
+ activity: AppCompatActivity,
+ progressDialog: AlertDialog?,
+ reason: InvalidBuildReason
+ ) {
+ progressDialog?.dismiss()
+
+ val message = activity.getString(
+ reason.message,
+ gitRemote,
+ gitBranch,
+ gitAuthor
+ )
+
+ val color = reason.color.resolveColor(activity)
+
+ val intent = Intent(
+ activity,
+ BuildInvalidActivity::class.java,
+ "message" to message,
+ "color" to color,
+ "isCritical" to reason.isCritical
+ )
+
+ activity.startActivity(intent)
+
+ if (reason.isCritical)
+ activity.finish()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt
index 4b80f44b..65430f60 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt
@@ -31,49 +31,91 @@ class PermissionManager(val app: App) : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
- private fun isStoragePermissionGranted() = if (Build.VERSION.SDK_INT >= 23) {
- app.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
- } else {
- true
+ private fun isPermissionGranted(name: String) =
+ if (Build.VERSION.SDK_INT >= 23)
+ app.checkSelfPermission(name) == PackageManager.PERMISSION_GRANTED
+ else
+ true
+
+ private fun openPermissionSettings(activity: AppCompatActivity) {
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ val uri = Uri.fromParts("package", app.packageName, null)
+ intent.data = uri
+ activity.startActivity(intent)
}
- fun requestStoragePermission(
- activity: AppCompatActivity,
- @StringRes permissionMessage: Int,
- onSuccess: suspend CoroutineScope.() -> Unit
+ private fun requestPermission(
+ activity: AppCompatActivity,
+ @StringRes permissionMessage: Int,
+ isRequired: Boolean = true,
+ permissionName: String,
+ onSuccess: suspend CoroutineScope.() -> Unit
) {
launch {
- if (isStoragePermissionGranted()) {
+ if (isPermissionGranted(permissionName)) {
onSuccess()
return@launch
}
- val result = activity.awaitAskPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ val result = activity.awaitAskPermissions(permissionName)
when {
result.hasAllGranted() -> onSuccess()
result.hasRational() -> {
+ if (!isRequired) {
+ onSuccess()
+ return@launch
+ }
MaterialAlertDialogBuilder(activity)
- .setTitle(R.string.permissions_required)
- .setMessage(permissionMessage)
- .setPositiveButton(R.string.ok) { _, _ ->
- requestStoragePermission(activity, permissionMessage, onSuccess)
- }
- .setNegativeButton(R.string.cancel, null)
- .show()
+ .setTitle(R.string.permissions_required)
+ .setMessage(permissionMessage)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ requestPermission(
+ activity,
+ permissionMessage,
+ isRequired,
+ permissionName,
+ onSuccess
+ )
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .show()
}
result.hasPermanentDenied() -> {
MaterialAlertDialogBuilder(activity)
- .setTitle(R.string.permissions_required)
- .setMessage(R.string.permissions_denied)
- .setPositiveButton(R.string.ok) { _, _ ->
- val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
- val uri = Uri.fromParts("package", app.packageName, null)
- intent.data = uri
- activity.startActivity(intent)
- }
- .setNegativeButton(R.string.cancel, null)
- .show()
+ .setTitle(R.string.permissions_required)
+ .setMessage(R.string.permissions_denied)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ openPermissionSettings(activity)
+ }
+ .setNegativeButton(R.string.cancel, null)
+ .show()
}
}
}
}
+
+ fun requestStoragePermission(
+ activity: AppCompatActivity,
+ @StringRes permissionMessage: Int,
+ isRequired: Boolean = true,
+ onSuccess: suspend CoroutineScope.() -> Unit
+ ) = requestPermission(
+ activity,
+ permissionMessage,
+ isRequired,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ onSuccess
+ )
+
+ fun requestCameraPermission(
+ activity: AppCompatActivity,
+ @StringRes permissionMessage: Int,
+ isRequired: Boolean = true,
+ onSuccess: suspend CoroutineScope.() -> Unit
+ ) = requestPermission(
+ activity,
+ permissionMessage,
+ isRequired,
+ Manifest.permission.CAMERA,
+ onSuccess
+ )
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java
index 3604b83d..b39d0298 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java
@@ -70,6 +70,13 @@ public class Date implements Comparable {
return new Date(c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH));
}
+ public static Date fromMillisUtc(long millis) {
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(millis);
+ c.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return new Date(c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH));
+ }
+
public static Date fromCalendar(Calendar c) {
return new Date(c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH));
}
@@ -94,6 +101,14 @@ public class Date implements Comparable {
return c.getTimeInMillis();
}
+ public long getInMillisUtc() {
+ Calendar c = Calendar.getInstance();
+ c.set(year, month - 1, day, 0, 0, 0);
+ c.set(Calendar.MILLISECOND, 0);
+ c.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return c.getTimeInMillis();
+ }
+
public long getInUnix() {
return getInMillis() / 1000;
}
diff --git a/app/src/main/res/anim/down_from_top.xml b/app/src/main/res/anim/down_from_top.xml
deleted file mode 100644
index e036f1ae..00000000
--- a/app/src/main/res/anim/down_from_top.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/anim/fast_out_extra_slow_in.xml b/app/src/main/res/anim/fast_out_extra_slow_in.xml
deleted file mode 100644
index f1605741..00000000
--- a/app/src/main/res/anim/fast_out_extra_slow_in.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/anim/fast_out_linear_in.xml b/app/src/main/res/anim/fast_out_linear_in.xml
deleted file mode 100644
index 19f95a69..00000000
--- a/app/src/main/res/anim/fast_out_linear_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/anim/fast_out_slow_in.xml b/app/src/main/res/anim/fast_out_slow_in.xml
deleted file mode 100644
index 2d68dbb8..00000000
--- a/app/src/main/res/anim/fast_out_slow_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/anim/linear.xml b/app/src/main/res/anim/linear.xml
deleted file mode 100644
index f4d256a6..00000000
--- a/app/src/main/res/anim/linear.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/anim/sync_rotate.xml b/app/src/main/res/anim/sync_rotate.xml
deleted file mode 100644
index c4cb8eca..00000000
--- a/app/src/main/res/anim/sync_rotate.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
diff --git a/app/src/main/res/anim/sync_rotate_0_180.xml b/app/src/main/res/anim/sync_rotate_0_180.xml
deleted file mode 100644
index 7e3ea0b2..00000000
--- a/app/src/main/res/anim/sync_rotate_0_180.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
diff --git a/app/src/main/res/anim/sync_rotate_180_0.xml b/app/src/main/res/anim/sync_rotate_180_0.xml
deleted file mode 100644
index 96f5921d..00000000
--- a/app/src/main/res/anim/sync_rotate_180_0.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
diff --git a/app/src/main/res/anim/up_from_bottom.xml b/app/src/main/res/anim/up_from_bottom.xml
deleted file mode 100644
index 649bed2f..00000000
--- a/app/src/main/res/anim/up_from_bottom.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml b/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml
index 845307b9..b007ed77 100644
--- a/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml
+++ b/app/src/main/res/drawable/bg_rounded_edittext_pressed.xml
@@ -5,5 +5,5 @@
-
-
\ No newline at end of file
+
+
diff --git a/app/src/main/res/drawable/bg_rounded_ripple_4dp_pressed.xml b/app/src/main/res/drawable/bg_rounded_ripple_4dp_pressed.xml
deleted file mode 100644
index aadf2255..00000000
--- a/app/src/main/res/drawable/bg_rounded_ripple_4dp_pressed.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_snackbar.xml b/app/src/main/res/drawable/bg_snackbar.xml
deleted file mode 100644
index 91835112..00000000
--- a/app/src/main/res/drawable/bg_snackbar.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bottom_sheet_controll_bar.xml b/app/src/main/res/drawable/bottom_sheet_controll_bar.xml
deleted file mode 100644
index ac5256a5..00000000
--- a/app/src/main/res/drawable/bottom_sheet_controll_bar.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/gtfo.png b/app/src/main/res/drawable/gtfo.png
deleted file mode 100644
index ff40e718..00000000
Binary files a/app/src/main/res/drawable/gtfo.png and /dev/null differ
diff --git a/app/src/main/res/drawable/ic_badge_drawable.xml b/app/src/main/res/drawable/ic_badge_drawable.xml
deleted file mode 100644
index 6091ab7b..00000000
--- a/app/src/main/res/drawable/ic_badge_drawable.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/timetable_lesson_bg_light.xml b/app/src/main/res/drawable/timetable_lesson_bg_light.xml
index 7a17b6cd..39d48096 100644
--- a/app/src/main/res/drawable/timetable_lesson_bg_light.xml
+++ b/app/src/main/res/drawable/timetable_lesson_bg_light.xml
@@ -4,4 +4,5 @@
-
\ No newline at end of file
+
+
diff --git a/app/src/main/res/interpolator/accelerate_quart.xml b/app/src/main/res/interpolator/accelerate_quart.xml
deleted file mode 100644
index 64efec6f..00000000
--- a/app/src/main/res/interpolator/accelerate_quart.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/interpolator/aggressive_ease.xml b/app/src/main/res/interpolator/aggressive_ease.xml
deleted file mode 100644
index 620424fb..00000000
--- a/app/src/main/res/interpolator/aggressive_ease.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/interpolator/decelerate_quart.xml b/app/src/main/res/interpolator/decelerate_quart.xml
deleted file mode 100644
index 9f6a51fd..00000000
--- a/app/src/main/res/interpolator/decelerate_quart.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/interpolator/decelerate_quint.xml b/app/src/main/res/interpolator/decelerate_quint.xml
deleted file mode 100644
index 7545b177..00000000
--- a/app/src/main/res/interpolator/decelerate_quint.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/interpolator/fast_out_slow_in.xml b/app/src/main/res/interpolator/fast_out_slow_in.xml
deleted file mode 100644
index 2d68dbb8..00000000
--- a/app/src/main/res/interpolator/fast_out_slow_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/interpolator/linear.xml b/app/src/main/res/interpolator/linear.xml
deleted file mode 100644
index f4d256a6..00000000
--- a/app/src/main/res/interpolator/linear.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/interpolator/linear_out_slow_in.xml b/app/src/main/res/interpolator/linear_out_slow_in.xml
deleted file mode 100644
index 83fc2230..00000000
--- a/app/src/main/res/interpolator/linear_out_slow_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/layout/activity_build_invalid.xml b/app/src/main/res/layout/activity_build_invalid.xml
new file mode 100644
index 00000000..0bc5fd85
--- /dev/null
+++ b/app/src/main/res/layout/activity_build_invalid.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_crash.xml b/app/src/main/res/layout/activity_crash.xml
index 459e4751..22f70a68 100644
--- a/app/src/main/res/layout/activity_crash.xml
+++ b/app/src/main/res/layout/activity_crash.xml
@@ -20,8 +20,7 @@
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/customactivityoncrash_activity_vertical_margin"
- android:paddingLeft="@dimen/customactivityoncrash_activity_horizontal_margin"
- android:paddingRight="@dimen/customactivityoncrash_activity_horizontal_margin"
+ android:paddingHorizontal="@dimen/customactivityoncrash_activity_horizontal_margin"
android:paddingTop="@dimen/customactivityoncrash_activity_vertical_margin">
-
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/activity_gtfo.xml b/app/src/main/res/layout/activity_gtfo.xml
deleted file mode 100644
index f0ff621c..00000000
--- a/app/src/main/res/layout/activity_gtfo.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_szkolny.xml b/app/src/main/res/layout/activity_szkolny.xml
index bdb2a6e7..2b35b431 100644
--- a/app/src/main/res/layout/activity_szkolny.xml
+++ b/app/src/main/res/layout/activity_szkolny.xml
@@ -40,13 +40,13 @@
android:layout_marginHorizontal="48dp"
android:layout_marginVertical="8dp"
android:background="@drawable/bg_rounded_4dp"
- android:backgroundTint="#a0ff0000"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:padding="4dp"
android:textAllCaps="true"
android:textSize="12sp"
android:textStyle="bold"
+ tools:backgroundTint="#a0ff0000"
tools:text="Nightly\n20200503" />
diff --git a/app/src/main/res/layout/attendance_config_dialog.xml b/app/src/main/res/layout/attendance_config_dialog.xml
index 5d7db447..a75da4ac 100644
--- a/app/src/main/res/layout/attendance_config_dialog.xml
+++ b/app/src/main/res/layout/attendance_config_dialog.xml
@@ -13,8 +13,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingStart="24dp"
- android:paddingEnd="24dp">
+ android:paddingHorizontal="24dp">
+ android:paddingHorizontal="24dp"
+ android:paddingTop="24dp">
diff --git a/app/src/main/res/layout/attendance_item_month.xml b/app/src/main/res/layout/attendance_item_month.xml
index 6016a81c..f3dcb13d 100644
--- a/app/src/main/res/layout/attendance_item_month.xml
+++ b/app/src/main/res/layout/attendance_item_month.xml
@@ -66,7 +66,7 @@
android:scaleType="centerInside"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-chevron-down"
- app:iiv_size="18dp"
+ app:iiv_size="24dp"
tools:src="@android:drawable/ic_menu_more" />
diff --git a/app/src/main/res/layout/attendance_item_subject.xml b/app/src/main/res/layout/attendance_item_subject.xml
index bcf95152..d1fb9ce8 100644
--- a/app/src/main/res/layout/attendance_item_subject.xml
+++ b/app/src/main/res/layout/attendance_item_subject.xml
@@ -66,7 +66,7 @@
android:scaleType="centerInside"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-chevron-down"
- app:iiv_size="18dp"
+ app:iiv_size="24dp"
tools:src="@android:drawable/ic_menu_more" />
diff --git a/app/src/main/res/layout/attendance_item_type.xml b/app/src/main/res/layout/attendance_item_type.xml
index 2ec5cd4e..682660a6 100644
--- a/app/src/main/res/layout/attendance_item_type.xml
+++ b/app/src/main/res/layout/attendance_item_type.xml
@@ -77,7 +77,7 @@
android:scaleType="centerInside"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-chevron-down"
- app:iiv_size="18dp"
+ app:iiv_size="24dp"
tools:background="@android:drawable/ic_menu_more" />
diff --git a/app/src/main/res/layout/card_home.xml b/app/src/main/res/layout/card_home.xml
index 60e58ec3..f013726b 100644
--- a/app/src/main/res/layout/card_home.xml
+++ b/app/src/main/res/layout/card_home.xml
@@ -6,9 +6,7 @@
diff --git a/app/src/main/res/layout/card_home_timetable.xml b/app/src/main/res/layout/card_home_timetable.xml
index 842e5b51..9b210f7b 100644
--- a/app/src/main/res/layout/card_home_timetable.xml
+++ b/app/src/main/res/layout/card_home_timetable.xml
@@ -178,35 +178,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/chat_view.xml b/app/src/main/res/layout/chat_view.xml
deleted file mode 100644
index f6cf2828..00000000
--- a/app/src/main/res/layout/chat_view.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_announcement.xml b/app/src/main/res/layout/dialog_announcement.xml
index 5872b067..69eb5d41 100644
--- a/app/src/main/res/layout/dialog_announcement.xml
+++ b/app/src/main/res/layout/dialog_announcement.xml
@@ -1,16 +1,16 @@
-
-
+
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/dialog_changelog.xml b/app/src/main/res/layout/dialog_changelog.xml
deleted file mode 100644
index d1902ec5..00000000
--- a/app/src/main/res/layout/dialog_changelog.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_config_grades.xml b/app/src/main/res/layout/dialog_config_grades.xml
index 8b7c0f07..1e0e9058 100644
--- a/app/src/main/res/layout/dialog_config_grades.xml
+++ b/app/src/main/res/layout/dialog_config_grades.xml
@@ -14,14 +14,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingStart="24dp"
- android:paddingEnd="24dp">
+ android:paddingHorizontal="24dp">
@@ -134,15 +132,14 @@
android:scaleType="centerInside"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-help-circle-outline"
- app:iiv_size="16dp"
+ app:iiv_size="24dp"
tools:src="@android:drawable/ic_menu_help" />
diff --git a/app/src/main/res/layout/dialog_day.xml b/app/src/main/res/layout/dialog_day.xml
index 484f2b2c..59fd7f8c 100644
--- a/app/src/main/res/layout/dialog_day.xml
+++ b/app/src/main/res/layout/dialog_day.xml
@@ -16,16 +16,14 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingLeft="16dp"
- android:paddingTop="24dp"
- android:paddingRight="16dp">
+ android:paddingHorizontal="16dp"
+ android:paddingTop="24dp">
@@ -74,10 +69,8 @@
layout="@layout/row_teacher_absence_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
+ android:layout_marginVertical="5dp"
android:visibility="gone"
tools:visibility="visible" />
@@ -86,10 +79,8 @@
android:id="@+id/eventsNoData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
+ android:layout_marginHorizontal="8dp"
+ android:paddingVertical="16dp"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
diff --git a/app/src/main/res/layout/dialog_edit_text.xml b/app/src/main/res/layout/dialog_edit_text.xml
new file mode 100644
index 00000000..6937705e
--- /dev/null
+++ b/app/src/main/res/layout/dialog_edit_text.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_event_details.xml b/app/src/main/res/layout/dialog_event_details.xml
index 11f57902..7a9d8004 100644
--- a/app/src/main/res/layout/dialog_event_details.xml
+++ b/app/src/main/res/layout/dialog_event_details.xml
@@ -27,9 +27,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingLeft="24dp"
- android:paddingTop="24dp"
- android:paddingRight="24dp">
+ android:paddingHorizontal="24dp"
+ android:paddingTop="24dp">
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_event_list.xml b/app/src/main/res/layout/dialog_event_list.xml
deleted file mode 100644
index 7e1c08fe..00000000
--- a/app/src/main/res/layout/dialog_event_list.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/dialog_event_manual.xml b/app/src/main/res/layout/dialog_event_manual.xml
deleted file mode 100644
index 0acaf493..00000000
--- a/app/src/main/res/layout/dialog_event_manual.xml
+++ /dev/null
@@ -1,234 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_event_manual_v2.xml b/app/src/main/res/layout/dialog_event_manual_v2.xml
index 0c091883..8d2fc267 100644
--- a/app/src/main/res/layout/dialog_event_manual_v2.xml
+++ b/app/src/main/res/layout/dialog_event_manual_v2.xml
@@ -139,18 +139,17 @@
android:id="@+id/showMore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
+ android:paddingVertical="16dp"
android:text="@string/dialog_event_manual_more_options"
android:background="?selectableItemBackground"
app:iiv_end_icon="cmd-chevron-down"
app:iiv_end_color="?android:textColorSecondary"
- app:iiv_end_size="16dp"
+ app:iiv_end_size="24dp"
app:iiv_end_checked_icon="cmd-chevron-up"
app:iiv_end_checked_color="?android:textColorSecondary"
- app:iiv_end_checked_size="16dp"/>
+ app:iiv_end_checked_size="24dp"/>
+ android:paddingHorizontal="24dp"
+ android:paddingTop="24dp">
diff --git a/app/src/main/res/layout/dialog_lesson_details.xml b/app/src/main/res/layout/dialog_lesson_details.xml
index 0a407420..dcc76e5e 100644
--- a/app/src/main/res/layout/dialog_lesson_details.xml
+++ b/app/src/main/res/layout/dialog_lesson_details.xml
@@ -31,9 +31,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingLeft="16dp"
- android:paddingTop="24dp"
- android:paddingRight="16dp">
+ android:paddingHorizontal="16dp"
+ android:paddingTop="24dp">
@@ -133,9 +130,8 @@
android:id="@+id/shiftedLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
- android:layout_marginRight="8dp"
android:baselineAligned="false"
android:gravity="center_vertical"
android:orientation="horizontal">
@@ -161,9 +157,8 @@
@@ -233,8 +228,7 @@
@@ -304,10 +298,8 @@
android:id="@+id/eventsNoData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
+ android:layout_marginHorizontal="8dp"
+ android:paddingVertical="16dp"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
diff --git a/app/src/main/res/layout/dialog_profile_config.xml b/app/src/main/res/layout/dialog_profile_config.xml
new file mode 100644
index 00000000..776d62a1
--- /dev/null
+++ b/app/src/main/res/layout/dialog_profile_config.xml
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_register_unavailable.xml b/app/src/main/res/layout/dialog_register_unavailable.xml
index a47bf17c..0880179d 100644
--- a/app/src/main/res/layout/dialog_register_unavailable.xml
+++ b/app/src/main/res/layout/dialog_register_unavailable.xml
@@ -36,10 +36,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingLeft="24dp"
- android:paddingTop="16dp"
- android:paddingRight="24dp"
- android:paddingBottom="16dp">
+ android:paddingHorizontal="24dp"
+ android:paddingVertical="16dp">
diff --git a/app/src/main/res/layout/dialog_template.xml b/app/src/main/res/layout/dialog_template.xml
index e9b1011f..2aa3790d 100644
--- a/app/src/main/res/layout/dialog_template.xml
+++ b/app/src/main/res/layout/dialog_template.xml
@@ -8,9 +8,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingLeft="16dp"
- android:paddingTop="24dp"
- android:paddingRight="16dp">
+ android:paddingHorizontal="16dp"
+ android:paddingTop="24dp">
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/dialog_widget_config.xml b/app/src/main/res/layout/dialog_widget_config.xml
index a0a69c44..41c9b6d4 100644
--- a/app/src/main/res/layout/dialog_widget_config.xml
+++ b/app/src/main/res/layout/dialog_widget_config.xml
@@ -2,122 +2,129 @@
+
+
+
-
-
+ android:padding="24dp">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:textAppearance="@style/NavView.TextView.Helper"
+ android:visibility="@{profileName == null ? View.GONE : View.VISIBLE}"
+ android:text="@string/dialog_widget_config_profile" />
-
+
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/event_list_item.xml b/app/src/main/res/layout/event_list_item.xml
index 295ffdc2..24445327 100644
--- a/app/src/main/res/layout/event_list_item.xml
+++ b/app/src/main/res/layout/event_list_item.xml
@@ -73,14 +73,15 @@
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia. Nie wiem co się dzieje w tym roku nie będzie już religii w szkołach podstawowych w Polsce i Europie zachodniej Afryki" />
+
@@ -89,8 +90,7 @@
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="top"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
+ android:layout_marginHorizontal="4dp"
android:visibility="gone"
app:iiv_color="@color/md_green_500"
app:iiv_icon="cmd-check"
diff --git a/app/src/main/res/layout/fragment_announcements.xml b/app/src/main/res/layout/fragment_announcements.xml
index e25911f8..cb7d38d0 100644
--- a/app/src/main/res/layout/fragment_announcements.xml
+++ b/app/src/main/res/layout/fragment_announcements.xml
@@ -21,12 +21,7 @@
android:id="@+id/announcementsNoData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginBottom="8dp"
+ android:layout_margin="8dp"
android:text="@string/school_notices_no_data"
android:textSize="18sp"
android:textStyle="italic"
@@ -37,4 +32,4 @@
app:layout_constraintTop_toTopOf="parent" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_attendance.xml b/app/src/main/res/layout/fragment_attendance.xml
deleted file mode 100644
index c0ddb3d4..00000000
--- a/app/src/main/res/layout/fragment_attendance.xml
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_behaviour.xml b/app/src/main/res/layout/fragment_behaviour.xml
index 23d2a99f..79b8554e 100644
--- a/app/src/main/res/layout/fragment_behaviour.xml
+++ b/app/src/main/res/layout/fragment_behaviour.xml
@@ -17,8 +17,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp">
+ android:layout_marginHorizontal="8dp">
@@ -63,8 +61,7 @@
android:id="@+id/noticesWarningsCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="5dp"
- android:layout_marginRight="5dp"
+ android:layout_marginHorizontal="5dp"
android:textStyle="bold"
tools:text="0" />
@@ -83,8 +80,7 @@
android:id="@+id/noticesOtherCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="5dp"
- android:layout_marginRight="5dp"
+ android:layout_marginHorizontal="5dp"
android:textStyle="bold"
tools:text="0" />
@@ -132,4 +128,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_debug.xml b/app/src/main/res/layout/fragment_debug.xml
index 2fecffa5..bf27e110 100644
--- a/app/src/main/res/layout/fragment_debug.xml
+++ b/app/src/main/res/layout/fragment_debug.xml
@@ -11,11 +11,8 @@
android:id="@+id/runLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -33,10 +30,7 @@
android:id="@+id/textView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
android:text="@string/debug_notice"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
@@ -48,10 +42,7 @@
android:id="@+id/debugRegister"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
style="@style/Widget.MaterialComponents.Button"
android:text="Run"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
@@ -69,10 +60,7 @@
android:id="@+id/debugAppconfig"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
style="@style/Widget.MaterialComponents.Button"
android:text="AppConfig"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
@@ -90,10 +78,7 @@
android:id="@+id/debugAppprofile"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
style="@style/Widget.MaterialComponents.Button"
android:text="AppProfile"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/fragment_feedback.xml b/app/src/main/res/layout/fragment_feedback.xml
index 68e75a12..79d1466d 100644
--- a/app/src/main/res/layout/fragment_feedback.xml
+++ b/app/src/main/res/layout/fragment_feedback.xml
@@ -18,9 +18,7 @@
android:id="@+id/targetDeviceDropDown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:hint=""
- android:paddingEnd="6.0dip"
- android:paddingRight="6.0dip" />
+ android:hint="" />
@@ -66,11 +60,8 @@
@@ -78,11 +69,8 @@
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
android:hint="@string/feedback_ask_a_question"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
@@ -115,16 +103,14 @@
android:id="@+id/chatLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
+ android:layout_marginVertical="8dp"
android:orientation="vertical"
android:visibility="visible">
@@ -132,9 +118,8 @@
android:id="@+id/chat_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp" />
+ android:layout_marginVertical="8dp" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grades.xml
deleted file mode 100644
index 16032680..00000000
--- a/app/src/main/res/layout/fragment_grades.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_grades_editor.xml b/app/src/main/res/layout/fragment_grades_editor.xml
index 805aee24..242b8a02 100644
--- a/app/src/main/res/layout/fragment_grades_editor.xml
+++ b/app/src/main/res/layout/fragment_grades_editor.xml
@@ -10,9 +10,8 @@
android:id="@+id/subjectName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
- android:layout_marginRight="8dp"
android:textSize="24sp"
android:textAppearance="@style/NavView.TextView.Title"
tools:text="geografia" />
@@ -21,9 +20,8 @@
android:id="@+id/semesterName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
- android:layout_marginRight="8dp"
android:textAppearance="@style/NavView.TextView.Subtitle"
tools:text="Semestr 1" />
@@ -36,8 +34,7 @@
@@ -63,8 +59,7 @@
@@ -96,8 +90,7 @@
@@ -123,8 +115,7 @@
@@ -146,9 +136,8 @@
@@ -156,9 +145,8 @@
android:id="@+id/addGrade"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
- android:layout_marginRight="8dp"
android:minHeight="0dp"
android:text="@string/grades_editor_add_grade" />
@@ -166,9 +154,8 @@
android:id="@+id/restoreGrades"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
- android:layout_marginRight="8dp"
android:minHeight="0dp"
android:text="@string/grades_editor_restore" />
@@ -179,4 +166,4 @@
android:layout_height="match_parent" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_help.xml b/app/src/main/res/layout/fragment_help.xml
deleted file mode 100644
index faf46187..00000000
--- a/app/src/main/res/layout/fragment_help.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_loading.xml b/app/src/main/res/layout/fragment_loading.xml
index 1c740c19..b6e4ae34 100644
--- a/app/src/main/res/layout/fragment_loading.xml
+++ b/app/src/main/res/layout/fragment_loading.xml
@@ -22,11 +22,10 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_messages.xml b/app/src/main/res/layout/fragment_messages.xml
deleted file mode 100644
index bb22dc0b..00000000
--- a/app/src/main/res/layout/fragment_messages.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_messages_web.xml b/app/src/main/res/layout/fragment_messages_web.xml
deleted file mode 100644
index 424dc909..00000000
--- a/app/src/main/res/layout/fragment_messages_web.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_timetable.xml b/app/src/main/res/layout/fragment_timetable.xml
deleted file mode 100644
index b13e6260..00000000
--- a/app/src/main/res/layout/fragment_timetable.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_timetable_day.xml b/app/src/main/res/layout/fragment_timetable_day.xml
deleted file mode 100644
index e00631bd..00000000
--- a/app/src/main/res/layout/fragment_timetable_day.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_timetable_v2.xml b/app/src/main/res/layout/fragment_timetable_v2.xml
index 953638cf..af7995d2 100644
--- a/app/src/main/res/layout/fragment_timetable_v2.xml
+++ b/app/src/main/res/layout/fragment_timetable_v2.xml
@@ -73,9 +73,8 @@
@@ -83,9 +82,8 @@
diff --git a/app/src/main/res/layout/grades_item_grade.xml b/app/src/main/res/layout/grades_item_grade.xml
index 10cc06b2..1ff1f0b0 100644
--- a/app/src/main/res/layout/grades_item_grade.xml
+++ b/app/src/main/res/layout/grades_item_grade.xml
@@ -11,8 +11,7 @@
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:orientation="horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
+ android:paddingVertical="8dp">
diff --git a/app/src/main/res/layout/grades_item_stats.xml b/app/src/main/res/layout/grades_item_stats.xml
index 1d990737..8ffeab4f 100644
--- a/app/src/main/res/layout/grades_item_stats.xml
+++ b/app/src/main/res/layout/grades_item_stats.xml
@@ -41,8 +41,7 @@
android:id="@+id/normalTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
+ android:layout_marginHorizontal="8dp"
android:text="@string/grades_stats_normal"
android:textAppearance="@style/NavView.TextView.Subtitle" />
@@ -51,8 +50,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingStart="8dp"
- android:paddingEnd="8dp">
+ android:paddingHorizontal="8dp">
@@ -194,8 +191,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingStart="8dp"
- android:paddingEnd="8dp">
+ android:paddingHorizontal="8dp">
diff --git a/app/src/main/res/layout/lab_item_object.xml b/app/src/main/res/layout/lab_item_object.xml
index 76800f1a..0336f65e 100644
--- a/app/src/main/res/layout/lab_item_object.xml
+++ b/app/src/main/res/layout/lab_item_object.xml
@@ -47,7 +47,7 @@
android:scaleType="centerInside"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-chevron-down"
- app:iiv_size="18dp"
+ app:iiv_size="24dp"
tools:src="@android:drawable/ic_menu_more" />
diff --git a/app/src/main/res/layout/lab_item_sub_object.xml b/app/src/main/res/layout/lab_item_sub_object.xml
index c0fb2f05..9bd72dca 100644
--- a/app/src/main/res/layout/lab_item_sub_object.xml
+++ b/app/src/main/res/layout/lab_item_sub_object.xml
@@ -42,7 +42,7 @@
android:scaleType="centerInside"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-chevron-down"
- app:iiv_size="18dp"
+ app:iiv_size="24dp"
tools:src="@android:drawable/ic_menu_more" />
diff --git a/app/src/main/res/layout/login_chooser_fragment.xml b/app/src/main/res/layout/login_chooser_fragment.xml
index 27e6f309..6e83c68c 100644
--- a/app/src/main/res/layout/login_chooser_fragment.xml
+++ b/app/src/main/res/layout/login_chooser_fragment.xml
@@ -18,7 +18,7 @@
android:layout_marginHorizontal="24dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
- app:iiv_icon="cmd-school"
+ app:iiv_icon="cmd-school-outline"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
diff --git a/app/src/main/res/layout/login_form_fragment.xml b/app/src/main/res/layout/login_form_fragment.xml
index 6bfb817f..c1026eb7 100644
--- a/app/src/main/res/layout/login_form_fragment.xml
+++ b/app/src/main/res/layout/login_form_fragment.xml
@@ -29,7 +29,7 @@
android:layout_height="32dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
- app:iiv_icon="cmd-account-circle"
+ app:iiv_icon="cmd-account-circle-outline"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
@@ -106,7 +106,7 @@
android:layout_height="24dp"
app:iiv_color="?colorOnError"
app:iiv_icon="cmd-alert-circle-outline"
- app:iiv_size="20dp" />
+ app:iiv_size="24dp" />
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/login_platform_item.xml b/app/src/main/res/layout/login_platform_item.xml
index a0fb08ae..c5a5b9fb 100644
--- a/app/src/main/res/layout/login_platform_item.xml
+++ b/app/src/main/res/layout/login_platform_item.xml
@@ -60,6 +60,6 @@
android:background="?selectableItemBackgroundBorderless"
app:iiv_color="?colorOnBackground"
app:iiv_icon="cmd-image-search-outline"
- app:iiv_size="36dp" />
+ app:iiv_size="40dp" />
diff --git a/app/src/main/res/layout/login_platform_list_fragment.xml b/app/src/main/res/layout/login_platform_list_fragment.xml
index 699177ff..7604f1c7 100644
--- a/app/src/main/res/layout/login_platform_list_fragment.xml
+++ b/app/src/main/res/layout/login_platform_list_fragment.xml
@@ -18,7 +18,7 @@
android:layout_marginHorizontal="24dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
- app:iiv_icon="cmd-tooltip-account"
+ app:iiv_icon="cmd-comment-account-outline"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
diff --git a/app/src/main/res/layout/login_summary_fragment.xml b/app/src/main/res/layout/login_summary_fragment.xml
index 1b7aac65..3f4ba4dd 100644
--- a/app/src/main/res/layout/login_summary_fragment.xml
+++ b/app/src/main/res/layout/login_summary_fragment.xml
@@ -28,7 +28,7 @@
android:layout_marginHorizontal="24dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
- app:iiv_icon="cmd-account-check"
+ app:iiv_icon="cmd-account-check-outline"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
@@ -64,8 +64,7 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:checked="true"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
+ android:paddingVertical="16dp"
android:text="@string/login_allow_registration" />
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/material_drawer_header.xml b/app/src/main/res/layout/material_drawer_header.xml
index b286b60c..51fffb92 100644
--- a/app/src/main/res/layout/material_drawer_header.xml
+++ b/app/src/main/res/layout/material_drawer_header.xml
@@ -48,8 +48,7 @@
android:gravity="center"
android:lines="1"
android:minWidth="20dp"
- android:paddingLeft="1dp"
- android:paddingRight="1dp"
+ android:paddingHorizontal="1dp"
android:singleLine="true"
android:textSize="@dimen/material_drawer_item_badge_text"
app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_current"
@@ -82,8 +81,7 @@
android:gravity="center"
android:lines="1"
android:minWidth="20dp"
- android:paddingLeft="1dp"
- android:paddingRight="1dp"
+ android:paddingHorizontal="1dp"
android:singleLine="true"
android:textSize="@dimen/material_drawer_item_badge_small_text"
app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_small_first"
@@ -116,8 +114,7 @@
android:gravity="center"
android:lines="1"
android:minWidth="20dp"
- android:paddingLeft="1dp"
- android:paddingRight="1dp"
+ android:paddingHorizontal="1dp"
android:singleLine="true"
android:textSize="@dimen/material_drawer_item_badge_small_text"
app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_small_second"
@@ -150,8 +147,7 @@
android:gravity="center"
android:lines="1"
android:minWidth="20dp"
- android:paddingLeft="1dp"
- android:paddingRight="1dp"
+ android:paddingHorizontal="1dp"
android:singleLine="true"
android:textSize="@dimen/material_drawer_item_badge_small_text"
app:layout_constraintBottom_toBottomOf="@id/material_drawer_account_header_small_third"
diff --git a/app/src/main/res/layout/material_drawer_item_profile.xml b/app/src/main/res/layout/material_drawer_item_profile.xml
index e1ac9f8e..a71ce017 100644
--- a/app/src/main/res/layout/material_drawer_item_profile.xml
+++ b/app/src/main/res/layout/material_drawer_item_profile.xml
@@ -7,10 +7,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal"
- android:paddingStart="@dimen/material_drawer_vertical_padding"
- android:paddingLeft="@dimen/material_drawer_vertical_padding"
- android:paddingEnd="@dimen/material_drawer_vertical_padding"
- android:paddingRight="@dimen/material_drawer_vertical_padding">
+ android:paddingHorizontal="@dimen/material_drawer_vertical_padding">
diff --git a/app/src/main/res/layout/md_simplelist_item.xml b/app/src/main/res/layout/md_simplelist_item.xml
deleted file mode 100644
index 6b16dc46..00000000
--- a/app/src/main/res/layout/md_simplelist_item.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/message_fragment.xml b/app/src/main/res/layout/message_fragment.xml
index a58f610f..1bae5bb5 100644
--- a/app/src/main/res/layout/message_fragment.xml
+++ b/app/src/main/res/layout/message_fragment.xml
@@ -117,9 +117,8 @@
android:background="?selectableItemBackground"
android:ellipsize="end"
android:maxLines="2"
- android:paddingLeft="8dp"
+ android:paddingHorizontal="8dp"
android:paddingTop="12dp"
- android:paddingRight="8dp"
android:textAppearance="@style/NavView.TextView.Subtitle"
tools:text="Allegro - wysyłamy duużo wiadomości!!! Masz nowe oferty! Możesz kupić nowego laptopa! Ale super! Ehh, to jest nadawca a nie temat więc nwm czemu to tutaj wpisałem" />
@@ -139,11 +138,9 @@
android:id="@+id/body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
+ android:layout_marginVertical="8dp"
android:minHeight="250dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
+ android:paddingHorizontal="16dp"
android:textIsSelectable="true"
tools:text="To jest treść wiadomości.\n\nZazwyczaj ma wiele linijek.\n\nTak" />
@@ -155,9 +152,8 @@
@@ -165,17 +161,15 @@
android:id="@+id/recipients"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
+ android:paddingHorizontal="16dp"
tools:text=" - Jan Kowalski, przeczytano: nie\n - Adam Dodatkowy, przeczytano: 20 marca, 17:35" />
@@ -183,15 +177,13 @@
android:id="@+id/attachmentsFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="8dp"
- android:layout_marginBottom="8dp"/>
+ android:layout_marginHorizontal="8dp" />
@@ -200,24 +192,20 @@
android:id="@+id/replyButton"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
+ android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:background="@drawable/bg_rounded_ripple"
android:gravity="center"
android:orientation="vertical"
- android:paddingLeft="4dp"
- android:paddingTop="8dp"
- android:paddingRight="4dp"
- android:paddingBottom="8dp">
+ android:paddingHorizontal="4dp"
+ android:paddingVertical="8dp">
+ android:paddingHorizontal="4dp"
+ android:paddingVertical="8dp">
@@ -267,22 +251,18 @@
android:id="@+id/deleteButton"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
+ android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:background="@drawable/bg_rounded_ripple"
android:gravity="center"
android:orientation="vertical"
- android:paddingLeft="4dp"
- android:paddingTop="8dp"
- android:paddingRight="4dp"
- android:paddingBottom="8dp"
+ android:paddingHorizontal="4dp"
+ android:paddingVertical="8dp"
android:visibility="visible">
@@ -300,22 +280,18 @@
android:id="@+id/downloadButton"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
+ android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:background="@drawable/bg_rounded_ripple"
android:gravity="center"
android:orientation="vertical"
- android:paddingLeft="4dp"
- android:paddingTop="8dp"
- android:paddingRight="4dp"
- android:paddingBottom="8dp"
+ android:paddingHorizontal="4dp"
+ android:paddingVertical="8dp"
android:visibility="visible">
diff --git a/app/src/main/res/layout/messages_compose_fragment.xml b/app/src/main/res/layout/messages_compose_fragment.xml
index fa056966..9363a92f 100644
--- a/app/src/main/res/layout/messages_compose_fragment.xml
+++ b/app/src/main/res/layout/messages_compose_fragment.xml
@@ -87,8 +87,7 @@
android:id="@+id/fontStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginTop="4dp">
diff --git a/app/src/main/res/layout/messages_details.xml b/app/src/main/res/layout/messages_details.xml
deleted file mode 100644
index 3be6310b..00000000
--- a/app/src/main/res/layout/messages_details.xml
+++ /dev/null
@@ -1,383 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/messages_item.xml b/app/src/main/res/layout/messages_item.xml
deleted file mode 100644
index 32616e01..00000000
--- a/app/src/main/res/layout/messages_item.xml
+++ /dev/null
@@ -1,126 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/messages_list.xml b/app/src/main/res/layout/messages_list.xml
deleted file mode 100644
index e3eca8fe..00000000
--- a/app/src/main/res/layout/messages_list.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/messages_list_item.xml b/app/src/main/res/layout/messages_list_item.xml
index 6bd8af55..d8c1b8d8 100644
--- a/app/src/main/res/layout/messages_list_item.xml
+++ b/app/src/main/res/layout/messages_list_item.xml
@@ -39,10 +39,7 @@
android:id="@+id/messageSubject"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
android:singleLine="true"
android:textStyle="normal"
android:textAppearance="@style/NavView.TextView.Helper"
@@ -73,10 +70,7 @@
android:id="@+id/messageBody"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
android:layout_marginBottom="12dp"
android:singleLine="true"
android:textAppearance="@style/NavView.TextView.Helper"
@@ -105,8 +99,7 @@
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:adjustViewBounds="true"
- android:paddingTop="2dp"
- android:paddingBottom="2dp"
+ android:paddingVertical="2dp"
android:scaleType="fitCenter"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-attachment"
diff --git a/app/src/main/res/layout/recaptcha_view.xml b/app/src/main/res/layout/recaptcha_view.xml
index dba7824b..42f430e2 100644
--- a/app/src/main/res/layout/recaptcha_view.xml
+++ b/app/src/main/res/layout/recaptcha_view.xml
@@ -8,9 +8,8 @@
@@ -67,8 +65,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/row_dialog_event_list_item.xml b/app/src/main/res/layout/row_dialog_event_list_item.xml
deleted file mode 100644
index 1ac0f53b..00000000
--- a/app/src/main/res/layout/row_dialog_event_list_item.xml
+++ /dev/null
@@ -1,165 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/row_dialog_teacher_absence_item.xml b/app/src/main/res/layout/row_dialog_teacher_absence_item.xml
index 8d303464..0b8383d1 100644
--- a/app/src/main/res/layout/row_dialog_teacher_absence_item.xml
+++ b/app/src/main/res/layout/row_dialog_teacher_absence_item.xml
@@ -10,10 +10,8 @@
diff --git a/app/src/main/res/layout/row_grades_editor_item.xml b/app/src/main/res/layout/row_grades_editor_item.xml
index 0e78bbec..113f1bf3 100644
--- a/app/src/main/res/layout/row_grades_editor_item.xml
+++ b/app/src/main/res/layout/row_grades_editor_item.xml
@@ -17,7 +17,7 @@
android:layout_height="60dp"
android:layout_gravity="center_vertical"
android:background="@color/md_red_500"
- android:padding="20dp"
+ android:padding="18dp"
app:iiv_color="@color/md_white_1000"
app:iiv_icon="cmd-delete"
tools:srcCompat="@tools:sample/avatars" />
@@ -27,7 +27,7 @@
android:layout_height="60dp"
android:layout_gravity="center_vertical"
android:background="@color/md_green_500"
- android:padding="20dp"
+ android:padding="18dp"
app:iiv_color="@color/md_white_1000"
app:iiv_icon="cmd-pencil"
tools:srcCompat="@tools:sample/avatars" />
@@ -38,8 +38,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:windowBackground"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
+ android:paddingVertical="8dp">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/row_login_profile_list_item.xml b/app/src/main/res/layout/row_login_profile_list_item.xml
deleted file mode 100644
index 550034a3..00000000
--- a/app/src/main/res/layout/row_login_profile_list_item.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/row_notices_item.xml b/app/src/main/res/layout/row_notices_item.xml
index 9af3b7a7..83f8a5d9 100644
--- a/app/src/main/res/layout/row_notices_item.xml
+++ b/app/src/main/res/layout/row_notices_item.xml
@@ -14,9 +14,8 @@
app:cardElevation="4dp"
app:cardCornerRadius="5dp"
android:background="?selectableItemBackground"
- android:paddingLeft="10dp"
+ android:paddingHorizontal="10dp"
android:paddingTop="5dp"
- android:paddingRight="10dp"
android:paddingBottom="3dp">
@@ -76,4 +74,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_timetable_item.xml b/app/src/main/res/layout/row_timetable_item.xml
deleted file mode 100644
index cde2600f..00000000
--- a/app/src/main/res/layout/row_timetable_item.xml
+++ /dev/null
@@ -1,164 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/row_widget_notifications_big_item.xml b/app/src/main/res/layout/row_widget_notifications_big_item.xml
index d95daaa8..3b369ed6 100644
--- a/app/src/main/res/layout/row_widget_notifications_big_item.xml
+++ b/app/src/main/res/layout/row_widget_notifications_big_item.xml
@@ -1,6 +1,5 @@
@@ -48,4 +46,4 @@
android:textSize="14sp"
tools:text="10:00 - 10:45" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml b/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml
index 3917cb91..fda1a2cb 100644
--- a/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml
+++ b/app/src/main/res/layout/row_widget_notifications_dark_big_item.xml
@@ -1,6 +1,5 @@
@@ -48,4 +46,4 @@
android:textSize="14sp"
tools:text="10:00 - 10:45" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_widget_notifications_dark_item.xml b/app/src/main/res/layout/row_widget_notifications_dark_item.xml
index 3bb9a0c9..6426a4bb 100644
--- a/app/src/main/res/layout/row_widget_notifications_dark_item.xml
+++ b/app/src/main/res/layout/row_widget_notifications_dark_item.xml
@@ -1,6 +1,5 @@
@@ -48,4 +46,4 @@
android:textSize="11sp"
tools:text="10:00 - 10:45" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_widget_notifications_item.xml b/app/src/main/res/layout/row_widget_notifications_item.xml
index 3eb37e94..47d228b8 100644
--- a/app/src/main/res/layout/row_widget_notifications_item.xml
+++ b/app/src/main/res/layout/row_widget_notifications_item.xml
@@ -1,6 +1,5 @@
@@ -48,4 +46,4 @@
android:textSize="11sp"
tools:text="10:00 - 10:45" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_widget_timetable_big_item.xml b/app/src/main/res/layout/row_widget_timetable_big_item.xml
index 4543536e..003600b4 100644
--- a/app/src/main/res/layout/row_widget_timetable_big_item.xml
+++ b/app/src/main/res/layout/row_widget_timetable_big_item.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml b/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml
index 794069a3..1e80afb6 100644
--- a/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml
+++ b/app/src/main/res/layout/row_widget_timetable_dark_big_item.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_widget_timetable_dark_item.xml b/app/src/main/res/layout/row_widget_timetable_dark_item.xml
index 813f7186..77149eeb 100644
--- a/app/src/main/res/layout/row_widget_timetable_dark_item.xml
+++ b/app/src/main/res/layout/row_widget_timetable_dark_item.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_widget_timetable_item.xml b/app/src/main/res/layout/row_widget_timetable_item.xml
index 84942a94..c0383b1a 100644
--- a/app/src/main/res/layout/row_widget_timetable_item.xml
+++ b/app/src/main/res/layout/row_widget_timetable_item.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/timetable_free_day.xml b/app/src/main/res/layout/timetable_free_day.xml
index bd434b6e..0cc275a2 100644
--- a/app/src/main/res/layout/timetable_free_day.xml
+++ b/app/src/main/res/layout/timetable_free_day.xml
@@ -32,8 +32,7 @@
android:id="@+id/freeDayText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="32dp"
- android:layout_marginEnd="32dp"
+ android:layout_marginHorizontal="32dp"
android:gravity="center"
android:textSize="16sp"
tools:text="Dzień wolny dla szkoły z puli dyrektorskiej z okazji obchodów Światowego Dnia Wtorku w mieście Poznań i na przedmieśiach" />
@@ -45,4 +44,4 @@
android:layout_marginTop="16dp"
android:text="@string/timetable_free_day_show" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/timetable_lesson.xml b/app/src/main/res/layout/timetable_lesson.xml
index 9992da27..3b51a197 100644
--- a/app/src/main/res/layout/timetable_lesson.xml
+++ b/app/src/main/res/layout/timetable_lesson.xml
@@ -35,8 +35,7 @@
android:layout_height="wrap_content"
android:background="@drawable/timetable_lesson_annotation"
android:fontFamily="sans-serif-condensed"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
+ android:paddingHorizontal="8dp"
android:text="@string/timetable_lesson_cancelled"
android:textColor="#000"
android:textSize="12sp"
@@ -49,8 +48,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
+ android:paddingHorizontal="8dp"
android:orientation="horizontal"
android:baselineAligned="false">
@@ -59,8 +57,7 @@
android:id="@+id/subjectName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:layout_marginBottom="4dp"
+ android:layout_marginVertical="4dp"
android:layout_weight="1"
android:ellipsize="end"
android:fontFamily="sans-serif-light"
@@ -77,10 +74,7 @@
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_marginHorizontal="8dp"
android:visibility="@{unread ? View.VISIBLE : View.GONE}"
android:background="@drawable/unread_red_circle" />
@@ -109,8 +103,7 @@
android:fontFamily="sans-serif-condensed-light"
android:includeFontPadding="false"
android:layout_marginBottom="-4dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
+ android:paddingHorizontal="4dp"
android:text="@{Integer.toString(lessonNumber)}"
android:textSize="28sp"
android:visibility="@{lessonNumber != null ? View.VISIBLE : View.GONE}"
@@ -126,8 +119,7 @@
android:layout_weight="1"
android:gravity="bottom"
android:orientation="horizontal"
- android:paddingStart="8dp"
- android:paddingEnd="8dp">
+ android:paddingHorizontal="8dp">
@@ -48,4 +47,4 @@
tools:text="@string/timetable_no_timetable_week" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_lucky_number.xml b/app/src/main/res/layout/widget_lucky_number.xml
index a0da5179..0ab862eb 100644
--- a/app/src/main/res/layout/widget_lucky_number.xml
+++ b/app/src/main/res/layout/widget_lucky_number.xml
@@ -1,5 +1,4 @@
@@ -88,4 +81,4 @@
tools:visibility="gone" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_lucky_number_big.xml b/app/src/main/res/layout/widget_lucky_number_big.xml
index ca97f832..d1d8517b 100644
--- a/app/src/main/res/layout/widget_lucky_number_big.xml
+++ b/app/src/main/res/layout/widget_lucky_number_big.xml
@@ -1,5 +1,4 @@
@@ -86,4 +79,4 @@
tools:visibility="gone" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_lucky_number_dark.xml b/app/src/main/res/layout/widget_lucky_number_dark.xml
index 90ca469d..93f97e2d 100644
--- a/app/src/main/res/layout/widget_lucky_number_dark.xml
+++ b/app/src/main/res/layout/widget_lucky_number_dark.xml
@@ -1,5 +1,4 @@
@@ -85,4 +78,4 @@
tools:visibility="gone" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_lucky_number_dark_big.xml b/app/src/main/res/layout/widget_lucky_number_dark_big.xml
index 58684cbe..950c7064 100644
--- a/app/src/main/res/layout/widget_lucky_number_dark_big.xml
+++ b/app/src/main/res/layout/widget_lucky_number_dark_big.xml
@@ -1,5 +1,4 @@
@@ -86,4 +79,4 @@
tools:visibility="gone" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_notifications.xml b/app/src/main/res/layout/widget_notifications.xml
index 5b652da0..20b0f490 100644
--- a/app/src/main/res/layout/widget_notifications.xml
+++ b/app/src/main/res/layout/widget_notifications.xml
@@ -25,8 +25,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="18.0sp"
android:ellipsize="end"
@@ -67,4 +66,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_notifications_big.xml b/app/src/main/res/layout/widget_notifications_big.xml
index f5695da2..e97b8e48 100644
--- a/app/src/main/res/layout/widget_notifications_big.xml
+++ b/app/src/main/res/layout/widget_notifications_big.xml
@@ -26,8 +26,7 @@
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:text="@string/widget_notifications_title"
android:textColor="@color/primaryTextDark"
android:textSize="24sp" />
@@ -68,4 +67,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_notifications_dark.xml b/app/src/main/res/layout/widget_notifications_dark.xml
index 19a639ff..cf960ece 100644
--- a/app/src/main/res/layout/widget_notifications_dark.xml
+++ b/app/src/main/res/layout/widget_notifications_dark.xml
@@ -25,8 +25,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="18.0sp"
android:ellipsize="end"
@@ -67,4 +66,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_notifications_dark_big.xml b/app/src/main/res/layout/widget_notifications_dark_big.xml
index 47af8347..64aaabcf 100644
--- a/app/src/main/res/layout/widget_notifications_dark_big.xml
+++ b/app/src/main/res/layout/widget_notifications_dark_big.xml
@@ -26,8 +26,7 @@
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:text="@string/widget_notifications_title"
android:textColor="@color/primaryTextDark"
android:textSize="24sp" />
@@ -68,4 +67,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_profile_dialog_item.xml b/app/src/main/res/layout/widget_profile_dialog_item.xml
new file mode 100644
index 00000000..eeae7316
--- /dev/null
+++ b/app/src/main/res/layout/widget_profile_dialog_item.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/widget_timetable.xml b/app/src/main/res/layout/widget_timetable.xml
index 792a4f0d..4f990ef8 100644
--- a/app/src/main/res/layout/widget_timetable.xml
+++ b/app/src/main/res/layout/widget_timetable.xml
@@ -26,8 +26,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="18.0sp"
android:ellipsize="end"
@@ -39,8 +38,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="10.0sp"
tools:text="Test test etst tetete" />
@@ -115,4 +113,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_timetable_big.xml b/app/src/main/res/layout/widget_timetable_big.xml
index 1b82f9b1..264316a3 100644
--- a/app/src/main/res/layout/widget_timetable_big.xml
+++ b/app/src/main/res/layout/widget_timetable_big.xml
@@ -27,8 +27,7 @@
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:text="@string/widget_timetable_title"
android:textColor="@color/primaryTextDark"
android:textSize="24sp" />
@@ -39,8 +38,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="16sp"
tools:text="Test test etst tetete" />
@@ -116,4 +114,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_timetable_dark.xml b/app/src/main/res/layout/widget_timetable_dark.xml
index 87034cd5..72301f70 100644
--- a/app/src/main/res/layout/widget_timetable_dark.xml
+++ b/app/src/main/res/layout/widget_timetable_dark.xml
@@ -26,8 +26,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="18.0sp"
android:ellipsize="end"
@@ -39,8 +38,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="10.0sp"
tools:text="Test test etst tetete" />
diff --git a/app/src/main/res/layout/widget_timetable_dark_big.xml b/app/src/main/res/layout/widget_timetable_dark_big.xml
index cbc28535..cba3e565 100644
--- a/app/src/main/res/layout/widget_timetable_dark_big.xml
+++ b/app/src/main/res/layout/widget_timetable_dark_big.xml
@@ -27,8 +27,7 @@
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:text="@string/widget_timetable_title"
android:textColor="@color/primaryTextDark"
android:textSize="24sp" />
@@ -39,8 +38,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
- android:paddingLeft="15.0dip"
- android:paddingRight="15.0dip"
+ android:paddingHorizontal="15dp"
android:textColor="@color/primaryTextDark"
android:textSize="16sp"
tools:text="Test test etst tetete" />
@@ -116,4 +114,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/menu/menu_compose.xml b/app/src/main/res/menu/menu_compose.xml
deleted file mode 100644
index ab6ae4a6..00000000
--- a/app/src/main/res/menu/menu_compose.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
deleted file mode 100644
index 39224ace..00000000
--- a/app/src/main/res/menu/menu_main.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_login.xml b/app/src/main/res/navigation/nav_login.xml
index 569fffa8..6fb5e503 100644
--- a/app/src/main/res/navigation/nav_login.xml
+++ b/app/src/main/res/navigation/nav_login.xml
@@ -22,9 +22,6 @@
-
-
-
-
-
Hinzugefügt %1$s%3$s
{cmd-share-variant} %1$s von %2$s%3$s
{cmd-share-variant} %1$s von Ihnen%3$s
- Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren.
- Ereignisse teilen
Ereignis entfernen…
Ereignis speichern…
Ereignis teilen…
@@ -830,9 +828,13 @@
etzt bewerten
Zeigen Sie, dass Ihnen Szkolny.eu gefällt - bewerten Sie die App und machen Sie sie noch besser!
Aktualisieren
- Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der Datenschutzrichtlinie lesen und die Bestimmungen akzeptieren.
- Server-Registrierung
- Gemeinsame Ereignisse herunterladen…
+ Benutzerregistrierung aufheben…
+ Einige Funktionen wie Ereignisfreigabe oder Benachrichtigungsweiterleitung können nicht mehr verwendet werden.\n\nDie Funktion kann je nach ausgewähltem Profil aktiviert / deaktiviert werden.
+ Gemeinsame Ereignisse herunterladen…
+ Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der Datenschutzrichtlinie lesen und die Bestimmungen akzeptieren.
+ Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren.
+ Ereignisse teilen
+ Szkolny.eu Server-Registrierung
Löschen
gelöschtet
Melden
@@ -847,13 +849,13 @@
Klicken Sie hier, um eine unerwartete Ausnahme auszulösen
Treten Sie unserem Discord-Server bei!
Discord Server
- Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht.
- App-Sprache ändern
+ Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht.
+ App-Sprache ändern
Deutsch
Sprache der App
Open-Source-Lizenzen
Datenschutzrichtlinie
- E-Klassenbuch
+ E-Klassenbuch
© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - Februar 2021
Klicken Sie hier, um nach Aktualisierungen zu suchen
Aktualisierung
@@ -944,7 +946,7 @@
Deaktiviert
Daten alle %s herunterladen
Automatische Synchronisierung
- Synchronisation und Benachrichtigungen
+ Synchronisation und Benachrichtigungen
Über App-Aktualisierungen benachrichtigen
Benachrichtigungen auf Ihrem PC anzeigen
Benachrichtigungsweiterleitung
@@ -968,7 +970,7 @@
Rosa
System
Thema
- Aussehen
+ Aussehen
Teilen
Teilen über…
Daten Teilen…
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index ab80b93c..2f5cb1fe 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -351,8 +351,6 @@
Adde %1$s%3$s
{cmd-share-variant} %1$s by %2$s%3$s
{cmd-share-variant} %1$s by you%3$s
- You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nBefore turning it on, make sure you\'ve read the terms and accept them
- Sharing events
Removing event…
Saving event…
Sharing event…
@@ -832,9 +830,13 @@
Rate now
Show that you like Szkolny.eu - rate the app and make it even better!
Refresh
- Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nMake sure you read the terms and accept them.
- Server registration
- Syncing shared events…
+ Unregistering the user…
+ You won\'t be able to use some functions anymore, like Event sharing and Notification forwarding.\n\nThis feature may be enabled/disabled depending on the active profile.
+ Syncing shared events…
+ Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nContinuing means reading and accepting the Privacy policy .
+ You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nContinuing means reading and accepting the Privacy policy .
+ Sharing events
+ Szkolny.eu server registration
Remove
Removed
Report
@@ -849,13 +851,13 @@
Click to throw an unexpected exception
Join our Discord community!
Discord server
- Notice. This feature may not work on some devices or in some parts of the app.
- Change app language
- "English "
+ Notice. This feature may not work on some devices or in some parts of the app.
+ Change app language
+ English
App language
Open-source licenses
Privacy policy
- E-register
+ E-register
© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - February 2021
Click to check for updates
Update
@@ -946,7 +948,7 @@
Disabled
Download data every %s
Automatic sync
- Sync & notifications
+ Sync & notifications
Notify about app updates
Show notifications on your PC
Notification forwarding
@@ -970,7 +972,7 @@
Pink
System
Theme
- Appearance
+ Appearance
Share
Share…
Sharing events…
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index dc9d55f7..55e0d3b5 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -1,12 +1,9 @@
-
-
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index a5e975f1..3c17d618 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -4,7 +4,6 @@
#1976D2
#6EC6FF
#4caf50
- #4CAF50
#ff101010
#fff3f3f3
@@ -13,10 +12,6 @@
#3e7f7f7f
- #2196f3
- #64b5f6
-
-
#ffffffff
#ffffffff
diff --git a/app/src/main/res/values/errors.xml b/app/src/main/res/values/errors.xml
index 3dabf589..d90af9ed 100644
--- a/app/src/main/res/values/errors.xml
+++ b/app/src/main/res/values/errors.xml
@@ -36,6 +36,30 @@
ERROR_CAPTCHA_NEEDED
ERROR_CAPTCHA_LIBRUS_PORTAL
+ ERROR_API_PDO_ERROR
+ ERROR_API_INVALID_CLIENT
+ ERROR_API_INVALID_ARGUMENT
+ ERROR_API_INVALID_SIGNATURE
+ ERROR_API_MISSING_SCOPES
+ ERROR_API_RESOURCE_NOT_FOUND
+ ERROR_API_INTERNAL_SERVER_ERROR
+ ERROR_API_PHP_E_ERROR
+ ERROR_API_PHP_E_WARNING
+ ERROR_API_PHP_E_PARSE
+ ERROR_API_PHP_E_NOTICE
+ ERROR_API_PHP_E_OTHER
+ ERROR_API_MAINTENANCE
+ ERROR_API_MISSING_ARGUMENT
+ ERROR_API_PAYLOAD_EMPTY
+ ERROR_API_INVALID_ACTION
+ ERROR_API_UPDATE_NOT_FOUND
+ ERROR_API_INVALID_DEVICEID_USERCODE
+ ERROR_API_INVALID_PAIRTOKEN
+ ERROR_API_INVALID_BROWSERID
+ ERROR_API_INVALID_DEVICEID
+ ERROR_API_INVALID_DEVICEID_BROWSERID
+ ERROR_API_HELP_CATEGORY_NOT_FOUND
+
CODE_INTERNAL_LIBRUS_ACCOUNT_410
CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED
ERROR_LOGIN_LIBRUS_API_CAPTCHA_NEEDED
@@ -210,6 +234,30 @@
Wymagane rozwiązanie zadania Captcha
LIBRUS®️: wymagane rozwiązanie zadania Captcha
+ ERROR_API_PDO_ERROR
+ Nieprawidłowy ID klienta API
+ API: nieprawidłowy argument
+ Brak dostępu do API
+ Brak uprawnień do zasobu API
+ Nie znaleziono zasobu API
+ Błąd serwera API Szkolny.eu
+ ERROR_API_PHP_E_ERROR
+ ERROR_API_PHP_E_WARNING
+ ERROR_API_PHP_E_PARSE
+ ERROR_API_PHP_E_NOTICE
+ ERROR_API_PHP_E_OTHER
+ API Szkolny.eu: przerwa techniczna
+ API: brakujący argument
+ API: brak przesłanej zawartości
+ ERROR_API_INVALID_ACTION
+ API: nie znaleziono wybranej aktualizacji
+ ERROR_API_INVALID_DEVICEID_USERCODE
+ Nieprawidłowy token przeglądarki
+ ERROR_API_INVALID_BROWSERID
+ ERROR_API_INVALID_DEVICEID
+ ERROR_API_INVALID_DEVICEID_BROWSERID
+ ERROR_API_HELP_CATEGORY_NOT_FOUND
+
CODE_INTERNAL_LIBRUS_ACCOUNT_410
CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED
Wymagane wypełnienie CAPTCHA
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a913914d..e9a9befb 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -386,8 +386,6 @@
Dodano %1$s%3$s
{cmd-share-variant} %1$s przez %2$s%3$s
{cmd-share-variant} %1$s przez Ciebie%3$s
- Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nUpewnij się, że zapoznałeś się z warunkami i akceptujesz jej postanowienia.
- Udostępnianie wydarzeń
Usuwam wydarzenie…
Zapisuję wydarzenie…
Udostępniam wydarzenie…
@@ -895,9 +893,13 @@
Oceń teraz
Pokaż, że podoba ci się Szkolny.eu - oceń aplikację i spraw, by była jeszcze lepsza!
Odśwież
- Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nUpewnij się, że zapoznałeś się z warunkami Polityki prywatności i akceptujesz jej postanowienia.
- Rejestracja na serwerze
- Pobieranie udostępnionych wydarzeń…
+ Trwa wyrejestrowywanie użytkownika…
+ Stracisz możliwość korzystania z niektórych funkcji, takich jak Udostępnianie wydarzeń czy Przekazywanie powiadomień.\n\nFunkcja może być włączona/wyłączona w zależności od wybranego profilu.
+ Pobieranie udostępnionych wydarzeń…
+ Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień Polityki prywatności .
+ Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień Polityki prywatności .
+ Udostępnianie wydarzeń
+ Rejestracja aplikacji Szkolny.eu
Usuń
Usunięto
Zgłoś
@@ -912,13 +914,13 @@
Kliknij, aby wywołać nieoczekiwany wyjątek
Dołącz do naszego serwera Discord!
Serwer Discord
- Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji.
- Zmień język aplikacji
+ Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji.
+ Zmień język aplikacji
Polski
Język aplikacji
Licencje open-source
Polityka prywatności
- E-dziennik
+ E-dziennik
© Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - luty 2021
Kliknij, aby sprawdzić aktualizacje
Aktualizacja
@@ -1011,7 +1013,7 @@
Wyłączona
Pobieraj dane co %s
Synchronizacja automatyczna
- Synchronizacja i powiadomienia
+ Synchronizacja i powiadomienia
Powiadamiaj o aktualizacjach aplikacji
Pokazuj powiadomienia na swoim komputerze
Przekazywanie powiadomień
@@ -1035,7 +1037,7 @@
Różowy
Systemowy
Motyw
- Wygląd
+ Wygląd
Udostępnij
Udostępnij przez…
Udostępnianie danych…
@@ -1386,4 +1388,43 @@
{cmd-alert-circle-outline} Wersja testowa
{cmd-android-studio} Wersja deweloperska
\???
+ Szkoda, opinie innych pomagają mi rozwijać aplikację.
+ Nie znaleziono profilu ucznia.
+ Zobacz także
+ Wejdź na stronę aplikacji
+ Uzyskaj pomoc lub wesprzyj autorów
+ Kod źródłowy
+ Pomóż w rozwoju aplikacji na GitHubie
+ Nazwa profilu
+ Synchronizuj ten profil
+ Wyloguj się
+ Aby móc zeskanować kod QR musisz przyznać uprawnienia dostępu do kamery.\n\nKliknij OK, aby przyznać uprawnienia.
+ Wersja aplikacji
+ Wydanie oficjalne
+ Dystrybucja
+ Google Play
+ .APK
+ Nieoficjalnie (.APK)
+ Gałąź Git
+ Identyfikator rewizji
+ Niezapisane zmiany
+ Ostatni tag
+ Rewizje od ostatniego tagu
+ Repozytorium zdalne
+ Informacje o kompilacji
+ Trwa weryfikowanie kompilacji…
+ Nie znaleziono odniesienia do repozytorium zdalnego. Upewnij się, że korzystasz z fork\'a oficjalnego repozytorium oraz zweryfikuj konfigurację Gradle.
+ Nie znaleziono wartości skrótu aktualnej rewizji. Sprawdź konfigurację Gradle.
+ Posiadasz kompilację aplikacji zawierającą nieopublikowane zmiany. Kompilacja znajduje się w repozytorium:\n%1$s (%2$s)\nktóre jest prywatne lub nie zawiera najnowszych zmian.\n\nDla bezpieczeństwa oraz ze względów zgodności z licencją, korzystanie z aplikacji zostało zablokowane.
+ Nie możesz modyfikować tego rodzaju kompilacji aplikacji Szkolny.eu.\n\nAby wprowadzić własne zmiany, skorzystaj z kodu źródłowego dostępnego na GitHubie oraz zapoznaj się z README i informacją o licencji.\n\nhttps://szkolny.eu/github/android
+ Ta kompilacja zawiera zmiany niezatwierdzone do żadnej rewizji. Zapisz oraz opublikuj wszystkie zmiany przed wydaniem wersji \"release\".\n\nDla bezpieczeństwa oraz ze względów zgodności z licencją, korzystanie z aplikacji zostało zablokowane.
+ Korzystasz z kompilacji typu \"debug\". Ta informacja zostanie wyświetlona tylko jeden raz dla aktualnego urządzenia.
+ Korzystasz z nieoficjalnej kompilacji aplikacji Szkolny.eu. Zalecamy używanie wyłącznie oficjalnych wersji aplikacji.\n\nOstatnie zmiany w tej wersji zostały wprowadzone przez %3$s w repozytorium %2$s (%1$s).\n\nTo okno nie wyświetli się ponownie.
+ Informacja dotycząca wersji aplikacji
+ Szczegóły wersji
+ Informacje o kompilacji
+ Sprawdź kod
+ Brak dostępu do API
+ Data kompilacji
+ Aby móc zapisać wygenerowany plan lekcji musisz przyznać uprawnienia dostępu do pamięci urządzenia.\n\nKliknij OK, aby przyznać uprawnienia.
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 9983ecf0..4f22fc81 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -87,36 +87,30 @@
- ?android:textColorSecondary
- ?android:textColorSecondary
+
+
-
-
diff --git a/app/src/main/res/xml/backup_descriptor.xml b/app/src/main/res/xml/backup_descriptor.xml
index 9b85b4b7..f5417ebb 100644
--- a/app/src/main/res/xml/backup_descriptor.xml
+++ b/app/src/main/res/xml/backup_descriptor.xml
@@ -2,6 +2,4 @@
-
-
diff --git a/build.gradle b/build.gradle
index c0fb9910..441d5c9c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,59 +2,18 @@
buildscript {
ext {
- kotlin_version = '1.4.30'
+ kotlin_version = '1.4.31'
release = [
- versionName: "4.6.1",
- versionCode: 4060199
+ versionName: "4.7-rc.1",
+ versionCode: 4070010
]
setup = [
compileSdk: 30,
- buildTools: "28.0.3",
minSdk : 16,
targetSdk : 30
]
-
- versions = [
- gradleAndroid : '4.2.0-beta04',
-
- kotlin : ext.kotlin_version,
- ktx : "1.3.2",
-
- androidX : '1.0.0',
- annotation : '1.1.0',
- recyclerView : '1.2.0-beta01',
- material : '1.3.0',
- appcompat : '1.3.0-beta01',
- constraintLayout : '2.1.0-alpha2',
- cardview : '1.0.0',
- gridLayout : '1.0.0',
- navigation : "2.0.0",
- navigationFragment: "1.0.0",
- legacy : "1.0.0",
-
- room : "2.2.6",
- lifecycle : "2.3.0",
- work : "2.5.0",
-
- firebase : '18.0.2',
- firebasemessaging: "20.1.3",
- play_services : "17.0.0",
-
- materialdialogs : "0.9.6.0",
- materialdrawer : "817e45765c367034b03046aaea6e95eeabcb40e9",
- iconics : "4.0.1",
- font_cmd : "3.5.95.1-kotlin",
-
- navlib : "28cdab341470dffa5f331379fe9702482681d7de",
-
- gifdrawable : "1.2.15",
-
- retrofit : "2.6.4"
- ]
- versions.kotlin = '1.4.0'
- versions.kotlin = '1.4.0'
}
repositories {
@@ -62,11 +21,10 @@ buildscript {
jcenter()
}
dependencies {
- classpath "com.android.tools.build:gradle:${versions.gradleAndroid}"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
- classpath 'me.tatarka:gradle-retrolambda:3.7.0'
+ classpath "com.android.tools.build:gradle:4.2.0-beta06"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.5'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.0'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1'
}
}
diff --git a/cafebar/build.gradle b/cafebar/build.gradle
deleted file mode 100644
index 4e992077..00000000
--- a/cafebar/build.gradle
+++ /dev/null
@@ -1,64 +0,0 @@
-apply plugin: 'com.android.library'
-
-/*
- * CafeBar
- *
- * Copyright (c) 2017 Dani Mahardhika
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-group = 'com.github.danimahardhika'
-
-android {
- compileSdkVersion setup.compileSdk
-
- defaultConfig {
- minSdkVersion 16
- targetSdkVersion setup.targetSdk
- versionCode 132
- versionName "1.3.2"
- vectorDrawables.useSupportLibrary = true
-
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- debugMinify {
- debuggable = true
- minifyEnabled = true
- proguardFiles 'proguard-android.txt'
- }
- }
-
- lintOptions {
- abortOnError false
- }
-
- sourceSets {
- main.res.srcDirs = [
- 'src/main/res',
- 'src/main/res-public'
- ]
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation "com.google.android.material:material:${versions.material}"
- implementation "androidx.cardview:cardview:${versions.cardview}"
- implementation "androidx.appcompat:appcompat:${versions.appcompat}"
-}
diff --git a/cafebar/src/main/AndroidManifest.xml b/cafebar/src/main/AndroidManifest.xml
deleted file mode 100644
index e0513a98..00000000
--- a/cafebar/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
diff --git a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBar.java b/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBar.java
deleted file mode 100644
index 7c376733..00000000
--- a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBar.java
+++ /dev/null
@@ -1,712 +0,0 @@
-package com.danimahardhika.cafebar;
-
-/*
- * CafeBar
- *
- * Copyright (c) 2017 Dani Mahardhika
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.text.SpannableStringBuilder;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.google.android.material.snackbar.Snackbar;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.HashMap;
-
-import androidx.annotation.BoolRes;
-import androidx.annotation.ColorInt;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.IntDef;
-import androidx.annotation.IntRange;
-import androidx.annotation.LayoutRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.appcompat.view.ContextThemeWrapper;
-import androidx.cardview.widget.CardView;
-import androidx.coordinatorlayout.widget.CoordinatorLayout;
-
-@SuppressWarnings("unused")
-public class CafeBar {
-
- static final String FONT_CONTENT = "content";
- static final String FONT_POSITIVE = "positive";
- static final String FONT_NEGATIVE = "negative";
- static final String FONT_NEUTRAL = "neutral";
-
- private Builder mBuilder;
- private Snackbar mSnackBar;
-
- private CafeBar(@NonNull Builder builder) {
- mBuilder = builder;
-
- View baseLayout = mBuilder.mCustomView;
- if (baseLayout == null) {
- LogUtil.d("CafeBar doesn't have customView, preparing it ...");
- baseLayout = CafeBarUtil.getBaseCafeBarView(mBuilder);
- }
-
- mSnackBar = CafeBarUtil.getBaseSnackBar(baseLayout, mBuilder);
- if (mSnackBar == null) {
- mBuilder = null;
- throw new IllegalStateException("CafeBar base is null");
- }
-
- if (mBuilder.mCustomView != null) {
- LogUtil.d("CafeBar has custom view, set buttons ignored");
- return;
- }
-
- if (mBuilder.mPositiveText == null && mBuilder.mNegativeText == null) {
- //Only contains neutral button
- if (mBuilder.mNeutralText != null) {
- int neutralColor = CafeBarUtil.getAccentColor(mBuilder.mContext, mBuilder.mNegativeColor);
- setAction(mBuilder.mNeutralText, neutralColor, mBuilder.mNeutralCallback);
- }
- } else {
- //Contains positive or negative button
- LinearLayout root = (LinearLayout) getView();
- LinearLayout buttonBase = root.findViewById(R.id.cafebar_button_base);
-
- if (mBuilder.mNeutralText != null) {
- TextView neutral = buttonBase.findViewById(R.id.cafebar_button_neutral);
- neutral.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mBuilder.mNeutralCallback != null) {
- mBuilder.mNeutralCallback.OnClick(getCafeBar());
- return;
- }
-
- dismiss();
- }
- });
- }
-
- if (mBuilder.mNegativeText != null) {
- TextView negative = buttonBase.findViewById(R.id.cafebar_button_negative);
- negative.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mBuilder.mNegativeCallback != null) {
- mBuilder.mNegativeCallback.OnClick(getCafeBar());
- return;
- }
-
- dismiss();
- }
- });
- }
-
- if (mBuilder.mPositiveText != null) {
- TextView positive = buttonBase.findViewById(R.id.cafebar_button_positive);
- positive.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mBuilder.mPositiveCallback != null) {
- mBuilder.mPositiveCallback.OnClick(getCafeBar());
- return;
- }
-
- dismiss();
- }
- });
- }
- }
- }
-
- public static void enableLogging(boolean enableLogging) {
- LogUtil.sEnableLogging = enableLogging;
- }
-
- @NonNull
- public static CafeBar make(@NonNull Context context, @StringRes int res, @Snackbar.Duration int duration) {
- String string = context.getResources().getString(res);
- return create(context, null, string, duration);
- }
-
- @NonNull
- public static CafeBar make(@NonNull Context context, @NonNull String content, @Snackbar.Duration int duration) {
- return create(context, null, content, duration);
- }
-
- @NonNull
- public static CafeBar make(@NonNull View to, @StringRes int res, @Snackbar.Duration int duration) {
- Context context = to.getContext();
- if (context instanceof ContextThemeWrapper) {
- context = ((ContextThemeWrapper) context).getBaseContext();
- }
- String string = context.getResources().getString(res);
- return create(context, to, string, duration);
- }
-
- @NonNull
- public static CafeBar make(@NonNull View to, @NonNull String content, @Snackbar.Duration int duration) {
- Context context = to.getContext();
- if (context instanceof ContextThemeWrapper) {
- context = ((ContextThemeWrapper) context).getBaseContext();
- }
- return create(context, to, content, duration);
- }
-
- @NonNull
- private static CafeBar create(@NonNull Context context, @Nullable View to, @NonNull String content, @Snackbar.Duration int duration) {
- CafeBar.Builder builder = new Builder(context);
- builder.to(to);
- builder.content(content);
- builder.duration(duration);
- if (duration == Snackbar.LENGTH_INDEFINITE) {
- builder.autoDismiss(false);
- }
- return new CafeBar(builder);
- }
-
- public CafeBar setAction(@StringRes int res, @Nullable CafeBarCallback callback) {
- String string = mBuilder.mContext.getResources().getString(res);
- int actionColor = CafeBarUtil.getAccentColor(mBuilder.mContext, mBuilder.mTheme.getTitleColor());
- setButtonAction(string, actionColor, callback);
- return this;
- }
-
- public CafeBar setAction(@NonNull String action, @Nullable CafeBarCallback callback) {
- int actionColor = CafeBarUtil.getAccentColor(mBuilder.mContext, mBuilder.mTheme.getTitleColor());
- setButtonAction(action, actionColor, callback);
- return this;
- }
-
- public CafeBar setAction(@StringRes int res, int color, @Nullable CafeBarCallback callback) {
- String string = mBuilder.mContext.getResources().getString(res);
- setButtonAction(string, color, callback);
- return this;
- }
-
- public CafeBar setAction(@NonNull String action, int color, @Nullable CafeBarCallback callback) {
- setButtonAction(action, color, callback);
- return this;
- }
-
- private void setButtonAction(@NonNull String action, int color, @Nullable final CafeBarCallback callback) {
- if (mBuilder.mCustomView != null) {
- LogUtil.d("CafeBar has customView, setAction ignored.");
- return;
- }
-
- LogUtil.d("preparing action view");
- mBuilder.mNeutralText = action;
- mBuilder.mNeutralColor = color;
-
- LinearLayout root = (LinearLayout) getView();
- boolean longAction = CafeBarUtil.isLongAction(action);
-
- if (root.getChildCount() > 1) {
- LogUtil.d("setAction already set from builder via neutralText");
- return;
- }
-
- TextView content = root.findViewById(R.id.cafebar_content);
-
- int side = mBuilder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_content_padding_side);
- int top = mBuilder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_content_padding_top);
- int buttonPadding = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.cafebar_button_padding);
- int bottom = 0;
-
- if (longAction) {
- bottom = buttonPadding;
- root.setOrientation(LinearLayout.VERTICAL);
- content.setPadding(0, 0, buttonPadding, 0);
- } else {
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) content.getLayoutParams();
- params.width = 0;
- params.weight = 1f;
- content.setLayoutParams(params);
- }
-
- int navBar = 0;
- if (mBuilder.mFitSystemWindow && !mBuilder.mFloating) {
- navBar = CafeBarUtil.getNavigationBarHeight(mBuilder.mContext);
- }
-
- Configuration configuration = mBuilder.mContext.getResources().getConfiguration();
- boolean tabletMode = mBuilder.mContext.getResources().getBoolean(R.bool.cafebar_tablet_mode);
-
- if (tabletMode || configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
- if (mBuilder.mLongContent) {
- LogUtil.d("content has multi lines");
- root.setPadding(side, side, (side - buttonPadding), (side - bottom + navBar));
- } else if (longAction){
- LogUtil.d("content only 1 line with longAction");
- root.setPadding(side, top, (side - buttonPadding), (top - buttonPadding + navBar));
- } else {
- LogUtil.d("content only 1 line");
- root.setPadding(side, (top - buttonPadding), (side - buttonPadding), (top - buttonPadding + navBar));
- }
- } else {
- if (mBuilder.mLongContent) {
- LogUtil.d("content has multi lines");
- root.setPadding(side, side, (side - buttonPadding + navBar), (side - bottom));
- } else if (longAction) {
- LogUtil.d("content only 1 line with longAction");
- root.setPadding(side, top, (side - buttonPadding + navBar), (top - buttonPadding));
- } else {
- LogUtil.d("content only 1 line");
- root.setPadding(side, (top - buttonPadding), (side - buttonPadding + navBar), (top - buttonPadding));
- }
- }
-
- TextView button = CafeBarUtil.getActionView(mBuilder, action, color);
- if (mBuilder.getTypeface(FONT_NEUTRAL) != null) {
- button.setTypeface(mBuilder.getTypeface(FONT_NEUTRAL));
- }
-
- if (!longAction) {
- boolean multiLines = CafeBarUtil.isContentMultiLines(mBuilder);
- if (multiLines) {
- if (mBuilder.mFitSystemWindow && !mBuilder.mFloating) {
- if (tabletMode || configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
- root.setPadding(side, side, (side - buttonPadding), (side + navBar));
- } else {
- root.setPadding(side, side, (side - buttonPadding + navBar), side);
- }
- } else {
- root.setPadding(side, side, (side - buttonPadding), side);
- }
- }
- }
-
- button.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View view) {
- if (callback != null) {
- callback.OnClick(getCafeBar());
- return;
- }
-
- LogUtil.d("callback = null, CafeBar dismissed");
- dismiss();
- }
- });
-
- root.addView(button);
- }
-
-
-
- @NonNull
- private CafeBar getCafeBar() {
- return this;
- }
-
- @NonNull
- public View getView() {
- Snackbar.SnackbarLayout snackBarLayout = (Snackbar.SnackbarLayout) mSnackBar.getView();
-
- boolean tabletMode = mBuilder.mContext.getResources().getBoolean(R.bool.cafebar_tablet_mode);
-
- if (tabletMode || mBuilder.mFloating) {
- CardView cardView = (CardView) snackBarLayout.getChildAt(0);
- return cardView.getChildAt(0);
- }
-
- LinearLayout linearLayout = (LinearLayout) snackBarLayout.getChildAt(0);
- if (mBuilder.mShowShadow) return linearLayout.getChildAt(1);
- return linearLayout.getChildAt(0);
- }
-
- public void dismiss() {
- if (mSnackBar == null) return;
-
- mSnackBar.dismiss();
- }
-
- public void show() {
- mSnackBar.show();
-
- if (mBuilder.mSwipeToDismiss) return;
-
- if (mSnackBar.getView().getLayoutParams() instanceof CoordinatorLayout.LayoutParams) {
- mSnackBar.getView().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-
- @Override
- public boolean onPreDraw() {
- mSnackBar.getView().getViewTreeObserver().removeOnPreDrawListener(this);
- ((CoordinatorLayout.LayoutParams) mSnackBar.getView().getLayoutParams()).setBehavior(null);
- return true;
- }
- });
- }
- }
-
- @NonNull
- public static Builder builder(@NonNull Context context) {
- return new Builder(context);
- }
-
- @SuppressWarnings("unused")
- public static class Builder {
-
- Context mContext;
-
- @NonNull View mTo;
- @Nullable View mCustomView;
- CafeBarTheme.Custom mTheme = CafeBarTheme.Custom(CafeBarTheme.DARK.getColor());
- CafeBarGravity mGravity = CafeBarGravity.CENTER;
-
- @Snackbar.Duration
- int mDuration = Snackbar.LENGTH_SHORT;
- int mMaxLines = 2;
- @ColorInt
- int mPositiveColor = mTheme.getTitleColor();
- @ColorInt int mNegativeColor = mTheme.getTitleColor();
- @ColorInt int mNeutralColor = mTheme.getTitleColor();
-
- boolean mLongContent = false;
- boolean mAutoDismiss = true;
- boolean mShowShadow = true;
- boolean mFitSystemWindow = false;
- boolean mFloating = false;
- boolean mTintIcon = true;
- boolean mSwipeToDismiss = true;
-
- private HashMap> mTypefaces;
-
- @Nullable Drawable mIcon = null;
-
- String mContent = "";
- @Nullable String mPositiveText = null;
- @Nullable String mNegativeText = null;
- @Nullable String mNeutralText = null;
-
- @Nullable SpannableStringBuilder mSpannableBuilder = null;
-
- @Nullable CafeBarCallback mPositiveCallback;
- @Nullable CafeBarCallback mNegativeCallback;
- @Nullable CafeBarCallback mNeutralCallback;
-
- public Builder(@NonNull Context context) {
- mContext = context;
- mTypefaces = new HashMap<>();
-
- mTo = ((Activity) mContext).getWindow().getDecorView()
- .findViewById(android.R.id.content);
- }
-
- public Builder to(@Nullable View view) {
- if (view != null) {
- mTo = view;
- return this;
- }
-
- LogUtil.e("to(View): view is null, ignored");
- return this;
- }
-
- public Builder customView(@LayoutRes int res) {
- View view = View.inflate(mContext, res, null);
- return customView(view);
- }
-
- public Builder customView(@Nullable View customView) {
- mCustomView = customView;
- return this;
- }
-
- public Builder content(@StringRes int res) {
- return content(mContext.getResources().getString(res));
- }
-
- public Builder content(@NonNull String content) {
- mContent = content;
- return this;
- }
-
- public Builder content(@NonNull SpannableStringBuilder spannableBuilder) {
- mSpannableBuilder = spannableBuilder;
- return this;
- }
-
- public Builder maxLines(@IntRange(from = 1, to = 6) int maxLines) {
- mMaxLines = maxLines;
- return this;
- }
-
- public Builder duration(@Snackbar.Duration int duration) {
- mDuration = duration;
- return this;
- }
-
- public Builder theme(@NonNull CafeBarTheme theme) {
- return theme(CafeBarTheme.Custom(theme.getColor()));
- }
-
- public Builder theme(@NonNull CafeBarTheme.Custom customTheme) {
- mTheme = customTheme;
- mPositiveColor = mTheme.getTitleColor();
- mNegativeColor = mNeutralColor = mTheme.getSubTitleColor();
- return this;
- }
-
- public Builder icon(@Nullable Bitmap icon) {
- return icon(CafeBarUtil.toDrawable(mContext, icon), true);
- }
-
- public Builder icon(@DrawableRes int res) {
- return icon(CafeBarUtil.getDrawable(mContext, res), true);
- }
-
- public Builder icon(@Nullable Drawable icon) {
- return icon(icon, true);
- }
-
- public Builder icon(@Nullable Bitmap icon, boolean tintIcon) {
- return icon(CafeBarUtil.toDrawable(mContext, icon), tintIcon);
- }
-
- public Builder icon(@DrawableRes int res, boolean tintIcon) {
- return icon(CafeBarUtil.getDrawable(mContext, res), tintIcon);
- }
-
- public Builder icon(@Nullable Drawable icon, boolean tintIcon) {
- mIcon = icon;
- mTintIcon = tintIcon;
- return this;
- }
-
- public Builder showShadow(@BoolRes int res) {
- return showShadow(mContext.getResources().getBoolean(res));
- }
-
- public Builder showShadow(boolean showShadow) {
- mShowShadow = showShadow;
- return this;
- }
-
- public Builder autoDismiss(@BoolRes int res) {
- return autoDismiss(mContext.getResources().getBoolean(res));
- }
-
- public Builder autoDismiss(boolean autoDismiss) {
- mAutoDismiss = autoDismiss;
- return this;
- }
-
- public Builder swipeToDismiss(@BoolRes int res) {
- return swipeToDismiss(mContext.getResources().getBoolean(res));
- }
-
- public Builder swipeToDismiss(boolean swipeToDismiss) {
- mSwipeToDismiss = swipeToDismiss;
- return this;
- }
-
- public Builder floating(@BoolRes int res) {
- return floating(mContext.getResources().getBoolean(res));
- }
-
- public Builder floating(boolean floating) {
- mFloating = floating;
- return this;
- }
-
- public Builder gravity(@NonNull CafeBarGravity gravity) {
- mGravity = gravity;
- return this;
- }
-
- public Builder fitSystemWindow() {
- Activity activity = (Activity) mContext;
- Window window = activity.getWindow();
- if (window == null) {
- LogUtil.d("fitSystemWindow() window is null");
- return this;
- }
-
- WindowManager.LayoutParams params = window.getAttributes();
- int navigationBarHeight = CafeBarUtil.getNavigationBarHeight(mContext);
-
- boolean isInMultiWindowMode = false;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- isInMultiWindowMode = activity.isInMultiWindowMode();
- }
-
- if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) ==
- WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) {
- mFitSystemWindow = navigationBarHeight > 0 && !isInMultiWindowMode;
- }
- return this;
- }
-
- public Builder typeface(String contentFontName, String buttonFontName) {
- return typeface(CafeBarUtil.getTypeface(mContext, contentFontName),
- CafeBarUtil.getTypeface(mContext, buttonFontName));
- }
-
- public Builder typeface(@Nullable Typeface content, @Nullable Typeface button) {
- addTypeface(FONT_CONTENT, content);
- addTypeface(FONT_POSITIVE, button);
- addTypeface(FONT_NEGATIVE, button);
- addTypeface(FONT_NEUTRAL, button);
- return this;
- }
-
- public Builder contentTypeface(String fontName) {
- return contentTypeface(CafeBarUtil.getTypeface(mContext, fontName));
- }
-
- public Builder contentTypeface(@Nullable Typeface typeface) {
- addTypeface(FONT_CONTENT, typeface);
- return this;
- }
-
- public Builder positiveTypeface(String fontName) {
- return positiveTypeface(CafeBarUtil.getTypeface(mContext, fontName));
- }
-
- public Builder positiveTypeface(@Nullable Typeface typeface) {
- addTypeface(FONT_POSITIVE,typeface);
- return this;
- }
-
- public Builder negativeTypeface(String fontName) {
- return negativeTypeface(CafeBarUtil.getTypeface(mContext, fontName));
- }
-
- public Builder negativeTypeface(@Nullable Typeface typeface) {
- addTypeface(FONT_NEGATIVE, typeface);
- return this;
- }
-
- public Builder neutralTypeface(String fontName) {
- return neutralTypeface(CafeBarUtil.getTypeface(mContext, fontName));
- }
-
- public Builder neutralTypeface(@Nullable Typeface typeface) {
- addTypeface(FONT_NEUTRAL, typeface);
- return this;
- }
-
- public Builder buttonTypeface(String fontName) {
- return buttonTypeface(CafeBarUtil.getTypeface(mContext, fontName));
- }
-
- public Builder buttonTypeface(@Nullable Typeface typeface) {
- addTypeface(FONT_POSITIVE, typeface);
- addTypeface(FONT_NEGATIVE, typeface);
- addTypeface(FONT_NEUTRAL, typeface);
- return this;
- }
-
- public Builder positiveColor(int positiveColor) {
- mPositiveColor = CafeBarUtil.getColor(mContext, positiveColor);
- return this;
- }
-
- public Builder negativeColor(int negativeColor) {
- mNegativeColor = CafeBarUtil.getColor(mContext, negativeColor);
- return this;
- }
-
- public Builder neutralColor(int neutralColor) {
- mNeutralColor = CafeBarUtil.getColor(mContext, neutralColor);
- return this;
- }
-
- public Builder buttonColor(int buttonColor) {
- int color = CafeBarUtil.getColor(mContext, buttonColor);
- mNeutralColor = mPositiveColor = mNegativeColor = color;
- return this;
- }
-
- public Builder positiveText(@StringRes int res) {
- return positiveText(mContext.getResources().getString(res));
- }
-
- public Builder positiveText(@NonNull String positiveText) {
- mPositiveText = positiveText;
- return this;
- }
-
- public Builder negativeText(@StringRes int res) {
- return negativeText(mContext.getResources().getString(res));
- }
-
- public Builder negativeText(@NonNull String negativeText) {
- mNegativeText = negativeText;
- return this;
- }
-
- public Builder neutralText(@StringRes int res) {
- return neutralText(mContext.getResources().getString(res));
- }
-
- public Builder neutralText(@NonNull String neutralText) {
- mNeutralText = neutralText;
- return this;
- }
-
- public Builder onPositive(@Nullable CafeBarCallback positiveCallback) {
- mPositiveCallback = positiveCallback;
- return this;
- }
-
- public Builder onNegative(@Nullable CafeBarCallback negativeCallback) {
- mNegativeCallback = negativeCallback;
- return this;
- }
-
- public Builder onNeutral(@Nullable CafeBarCallback neutralCallback) {
- mNeutralCallback = neutralCallback;
- return this;
- }
-
- public CafeBar build() {
- return new CafeBar(this);
- }
-
- public void show() {
- build().show();
- }
-
- private void addTypeface(String name, Typeface typeface) {
- if (!mTypefaces.containsKey(name) || mTypefaces.get(name) == null) {
- mTypefaces.put(name, new WeakReference<>(typeface));
- }
- }
-
- @Nullable
- Typeface getTypeface(String name) {
- if (mTypefaces.get(name) != null) {
- return mTypefaces.get(name).get();
- }
- return null;
- }
- }
-}
diff --git a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarCallback.java b/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarCallback.java
deleted file mode 100644
index 4a25749a..00000000
--- a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarCallback.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.danimahardhika.cafebar;
-
-/*
- * CafeBar
- *
- * Copyright (c) 2017 Dani Mahardhika
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import androidx.annotation.NonNull;
-
-public interface CafeBarCallback {
-
- void OnClick(@NonNull CafeBar cafeBar);
-}
diff --git a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarGravity.java b/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarGravity.java
deleted file mode 100644
index 9cd17023..00000000
--- a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarGravity.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.danimahardhika.cafebar;
-
-/*
- * CafeBar
- *
- * Copyright (c) 2017 Dani Mahardhika
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import android.view.Gravity;
-
-@SuppressWarnings("unused")
-public enum CafeBarGravity {
- START(Gravity.START),
- CENTER(Gravity.CENTER),
- END(Gravity.END);
-
- private int mGravity;
-
- CafeBarGravity(int gravity) {
- mGravity = gravity;
- }
-
- int getGravity() {
- return mGravity;
- }
-}
diff --git a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarTheme.java b/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarTheme.java
deleted file mode 100644
index 2ec8f3c8..00000000
--- a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarTheme.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.danimahardhika.cafebar;
-
-/*
- * CafeBar
- *
- * Copyright (c) 2017 Dani Mahardhika
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.graphics.Color;
-
-import androidx.annotation.ColorInt;
-
-@SuppressWarnings("unused")
-public enum CafeBarTheme {
-
- LIGHT(Color.parseColor("#F5F5F5")),
- DARK(Color.parseColor("#323232")),
- CLEAR_BLACK(Color.BLACK);
-
- private int mColor;
-
- CafeBarTheme(@ColorInt int color) {
- mColor = color;
- }
-
- @ColorInt
- int getColor() {
- return mColor;
- }
-
- public static Custom Custom(@ColorInt int color) {
- return new Custom(color);
- }
-
- public static class Custom {
-
- private int mColor;
-
- private Custom(int color) {
- mColor = color;
- }
-
- @ColorInt
- int getColor() {
- return mColor;
- }
-
- @ColorInt
- int getTitleColor() {
- return CafeBarUtil.getTitleTextColor(mColor);
- }
-
- @ColorInt
- int getSubTitleColor() {
- return CafeBarUtil.getSubTitleTextColor(mColor);
- }
- }
-}
diff --git a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarUtil.java b/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarUtil.java
deleted file mode 100644
index 7a776342..00000000
--- a/cafebar/src/main/java/com/danimahardhika/cafebar/CafeBarUtil.java
+++ /dev/null
@@ -1,593 +0,0 @@
-package com.danimahardhika.cafebar;
-
-/*
- * CafeBar
- *
- * Copyright (c) 2017 Dani Mahardhika
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.Typeface;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.google.android.material.snackbar.Snackbar;
-
-import java.util.Locale;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.cardview.widget.CardView;
-import androidx.core.content.ContextCompat;
-
-class CafeBarUtil {
-
- @NonNull
- static View getBaseCafeBarView(@NonNull CafeBar.Builder builder) {
- int color = builder.mTheme.getColor();
- int titleColor = builder.mTheme.getTitleColor();
-
- //Creating LinearLayout as rootView
- LinearLayout root = new LinearLayout(builder.mContext);
- root.setId(R.id.cafebar_root);
- root.setOrientation(LinearLayout.HORIZONTAL);
- root.setGravity(Gravity.CENTER_VERTICAL);
- root.setBackgroundColor(color);
- root.setLayoutParams(new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- root.setClickable(true);
-
- //Creating TextView for content
- TextView content = new TextView(builder.mContext);
- content.setId(R.id.cafebar_content);
- content.setMaxLines(builder.mMaxLines);
- content.setEllipsize(TextUtils.TruncateAt.END);
- content.setTextColor(titleColor);
- content.setTextSize(TypedValue.COMPLEX_UNIT_PX, builder.mContext.getResources()
- .getDimensionPixelSize(R.dimen.cafebar_content_text));
- if (builder.getTypeface(CafeBar.FONT_CONTENT) != null) {
- content.setTypeface(builder.getTypeface(CafeBar.FONT_CONTENT));
- }
-
- content.setText(builder.mContent);
- if (builder.mSpannableBuilder != null) {
- content.setText(builder.mSpannableBuilder, TextView.BufferType.SPANNABLE);
- }
-
- content.setLayoutParams(new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
- content.setGravity(Gravity.CENTER_VERTICAL);
-
- boolean tabletMode = builder.mContext.getResources().getBoolean(R.bool.cafebar_tablet_mode);
- if (tabletMode || builder.mFloating) {
- content.setLayoutParams(new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
- content.setMinWidth(builder.mContext.getResources()
- .getDimensionPixelSize(R.dimen.cafebar_floating_min_width));
- content.setMaxWidth(builder.mContext.getResources()
- .getDimensionPixelSize(R.dimen.cafebar_floating_max_width));
- }
-
- int side = builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_content_padding_side);
- int top = builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_content_padding_top);
-
- if (builder.mIcon != null) {
- Drawable drawable = getResizedDrawable(
- builder.mContext,
- builder.mIcon,
- titleColor,
- builder.mTintIcon);
- if (drawable != null) {
- content.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
- content.setCompoundDrawablePadding(top);
- }
- }
-
- boolean multiLines = isContentMultiLines(builder);
- boolean containsPositive = builder.mPositiveText != null;
- boolean containsNegative = builder.mNegativeText != null;
- boolean longNeutralAction = isLongAction(builder.mNeutralText);
-
- if (multiLines || containsPositive || containsNegative || longNeutralAction) {
- top = side;
- builder.mLongContent = true;
- }
-
- root.setPadding(side, top, side, top);
-
- if (builder.mPositiveText == null && builder.mNegativeText == null) {
- if (builder.mFitSystemWindow && !builder.mFloating) {
- Configuration configuration = builder.mContext.getResources().getConfiguration();
- int navBar = getNavigationBarHeight(builder.mContext);
-
- if (tabletMode || configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
- root.setPadding(side, top, side, (top + navBar));
- } else {
- root.setPadding(side, top, (side + navBar), top);
- }
- }
-
- //Adding childView to rootView
- root.addView(content);
-
- //Returning rootView
- return root;
- }
-
- //Change root orientation to vertical
- root.setOrientation(LinearLayout.VERTICAL);
-
- //Creating another linear layout for button container
- LinearLayout buttonBase = new LinearLayout(builder.mContext);
- buttonBase.setId(R.id.cafebar_button_base);
- buttonBase.setOrientation(LinearLayout.HORIZONTAL);
- buttonBase.setGravity(Gravity.END);
- buttonBase.setLayoutParams(new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
-
- //Adding button
- String neutralText = builder.mNeutralText;
- if (neutralText != null) {
- TextView neutral = getActionView(builder, neutralText, builder.mNeutralColor);
- neutral.setId(R.id.cafebar_button_neutral);
-
- if (builder.getTypeface(CafeBar.FONT_NEUTRAL) != null) {
- neutral.setTypeface(builder.getTypeface(CafeBar.FONT_NEUTRAL));
- }
-
- buttonBase.addView(neutral);
- }
-
- String negativeText = builder.mNegativeText;
- if (negativeText != null) {
- TextView negative = getActionView(builder, negativeText, builder.mNegativeColor);
- negative.setId(R.id.cafebar_button_negative);
-
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) negative.getLayoutParams();
- params.setMargins(
- params.leftMargin + builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_button_margin),
- params.topMargin,
- params.rightMargin,
- params.bottomMargin);
-
- if (builder.getTypeface(CafeBar.FONT_NEGATIVE) != null) {
- negative.setTypeface(builder.getTypeface(CafeBar.FONT_NEGATIVE));
- }
-
- buttonBase.addView(negative);
- }
-
- String positiveText = builder.mPositiveText;
- if (positiveText != null) {
- int positiveColor = CafeBarUtil.getAccentColor(builder.mContext, builder.mPositiveColor);
- TextView positive = getActionView(builder, positiveText, positiveColor);
- positive.setId(R.id.cafebar_button_positive);
-
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) positive.getLayoutParams();
- params.setMargins(
- params.leftMargin + builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_button_margin),
- params.topMargin,
- params.rightMargin,
- params.bottomMargin);
-
- if (builder.getTypeface(CafeBar.FONT_POSITIVE) != null) {
- positive.setTypeface(builder.getTypeface(CafeBar.FONT_POSITIVE));
- }
-
- buttonBase.addView(positive);
- }
-
- //Adjust padding
- int buttonPadding = builder.mContext.getResources().getDimensionPixelSize(
- R.dimen.cafebar_button_padding);
- root.setPadding(side, top, (side - buttonPadding), (top - buttonPadding));
-
- if (builder.mFitSystemWindow && !builder.mFloating) {
- Configuration configuration = builder.mContext.getResources().getConfiguration();
- int navBar = getNavigationBarHeight(builder.mContext);
-
- if (tabletMode || configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
- root.setPadding(side, top, (side - buttonPadding), (top - buttonPadding + navBar));
- } else {
- root.setPadding(side, top, (side - buttonPadding + navBar), top);
- }
- }
-
- //Adding content to container
- content.setPadding(0, 0, buttonPadding, 0);
-
- //Adding childView to rootView
- root.addView(content);
-
- //Adding button container to root
- root.addView(buttonBase);
-
- //Returning rootView
- return root;
- }
-
- static Snackbar getBaseSnackBar(@NonNull View cafeBarLayout,
- @NonNull CafeBar.Builder builder) {
- View view = builder.mTo;
-
- Snackbar snackBar = Snackbar.make(view, "", builder.mAutoDismiss ?
- builder.mDuration : Snackbar.LENGTH_INDEFINITE);
- Snackbar.SnackbarLayout snackBarLayout = (Snackbar.SnackbarLayout) snackBar.getView();
- snackBarLayout.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
- snackBarLayout.setPadding(0, 0, 0, 0);
- snackBarLayout.setBackgroundColor(Color.TRANSPARENT);
- snackBarLayout.setClickable(false);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- snackBarLayout.setElevation(0);
- }
-
- TextView textView = snackBarLayout.findViewById(
- R.id.snackbar_text);
- if (textView != null) textView.setVisibility(View.INVISIBLE);
-
- boolean tabletMode = builder.mContext.getResources().getBoolean(R.bool.cafebar_tablet_mode);
- if (tabletMode || builder.mFloating) {
- int shadow = builder.mContext.getResources().getDimensionPixelSize(R.dimen.cardview_default_elevation);
- int padding = builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_floating_padding);
-
- CardView cardView = new CardView(builder.mContext);
- cardView.setUseCompatPadding(false);
- Snackbar.SnackbarLayout.LayoutParams params = new Snackbar.SnackbarLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT);
- params.gravity = builder.mGravity.getGravity();
-
- int bottom = builder.mFloating ? padding : 0;
- snackBarLayout.setClipToPadding(false);
- snackBarLayout.setPadding(padding, shadow, padding, bottom);
-
- if (builder.mFitSystemWindow && builder.mFloating) {
- Configuration configuration = builder.mContext.getResources().getConfiguration();
- int navBar = getNavigationBarHeight(builder.mContext);
-
- if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
- snackBarLayout.setPadding(padding, shadow, padding, bottom + navBar);
- } else {
- snackBarLayout.setPadding(padding, shadow, padding + navBar, bottom);
- }
- }
-
- cardView.setLayoutParams(params);
- cardView.setClickable(true);
- if (!builder.mShowShadow) {
- cardView.setCardElevation(0f);
- }
-
- cardView.addView(cafeBarLayout);
- snackBarLayout.addView(cardView, 0);
- return snackBar;
- }
-
- LinearLayout root = new LinearLayout(builder.mContext);
- root.setOrientation(LinearLayout.VERTICAL);
- root.setLayoutParams(new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
-
- if (builder.mShowShadow) {
- View shadow = new View(builder.mContext);
- shadow.setLayoutParams(new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- builder.mContext.getResources().getDimensionPixelSize(
- R.dimen.cafebar_shadow_top)));
- shadow.setBackgroundResource(R.drawable.cafebar_shadow_top);
- root.addView(shadow);
- }
-
- root.addView(cafeBarLayout);
- snackBarLayout.addView(root, 0);
- return snackBar;
- }
-
- @NonNull
- static TextView getActionView(@NonNull CafeBar.Builder builder, @NonNull String action, int color) {
- boolean longAction = isLongAction(action);
- int res = R.layout.cafebar_action_button_dark;
-
- CafeBarTheme.Custom customTheme = builder.mTheme;
- int titleColor = customTheme.getTitleColor();
- boolean dark = titleColor != Color.WHITE;
- if (dark) {
- res = R.layout.cafebar_action_button;
- }
-
- int padding = builder.mContext.getResources().getDimensionPixelSize(
- R.dimen.cafebar_button_padding);
-
- TextView button = (TextView) View.inflate(builder.mContext, res, null);
- button.setText(action.toUpperCase(Locale.getDefault()));
- button.setMaxLines(1);
- button.setEllipsize(TextUtils.TruncateAt.END);
- button.setTextColor(color);
- button.setPadding(padding, padding, padding, padding);
-
- LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT);
-
- int side = builder.mContext.getResources().getDimensionPixelSize(
- R.dimen.cafebar_content_padding_side);
- int margin = builder.mContext.getResources().getDimensionPixelSize(
- R.dimen.cafebar_button_margin_start);
- params.setMargins(margin, 0, 0, 0);
-
- if (longAction) {
- params.setMargins(0, (side - padding), 0, 0);
- }
-
- if (builder.mPositiveText != null || builder.mNegativeText != null) {
- longAction = true;
- params.setMargins(0, (side - padding), 0, 0);
- } else {
- params.gravity = Gravity.CENTER_VERTICAL | Gravity.END;
- }
-
- button.setLayoutParams(params);
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- button.setBackgroundResource(dark ? R.drawable.cafebar_action_button_selector_dark :
- R.drawable.cafebar_action_button_selector);
- return button;
- }
-
- TypedValue outValue = new TypedValue();
- builder.mContext.getTheme().resolveAttribute(longAction ?
- R.attr.selectableItemBackground : R.attr.selectableItemBackgroundBorderless,
- outValue, true);
- button.setBackgroundResource(outValue.resourceId);
- return button;
- }
-
- static boolean isContentMultiLines(@NonNull CafeBar.Builder builder) {
- DisplayMetrics metrics = new DisplayMetrics();
- ((Activity) builder.mContext).getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
- boolean tabletMode = builder.mContext.getResources().getBoolean(R.bool.cafebar_tablet_mode);
- int padding = (builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_content_padding_side) * 2);
-
- if (builder.mNeutralText != null && builder.mNegativeText == null && builder.mPositiveText == null &&
- !isLongAction(builder.mNeutralText)) {
- padding += builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_button_margin_start);
-
- int actionPadding = builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_button_padding);
- TextView action = new TextView(builder.mContext);
- action.setTextSize(TypedValue.COMPLEX_UNIT_PX, builder.mContext.getResources()
- .getDimensionPixelSize(R.dimen.cafebar_content_text));
- if (builder.getTypeface(CafeBar.FONT_NEUTRAL) != null) {
- action.setTypeface(builder.getTypeface(CafeBar.FONT_CONTENT));
- }
- action.setPadding(actionPadding, 0, actionPadding, 0);
- action.setText(builder.mNeutralText.substring(0,
- builder.mNeutralText.length() > 10 ? 10 : builder.mNeutralText.length()));
-
- int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(metrics.widthPixels, View.MeasureSpec.AT_MOST);
- int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- action.measure(widthMeasureSpec, heightMeasureSpec);
-
- LogUtil.d("measured action width: " +action.getMeasuredWidth());
- padding += action.getMeasuredWidth();
- }
-
- if (builder.mIcon != null) {
- int icon = builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_icon_size);
- icon += builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_content_padding_top);
- padding += icon;
- }
-
- TextView textView = new TextView(builder.mContext);
- textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, builder.mContext.getResources()
- .getDimension(R.dimen.cafebar_content_text));
- textView.setPadding(padding, 0, 0, 0);
- if (builder.getTypeface(CafeBar.FONT_CONTENT) != null) {
- textView.setTypeface(builder.getTypeface(CafeBar.FONT_CONTENT));
- }
-
- if (builder.mSpannableBuilder != null) {
- textView.setText(builder.mSpannableBuilder, TextView.BufferType.SPANNABLE);
- } else {
- textView.setText(builder.mContent);
- }
-
- int maxWidth = metrics.widthPixels;
- if (builder.mFloating || tabletMode) {
- maxWidth = builder.mContext.getResources().getDimensionPixelSize(R.dimen.cafebar_floating_max_width);
- }
-
- int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST);
- int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- textView.measure(widthMeasureSpec, heightMeasureSpec);
- return textView.getLineCount() > 1;
- }
-
- @Nullable
- static Drawable getDrawable(@NonNull Context context, @DrawableRes int res) {
- try {
- Drawable drawable = context.getResources().getDrawable(res);
- return drawable.mutate();
- } catch (OutOfMemoryError e) {
- return null;
- }
- }
-
- @Nullable
- static Drawable toDrawable(@NonNull Context context, @Nullable Bitmap bitmap) {
- try {
- if (bitmap == null) return null;
- return new BitmapDrawable(context.getResources(), bitmap);
- } catch (OutOfMemoryError e) {
- return null;
- }
- }
-
- @Nullable
- private static Drawable getResizedDrawable(@NonNull Context context, @Nullable Drawable drawable,
- int color, boolean tint) {
- try {
- if (drawable == null) {
- LogUtil.d("drawable: null");
- return null;
- }
-
- if (tint) {
- drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
- drawable.mutate();
- }
-
- int size = context.getResources().getDimensionPixelSize(R.dimen.cafebar_icon_size);
- Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
- drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
-
- return new BitmapDrawable(context.getResources(),
- Bitmap.createScaledBitmap(bitmap, size, size, true));
- } catch (Exception | OutOfMemoryError e) {
- LogUtil.e(Log.getStackTraceString(e));
- return null;
- }
- }
-
- static int getNavigationBarHeight(@NonNull Context context) {
- Point appUsableSize = getAppUsableScreenSize(context);
- Point realScreenSize = getRealScreenSize(context);
-
- if (appUsableSize.x < realScreenSize.x) {
- Point point = new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y);
- return point.x;
- }
-
- if (appUsableSize.y < realScreenSize.y) {
- Point point = new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y);
- return point.y;
- }
- return 0;
- }
-
- private static Point getAppUsableScreenSize(@NonNull Context context) {
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = windowManager.getDefaultDisplay();
- Point size = new Point();
- display.getSize(size);
- return size;
- }
-
- private static Point getRealScreenSize(@NonNull Context context) {
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = windowManager.getDefaultDisplay();
- Point size = new Point();
-
- if (Build.VERSION.SDK_INT >= 17) {
- display.getRealSize(size);
- } else if (Build.VERSION.SDK_INT >= 14) {
- try {
- size.x = (Integer) Display.class.getMethod("getRawWidth").invoke(display);
- size.y = (Integer) Display.class.getMethod("getRawHeight").invoke(display);
- } catch (Exception e) {
- LogUtil.e(Log.getStackTraceString(e));
- }
- }
- return size;
- }
-
- static boolean isLongAction(@Nullable String action) {
- return action != null && action.length() > 10;
- }
-
- static int getAccentColor(Context context, int defaultColor) {
- if (context == null) {
- LogUtil.e("getAccentColor() context is null");
- return defaultColor;
- }
-
- TypedValue typedValue = new TypedValue();
- Resources.Theme theme = context.getTheme();
- theme.resolveAttribute(R.attr.colorAccent, typedValue, true);
- return typedValue.data;
- }
-
- static int getTitleTextColor(@ColorInt int color) {
- double darkness = 1-(0.299*Color.red(color) + 0.587*Color.green(color) + 0.114*Color.blue(color))/255;
- return (darkness < 0.35) ? getDarkerColor(color) : Color.WHITE;
- }
-
- static int getSubTitleTextColor(@ColorInt int color) {
- int titleColor = getTitleTextColor(color);
- int alpha2 = Math.round(Color.alpha(titleColor) * 0.7f);
- int red = Color.red(titleColor);
- int green = Color.green(titleColor);
- int blue = Color.blue(titleColor);
- return Color.argb(alpha2, red, green, blue);
- }
-
- private static int getDarkerColor(@ColorInt int color) {
- float[] hsv = new float[3];
- Color.colorToHSV(color, hsv);
- hsv[2] *= 0.25f;
- return Color.HSVToColor(hsv);
- }
-
- static int getColor(@NonNull Context context, int color) {
- try {
- return ContextCompat.getColor(context, color);
- } catch (Exception e) {
- LogUtil.e(Log.getStackTraceString(e));
- return color;
- }
- }
-
- @Nullable
- static Typeface getTypeface(@NonNull Context context, String fontName) {
- try {
- return Typeface.createFromAsset(context.getAssets(), "fonts/" +fontName);
- } catch (Exception e) {
- LogUtil.e(Log.getStackTraceString(e));
- }
- return null;
- }
-}
diff --git a/cafebar/src/main/java/com/danimahardhika/cafebar/LogUtil.java b/cafebar/src/main/java/com/danimahardhika/cafebar/LogUtil.java
deleted file mode 100644
index 6a0aad64..00000000
--- a/cafebar/src/main/java/com/danimahardhika/cafebar/LogUtil.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.danimahardhika.cafebar;
-
-/*
- * CafeBar
- *
- * Copyright (c) 2017 Dani Mahardhika
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-class LogUtil {
-
- static boolean sEnableLogging = false;
-
- private static final String TAG = "CafeBar";
-
- static void d(@NonNull String message) {
- if (LogUtil.sEnableLogging)
- Log.d(TAG, message);
- }
-
- static void e(@NonNull String message) {
- if (LogUtil.sEnableLogging)
- Log.e(TAG, message);
- }
-}
diff --git a/cafebar/src/main/res-public/values/public.xml b/cafebar/src/main/res-public/values/public.xml
deleted file mode 100644
index 4705295e..00000000
--- a/cafebar/src/main/res-public/values/public.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/drawable/cafebar_action_button_selector.xml b/cafebar/src/main/res/drawable/cafebar_action_button_selector.xml
deleted file mode 100644
index ebca92b2..00000000
--- a/cafebar/src/main/res/drawable/cafebar_action_button_selector.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/drawable/cafebar_action_button_selector_dark.xml b/cafebar/src/main/res/drawable/cafebar_action_button_selector_dark.xml
deleted file mode 100644
index 075d3975..00000000
--- a/cafebar/src/main/res/drawable/cafebar_action_button_selector_dark.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/drawable/cafebar_shadow_top.xml b/cafebar/src/main/res/drawable/cafebar_shadow_top.xml
deleted file mode 100644
index eb6c9068..00000000
--- a/cafebar/src/main/res/drawable/cafebar_shadow_top.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/layout/cafebar_action_button.xml b/cafebar/src/main/res/layout/cafebar_action_button.xml
deleted file mode 100644
index 6f21978d..00000000
--- a/cafebar/src/main/res/layout/cafebar_action_button.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/layout/cafebar_action_button_dark.xml b/cafebar/src/main/res/layout/cafebar_action_button_dark.xml
deleted file mode 100644
index 888a548d..00000000
--- a/cafebar/src/main/res/layout/cafebar_action_button_dark.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values-sw600dp-land/dimens.xml b/cafebar/src/main/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index 5799a6b2..00000000
--- a/cafebar/src/main/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
- 288dp
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values-sw600dp/bools.xml b/cafebar/src/main/res/values-sw600dp/bools.xml
deleted file mode 100644
index c203d3be..00000000
--- a/cafebar/src/main/res/values-sw600dp/bools.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
- true
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values-sw600dp/dimens.xml b/cafebar/src/main/res/values-sw600dp/dimens.xml
deleted file mode 100644
index a9a49daf..00000000
--- a/cafebar/src/main/res/values-sw600dp/dimens.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- 48dp
-
-
- 188dp
- 568dp
- 24dp
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values/bools.xml b/cafebar/src/main/res/values/bools.xml
deleted file mode 100644
index 944cf2a0..00000000
--- a/cafebar/src/main/res/values/bools.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
- false
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values/colors.xml b/cafebar/src/main/res/values/colors.xml
deleted file mode 100644
index eac88795..00000000
--- a/cafebar/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- #44000000
- #44FFFFFF
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values/dimens.xml b/cafebar/src/main/res/values/dimens.xml
deleted file mode 100644
index 6082bac0..00000000
--- a/cafebar/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- 24dp
-
- 24dp
- 14dp
-
- 24dp
- 10dp
- 8dp
-
- 4dp
- 14sp
-
-
- 108dp
- 368dp
- 16dp
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values/ids.xml b/cafebar/src/main/res/values/ids.xml
deleted file mode 100644
index c5bb9f24..00000000
--- a/cafebar/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cafebar/src/main/res/values/styles.xml b/cafebar/src/main/res/values/styles.xml
deleted file mode 100644
index 2d8c8ae4..00000000
--- a/cafebar/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/codegen/.gitignore b/codegen/.gitignore
deleted file mode 100644
index 796b96d1..00000000
--- a/codegen/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/codegen/build.gradle b/codegen/build.gradle
deleted file mode 100644
index e2630bd0..00000000
--- a/codegen/build.gradle
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-3-28.
- */
-
-apply plugin: 'java-library'
-apply plugin: 'kotlin'
-apply plugin: 'kotlin-kapt'
-
-kapt {
- generateStubs = true
-}
-
-sourceSets {
- main {
- java {
- srcDir "${buildDir.absolutePath}/tmp/kapt/main/kotlinGenerated/"
- }
- }
-}
-
-
-dependencies {
- kapt project(":annotation")
- compileOnly project(':annotation')
- implementation fileTree(include: ['*.jar'], dir: 'libs')
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-
- // configuration generator for service providers
- implementation "com.google.auto.service:auto-service:1.0-rc4"
- kapt "com.google.auto.service:auto-service:1.0-rc4"
- kapt "androidx.room:room-compiler:${versions.room}"
- implementation "androidx.room:room-runtime:${versions.room}"
- implementation "com.squareup:kotlinpoet:1.5.0"
- implementation "androidx.sqlite:sqlite:2.1.0@aar"
-
-}
-
-sourceCompatibility = "7"
-targetCompatibility = "7"
diff --git a/codegen/src/main/java/pl/szczodrzynski/edziennik/codegen/FileGenerator.kt b/codegen/src/main/java/pl/szczodrzynski/edziennik/codegen/FileGenerator.kt
deleted file mode 100644
index 5b5b1f71..00000000
--- a/codegen/src/main/java/pl/szczodrzynski/edziennik/codegen/FileGenerator.kt
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2020-3-28.
- */
-
-package pl.szczodrzynski.edziennik.codegen
-
-import androidx.room.ColumnInfo
-import androidx.room.Entity
-import androidx.room.Ignore
-import androidx.room.TypeConverters
-import com.google.auto.service.AutoService
-import com.squareup.kotlinpoet.*
-import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
-import pl.szczodrzynski.edziennik.annotation.SelectiveDao
-import pl.szczodrzynski.edziennik.annotation.UpdateSelective
-import java.io.File
-import javax.annotation.processing.*
-import javax.lang.model.SourceVersion
-import javax.lang.model.element.*
-import javax.lang.model.type.*
-import javax.lang.model.util.ElementFilter
-import javax.tools.Diagnostic
-import kotlin.reflect.KClass
-
-@Suppress("unused")
-@AutoService(Processor::class)
-@SupportedSourceVersion(SourceVersion.RELEASE_8)
-@SupportedOptions(FileGenerator.KAPT_KOTLIN_GENERATED_OPTION_NAME)
-class FileGenerator : AbstractProcessor() {
- companion object {
- const val KAPT_KOTLIN_GENERATED_OPTION_NAME = "kapt.kotlin.generated"
- }
-
- private data class TypeConverter(val dataType: TypeMirror, val converterType: TypeElement, val methodName: Name, val returnType: TypeMirror)
-
- private inline fun Element.getAnnotationClassValue(f: T.() -> KClass<*>) = try {
- getAnnotation(T::class.java).f()
- throw Exception("Expected to get a MirroredTypeException")
- } catch (e: MirroredTypeException) {
- e.typeMirror
- }
- private inline fun Element.getAnnotationClassValues(f: T.() -> Array>) = try {
- getAnnotation(T::class.java).f()
- throw Exception("Expected to get a MirroredTypesException")
- } catch (e: MirroredTypesException) {
- e.typeMirrors
- }
-
- override fun process(set: MutableSet?, roundEnvironment: RoundEnvironment?): Boolean {
- roundEnvironment?.getElementsAnnotatedWith(SelectiveDao::class.java)?.forEach { it ->
- if (it.kind != ElementKind.CLASS) {
- processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "Can only be applied to classes, element: $it")
- return false
- }
-
- val generatedSourcesRoot = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME]
- if (generatedSourcesRoot?.isEmpty() != false) {
- processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "Can't find the target directory for generated Kotlin files.")
- return false
- }
-
- val file = File(generatedSourcesRoot)
- file.mkdirs()
-
- val dao = it as TypeElement
- processClass(dao, file)
-
- //processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "package = $packageName, className = $className, methodName = $methodName, tableName = $tableName, paramName = $paramName, paramClass = $paramClass")
- }
- return true
- }
-
- private fun processClass(dao: TypeElement, file: File) {
- val daoName = dao.simpleName.toString()
- val packageName = processingEnv.elementUtils.getPackageOf(dao).toString()
-
- val dbType = processingEnv.typeUtils.asElement(dao.getAnnotationClassValue { db }) as TypeElement
- val typeConverters = dbType.getAnnotationClassValues { value }.map {
- processingEnv.typeUtils.asElement(it) as TypeElement
- }.map { type ->
- processingEnv.elementUtils.getAllMembers(type).mapNotNull { element ->
- if (element is ExecutableElement) {
- if (element.returnType.toString() == "java.lang.String"
- || element.returnType.toString() == "java.lang.Long"
- || element.returnType.toString() == "java.lang.Integer"
- || element.returnType.kind.isPrimitive) {
- if (element.simpleName.startsWith("to") && element.parameters.isNotEmpty())
- return@mapNotNull TypeConverter(element.parameters.first().asType(), type, element.simpleName, element.returnType)
- }
- }
- null
- }
- }.flatten()
-
- //processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "c = ${typeConverters.joinToString()}")
-
- val roomDatabase = ClassName("androidx.room", "RoomDatabase")
- val selective = TypeSpec.classBuilder("${daoName}Selective")
- .primaryConstructor(FunSpec.constructorBuilder()
- .addParameter("__db", roomDatabase, KModifier.PRIVATE)
- .build())
- .addProperty(PropertySpec.builder("__db", roomDatabase)
- .initializer("__db")
- .addModifiers(KModifier.PRIVATE)
- .build())
-
- val usedTypeConverters = mutableSetOf()
-
- processingEnv.elementUtils.getAllMembers(dao).forEach { element ->
- if (element.kind != ElementKind.METHOD)
- return@forEach
- val method = element as ExecutableElement
- val annotation = method.getAnnotation(UpdateSelective::class.java) ?: return@forEach
- usedTypeConverters.addAll(processMethod(selective, method, annotation, typeConverters))
- }
-
- usedTypeConverters.forEach { converter ->
- selective.addProperty(PropertySpec.builder("__${converter.converterType.simpleName}", converter.converterType.asType().asTypeName(), KModifier.PRIVATE)
- .delegate(CodeBlock.builder()
- .beginControlFlow("lazy")
- .addStatement("%T()", converter.converterType.asType().asTypeName())
- .endControlFlow()
- .build())
- .build())
- }
-
- FileSpec.builder(packageName, "${daoName}Selective")
- .addType(selective.build())
- .build()
- .writeTo(file)
- }
-
- private fun VariableElement.name() = getAnnotation(ColumnInfo::class.java)?.name ?: simpleName.toString()
-
- private fun processMethod(cls: TypeSpec.Builder, method: ExecutableElement, annotation: UpdateSelective, typeConverters: List): List {
- val methodName = method.simpleName.toString()
- val parameter = method.parameters.first()
- val paramName = parameter.simpleName.toString()
- val paramTypeElement = processingEnv.typeUtils.asElement(parameter.asType()) as TypeElement
- val paramTypeAnnotation = paramTypeElement.getAnnotation(Entity::class.java)
-
- val tableName = paramTypeAnnotation.tableName
- val primaryKeys = annotation.primaryKeys
- val skippedColumns = annotation.skippedColumns
-
-
- var members = processingEnv.elementUtils.getAllMembers(paramTypeElement)
- val allFields = ElementFilter.fieldsIn(members)
-
- // check all super classes
- var superType = paramTypeElement.superclass
- while (superType !is NoType) {
- val superTypeElement = processingEnv.typeUtils.asElement(superType) as TypeElement
- members = processingEnv.elementUtils.getAllMembers(superTypeElement)
- allFields += ElementFilter.fieldsIn(members)
- superType = superTypeElement.superclass
- }
-
- allFields.removeAll { skippedColumns.contains(it.name()) }
- allFields.removeAll { it.getAnnotation(Ignore::class.java) != null }
- allFields.removeAll { field -> field.modifiers.any { it == Modifier.STATIC } }
- val allFieldsDistinct = allFields.distinct()
-
- // dump fields
- //processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, allFieldsDistinct.joinToString())
-
- val fields = allFieldsDistinct.filterNot { primaryKeys.contains(it.name()) }
- val primaryFields = allFieldsDistinct.filter { primaryKeys.contains(it.name()) }
- val fieldNames = fields.map { it.name() }
- val primaryFieldNames = primaryFields.map { it.name() }
-
- val fieldNamesQuery = fieldNames.joinToString { "$it = ?" }
- val primaryFieldNamesQuery = primaryFieldNames.joinToString(" AND ") { "$it = ?" }
- val query = "\"\"\"UPDATE $tableName SET $fieldNamesQuery WHERE $primaryFieldNamesQuery\"\"\""
-
- val entityInsertionAdapter = ClassName("androidx.room", "EntityInsertionAdapter")
- val supportSQLiteStatement = ClassName("androidx.sqlite.db", "SupportSQLiteStatement")
-
- val usedTypeConverters = mutableListOf()
-
- val bind = CodeBlock.builder()
- (fields+primaryFields).forEachIndexed { i, field ->
- val index = i+1
- val fieldName = field.simpleName.toString()
- val name = "${paramName}_$fieldName"
- val realName = "${paramName}.$fieldName"
- val nullable = field.getAnnotation(org.jetbrains.annotations.Nullable::class.java) != null
-
- var param = when (field.asType().kind) {
- TypeKind.BOOLEAN -> "if ($name) 1L else 0L"
- TypeKind.BYTE,
- TypeKind.SHORT,
- TypeKind.INT -> "$name.toLong()"
- TypeKind.CHAR -> "$name.toString()"
- TypeKind.FLOAT -> "$name.toDouble()"
- else -> when (field.asType().toString()) {
- "java.lang.String" -> name
- "java.lang.Boolean" -> "if ($name == true) 1L else 0L"
- "java.lang.Byte",
- "java.lang.Short",
- "java.lang.Integer" -> "$name.toLong()"
- "java.lang.Long" -> name
- "java.lang.Char" -> "$name.toString()"
- "java.lang.Float" -> "$name.toDouble()"
- "java.lang.Double" -> name
- else -> name
- }
- }
-
- var isConvert = false
- val bindMethod = when (field.asType().kind) {
- TypeKind.BOOLEAN -> "bindLong"
- TypeKind.BYTE -> "bindLong"
- TypeKind.SHORT -> "bindLong"
- TypeKind.INT -> "bindLong"
- TypeKind.LONG -> "bindLong"
- TypeKind.CHAR -> "bindString"
- TypeKind.FLOAT -> "bindDouble"
- TypeKind.DOUBLE -> "bindDouble"
- else -> when (field.asType().toString()) {
- "java.lang.String" -> "bindString"
- "java.lang.Boolean" -> "bindLong"
- "java.lang.Byte" -> "bindLong"
- "java.lang.Short" -> "bindLong"
- "java.lang.Integer" -> "bindLong"
- "java.lang.Long" -> "bindLong"
- "java.lang.Char" -> "bindString"
- "java.lang.Float" -> "bindDouble"
- "java.lang.Double" -> "bindDouble"
- else -> {
- val converter = typeConverters.firstOrNull {
- it.dataType.toString() == field.asType().toString()
- }
- if (converter != null) {
- param = "__${converter.converterType.simpleName}.${converter.methodName}($realName)"
- param = when (converter.returnType.toString()) {
- "java.lang.Integer", "int",
- "java.lang.Short", "short",
- "java.lang.Byte", "byte" -> "$param.toLong()"
- "java.lang.Boolean", "boolean" -> "if ($param) 1L else 0L"
- "java.lang.Char", "char" -> "$param.toString()"
- "java.lang.Float", "float" -> "$param.toDouble()"
- else -> param
- }
- isConvert = true
- usedTypeConverters += converter
- when (converter.returnType.toString()) {
- "java.lang.Integer", "int",
- "java.lang.Short", "short",
- "java.lang.Byte", "byte",
- "java.lang.Boolean", "boolean" -> "bindLong"
- "java.lang.Char", "char" -> "bindString"
- "java.lang.Float", "float" -> "bindDouble"
- else -> "bindString"
- }
- }
- else "bind${field.asType()}"
- }
- }
- }
-
- if (!isConvert) {
- bind.addStatement("val $name = $realName")
- }
- else {
- bind.addStatement("val $name = $param")
- param = name
- }
- if (nullable) {
- bind.beginControlFlow("if ($name == null)")
- .addStatement("stmt.bindNull($index)")
- .endControlFlow()
- .beginControlFlow("else")
- .addStatement("stmt.$bindMethod($index, $param)")
- .endControlFlow()
- }
- else {
- bind.addStatement("stmt.$bindMethod($index, $param)")
- }
- }
-
- val adapterName = "__insertionAdapterOf$methodName"
- val delegate = CodeBlock.builder().add("""
- |lazy {
- | object : EntityInsertionAdapter<%T>(__db) {
- | override fun createQuery() = $query
- | override fun bind(stmt: %T, $paramName: %T) {
- |${bind.indent().indent().indent().build()}
- | }
- | }
- |}""".trimMargin(), paramTypeElement.asClassName(), supportSQLiteStatement, paramTypeElement.asClassName())
-
- cls.addProperty(PropertySpec.builder(adapterName, entityInsertionAdapter.parameterizedBy(paramTypeElement.asClassName()), KModifier.PRIVATE)
- .delegate(delegate.build())
- .build())
-
- val list = ClassName("kotlin.collections", "List")
- val longArray = ClassName("kotlin", "LongArray")
-
- val function = FunSpec.builder(methodName)
- .addModifiers(KModifier.INTERNAL)
- .addParameter("item", parameter.asType().asTypeName())
- .returns(Long::class.java)
- .addStatement("__db.assertNotSuspendingTransaction()")
- .addStatement("__db.beginTransaction()")
- .addCode("""
- |try {
- | val _result = $adapterName.insertAndReturnId(item)
- | __db.setTransactionSuccessful()
- | return _result
- |} finally {
- | __db.endTransaction()
- |}
- """.trimMargin())
- .build()
-
- val functionAll = FunSpec.builder(methodName+"All")
- .addModifiers(KModifier.INTERNAL)
- .addParameter("items", list.parameterizedBy(parameter.asType().asTypeName()))
- .returns(longArray)
- .addStatement("__db.assertNotSuspendingTransaction()")
- .addStatement("__db.beginTransaction()")
- .addCode("""
- |try {
- | val _result = $adapterName.insertAndReturnIdsArray(items)
- | __db.setTransactionSuccessful()
- | return _result
- |} finally {
- | __db.endTransaction()
- |}
- """.trimMargin())
- .build()
-
- cls.addFunction(function)
- cls.addFunction(functionAll)
- return usedTypeConverters
- }
-
- override fun getSupportedAnnotationTypes(): MutableSet {
- return mutableSetOf(SelectiveDao::class.java.canonicalName)
- }
-}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 1a62f29e..9bd0ad16 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Wed Feb 17 14:04:38 CET 2021
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/material-about-library/build.gradle b/material-about-library/build.gradle
deleted file mode 100644
index c79c427c..00000000
--- a/material-about-library/build.gradle
+++ /dev/null
@@ -1,38 +0,0 @@
-apply plugin: 'com.android.library'
-
-group = 'com.github.daniel-stoneuk'
-
-def versionMajor = 2
-def versionMinor = 3
-def versionPatch = 0
-def versionBuild = 0 // bump for dogfood builds, public betas, etc.
-
-android {
- compileSdkVersion setup.compileSdk
-
- defaultConfig {
- minSdkVersion 14
- targetSdkVersion setup.targetSdk
- versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild
- versionName "${versionMajor}.${versionMinor}" + (versionPatch == 0 ? "" : ".${versionPatch}")
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- debugMinify {
- debuggable = true
- minifyEnabled = true
- proguardFiles 'proguard-android.txt'
- }
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation "androidx.appcompat:appcompat:${versions.appcompat}"
- implementation "androidx.cardview:cardview:${versions.cardview}"
- implementation "com.google.android.material:material:${versions.material}"
-}
diff --git a/material-about-library/src/main/AndroidManifest.xml b/material-about-library/src/main/AndroidManifest.xml
deleted file mode 100644
index 71d1ecd9..00000000
--- a/material-about-library/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/ConvenienceBuilder.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/ConvenienceBuilder.java
deleted file mode 100644
index f0e17e95..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/ConvenienceBuilder.java
+++ /dev/null
@@ -1,357 +0,0 @@
-package com.danielstone.materialaboutlibrary;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Build;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import android.webkit.WebView;
-import android.widget.Toast;
-
-import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutItemOnClickAction;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem;
-import com.danielstone.materialaboutlibrary.model.MaterialAboutCard;
-import com.danielstone.materialaboutlibrary.util.OpenSourceLicense;
-
-@SuppressWarnings("JavaDoc")
-public class ConvenienceBuilder {
-
- public static MaterialAboutTitleItem createAppTitleItem(String appName, Drawable applicationIcon) {
- return new MaterialAboutTitleItem(appName, null, applicationIcon);
- }
-
- public static MaterialAboutTitleItem createAppTitleItem(Context c) {
- Context applicationContext = c.getApplicationContext();
- PackageManager packageManager = applicationContext.getPackageManager();
- ApplicationInfo applicationInfo = applicationContext.getApplicationInfo();
- CharSequence appName = packageManager.getApplicationLabel(applicationInfo);
- Drawable applicationIcon = packageManager.getApplicationIcon(applicationInfo);
- return createAppTitleItem(appName == null ? "" : appName.toString(), applicationIcon);
- }
-
- /**
- * Creates an item with version info read from the PackageManager for current application.
- *
- * @param c context
- * @param icon
- * @param text
- * @param includeVersionCode
- * @return Item to add to card.
- */
- public static MaterialAboutActionItem createVersionActionItem(Context c, Drawable icon, CharSequence text, boolean includeVersionCode) {
- String versionName = "";
- int versionCode = 0;
- try {
- PackageInfo pInfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0);
- versionName = pInfo.versionName;
- versionCode = pInfo.versionCode;
- } catch (PackageManager.NameNotFoundException ignored) {
- // This shouldn't happen.
- }
- return new MaterialAboutActionItem.Builder()
- .text(text)
- .subText(versionName + (includeVersionCode ? " (" + versionCode + ")" : ""))
- .icon(icon)
- .build();
- }
-
- public static MaterialAboutItemOnClickAction createWebViewDialogOnClickAction(final Context c, final CharSequence dialogTitle, final String htmlString, final boolean isStringUrl, final boolean supportZoom) {
- return createWebViewDialogOnClickAction(c, dialogTitle, c.getString(R.string.mal_close), htmlString, isStringUrl, supportZoom);
- }
-
- public static MaterialAboutItemOnClickAction createWebViewDialogOnClickAction(final Context c, final CharSequence dialogTitle, final CharSequence dialogNegativeButton, final String htmlString, final boolean isStringUrl, final boolean supportZoom) {
-
- return new MaterialAboutItemOnClickAction() {
- @Override
- public void onClick() {
- AlertDialog.Builder alertBuilder = new AlertDialog.Builder(c);
- alertBuilder.setTitle(dialogTitle);
-
- final WebView wv = new WebView(c);
- wv.getSettings().setSupportZoom(supportZoom);
- if (!supportZoom) {
- wv.getSettings().setLoadWithOverviewMode(true);
- wv.getSettings().setUseWideViewPort(true);
- }
- if (isStringUrl) {
- wv.loadUrl(htmlString);
- } else {
- wv.loadData(htmlString, "text/html; charset=utf-8", "UTF-8");
- }
-
- alertBuilder.setView(wv);
- alertBuilder.setNegativeButton(dialogNegativeButton, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- wv.destroy();
- dialog.dismiss();
- }
- });
-
- final AlertDialog dialog = alertBuilder.create();
- dialog.show();
- }
- };
- }
-
-
- public static MaterialAboutActionItem createWebViewDialogItem(Context c, Drawable icon, CharSequence text, @Nullable CharSequence subText, CharSequence dialogTitle, String htmlString, boolean isStringUrl, boolean supportZoom) {
- return createWebViewDialogItem(c, icon, text, subText, dialogTitle, c.getString(R.string.mal_close), htmlString, isStringUrl, supportZoom);
- }
-
- public static MaterialAboutActionItem createWebViewDialogItem(Context c, Drawable icon, CharSequence text, @Nullable CharSequence subText, CharSequence dialogTitle, CharSequence dialogNegativeButton, String htmlString, boolean isStringUrl, boolean supportZoom) {
- return new MaterialAboutActionItem.Builder()
- .text(text)
- .subText(subText)
- .icon(icon)
- .setOnClickAction(createWebViewDialogOnClickAction(c, dialogTitle, dialogNegativeButton, htmlString, isStringUrl, supportZoom))
- .build();
- }
-
-
- public static MaterialAboutItemOnClickAction createWebsiteOnClickAction(final Context c, final Uri websiteUrl) {
- return new MaterialAboutItemOnClickAction() {
- @Override
- public void onClick() {
- Intent i = new Intent(Intent.ACTION_VIEW);
- i.setData(websiteUrl);
- try {
- c.startActivity(i);
- } catch (Exception e) {
- // No activity to handle intent
- Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show();
- }
- }
- };
- }
-
- /**
- * Creates an ActionItem which will open a url when tapped
- *
- * @param c context
- * @param text
- * @param icon
- * @param websiteUrl (subText)
- * @return Item to add to card.
- */
- public static MaterialAboutActionItem createWebsiteActionItem(Context c, Drawable icon, CharSequence text, boolean showAddress, final Uri websiteUrl) {
- return new MaterialAboutActionItem.Builder()
- .text(text)
- .subText((showAddress ? websiteUrl.toString() : null))
- .icon(icon)
- .setOnClickAction(createWebsiteOnClickAction(c, websiteUrl))
- .build();
- }
-
- /**
- * Creates a MaterialAboutItemOnClickAction that will open
- * the Google Play store listing for the app.
- *
- * @param c context
- * @return onClickAction
- */
- public static MaterialAboutItemOnClickAction createRateOnClickAction(final Context c) {
- Uri uri = Uri.parse("market://details?id=" + c.getPackageName());
- final Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
- Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- } else {
- goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- }
-
- return new MaterialAboutItemOnClickAction() {
- @Override
- public void onClick() {
- try {
- c.startActivity(goToMarket);
- } catch (ActivityNotFoundException e) {
- c.startActivity(new Intent(Intent.ACTION_VIEW,
- Uri.parse("http://play.google.com/store/apps/details?id=" + c.getPackageName())));
- }
- }
- };
- }
-
- /**
- * Creates an ActionItem which will open the play store when tapped
- *
- * @param c context
- * @param text
- * @param subText
- * @param icon
- * @return Item to add to card.
- */
- public static MaterialAboutActionItem createRateActionItem(Context c, Drawable icon, CharSequence text, @Nullable CharSequence subText) {
-
- return new MaterialAboutActionItem.Builder()
- .text(text)
- .subText(subText)
- .icon(icon)
- .setOnClickAction(createRateOnClickAction(c))
- .build();
- }
-
- public static MaterialAboutItemOnClickAction createEmailOnClickAction(final Context c, String email, String emailSubject) {
- return createEmailOnClickAction(c, email, emailSubject, c.getString(R.string.mal_send_email));
- }
-
- /**
- * Creates a MaterialAboutItemOnClickAction that will open
- * an email intent with specified address.
- *
- * @param c context
- * @param email email address
- * @return onClickAction
- */
- public static MaterialAboutItemOnClickAction createEmailOnClickAction(final Context c, String email, String emailSubject, final CharSequence chooserTitle) {
-
- final Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + email));
- emailIntent.putExtra(Intent.EXTRA_SUBJECT, emailSubject);
-
- return new MaterialAboutItemOnClickAction() {
- @Override
- public void onClick() {
- try {
- c.startActivity(Intent.createChooser(emailIntent, chooserTitle));
- } catch (Exception e) {
- // No activity to handle intent
- Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show();
- }
- }
- };
- }
-
- /**
- * Creates an ActionItem which will open the an email intent when tapped
- *
- * @param c context
- * @param text
- * @param icon
- * @param email email address (also used as subText)
- * @return Item to add to card.
- */
- public static MaterialAboutActionItem createEmailItem(Context c, Drawable icon, CharSequence text, boolean showEmail, String email, String emailSubject, CharSequence chooserTitle) {
- return new MaterialAboutActionItem.Builder()
- .text(text)
- .subText((showEmail ? email : null))
- .icon(icon)
- .setOnClickAction(createEmailOnClickAction(c, email, emailSubject, chooserTitle))
- .build();
- }
-
- public static MaterialAboutActionItem createEmailItem(Context c, Drawable icon, CharSequence text, boolean showEmail, String email, String emailSubject) {
- return createEmailItem(c, icon, text, showEmail, email, emailSubject, c.getString(R.string.mal_send_email));
- }
-
- /**
- * Creates a MaterialAboutItemOnClickAction that will open
- * the dialer with specified number.
- *
- * @param c context
- * @param number phone number
- * @return onClickAction
- */
- public static MaterialAboutItemOnClickAction createPhoneOnClickAction(final Context c, String number) {
- final Intent phoneIntent = new Intent(Intent.ACTION_DIAL);
- phoneIntent.setData(Uri.parse("tel:" + number));
-
- return new MaterialAboutItemOnClickAction() {
- @Override
- public void onClick() {
- try {
- c.startActivity(phoneIntent);
- } catch (Exception e) {
- // No activity to handle intent
- Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show();
- }
- }
- };
- }
-
- /**
- * Creates an ActionItem which will open the dialer when tapped
- *
- * @param c context
- * @param text
- * @param icon
- * @param number phone number (also used as subText)
- * @return Item to add to card.
- */
- public static MaterialAboutActionItem createPhoneItem(Context c, Drawable icon, CharSequence text, boolean showNumber, String number) {
- return new MaterialAboutActionItem.Builder()
- .text(text)
- .subText((showNumber ? number : null))
- .icon(icon)
- .setOnClickAction(createPhoneOnClickAction(c, number))
- .build();
- }
-
- /**
- * Creates a MaterialAboutItemOnClickAction that will open
- * maps with a query.
- * Query can be either lat,lng(label) or written address
- *
- * @param c context
- * @param addressQuery address query
- * @return onClickAction
- */
- public static MaterialAboutItemOnClickAction createMapOnClickAction(final Context c, String addressQuery) {
- final Intent mapIntent = new Intent(Intent.ACTION_VIEW);
- mapIntent.setData(Uri.parse("geo:0,0").buildUpon().appendQueryParameter("q", addressQuery).build());
- return new MaterialAboutItemOnClickAction() {
- @Override
- public void onClick() {
- try {
- c.startActivity(mapIntent);
- } catch (Exception e) {
- // No activity to handle intent
- Toast.makeText(c, R.string.mal_activity_exception, Toast.LENGTH_SHORT).show();
- }
- }
- };
- }
-
- /**
- * Creates an ActionItem which will open maps when tapped
- * Query can be either lat,lng(label) or written address
- *
- * @param c context
- * @param text
- * @param subText can be set to null
- * @param icon
- * @param addressQuery addressQuery
- * @return Item to add to card.
- */
- public static MaterialAboutActionItem createMapItem(Context c, Drawable icon, CharSequence text, CharSequence subText, String addressQuery) {
- return new MaterialAboutActionItem.Builder()
- .text(text)
- .subText(subText)
- .icon(icon)
- .setOnClickAction(createMapOnClickAction(c, addressQuery))
- .build();
- }
-
- public static MaterialAboutCard createLicenseCard(Context c, Drawable icon, CharSequence libraryTitle, CharSequence year, CharSequence name, OpenSourceLicense license) {
-
- MaterialAboutActionItem licenseItem = new MaterialAboutActionItem.Builder()
- .icon(icon)
- .setIconGravity(MaterialAboutActionItem.GRAVITY_TOP)
- .text(libraryTitle)
- .subText(String.format(c.getString(license.getResourceId()), year, name))
- .build();
-
- return new MaterialAboutCard.Builder().addItem(licenseItem).build();
- }
-
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutActivity.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutActivity.java
deleted file mode 100644
index 9a5ec841..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutActivity.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.danielstone.materialaboutlibrary;
-
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import com.google.android.material.appbar.AppBarLayout;
-import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.SimpleItemAnimator;
-import androidx.appcompat.widget.Toolbar;
-import android.util.TypedValue;
-import android.view.MenuItem;
-
-import com.danielstone.materialaboutlibrary.adapters.MaterialAboutListAdapter;
-import com.danielstone.materialaboutlibrary.model.MaterialAboutList;
-import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import java.lang.ref.WeakReference;
-
-public abstract class MaterialAboutActivity extends AppCompatActivity {
-
- private MaterialAboutList list = new MaterialAboutList.Builder().build();
- private Toolbar toolbar;
- private RecyclerView recyclerView;
- private MaterialAboutListAdapter adapter;
-
- @NonNull
- protected abstract MaterialAboutList getMaterialAboutList(@NonNull Context context);
-
- @Nullable
- protected abstract CharSequence getActivityTitle();
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- verifyAttributesExist();
-
- setContentView(R.layout.mal_material_about_activity);
-
- CharSequence title = getActivityTitle();
- if (title == null)
- setTitle(R.string.mal_title_about);
- else
- setTitle(title);
-
-
- assignViews();
- initViews();
-
- ListTask task = new ListTask(this);
- task.execute();
- }
-
- private void verifyAttributesExist() {
- TypedValue typedValue = new TypedValue();
- boolean malColorPrimaryExists =
- getTheme().resolveAttribute(R.attr.mal_color_primary, typedValue, true);
- boolean malColorSecondaryExists =
- getTheme().resolveAttribute(R.attr.mal_color_secondary, typedValue, true);
- if (!malColorPrimaryExists || !malColorSecondaryExists) {
- throw new IllegalStateException(String.format("The current theme doesn't provide %s " +
- "and/or %s. Please use a theme provided by the library or an extension.",
- getResources().getResourceEntryName(R.attr.mal_color_primary),
- getResources().getResourceEntryName(R.attr.mal_color_secondary)));
- }
- }
-
- private void assignViews() {
- toolbar = (Toolbar) findViewById(R.id.mal_toolbar);
- recyclerView = (RecyclerView) findViewById(R.id.mal_recyclerview);
- recyclerView.setAlpha(0f);
- recyclerView.setTranslationY(20);
- }
-
- private void initViews() {
- setSupportActionBar(toolbar);
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- }
- adapter = new MaterialAboutListAdapter(getViewTypeManager());
- recyclerView.setLayoutManager(new LinearLayoutManager(this));
- recyclerView.setAdapter(adapter);
- RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
- if (animator instanceof SimpleItemAnimator) {
- ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
- }
- }
-
- @NonNull
- protected ViewTypeManager getViewTypeManager() {
- return new DefaultViewTypeManager();
- }
-
- @NonNull
- protected MaterialAboutList getList() {
- return list;
- }
-
- protected boolean shouldAnimate() {
- return true;
- }
-
- protected void refreshMaterialAboutList() {
- setMaterialAboutList(list);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- onBackPressed();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private void onTaskFinished(@Nullable MaterialAboutList materialAboutList) {
- if (materialAboutList != null) {
- list = materialAboutList;
- adapter.setData(list.getCards());
-
- if (shouldAnimate()) {
- recyclerView.animate()
- .alpha(1f)
- .translationY(0f)
- .setDuration(600)
- .setInterpolator(new FastOutSlowInInterpolator()).start();
- } else {
- recyclerView.setAlpha(1f);
- recyclerView.setTranslationY(0f);
- }
- } else {
- finish();//?? why we remain here anyway?
- }
- }
-
- protected void setMaterialAboutList(MaterialAboutList materialAboutList) {
- list = materialAboutList;
- adapter.setData(list.getCards());
- }
-
- protected void setScrollToolbar(boolean scrollToolbar) {
- if (toolbar != null) {
- AppBarLayout.LayoutParams params =
- (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
- if (scrollToolbar) {
- params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
- | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
- } else {
- params.setScrollFlags(0);
- }
- }
- }
-
- private static class ListTask extends AsyncTask {
-
- private WeakReference context;
-
- ListTask(MaterialAboutActivity context) {
- this.context = new WeakReference<>(context);
- }
-
- @Override
- protected MaterialAboutList doInBackground(String... params) {
- return isCancelled() || context.get() == null ? null : context.get().getMaterialAboutList(context.get());
- }
-
- @Override
- protected void onPostExecute(MaterialAboutList materialAboutList) {
- super.onPostExecute(materialAboutList);
- if (context.get() != null) {
- if (!context.get().isFinishing()) {
- context.get().onTaskFinished(materialAboutList);
- }
- }
- context = null;
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutFragment.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutFragment.java
deleted file mode 100644
index c3ad1f04..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/MaterialAboutFragment.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.danielstone.materialaboutlibrary;
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.Bundle;
-
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.SimpleItemAnimator;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.danielstone.materialaboutlibrary.adapters.MaterialAboutListAdapter;
-import com.danielstone.materialaboutlibrary.model.MaterialAboutList;
-import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-public abstract class MaterialAboutFragment extends Fragment {
-
- private MaterialAboutList list = new MaterialAboutList.Builder().build();
- private RecyclerView recyclerView;
- private MaterialAboutListAdapter adapter;
-
- public static MaterialAboutFragment newInstance(MaterialAboutFragment fragment) {
- return fragment;
- }
-
- protected abstract MaterialAboutList getMaterialAboutList(Context activityContext);
-
- protected int getTheme() {
- return R.style.Theme_Mal_Light;
- }
-
- protected boolean shouldAnimate() {
- return true;
- }
-
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- int style = getTheme();
-
- // create ContextThemeWrapper from the original Activity Context with the custom theme
- final Context contextThemeWrapper = new android.view.ContextThemeWrapper(getActivity(), style);
- LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
- View rootView = localInflater.inflate(R.layout.mal_material_about_fragment, container, false);
-
- recyclerView = (RecyclerView) rootView.findViewById(R.id.mal_recyclerview);
- adapter = new MaterialAboutListAdapter(getViewTypeManager());
- recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
- recyclerView.setAdapter(adapter);
-
- RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
- if (animator instanceof SimpleItemAnimator) {
- ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
- }
-
- recyclerView.setAlpha(0f);
- recyclerView.setTranslationY(20);
-
- ListTask task = new ListTask(getActivity());
- task.execute();
-
- return rootView;
- }
-
- protected ViewTypeManager getViewTypeManager() {
- return new DefaultViewTypeManager();
- }
-
- protected MaterialAboutList getList() {
- return list;
- }
-
- protected void setMaterialAboutList(MaterialAboutList materialAboutList) {
- //recyclerView.stopScroll();
- //recyclerView.getRecycledViewPool().clear();
- list = materialAboutList;
- adapter.setData(list.getCards());
- }
-
- @Override
- public void onPause() {
- super.onPause();
- }
-
- protected void refreshMaterialAboutList() {
- setMaterialAboutList(list);
- }
-
- private class ListTask extends AsyncTask {
-
- Context fragmentContext;
-
- public ListTask(Context activityContext) {
- this.fragmentContext = activityContext;
- }
-
- @Override
- protected String doInBackground(String... params) {
- list = getMaterialAboutList(fragmentContext);
- return null;
- }
-
- @Override
- protected void onPostExecute(String s) {
- if (list == null)
- return;// TODO: 2019-05-09 dirty fix tbh
- adapter.setData(list.getCards());
-
- if (shouldAnimate()) {
- recyclerView.animate()
- .alpha(1f)
- .translationY(0f)
- .setDuration(600)
- .setInterpolator(new FastOutSlowInInterpolator())
- .start();
- } else {
- recyclerView.setAlpha(1f);
- recyclerView.setTranslationY(0f);
- }
-
- super.onPostExecute(s);
- fragmentContext = null;
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutItemAdapter.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutItemAdapter.java
deleted file mode 100644
index a3cd1e47..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutItemAdapter.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package com.danielstone.materialaboutlibrary.adapters;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.AsyncListDiffer;
-import androidx.recyclerview.widget.DiffUtil;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutItem;
-import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-public class MaterialAboutItemAdapter extends RecyclerView.Adapter {
-
- private final AsyncListDiffer differ = new AsyncListDiffer(this, DIFF_CALLBACK);
-
- private ViewTypeManager viewTypeManager;
-
- private Context context;
-
- private List data = new ArrayList<>();
- private List oldData = new ArrayList<>();
-
- MaterialAboutItemAdapter() {
- setHasStableIds(true);
- this.viewTypeManager = new DefaultViewTypeManager();
- }
-
- MaterialAboutItemAdapter(ViewTypeManager customViewTypeManager) {
- //Log.d("MaterialItem", "Created adapter");
- setHasStableIds(true);
- this.viewTypeManager = customViewTypeManager;
- }
-
- @NonNull
- @Override
- public MaterialAboutItemViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
- context = viewGroup.getContext();
- if (!(viewGroup instanceof RecyclerView)) {
- throw new RuntimeException("Not bound to RecyclerView");
- }
-
- int layoutId = viewTypeManager.getLayout(viewType);
-
- View view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutId, viewGroup, false);
- view.setFocusable(true);
-
- return viewTypeManager.getViewHolder(viewType, view);
- }
-
- @Override
- public void onBindViewHolder(MaterialAboutItemViewHolder holder, int position) {
- /*if (data.get(position) instanceof MaterialAboutSwitchItem) {
- Log.d("MaterialAdapter", "Item "+((MaterialAboutSwitchItem) data.get(position)).getText()+" checked "+((MaterialAboutSwitchItem) data.get(position)).getChecked());
- }*/
- //Log.d("MaterialItem", "Binding "+data.get(position).getDetailString());
- viewTypeManager.setupItem(getItemViewType(position), holder, data.get(position), context);
- }
-
-
- @Override
- public long getItemId(int position) {
- return UUID.fromString(data.get(position).getId()).getMostSignificantBits() & Long.MAX_VALUE;
- }
-
- @Override
- public int getItemCount() {
- return data.size();
- }
-
- @Override
- public int getItemViewType(int position) {
- return data.get(position).getType();
- }
-
- public void setData(ArrayList data) {
- this.data = data;
-
- notifyDataSetChanged();
- // diff this with previous data
- /*DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffCallback(oldData, data));
- try {
- diffResult.dispatchUpdatesTo(this);
- }
- catch (IllegalStateException e) {
- e.printStackTrace();
- }
-
- // clone the new data to make further diffs
- oldData = new ArrayList<>();
- for (MaterialAboutItem item : data) {
- oldData.add(item.clone());
- }*/
-
- /*List newData = new ArrayList<>();
- for (MaterialAboutItem item : data) {
- newData.add(item.clone());
- }
- differ.submitList(newData);*/
- }
-
- public List getData() {
- return data;
- }
-
-
- public static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() {
- @Override
- public boolean areItemsTheSame(MaterialAboutItem oldItem, MaterialAboutItem newItem) {
- return oldItem.getId().equals(newItem.getId());
- }
-
- @Override
- public boolean areContentsTheSame(MaterialAboutItem oldItem, MaterialAboutItem newItem) {
- return oldItem.getDetailString().equals(newItem.getDetailString());
- }
- };
-
- public class MyDiffCallback extends DiffUtil.Callback{
-
- List oldPersons;
- List newPersons;
-
- public MyDiffCallback(List newPersons, List oldPersons) {
- this.newPersons = newPersons;
- this.oldPersons = oldPersons;
- }
-
- @Override
- public int getOldListSize() {
- return oldPersons.size();
- }
-
- @Override
- public int getNewListSize() {
- return newPersons.size();
- }
-
- @Override
- public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
- return oldPersons.get(oldItemPosition).getId().equals(newPersons.get(newItemPosition).getId());
- }
-
- @Override
- public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
- return oldPersons.get(oldItemPosition).getDetailString().equals(newPersons.get(newItemPosition).getDetailString());
- }
-
- @Nullable
- @Override
- public Object getChangePayload(int oldItemPosition, int newItemPosition) {
- //you can return particular field for changed item.
- return super.getChangePayload(oldItemPosition, newItemPosition);
- }
- }
-
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutListAdapter.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutListAdapter.java
deleted file mode 100644
index e795ee31..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/adapters/MaterialAboutListAdapter.java
+++ /dev/null
@@ -1,237 +0,0 @@
-package com.danielstone.materialaboutlibrary.adapters;
-
-import android.content.Context;
-
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.AsyncListDiffer;
-import androidx.recyclerview.widget.DiffUtil;
-import androidx.cardview.widget.CardView;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.model.MaterialAboutCard;
-import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-import com.google.android.material.card.MaterialCardView;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-public class MaterialAboutListAdapter extends RecyclerView.Adapter {
-
- private final AsyncListDiffer differ = new AsyncListDiffer(this, DIFF_CALLBACK);
-
- private ViewTypeManager viewTypeManager;
-
- private Context context;
-
- private List data = new ArrayList<>();
- private List oldData = new ArrayList<>();
-
- public MaterialAboutListAdapter() {
- setHasStableIds(true);
- this.viewTypeManager = new DefaultViewTypeManager();
- }
-
- public MaterialAboutListAdapter(ViewTypeManager customViewTypeManager) {
- //Log.d("MaterialList", "Created list adapter");
- setHasStableIds(true);
- this.viewTypeManager = customViewTypeManager;
- }
-
- @Override
- public MaterialAboutListViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
- context = viewGroup.getContext();
- if (viewGroup instanceof RecyclerView) {
- View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.mal_material_about_list_card, viewGroup, false);
- view.setFocusable(true);
- return new MaterialAboutListViewHolder(view);
- } else {
- throw new RuntimeException("Not bound to RecyclerView");
- }
- }
-
- @Override
- public void onBindViewHolder(MaterialAboutListViewHolder holder, int position) {
- MaterialAboutCard card = data.get(position);
-
- if (holder.cardView instanceof CardView) {
- CardView cardView = (CardView) holder.cardView;
- int cardColor = card.getCardColor();
- if (cardColor != 0) {
- cardView.setCardBackgroundColor(cardColor);
- }
- }
-
- CharSequence title = card.getTitle();
- int titleRes = card.getTitleRes();
-
- holder.title.setVisibility(View.VISIBLE);
- if (title != null) {
- holder.title.setText(title);
- } else if (titleRes != 0) {
- holder.title.setText(titleRes);
- } else {
- holder.title.setVisibility(View.GONE);
- }
-
- int titleColor = card.getTitleColor();
-
- if (holder.title.getVisibility() == View.VISIBLE) {
- if (titleColor != 0) {
- holder.title.setTextColor(titleColor);
- } else {
- holder.title.setTextColor(holder.title.getTextColors().getDefaultColor());
- }
- }
-
- if (card.getCustomAdapter() != null) {
- holder.useCustomAdapter(card.getCustomAdapter());
- } else {
- holder.useMaterialAboutItemAdapter();
- ((MaterialAboutItemAdapter) holder.adapter).setData(card.getItems());
- }
- }
-
- @Override
- public long getItemId(int position) {
- return UUID.fromString(data.get(position).getId()).getMostSignificantBits() & Long.MAX_VALUE;
- }
-
- @Override
- public int getItemCount() {
- return data.size();
- }
-
- public void setData(ArrayList data) {
- this.data = data;
-
- notifyDataSetChanged();
-
- /*// diff this with previous data
- DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffCallback(oldData, data));
- try {
- diffResult.dispatchUpdatesTo(this);
- }
- catch (IllegalStateException e) {
- e.printStackTrace();
- }
-
- // clone the new data to make further diffs
- oldData = new ArrayList<>();
- for (MaterialAboutCard card : data) {
- oldData.add(card.clone());
- }*/
- //differ.submitList(newData);
- }
-
-
- List getData() {
- return data;
- }
-
- class MaterialAboutListViewHolder extends RecyclerView.ViewHolder {
-
- final View cardView;
- final TextView title;
- final RecyclerView recyclerView;
- RecyclerView.Adapter adapter;
-
- MaterialAboutListViewHolder(View view) {
- super(view);
- cardView = view.findViewById(R.id.mal_list_card);
- title = (TextView) view.findViewById(R.id.mal_list_card_title);
- recyclerView = (RecyclerView) view.findViewById(R.id.mal_card_recyclerview);
- adapter = new MaterialAboutItemAdapter(viewTypeManager);
- recyclerView.setLayoutManager(new LinearLayoutManager(context));
- recyclerView.setAdapter(adapter);
- recyclerView.setNestedScrollingEnabled(false);
- }
-
- public void useMaterialAboutItemAdapter() {
- if (!(adapter instanceof MaterialAboutItemAdapter)) {
- adapter = new MaterialAboutItemAdapter(viewTypeManager);
- recyclerView.setLayoutManager(new LinearLayoutManager(context));
- recyclerView.setAdapter(adapter);
- }
- }
-
- public void useCustomAdapter(RecyclerView.Adapter newAdapter) {
- if (adapter instanceof MaterialAboutItemAdapter) {
- recyclerView.setLayoutManager(new LinearLayoutManager(context));
- recyclerView.setAdapter(newAdapter);
- }
- }
- }
-
-
- public static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() {
- @Override
- public boolean areItemsTheSame(MaterialAboutCard oldItem, MaterialAboutCard newItem) {
- return oldItem.getId().equals(newItem.getId());
- }
-
- @Override
- public boolean areContentsTheSame(MaterialAboutCard oldCard, MaterialAboutCard newCard) {
- boolean result;
- result = oldCard.toString().equals(newCard.toString());
- if (oldCard.getItems().size() != newCard.getItems().size()) return false;
- for (int i = 0; i < oldCard.getItems().size(); i++) {
- if (!oldCard.getItems().get(i).getDetailString().equals(newCard.getItems().get(i).getDetailString())) return false;
- }
- return result;
- }
- };
-
- public class MyDiffCallback extends DiffUtil.Callback{
-
- List oldPersons;
- List newPersons;
-
- public MyDiffCallback(List newPersons, List oldPersons) {
- this.newPersons = newPersons;
- this.oldPersons = oldPersons;
- }
-
- @Override
- public int getOldListSize() {
- return oldPersons.size();
- }
-
- @Override
- public int getNewListSize() {
- return newPersons.size();
- }
-
- @Override
- public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
- return oldPersons.get(oldItemPosition).getId().equals(newPersons.get(newItemPosition).getId());
- }
-
- @Override
- public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
- boolean result;
- result = oldPersons.get(oldItemPosition).toString().equals(newPersons.get(newItemPosition).toString());
- if (oldPersons.get(oldItemPosition).getItems().size() != newPersons.get(newItemPosition).getItems().size()) return false;
- for (int i = 0; i < oldPersons.get(oldItemPosition).getItems().size(); i++) {
- if (!oldPersons.get(oldItemPosition).getItems().get(i).getDetailString().equals(newPersons.get(newItemPosition).getItems().get(i).getDetailString())) return false;
- }
- return result;
- }
-
- @Nullable
- @Override
- public Object getChangePayload(int oldItemPosition, int newItemPosition) {
- //you can return particular field for changed item.
- return super.getChangePayload(oldItemPosition, newItemPosition);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/holders/MaterialAboutItemViewHolder.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/holders/MaterialAboutItemViewHolder.java
deleted file mode 100644
index 6188817b..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/holders/MaterialAboutItemViewHolder.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.danielstone.materialaboutlibrary.holders;
-
-import androidx.recyclerview.widget.RecyclerView;
-import android.view.View;
-
-public abstract class MaterialAboutItemViewHolder extends RecyclerView.ViewHolder {
-
- public MaterialAboutItemViewHolder(View itemView) {
- super(itemView);
- }
-
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionItem.java
deleted file mode 100644
index c69f106d..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionItem.java
+++ /dev/null
@@ -1,488 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.IntDef;
-import androidx.annotation.StringRes;
-import android.text.Html;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-import static android.view.View.GONE;
-
-public class MaterialAboutActionItem extends MaterialAboutItem {
-
- public static final int GRAVITY_TOP = 0;
- public static final int GRAVITY_MIDDLE = 1;
- public static final int GRAVITY_BOTTOM = 2;
- private CharSequence text = null;
- private int textRes = 0;
- private CharSequence subText = null;
- private int subTextRes = 0;
- private int textColor = -1;
- private int subTextColor = -1;
- private Drawable icon = null;
- private int iconRes = 0;
- private boolean showIcon = true;
- private int iconGravity = GRAVITY_MIDDLE;
- private MaterialAboutItemOnClickAction onClickAction = null;
- private MaterialAboutItemOnClickAction onLongClickAction = null;
-
- private MaterialAboutActionItem(Builder builder) {
- super();
- this.text = builder.text;
- this.textRes = builder.textRes;
-
- this.subText = builder.subText;
- this.subTextRes = builder.subTextRes;
-
- this.textColor = builder.textColor;
- this.subTextColor = builder.subTextColor;
-
- this.icon = builder.icon;
- this.iconRes = builder.iconRes;
-
- this.showIcon = builder.showIcon;
-
- this.iconGravity = builder.iconGravity;
-
- this.onClickAction = builder.onClickAction;
- this.onLongClickAction = builder.onLongClickAction;
- }
-
- public MaterialAboutActionItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnClickAction onClickAction) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- this.onClickAction = onClickAction;
- }
-
- public MaterialAboutActionItem(CharSequence text, CharSequence subText, Drawable icon) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- }
-
- public MaterialAboutActionItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnClickAction onClickAction) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- this.onClickAction = onClickAction;
- }
-
- public MaterialAboutActionItem(int textRes, int subTextRes, int iconRes) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- }
-
- public static MaterialAboutItemViewHolder getViewHolder(View view) {
- return new MaterialAboutActionItemViewHolder(view);
- }
-
- public static void setupItem(MaterialAboutActionItemViewHolder holder, MaterialAboutActionItem item, Context context) {
- CharSequence text = item.getText();
- int textRes = item.getTextRes();
-
- holder.text.setVisibility(View.VISIBLE);
- if (text != null) {
- holder.text.setText(text);
- } else if (textRes != 0) {
- holder.text.setText(textRes);
- } else {
- holder.text.setVisibility(GONE);
- }
-
- CharSequence subText = item.getSubText();
- int subTextRes = item.getSubTextRes();
-
- holder.subText.setVisibility(View.VISIBLE);
- if (subText != null) {
- holder.subText.setText(subText);
- } else if (subTextRes != 0) {
- holder.subText.setText(subTextRes);
- } else {
- holder.subText.setVisibility(GONE);
- }
-
- if (item.getTextColor() != -1) {
- holder.text.setTextColor(item.getTextColor());
- }
- if (item.getSubTextColor() != -1) {
- holder.subText.setTextColor(item.getSubTextColor());
- }
-
- if (item.shouldShowIcon()) {
- holder.icon.setVisibility(View.VISIBLE);
- Drawable drawable = item.getIcon();
- int drawableRes = item.getIconRes();
- if (drawable != null) {
- holder.icon.setImageDrawable(drawable);
- } else if (drawableRes != 0) {
- holder.icon.setImageResource(drawableRes);
- }
- } else {
- holder.icon.setVisibility(GONE);
- }
-
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams();
- switch (item.getIconGravity()) {
- case MaterialAboutActionItem.GRAVITY_TOP:
- params.gravity = Gravity.TOP;
- break;
- case MaterialAboutActionItem.GRAVITY_MIDDLE:
- params.gravity = Gravity.CENTER_VERTICAL;
- break;
- case MaterialAboutActionItem.GRAVITY_BOTTOM:
- params.gravity = Gravity.BOTTOM;
- break;
- }
- holder.icon.setLayoutParams(params);
-
- int pL = 0, pT = 0, pR = 0, pB = 0;
- if (Build.VERSION.SDK_INT < 21) {
- pL = holder.view.getPaddingLeft();
- pT = holder.view.getPaddingTop();
- pR = holder.view.getPaddingRight();
- pB = holder.view.getPaddingBottom();
- }
-
- if (item.getOnClickAction() != null || item.getOnLongClickAction() != null) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true);
- holder.view.setBackgroundResource(outValue.resourceId);
- } else {
- holder.view.setBackgroundResource(0);
- }
- holder.setOnClickAction(item.getOnClickAction());
- holder.setOnLongClickAction(item.getOnLongClickAction());
-
- if (Build.VERSION.SDK_INT < 21) {
- holder.view.setPadding(pL, pT, pR, pB);
- }
- }
-
- @Override
- public int getType() {
- return ViewTypeManager.ItemType.ACTION_ITEM;
- }
-
- @Override
- public String getDetailString() {
- return "MaterialAboutActionItem{" +
- "text=" + text +
- ", textRes=" + textRes +
- ", subText=" + subText +
- ", subTextRes=" + subTextRes +
- ", textColor=" + textColor +
- ", descColor=" + subTextColor +
- ", icon=" + icon +
- ", iconRes=" + iconRes +
- ", showIcon=" + showIcon +
- ", iconGravity=" + iconGravity +
- ", onClickAction=" + onClickAction +
- ", onLongClickAction=" + onLongClickAction +
- '}';
- }
-
- public MaterialAboutActionItem(MaterialAboutActionItem item) {
- this.id = item.getId();
- this.text = item.getText();
- this.textRes = item.getTextRes();
- this.subText = item.getSubText();
- this.subTextRes = item.getSubTextRes();
- this.textColor = item.getTextColor();
- this.subTextColor = item.getSubTextColor();
- this.icon = item.getIcon();
- this.iconRes = item.getIconRes();
- this.showIcon = item.showIcon;
- this.iconGravity = item.iconGravity;
- this.onClickAction = item.onClickAction;
- this.onLongClickAction = item.onLongClickAction;
- }
-
- @Override
- public MaterialAboutItem clone() {
- return new MaterialAboutActionItem(this);
- }
-
- public CharSequence getText() {
- return text;
- }
- public MaterialAboutActionItem setText(CharSequence text) {
- this.textRes = 0;
- this.text = text;
- return this;
- }
-
- public int getTextRes() {
- return textRes;
- }
-
- public MaterialAboutActionItem setTextRes(int textRes) {
- this.text = null;
- this.textRes = textRes;
- return this;
- }
-
- public CharSequence getSubText() {
- return subText;
- }
-
- public MaterialAboutActionItem setSubText(CharSequence subText) {
- this.subTextRes = 0;
- this.subText = subText;
- return this;
- }
-
- public int getSubTextRes() {
- return subTextRes;
- }
-
- public MaterialAboutActionItem setSubTextRes(int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public int getTextColor() {
- return textColor;
- }
-
- public MaterialAboutActionItem setTextColor(int textColor) {
- this.textColor = textColor;
- return this;
- }
-
- public int getSubTextColor() {
- return subTextColor;
- }
-
- public MaterialAboutActionItem setSubTextColor(int subTextColor) {
- this.subTextColor = subTextColor;
- return this;
- }
-
- public Drawable getIcon() {
- return icon;
- }
-
- public MaterialAboutActionItem setIcon(Drawable icon) {
- this.iconRes = 0;
- this.icon = icon;
- return this;
- }
-
- public int getIconRes() {
- return iconRes;
- }
-
- public MaterialAboutActionItem setIconRes(int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public boolean shouldShowIcon() {
- return showIcon;
- }
-
- public MaterialAboutActionItem setShouldShowIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- @IconGravity
- public int getIconGravity() {
- return iconGravity;
- }
-
- public MaterialAboutActionItem setIconGravity(int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnClickAction() {
- return onClickAction;
- }
-
- public MaterialAboutActionItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnLongClickAction() {
- return onLongClickAction;
- }
-
- public MaterialAboutActionItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM})
- public @interface IconGravity {
- }
-
- public static class MaterialAboutActionItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
- public final View view;
- public final ImageView icon;
- public final TextView text;
- public final TextView subText;
- private MaterialAboutItemOnClickAction onClickAction;
- private MaterialAboutItemOnClickAction onLongClickAction;
-
- MaterialAboutActionItemViewHolder(View view) {
- super(view);
- this.view = view;
- icon = (ImageView) view.findViewById(R.id.mal_item_image);
- text = (TextView) view.findViewById(R.id.mal_item_text);
- subText = (TextView) view.findViewById(R.id.mal_action_item_subtext);
- }
-
- public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- view.setOnClickListener(onClickAction != null ? this : null);
- }
-
- public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- view.setOnLongClickListener(onLongClickAction != null ? this : null);
- }
-
- @Override
- public void onClick(View v) {
- if (onClickAction != null) {
- onClickAction.onClick();
- }
- }
-
- @Override
- public boolean onLongClick(View v) {
- if (onLongClickAction != null) {
- onLongClickAction.onClick();
- return true;
- }
- return false;
- }
- }
-
- public static class Builder {
-
- MaterialAboutItemOnClickAction onClickAction = null;
- MaterialAboutItemOnClickAction onLongClickAction = null;
- private CharSequence text = null;
- @StringRes
- private int textRes = 0;
- private CharSequence subText = null;
- @StringRes
- private int subTextRes = 0;
- @ColorInt
- private int textColor = -1;
- @ColorInt
- private int subTextColor = -1;
- private Drawable icon = null;
- @DrawableRes
- private int iconRes = 0;
- private boolean showIcon = true;
- @IconGravity
- private int iconGravity = GRAVITY_MIDDLE;
-
- public Builder text(CharSequence text) {
- this.text = text;
- this.textRes = 0;
- return this;
- }
-
- public Builder text(@StringRes int text) {
- this.textRes = text;
- this.text = null;
- return this;
- }
-
- public Builder subText(CharSequence subText) {
- this.subText = subText;
- this.subTextRes = 0;
- return this;
- }
-
- public Builder subText(@StringRes int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public Builder textColor(@ColorInt int textColor) {
- this.textColor = textColor;
- return this;
- }
-
- public Builder subTextColor(@ColorInt int subTextColor) {
- this.subTextColor = subTextColor;
- return this;
- }
-
- public Builder subTextHtml(String subTextHtml) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY);
- } else {
- //noinspection deprecation
- this.subText = Html.fromHtml(subTextHtml);
- }
- this.subTextRes = 0;
- return this;
- }
-
- public Builder icon(Drawable icon) {
- this.icon = icon;
- this.iconRes = 0;
- return this;
- }
-
- public Builder icon(@DrawableRes int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public Builder showIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- public Builder setIconGravity(@IconGravity int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
-
- public MaterialAboutActionItem build() {
- return new MaterialAboutActionItem(this);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionSwitchItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionSwitchItem.java
deleted file mode 100644
index eb6d9411..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutActionSwitchItem.java
+++ /dev/null
@@ -1,606 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.IntDef;
-import androidx.annotation.StringRes;
-import androidx.appcompat.widget.SwitchCompat;
-
-import android.text.Html;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-import static android.view.View.GONE;
-
-public class MaterialAboutActionSwitchItem extends MaterialAboutItem {
-
- public static final int GRAVITY_TOP = 0;
- public static final int GRAVITY_MIDDLE = 1;
- public static final int GRAVITY_BOTTOM = 2;
- private CharSequence text = null;
- private int textRes = 0;
- private CharSequence subText = null;
- private int subTextRes = 0;
- private CharSequence subTextChecked = null;
- private int subTextCheckedRes = 0;
- private Drawable icon = null;
- private int iconRes = 0;
- private boolean showIcon = true;
- private int iconGravity = GRAVITY_MIDDLE;
- private boolean checked = false;
- private int tag = -1;
- private MaterialAboutItemOnClickAction onClickAction = null;
- private MaterialAboutItemOnClickAction onLongClickAction = null;
- private MaterialAboutItemOnChangeAction onChangeAction = null;
-
- private MaterialAboutActionSwitchItem(Builder builder) {
- super();
- this.text = builder.text;
- this.textRes = builder.textRes;
-
- this.subText = builder.subText;
- this.subTextRes = builder.subTextRes;
-
- this.subTextChecked = builder.subTextChecked;
- this.subTextCheckedRes = builder.subTextCheckedRes;
-
- this.icon = builder.icon;
- this.iconRes = builder.iconRes;
-
- this.showIcon = builder.showIcon;
-
- this.iconGravity = builder.iconGravity;
-
- this.checked = builder.checked;
-
- this.tag = builder.tag;
-
- this.onClickAction = builder.onClickAction;
- this.onLongClickAction = builder.onLongClickAction;
- this.onChangeAction = builder.onChangeAction;
- }
-
- public MaterialAboutActionSwitchItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnChangeAction onChangeAction) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- this.onChangeAction = onChangeAction;
- }
-
- public MaterialAboutActionSwitchItem(CharSequence text, CharSequence subText, Drawable icon) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- }
-
- public MaterialAboutActionSwitchItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnChangeAction onChangeAction) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- this.onChangeAction = onChangeAction;
- }
-
- public MaterialAboutActionSwitchItem(int textRes, int subTextRes, int iconRes) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- }
-
- public static void setupItem(MaterialAboutActionSwitchItemViewHolder holder, MaterialAboutActionSwitchItem item, Context context) {
- holder.switchItem = item;
-
- CharSequence text = item.getText();
- int textRes = item.getTextRes();
-
- holder.text.setVisibility(View.VISIBLE);
- if (text != null) {
- holder.text.setText(text);
- } else if (textRes != 0) {
- holder.text.setText(textRes);
- } else {
- holder.text.setVisibility(GONE);
- }
-
- CharSequence subText = item.getSubText();
- int subTextRes = item.getSubTextRes();
-
- holder.subText.setVisibility(View.VISIBLE);
- if (subText != null) {
- holder.subText.setText(subText);
- } else if (subTextRes != 0) {
- holder.subText.setText(subTextRes);
- } else {
- holder.subText.setVisibility(GONE);
- }
-
- if (item.shouldShowIcon()) {
- holder.icon.setVisibility(View.VISIBLE);
- Drawable drawable = item.getIcon();
- int drawableRes = item.getIconRes();
- if (drawable != null) {
- holder.icon.setImageDrawable(drawable);
- } else if (drawableRes != 0) {
- holder.icon.setImageResource(drawableRes);
- }
- } else {
- holder.icon.setVisibility(GONE);
- }
-
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams();
- switch (item.getIconGravity()) {
- case MaterialAboutActionSwitchItem.GRAVITY_TOP:
- params.gravity = Gravity.TOP;
- break;
- case MaterialAboutActionSwitchItem.GRAVITY_MIDDLE:
- params.gravity = Gravity.CENTER_VERTICAL;
- break;
- case MaterialAboutActionSwitchItem.GRAVITY_BOTTOM:
- params.gravity = Gravity.BOTTOM;
- break;
- }
- holder.icon.setLayoutParams(params);
-
- int pL = 0, pT = 0, pR = 0, pB = 0;
- if (Build.VERSION.SDK_INT < 21) {
- pL = holder.view.getPaddingLeft();
- pT = holder.view.getPaddingTop();
- pR = holder.view.getPaddingRight();
- pB = holder.view.getPaddingBottom();
- }
-
- holder.setChecked(item.getChecked());
-
- if (item.getOnChangeAction() != null || item.getOnClickAction() != null || item.getOnLongClickAction() != null) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true);
- holder.view.setBackgroundResource(outValue.resourceId);
- } else {
- holder.view.setBackgroundResource(0);
- }
- holder.setOnClickAction(item.getOnClickAction());
- holder.setOnLongClickAction(item.getOnLongClickAction());
- holder.setOnChangeAction(item.getOnChangeAction());
-
- if (Build.VERSION.SDK_INT < 21) {
- holder.view.setPadding(pL, pT, pR, pB);
- }
- }
-
- public static MaterialAboutItemViewHolder getViewHolder(View view) {
- return new MaterialAboutActionSwitchItemViewHolder(view);
- }
-
- public static class MaterialAboutActionSwitchItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener, CompoundButton.OnCheckedChangeListener {
- public final View view;
- public final ImageView icon;
- public final TextView text;
- public final TextView subText;
- public final SwitchCompat switchView;
- private MaterialAboutItemOnClickAction onClickAction;
- private MaterialAboutItemOnClickAction onLongClickAction;
- private MaterialAboutItemOnChangeAction onChangeAction;
- private MaterialAboutActionSwitchItem switchItem;
-
- MaterialAboutActionSwitchItemViewHolder(View view) {
- super(view);
- this.view = view.findViewById(R.id.mal_action_root);
- icon = view.findViewById(R.id.mal_item_image);
- text = view.findViewById(R.id.mal_item_text);
- subText = view.findViewById(R.id.mal_action_item_subtext);
- switchView = view.findViewById(R.id.mal_switch);
- }
-
- public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- view.setOnClickListener(onClickAction != null ? this : null);
- }
-
- public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- view.setOnLongClickListener(onLongClickAction != null ? this : null);
- }
-
- public void setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- switchView.setOnCheckedChangeListener(this);
- }
-
- public void setChecked(boolean checked) {
- switchView.setChecked(checked);
- switchItem.checked = checked;
- updateSubText(checked);
- }
-
- public void updateSubText(boolean checked) {
- if (checked && switchItem.subTextChecked != null) {
- subText.setText(switchItem.subTextChecked);
- }
- else if (checked && switchItem.subTextCheckedRes != 0) {
- subText.setText(switchItem.subTextCheckedRes);
- }
- else if (switchItem.subText != null) {
- subText.setText(switchItem.subText);
- }
- else if (switchItem.subTextRes != 0) {
- subText.setText(switchItem.subTextRes);
- }
- }
-
- @Override
- public void onClick(View v) {
- if (onClickAction != null) {
- onClickAction.onClick();
- }
- }
-
- @Override
- public boolean onLongClick(View v) {
- if (onLongClickAction != null) {
- onLongClickAction.onClick();
- return true;
- }
- return false;
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- updateSubText(isChecked);
- if (onChangeAction != null) {
- if (!onChangeAction.onChange(isChecked, switchItem.getTag())) {
- setChecked(!isChecked);
- }
- else {
- switchItem.checked = isChecked;
- }
- }
- else {
- setChecked(!isChecked);
- }
- }
- }
-
- @Override
- public int getType() {
- return ViewTypeManager.ItemType.ACTION_SWITCH_ITEM;
- }
-
- @Override
- public String getDetailString() {
- return "MaterialAboutActionSwitchItem{" +
- "text=" + text +
- ", textRes=" + textRes +
- ", subText=" + subText +
- ", subTextRes=" + subTextRes +
- ", subTextChecked=" + subTextChecked +
- ", subTextCheckedRes=" + subTextCheckedRes +
- ", icon=" + icon +
- ", iconRes=" + iconRes +
- ", showIcon=" + showIcon +
- ", iconGravity=" + iconGravity +
- ", checked=" + checked +
- ", tag=" + tag +
- ", onClickAction=" + onClickAction +
- ", onLongClickAction=" + onLongClickAction +
- ", onChangeAction=" + onChangeAction +
- '}';
- }
-
- public MaterialAboutActionSwitchItem(MaterialAboutActionSwitchItem item) {
- this.id = item.getId();
- this.text = item.getText();
- this.textRes = item.getTextRes();
- this.subText = item.getSubText();
- this.subTextRes = item.getSubTextRes();
- this.subTextChecked = item.getSubTextChecked();
- this.subTextCheckedRes = item.getSubTextCheckedRes();
- this.icon = item.getIcon();
- this.iconRes = item.getIconRes();
- this.showIcon = item.showIcon;
- this.iconGravity = item.iconGravity;
- this.checked = item.checked;
- this.tag = item.tag;
- this.onClickAction = item.onClickAction;
- this.onLongClickAction = item.onLongClickAction;
- this.onChangeAction = item.onChangeAction;
- }
-
- @Override
- public MaterialAboutItem clone() {
- return new MaterialAboutActionSwitchItem(this);
- }
-
- public int getTag() {
- return tag;
- }
- public MaterialAboutActionSwitchItem setTag(int tag) {
- this.tag = tag;
- return this;
- }
-
- public CharSequence getText() {
- return text;
- }
- public MaterialAboutActionSwitchItem setText(CharSequence text) {
- this.textRes = 0;
- this.text = text;
- return this;
- }
-
- public int getTextRes() {
- return textRes;
- }
-
- public MaterialAboutActionSwitchItem setTextRes(int textRes) {
- this.text = null;
- this.textRes = textRes;
- return this;
- }
-
- public CharSequence getSubText() {
- return subText;
- }
-
- public MaterialAboutActionSwitchItem setSubText(CharSequence subText) {
- this.subTextRes = 0;
- this.subText = subText;
- return this;
- }
-
- public int getSubTextRes() {
- return subTextRes;
- }
-
- public MaterialAboutActionSwitchItem setSubTextRes(int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public CharSequence getSubTextChecked() {
- return subTextChecked;
- }
-
- public MaterialAboutActionSwitchItem setSubTextChecked(CharSequence subTextChecked) {
- this.subTextCheckedRes = 0;
- this.subTextChecked = subTextChecked;
- return this;
- }
-
- public int getSubTextCheckedRes() {
- return subTextCheckedRes;
- }
-
- public MaterialAboutActionSwitchItem setSubTextCheckedRes(int subTextCheckedRes) {
- this.subTextChecked = null;
- this.subTextCheckedRes = subTextCheckedRes;
- return this;
- }
-
- public Drawable getIcon() {
- return icon;
- }
-
- public MaterialAboutActionSwitchItem setIcon(Drawable icon) {
- this.iconRes = 0;
- this.icon = icon;
- return this;
- }
-
- public int getIconRes() {
- return iconRes;
- }
-
- public MaterialAboutActionSwitchItem setIconRes(int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public boolean shouldShowIcon() {
- return showIcon;
- }
-
- public MaterialAboutActionSwitchItem setShouldShowIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- @IconGravity
- public int getIconGravity() {
- return iconGravity;
- }
-
- public MaterialAboutActionSwitchItem setIconGravity(int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public boolean getChecked() {
- return checked;
- }
-
- public MaterialAboutActionSwitchItem setChecked(boolean checked) {
- this.checked = checked;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnClickAction() {
- return onClickAction;
- }
-
- public MaterialAboutActionSwitchItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnLongClickAction() {
- return onLongClickAction;
- }
-
- public MaterialAboutActionSwitchItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
-
- public MaterialAboutItemOnChangeAction getOnChangeAction() {
- return onChangeAction;
- }
-
- public MaterialAboutActionSwitchItem setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- return this;
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM})
- public @interface IconGravity {
- }
-
- public static class Builder {
-
- MaterialAboutItemOnClickAction onClickAction = null;
- MaterialAboutItemOnClickAction onLongClickAction = null;
- MaterialAboutItemOnChangeAction onChangeAction = null;
- private CharSequence text = null;
- @StringRes
- private int textRes = 0;
- private CharSequence subText = null;
- @StringRes
- private int subTextRes = 0;
- private CharSequence subTextChecked = null;
- @StringRes
- private int subTextCheckedRes = 0;
- private Drawable icon = null;
- @DrawableRes
- private int iconRes = 0;
- private boolean showIcon = true;
- @IconGravity
- private int iconGravity = GRAVITY_MIDDLE;
- private boolean checked = false;
- private int tag = -1;
-
- public Builder tag(int tag) {
- this.tag = tag;
- return this;
- }
-
- public Builder text(CharSequence text) {
- this.text = text;
- this.textRes = 0;
- return this;
- }
-
- public Builder text(@StringRes int text) {
- this.textRes = text;
- this.text = null;
- return this;
- }
-
- public Builder subText(CharSequence subText) {
- this.subText = subText;
- this.subTextRes = 0;
- return this;
- }
-
- public Builder subText(@StringRes int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public Builder subTextHtml(String subTextHtml) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY);
- } else {
- //noinspection deprecation
- this.subText = Html.fromHtml(subTextHtml);
- }
- this.subTextRes = 0;
- return this;
- }
-
- public Builder subTextChecked(CharSequence subTextChecked) {
- this.subTextChecked = subTextChecked;
- this.subTextCheckedRes = 0;
- return this;
- }
-
- public Builder subTextChecked(@StringRes int subTextCheckedRes) {
- this.subTextChecked = null;
- this.subTextCheckedRes = subTextCheckedRes;
- return this;
- }
-
- public Builder subTextCheckedHtml(String subTextCheckedHtml) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.subTextChecked = Html.fromHtml(subTextCheckedHtml, Html.FROM_HTML_MODE_LEGACY);
- } else {
- //noinspection deprecation
- this.subTextChecked = Html.fromHtml(subTextCheckedHtml);
- }
- this.subTextCheckedRes = 0;
- return this;
- }
-
- public Builder icon(Drawable icon) {
- this.icon = icon;
- this.iconRes = 0;
- return this;
- }
-
- public Builder icon(@DrawableRes int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public Builder showIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- public Builder setIconGravity(@IconGravity int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
-
- public Builder setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- return this;
- }
-
- public Builder checked(boolean isChecked) {
- this.checked = isChecked;
- return this;
- }
-
- public MaterialAboutActionSwitchItem build() {
- return new MaterialAboutActionSwitchItem(this);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutCheckboxItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutCheckboxItem.java
deleted file mode 100644
index 16a6cd45..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutCheckboxItem.java
+++ /dev/null
@@ -1,538 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.IntDef;
-import androidx.annotation.StringRes;
-import android.text.Html;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-import static android.view.View.GONE;
-
-public class MaterialAboutCheckboxItem extends MaterialAboutItem {
-
- public static final int GRAVITY_TOP = 0;
- public static final int GRAVITY_MIDDLE = 1;
- public static final int GRAVITY_BOTTOM = 2;
- private CharSequence text = null;
- private int textRes = 0;
- private CharSequence subText = null;
- private int subTextRes = 0;
- private CharSequence subTextChecked = null;
- private int subTextCheckedRes = 0;
- private Drawable icon = null;
- private int iconRes = 0;
- private boolean showIcon = true;
- private int iconGravity = GRAVITY_MIDDLE;
- private boolean checked = false;
- private int tag = -1;
- private MaterialAboutItemOnChangeAction onChangeAction = null;
-
- private MaterialAboutCheckboxItem(Builder builder) {
- super();
- this.text = builder.text;
- this.textRes = builder.textRes;
-
- this.subText = builder.subText;
- this.subTextRes = builder.subTextRes;
-
- this.subTextChecked = builder.subTextChecked;
- this.subTextCheckedRes = builder.subTextCheckedRes;
-
- this.icon = builder.icon;
- this.iconRes = builder.iconRes;
-
- this.showIcon = builder.showIcon;
-
- this.iconGravity = builder.iconGravity;
-
- this.checked = builder.checked;
-
- this.tag = builder.tag;
-
- this.onChangeAction = builder.onChangeAction;
- }
-
- public MaterialAboutCheckboxItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnChangeAction onChangeAction) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- this.onChangeAction = onChangeAction;
- }
-
- public MaterialAboutCheckboxItem(CharSequence text, CharSequence subText, Drawable icon) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- }
-
- public MaterialAboutCheckboxItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnChangeAction onChangeAction) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- this.onChangeAction = onChangeAction;
- }
-
- public MaterialAboutCheckboxItem(int textRes, int subTextRes, int iconRes) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- }
-
- public static MaterialAboutItemViewHolder getViewHolder(View view) {
- return new MaterialAboutCheckboxItemViewHolder(view);
- }
-
- public static void setupItem(MaterialAboutCheckboxItemViewHolder holder, MaterialAboutCheckboxItem item, Context context) {
- holder.switchItem = item;
-
- CharSequence text = item.getText();
- int textRes = item.getTextRes();
-
- holder.text.setVisibility(View.VISIBLE);
- if (text != null) {
- holder.text.setText(text);
- } else if (textRes != 0) {
- holder.text.setText(textRes);
- } else {
- holder.text.setVisibility(GONE);
- }
-
- CharSequence subText = item.getSubText();
- int subTextRes = item.getSubTextRes();
-
- holder.subText.setVisibility(View.VISIBLE);
- if (subText != null) {
- holder.subText.setText(subText);
- } else if (subTextRes != 0) {
- holder.subText.setText(subTextRes);
- } else {
- holder.subText.setVisibility(GONE);
- }
-
- if (item.shouldShowIcon()) {
- holder.icon.setVisibility(View.VISIBLE);
- Drawable drawable = item.getIcon();
- int drawableRes = item.getIconRes();
- if (drawable != null) {
- holder.icon.setImageDrawable(drawable);
- } else if (drawableRes != 0) {
- holder.icon.setImageResource(drawableRes);
- }
- } else {
- holder.icon.setVisibility(GONE);
- }
-
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams();
- switch (item.getIconGravity()) {
- case MaterialAboutCheckboxItem.GRAVITY_TOP:
- params.gravity = Gravity.TOP;
- break;
- case MaterialAboutCheckboxItem.GRAVITY_MIDDLE:
- params.gravity = Gravity.CENTER_VERTICAL;
- break;
- case MaterialAboutCheckboxItem.GRAVITY_BOTTOM:
- params.gravity = Gravity.BOTTOM;
- break;
- }
- holder.icon.setLayoutParams(params);
-
- int pL = 0, pT = 0, pR = 0, pB = 0;
- if (Build.VERSION.SDK_INT < 21) {
- pL = holder.view.getPaddingLeft();
- pT = holder.view.getPaddingTop();
- pR = holder.view.getPaddingRight();
- pB = holder.view.getPaddingBottom();
- }
-
-
- if (item.getOnChangeAction() != null) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true);
- holder.view.setBackgroundResource(outValue.resourceId);
- } else {
- holder.view.setBackgroundResource(0);
- }
- holder.setOnChangeAction(item.getOnChangeAction());
-
- if (Build.VERSION.SDK_INT < 21) {
- holder.view.setPadding(pL, pT, pR, pB);
- }
- }
-
- @Override
- public int getType() {
- return ViewTypeManager.ItemType.CHECKBOX_ITEM;
- }
-
- @Override
- public String getDetailString() {
- return "MaterialAboutCheckboxItem{" +
- "text=" + text +
- ", textRes=" + textRes +
- ", subText=" + subText +
- ", subTextRes=" + subTextRes +
- ", subTextChecked=" + subTextChecked +
- ", subTextCheckedRes=" + subTextCheckedRes +
- ", icon=" + icon +
- ", iconRes=" + iconRes +
- ", showIcon=" + showIcon +
- ", iconGravity=" + iconGravity +
- ", checked=" + checked +
- ", tag=" + tag +
- ", onChangeAction=" + onChangeAction +
- '}';
- }
-
- public MaterialAboutCheckboxItem(MaterialAboutCheckboxItem item) {
- this.id = item.getId();
- this.text = item.getText();
- this.textRes = item.getTextRes();
- this.subText = item.getSubText();
- this.subTextRes = item.getSubTextRes();
- this.subTextChecked = item.getSubTextChecked();
- this.subTextCheckedRes = item.getSubTextCheckedRes();
- this.icon = item.getIcon();
- this.iconRes = item.getIconRes();
- this.showIcon = item.showIcon;
- this.iconGravity = item.iconGravity;
- this.checked = item.checked;
- this.tag = item.tag;
- this.onChangeAction = item.onChangeAction;
- }
-
- @Override
- public MaterialAboutItem clone() {
- return new MaterialAboutCheckboxItem(this);
- }
-
- public int getTag() {
- return tag;
- }
- public MaterialAboutCheckboxItem setTag(int tag) {
- this.tag = tag;
- return this;
- }
-
- public CharSequence getText() {
- return text;
- }
- public MaterialAboutCheckboxItem setText(CharSequence text) {
- this.textRes = 0;
- this.text = text;
- return this;
- }
-
- public int getTextRes() {
- return textRes;
- }
-
- public MaterialAboutCheckboxItem setTextRes(int textRes) {
- this.text = null;
- this.textRes = textRes;
- return this;
- }
-
- public CharSequence getSubText() {
- return subText;
- }
-
- public MaterialAboutCheckboxItem setSubText(CharSequence subText) {
- this.subTextRes = 0;
- this.subText = subText;
- return this;
- }
-
- public int getSubTextRes() {
- return subTextRes;
- }
-
- public MaterialAboutCheckboxItem setSubTextRes(int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public CharSequence getSubTextChecked() {
- return subTextChecked;
- }
-
- public MaterialAboutCheckboxItem setSubTextChecked(CharSequence subTextChecked) {
- this.subTextCheckedRes = 0;
- this.subTextChecked = subTextChecked;
- return this;
- }
-
- public int getSubTextCheckedRes() {
- return subTextCheckedRes;
- }
-
- public MaterialAboutCheckboxItem setSubTextCheckedRes(int subTextCheckedRes) {
- this.subTextChecked = null;
- this.subTextCheckedRes = subTextCheckedRes;
- return this;
- }
-
- public Drawable getIcon() {
- return icon;
- }
-
- public MaterialAboutCheckboxItem setIcon(Drawable icon) {
- this.iconRes = 0;
- this.icon = icon;
- return this;
- }
-
- public int getIconRes() {
- return iconRes;
- }
-
- public MaterialAboutCheckboxItem setIconRes(int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public boolean shouldShowIcon() {
- return showIcon;
- }
-
- public MaterialAboutCheckboxItem setShouldShowIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- @IconGravity
- public int getIconGravity() {
- return iconGravity;
- }
-
- public MaterialAboutCheckboxItem setIconGravity(int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public boolean getChecked() {
- return checked;
- }
-
- public MaterialAboutCheckboxItem setChecked(boolean checked) {
- this.checked = checked;
- return this;
- }
-
- public MaterialAboutItemOnChangeAction getOnChangeAction() {
- return onChangeAction;
- }
-
- public MaterialAboutCheckboxItem setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- return this;
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM})
- public @interface IconGravity {
- }
-
- public static class MaterialAboutCheckboxItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
- public final View view;
- public final ImageView icon;
- public final TextView text;
- public final TextView subText;
- public final CheckBox checkBox;
- private MaterialAboutItemOnChangeAction onChangeAction;
- private MaterialAboutCheckboxItem switchItem;
-
- MaterialAboutCheckboxItemViewHolder(View view) {
- super(view);
- this.view = view;
- icon = view.findViewById(R.id.mal_item_image);
- text = view.findViewById(R.id.mal_item_text);
- subText = view.findViewById(R.id.mal_action_item_subtext);
- checkBox = view.findViewById(R.id.mal_checkbox);
- }
-
- public void setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- view.setOnClickListener(onChangeAction != null ? this : null);
- checkBox.setOnCheckedChangeListener(this);
- }
-
- public void setChecked(boolean checked) {
- checkBox.setOnCheckedChangeListener(null);
- checkBox.setChecked(checked);
- checkBox.setOnCheckedChangeListener(this);
- updateSubText(checked);
- }
-
- public void updateSubText(boolean checked) {
- if (checked && switchItem.subTextChecked != null) {
- subText.setText(switchItem.subTextChecked);
- }
- else if (checked && switchItem.subTextCheckedRes != 0) {
- subText.setText(switchItem.subTextCheckedRes);
- }
- else if (switchItem.subText != null) {
- subText.setText(switchItem.subText);
- }
- else if (switchItem.subTextRes != 0) {
- subText.setText(switchItem.subTextRes);
- }
- }
-
- @Override
- public void onClick(View v) {
- checkBox.toggle();
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- updateSubText(isChecked);
- if (onChangeAction != null) {
- if (!onChangeAction.onChange(isChecked, switchItem.getTag()))
- setChecked(!isChecked);
- }
- else {
- setChecked(!isChecked);
- }
- }
- }
-
- public static class Builder {
-
- MaterialAboutItemOnChangeAction onChangeAction = null;
- private CharSequence text = null;
- @StringRes
- private int textRes = 0;
- private CharSequence subText = null;
- @StringRes
- private int subTextRes = 0;
- private CharSequence subTextChecked = null;
- @StringRes
- private int subTextCheckedRes = 0;
- private Drawable icon = null;
- @DrawableRes
- private int iconRes = 0;
- private boolean showIcon = true;
- @IconGravity
- private int iconGravity = GRAVITY_MIDDLE;
- private boolean checked = false;
- private int tag = -1;
-
- public Builder tag(int tag) {
- this.tag = tag;
- return this;
- }
-
- public Builder text(CharSequence text) {
- this.text = text;
- this.textRes = 0;
- return this;
- }
-
- public Builder text(@StringRes int text) {
- this.textRes = text;
- this.text = null;
- return this;
- }
-
- public Builder subText(CharSequence subText) {
- this.subText = subText;
- this.subTextRes = 0;
- return this;
- }
-
- public Builder subText(@StringRes int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public Builder subTextHtml(String subTextHtml) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY);
- } else {
- //noinspection deprecation
- this.subText = Html.fromHtml(subTextHtml);
- }
- this.subTextRes = 0;
- return this;
- }
-
- public Builder subTextChecked(CharSequence subTextChecked) {
- this.subTextChecked = subTextChecked;
- this.subTextCheckedRes = 0;
- return this;
- }
-
- public Builder subTextChecked(@StringRes int subTextCheckedRes) {
- this.subTextChecked = null;
- this.subTextCheckedRes = subTextCheckedRes;
- return this;
- }
-
- public Builder subTextCheckedHtml(String subTextCheckedHtml) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.subTextChecked = Html.fromHtml(subTextCheckedHtml, Html.FROM_HTML_MODE_LEGACY);
- } else {
- //noinspection deprecation
- this.subTextChecked = Html.fromHtml(subTextCheckedHtml);
- }
- this.subTextCheckedRes = 0;
- return this;
- }
-
- public Builder icon(Drawable icon) {
- this.icon = icon;
- this.iconRes = 0;
- return this;
- }
-
- public Builder icon(@DrawableRes int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public Builder showIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- public Builder setIconGravity(@IconGravity int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public Builder setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- return this;
- }
-
- public Builder checked(boolean isChecked) {
- this.checked = isChecked;
- return this;
- }
-
- public MaterialAboutCheckboxItem build() {
- return new MaterialAboutCheckboxItem(this);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItem.java
deleted file mode 100644
index 2d6a5f48..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItem.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-import java.util.UUID;
-
-public abstract class MaterialAboutItem {
-
- public String id = "NO-UUID";
-
- public MaterialAboutItem() {
- this.id = UUID.randomUUID().toString();
- }
-
- public String getId() {
- return id;
- }
-
- public abstract int getType();
-
- public abstract String getDetailString();
-
- public abstract MaterialAboutItem clone();
-
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnChangeAction.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnChangeAction.java
deleted file mode 100644
index 836883db..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnChangeAction.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-public interface MaterialAboutItemOnChangeAction {
- boolean onChange(boolean isChecked, int tag);
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnClickAction.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnClickAction.java
deleted file mode 100644
index ca1cd610..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutItemOnClickAction.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-public interface MaterialAboutItemOnClickAction {
- void onClick();
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutProfileItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutProfileItem.java
deleted file mode 100644
index aeb4d4fe..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutProfileItem.java
+++ /dev/null
@@ -1,352 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.StringRes;
-
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import static android.view.View.GONE;
-
-public class MaterialAboutProfileItem extends MaterialAboutItem {
-
- private CharSequence text = null;
- private int textRes = 0;
- private CharSequence desc = null;
- private int descRes = 0;
- private Drawable icon = null;
- private int iconRes = 0;
- private MaterialAboutItemOnClickAction onClickAction = null;
- private MaterialAboutItemOnClickAction onLongClickAction = null;
-
- private MaterialAboutProfileItem(MaterialAboutProfileItem.Builder builder) {
- super();
- this.text = builder.text;
- this.textRes = builder.textRes;
-
- this.desc = builder.desc;
- this.descRes = builder.descRes;
-
- this.icon = builder.icon;
- this.iconRes = builder.iconRes;
-
- this.onClickAction = builder.onClickAction;
- this.onLongClickAction = builder.onLongClickAction;
- }
-
- public MaterialAboutProfileItem(CharSequence text, CharSequence desc, Drawable icon) {
- this.text = text;
- this.desc = desc;
- this.icon = icon;
- }
-
- public MaterialAboutProfileItem(int textRes, int descRes, int iconRes) {
- this.textRes = textRes;
- this.descRes = descRes;
- this.iconRes = iconRes;
- }
-
- public static MaterialAboutItemViewHolder getViewHolder(View view) {
- return new MaterialAboutProfileItem.MaterialAboutProfileItemViewHolder(view);
- }
-
- public static void setupItem(MaterialAboutProfileItemViewHolder holder, MaterialAboutProfileItem item, Context context) {
-
- CharSequence text = item.getText();
- int textRes = item.getTextRes();
-
- holder.text.setVisibility(View.VISIBLE);
- if (text != null) {
- holder.text.setText(text);
- } else if (textRes != 0) {
- holder.text.setText(textRes);
- } else {
- holder.text.setVisibility(GONE);
- }
-
- CharSequence desc = item.getDesc();
- int descRes = item.getDescRes();
-
- holder.desc.setVisibility(View.VISIBLE);
- if (desc != null) {
- holder.desc.setText(desc);
- } else if (descRes != 0) {
- holder.desc.setText(descRes);
- } else {
- holder.desc.setVisibility(GONE);
- }
-
- Drawable drawable = item.getIcon();
- int drawableRes = item.getIconRes();
- if (drawable != null) {
- holder.icon.setImageDrawable(drawable);
- } else if (drawableRes != 0) {
- holder.icon.setImageResource(drawableRes);
- }
-
- int pL = 0, pT = 0, pR = 0, pB = 0;
- if (Build.VERSION.SDK_INT < 21) {
- pL = holder.view.getPaddingLeft();
- pT = holder.view.getPaddingTop();
- pR = holder.view.getPaddingRight();
- pB = holder.view.getPaddingBottom();
- }
-
- if (item.getOnClickAction() != null || item.getOnLongClickAction() != null) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true);
- holder.view.setBackgroundResource(outValue.resourceId);
- } else {
- holder.view.setBackgroundResource(0);
- }
- holder.setOnClickAction(item.getOnClickAction());
- holder.setOnLongClickAction(item.getOnLongClickAction());
-
- if (Build.VERSION.SDK_INT < 21) {
- holder.view.setPadding(pL, pT, pR, pB);
- }
- }
-
- @Override
- public int getType() {
- return ViewTypeManager.ItemType.PROFILE_ITEM;
- }
-
- @Override
- public String getDetailString() {
- return "MaterialAboutProfileItem{" +
- "text=" + text +
- ", textRes=" + textRes +
- ", desc=" + desc +
- ", descRes=" + descRes +
- ", icon=" + icon +
- ", iconRes=" + iconRes +
- ", onClickAction=" + onClickAction +
- ", onLongClickAction=" + onLongClickAction +
- '}';
- }
-
- public MaterialAboutProfileItem(MaterialAboutProfileItem item) {
- this.id = item.getId();
- this.text = item.getText();
- this.textRes = item.getTextRes();
- this.desc = item.getDesc();
- this.descRes = item.getDescRes();
- this.icon = item.getIcon();
- this.iconRes = item.getIconRes();
- this.onClickAction = item.getOnClickAction();
- this.onLongClickAction = item.getOnLongClickAction();
- }
-
- @Override
- public MaterialAboutProfileItem clone() {
- return new MaterialAboutProfileItem(this);
- }
-
- public CharSequence getText() {
- return text;
- }
-
- public MaterialAboutProfileItem setText(CharSequence text) {
- this.textRes = 0;
- this.text = text;
- return this;
- }
-
- public int getTextRes() {
- return textRes;
- }
-
- public MaterialAboutProfileItem setTextRes(int textRes) {
- this.text = null;
- this.textRes = textRes;
- return this;
- }
-
- public CharSequence getDesc() {
- return desc;
- }
-
- public MaterialAboutProfileItem setDesc(CharSequence desc) {
- this.descRes = 0;
- this.desc = desc;
- return this;
- }
-
- public int getDescRes() {
- return descRes;
- }
-
- public MaterialAboutProfileItem setDescRes(int descRes) {
- this.desc = null;
- this.descRes = textRes;
- return this;
- }
-
- public Drawable getIcon() {
- return icon;
- }
-
- public MaterialAboutProfileItem setIcon(Drawable icon) {
- this.iconRes = 0;
- this.icon = icon;
- return this;
- }
-
- public int getIconRes() {
- return iconRes;
- }
-
- public MaterialAboutProfileItem setIconRes(int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnClickAction() {
- return onClickAction;
- }
-
- public MaterialAboutProfileItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnLongClickAction() {
- return onLongClickAction;
- }
-
- public MaterialAboutProfileItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
- public static class MaterialAboutProfileItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
- public final View view;
- public final ImageView icon;
- public final TextView text;
- public final TextView desc;
- private MaterialAboutItemOnClickAction onClickAction;
- private MaterialAboutItemOnClickAction onLongClickAction;
-
- MaterialAboutProfileItemViewHolder(View view) {
- super(view);
- this.view = view;
- icon = (ImageView) view.findViewById(R.id.mal_item_image);
- text = (TextView) view.findViewById(R.id.mal_item_text);
- desc = (TextView) view.findViewById(R.id.mal_item_desc);
- }
-
- public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- if (onClickAction != null) {
- view.setOnClickListener(this);
- } else {
- view.setClickable(false);
- }
- }
-
- public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- if (onLongClickAction != null) {
- view.setOnLongClickListener(this);
- } else {
- view.setLongClickable(false);
- }
- }
-
- @Override
- public void onClick(View v) {
- if (onClickAction != null) {
- onClickAction.onClick();
- }
- }
-
- @Override
- public boolean onLongClick(View v) {
- if (onLongClickAction != null) {
- onLongClickAction.onClick();
- return true;
- }
- return false;
- }
- }
-
- public static class Builder {
-
- MaterialAboutItemOnClickAction onClickAction = null;
- MaterialAboutItemOnClickAction onLongClickAction = null;
- private CharSequence text = null;
- @StringRes
- private int textRes = 0;
- private CharSequence desc = null;
- @StringRes
- private int descRes = 0;
- private Drawable icon = null;
- @DrawableRes
- private int iconRes = 0;
-
- public MaterialAboutProfileItem.Builder text(CharSequence text) {
- this.text = text;
- this.textRes = 0;
- return this;
- }
-
-
- public MaterialAboutProfileItem.Builder text(@StringRes int text) {
- this.textRes = text;
- this.text = null;
- return this;
- }
-
- public MaterialAboutProfileItem.Builder desc(CharSequence desc) {
- this.desc = desc;
- this.descRes = 0;
- return this;
- }
-
-
- public MaterialAboutProfileItem.Builder desc(@StringRes int desc) {
- this.descRes = desc;
- this.desc = null;
- return this;
- }
-
- public MaterialAboutProfileItem.Builder icon(Drawable icon) {
- this.icon = icon;
- this.iconRes = 0;
- return this;
- }
-
-
- public MaterialAboutProfileItem.Builder icon(@DrawableRes int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public MaterialAboutProfileItem.Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public MaterialAboutProfileItem.Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
-
- public MaterialAboutProfileItem build() {
- return new MaterialAboutProfileItem(this);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutSwitchItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutSwitchItem.java
deleted file mode 100644
index 4ce55683..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutSwitchItem.java
+++ /dev/null
@@ -1,548 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.IntDef;
-import androidx.annotation.StringRes;
-import androidx.appcompat.widget.SwitchCompat;
-
-import android.text.Html;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-import static android.view.View.GONE;
-
-public class MaterialAboutSwitchItem extends MaterialAboutItem {
-
- public static final int GRAVITY_TOP = 0;
- public static final int GRAVITY_MIDDLE = 1;
- public static final int GRAVITY_BOTTOM = 2;
- private CharSequence text = null;
- private int textRes = 0;
- private CharSequence subText = null;
- private int subTextRes = 0;
- private CharSequence subTextChecked = null;
- private int subTextCheckedRes = 0;
- private Drawable icon = null;
- private int iconRes = 0;
- private boolean showIcon = true;
- private int iconGravity = GRAVITY_MIDDLE;
- private boolean checked = false;
- private int tag = -1;
- private MaterialAboutItemOnChangeAction onChangeAction = null;
-
- private MaterialAboutSwitchItem(Builder builder) {
- super();
- this.text = builder.text;
- this.textRes = builder.textRes;
-
- this.subText = builder.subText;
- this.subTextRes = builder.subTextRes;
-
- this.subTextChecked = builder.subTextChecked;
- this.subTextCheckedRes = builder.subTextCheckedRes;
-
- this.icon = builder.icon;
- this.iconRes = builder.iconRes;
-
- this.showIcon = builder.showIcon;
-
- this.iconGravity = builder.iconGravity;
-
- this.checked = builder.checked;
-
- this.tag = builder.tag;
-
- this.onChangeAction = builder.onChangeAction;
- }
-
- public MaterialAboutSwitchItem(CharSequence text, CharSequence subText, Drawable icon, MaterialAboutItemOnChangeAction onChangeAction) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- this.onChangeAction = onChangeAction;
- }
-
- public MaterialAboutSwitchItem(CharSequence text, CharSequence subText, Drawable icon) {
- this.text = text;
- this.subText = subText;
- this.icon = icon;
- }
-
- public MaterialAboutSwitchItem(int textRes, int subTextRes, int iconRes, MaterialAboutItemOnChangeAction onChangeAction) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- this.onChangeAction = onChangeAction;
- }
-
- public MaterialAboutSwitchItem(int textRes, int subTextRes, int iconRes) {
- this.textRes = textRes;
- this.subTextRes = subTextRes;
- this.iconRes = iconRes;
- }
-
- public static void setupItem(MaterialAboutSwitchItemViewHolder holder, MaterialAboutSwitchItem item, Context context) {
- holder.switchItem = item;
-
- CharSequence text = item.getText();
- int textRes = item.getTextRes();
-
- holder.text.setVisibility(View.VISIBLE);
- if (text != null) {
- holder.text.setText(text);
- } else if (textRes != 0) {
- holder.text.setText(textRes);
- } else {
- holder.text.setVisibility(GONE);
- }
-
- CharSequence subText = item.getSubText();
- int subTextRes = item.getSubTextRes();
-
- holder.subText.setVisibility(View.VISIBLE);
- if (subText != null) {
- holder.subText.setText(subText);
- } else if (subTextRes != 0) {
- holder.subText.setText(subTextRes);
- } else {
- holder.subText.setVisibility(GONE);
- }
-
- if (item.shouldShowIcon()) {
- holder.icon.setVisibility(View.VISIBLE);
- Drawable drawable = item.getIcon();
- int drawableRes = item.getIconRes();
- if (drawable != null) {
- holder.icon.setImageDrawable(drawable);
- } else if (drawableRes != 0) {
- holder.icon.setImageResource(drawableRes);
- }
- } else {
- holder.icon.setVisibility(GONE);
- }
-
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams();
- switch (item.getIconGravity()) {
- case MaterialAboutSwitchItem.GRAVITY_TOP:
- params.gravity = Gravity.TOP;
- break;
- case MaterialAboutSwitchItem.GRAVITY_MIDDLE:
- params.gravity = Gravity.CENTER_VERTICAL;
- break;
- case MaterialAboutSwitchItem.GRAVITY_BOTTOM:
- params.gravity = Gravity.BOTTOM;
- break;
- }
- holder.icon.setLayoutParams(params);
-
- int pL = 0, pT = 0, pR = 0, pB = 0;
- if (Build.VERSION.SDK_INT < 21) {
- pL = holder.view.getPaddingLeft();
- pT = holder.view.getPaddingTop();
- pR = holder.view.getPaddingRight();
- pB = holder.view.getPaddingBottom();
- }
-
- holder.setChecked(item.getChecked());
-
- if (item.getOnChangeAction() != null) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true);
- holder.view.setBackgroundResource(outValue.resourceId);
- } else {
- holder.view.setBackgroundResource(0);
- }
- holder.setOnChangeAction(item.getOnChangeAction());
-
- if (Build.VERSION.SDK_INT < 21) {
- holder.view.setPadding(pL, pT, pR, pB);
- }
- }
-
- public static MaterialAboutItemViewHolder getViewHolder(View view) {
- return new MaterialAboutSwitchItemViewHolder(view);
- }
-
- public static class MaterialAboutSwitchItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
- public final View view;
- public final ImageView icon;
- public final TextView text;
- public final TextView subText;
- public final SwitchCompat switchView;
- private MaterialAboutItemOnChangeAction onChangeAction;
- private MaterialAboutSwitchItem switchItem;
-
- MaterialAboutSwitchItemViewHolder(View view) {
- super(view);
- this.view = view;
- icon = view.findViewById(R.id.mal_item_image);
- text = view.findViewById(R.id.mal_item_text);
- subText = view.findViewById(R.id.mal_action_item_subtext);
- switchView = view.findViewById(R.id.mal_switch);
- }
-
- public void setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- view.setOnClickListener(onChangeAction != null ? this : null);
- switchView.setOnCheckedChangeListener(this);
- }
-
- public void setChecked(boolean checked) {
- switchView.setOnCheckedChangeListener(null);
- switchView.setChecked(checked);
- switchView.setOnCheckedChangeListener(this);
- switchItem.setChecked(checked);
- updateSubText(checked);
- }
-
- public void updateSubText(boolean checked) {
- if (checked && switchItem.subTextChecked != null) {
- subText.setText(switchItem.subTextChecked);
- }
- else if (checked && switchItem.subTextCheckedRes != 0) {
- subText.setText(switchItem.subTextCheckedRes);
- }
- else if (switchItem.subText != null) {
- subText.setText(switchItem.subText);
- }
- else if (switchItem.subTextRes != 0) {
- subText.setText(switchItem.subTextRes);
- }
- }
-
- @Override
- public void onClick(View v) {
- switchView.toggle();
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- updateSubText(isChecked);
- if (onChangeAction != null) {
- if (!onChangeAction.onChange(isChecked, switchItem.getTag())) {
- setChecked(!isChecked);
- }
- else {
- switchItem.setChecked(isChecked);
- }
- }
- else {
- setChecked(!isChecked);
- }
- }
- }
-
- @Override
- public int getType() {
- return ViewTypeManager.ItemType.SWITCH_ITEM;
- }
-
- @Override
- public String getDetailString() {
- return "MaterialAboutSwitchItem{" +
- "text=" + text +
- ", textRes=" + textRes +
- ", subText=" + subText +
- ", subTextRes=" + subTextRes +
- ", subTextChecked=" + subTextChecked +
- ", subTextCheckedRes=" + subTextCheckedRes +
- ", icon=" + icon +
- ", iconRes=" + iconRes +
- ", showIcon=" + showIcon +
- ", iconGravity=" + iconGravity +
- ", checked=" + checked +
- ", tag=" + tag +
- ", onChangeAction=" + onChangeAction +
- '}';
- }
-
- public MaterialAboutSwitchItem(MaterialAboutSwitchItem item) {
- this.id = item.getId();
- this.text = item.getText();
- this.textRes = item.getTextRes();
- this.subText = item.getSubText();
- this.subTextRes = item.getSubTextRes();
- this.subTextChecked = item.getSubTextChecked();
- this.subTextCheckedRes = item.getSubTextCheckedRes();
- this.icon = item.getIcon();
- this.iconRes = item.getIconRes();
- this.showIcon = item.showIcon;
- this.iconGravity = item.iconGravity;
- this.checked = item.checked;
- this.tag = item.tag;
- this.onChangeAction = item.onChangeAction;
- }
-
- @Override
- public MaterialAboutItem clone() {
- return new MaterialAboutSwitchItem(this);
- }
-
- public int getTag() {
- return tag;
- }
- public MaterialAboutSwitchItem setTag(int tag) {
- this.tag = tag;
- return this;
- }
-
- public CharSequence getText() {
- return text;
- }
- public MaterialAboutSwitchItem setText(CharSequence text) {
- this.textRes = 0;
- this.text = text;
- return this;
- }
-
- public int getTextRes() {
- return textRes;
- }
-
- public MaterialAboutSwitchItem setTextRes(int textRes) {
- this.text = null;
- this.textRes = textRes;
- return this;
- }
-
- public CharSequence getSubText() {
- return subText;
- }
-
- public MaterialAboutSwitchItem setSubText(CharSequence subText) {
- this.subTextRes = 0;
- this.subText = subText;
- return this;
- }
-
- public int getSubTextRes() {
- return subTextRes;
- }
-
- public MaterialAboutSwitchItem setSubTextRes(int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public CharSequence getSubTextChecked() {
- return subTextChecked;
- }
-
- public MaterialAboutSwitchItem setSubTextChecked(CharSequence subTextChecked) {
- this.subTextCheckedRes = 0;
- this.subTextChecked = subTextChecked;
- return this;
- }
-
- public int getSubTextCheckedRes() {
- return subTextCheckedRes;
- }
-
- public MaterialAboutSwitchItem setSubTextCheckedRes(int subTextCheckedRes) {
- this.subTextChecked = null;
- this.subTextCheckedRes = subTextCheckedRes;
- return this;
- }
-
- public Drawable getIcon() {
- return icon;
- }
-
- public MaterialAboutSwitchItem setIcon(Drawable icon) {
- this.iconRes = 0;
- this.icon = icon;
- return this;
- }
-
- public int getIconRes() {
- return iconRes;
- }
-
- public MaterialAboutSwitchItem setIconRes(int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public boolean shouldShowIcon() {
- return showIcon;
- }
-
- public MaterialAboutSwitchItem setShouldShowIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- @IconGravity
- public int getIconGravity() {
- return iconGravity;
- }
-
- public MaterialAboutSwitchItem setIconGravity(int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public boolean getChecked() {
- return checked;
- }
-
- public MaterialAboutSwitchItem setChecked(boolean checked) {
- //Log.d("MaterialItem", "Setting item "+getText()+" to checked "+checked);
- this.checked = checked;
- return this;
- }
-
- public MaterialAboutItemOnChangeAction getOnChangeAction() {
- return onChangeAction;
- }
-
- public MaterialAboutSwitchItem setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- return this;
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM})
- public @interface IconGravity {
- }
-
- public static class Builder {
-
- MaterialAboutItemOnChangeAction onChangeAction = null;
- private CharSequence text = null;
- @StringRes
- private int textRes = 0;
- private CharSequence subText = null;
- @StringRes
- private int subTextRes = 0;
- private CharSequence subTextChecked = null;
- @StringRes
- private int subTextCheckedRes = 0;
- private Drawable icon = null;
- @DrawableRes
- private int iconRes = 0;
- private boolean showIcon = true;
- @IconGravity
- private int iconGravity = GRAVITY_MIDDLE;
- private boolean checked = false;
- private int tag = -1;
-
- public Builder tag(int tag) {
- this.tag = tag;
- return this;
- }
-
- public Builder text(CharSequence text) {
- this.text = text;
- this.textRes = 0;
- return this;
- }
-
- public Builder text(@StringRes int text) {
- this.textRes = text;
- this.text = null;
- return this;
- }
-
- public Builder subText(CharSequence subText) {
- this.subText = subText;
- this.subTextRes = 0;
- return this;
- }
-
- public Builder subText(@StringRes int subTextRes) {
- this.subText = null;
- this.subTextRes = subTextRes;
- return this;
- }
-
- public Builder subTextHtml(String subTextHtml) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY);
- } else {
- //noinspection deprecation
- this.subText = Html.fromHtml(subTextHtml);
- }
- this.subTextRes = 0;
- return this;
- }
-
- public Builder subTextChecked(CharSequence subTextChecked) {
- this.subTextChecked = subTextChecked;
- this.subTextCheckedRes = 0;
- return this;
- }
-
- public Builder subTextChecked(@StringRes int subTextCheckedRes) {
- this.subTextChecked = null;
- this.subTextCheckedRes = subTextCheckedRes;
- return this;
- }
-
- public Builder subTextCheckedHtml(String subTextCheckedHtml) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- this.subTextChecked = Html.fromHtml(subTextCheckedHtml, Html.FROM_HTML_MODE_LEGACY);
- } else {
- //noinspection deprecation
- this.subTextChecked = Html.fromHtml(subTextCheckedHtml);
- }
- this.subTextCheckedRes = 0;
- return this;
- }
-
- public Builder icon(Drawable icon) {
- this.icon = icon;
- this.iconRes = 0;
- return this;
- }
-
- public Builder icon(@DrawableRes int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public Builder showIcon(boolean showIcon) {
- this.showIcon = showIcon;
- return this;
- }
-
- public Builder setIconGravity(@IconGravity int iconGravity) {
- this.iconGravity = iconGravity;
- return this;
- }
-
- public Builder setOnChangeAction(MaterialAboutItemOnChangeAction onChangeAction) {
- this.onChangeAction = onChangeAction;
- return this;
- }
-
- public Builder checked(boolean isChecked) {
- this.checked = isChecked;
- return this;
- }
-
- public MaterialAboutSwitchItem build() {
- return new MaterialAboutSwitchItem(this);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutTitleItem.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutTitleItem.java
deleted file mode 100644
index a1b1bc72..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/items/MaterialAboutTitleItem.java
+++ /dev/null
@@ -1,400 +0,0 @@
-package com.danielstone.materialaboutlibrary.items;
-
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.StringRes;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.util.ViewTypeManager;
-
-import static android.view.View.GONE;
-
-public class MaterialAboutTitleItem extends MaterialAboutItem {
-
- private CharSequence text = null;
- private int textRes = 0;
- private CharSequence desc = null;
- private int descRes = 0;
- private int textColor = -1;
- private int descColor = -1;
- private Drawable icon = null;
- private int iconRes = 0;
- private MaterialAboutItemOnClickAction onClickAction = null;
- private MaterialAboutItemOnClickAction onLongClickAction = null;
-
- private MaterialAboutTitleItem(MaterialAboutTitleItem.Builder builder) {
- super();
- this.text = builder.text;
- this.textRes = builder.textRes;
-
- this.desc = builder.desc;
- this.descRes = builder.descRes;
-
- this.textColor = builder.textColor;
- this.descColor = builder.descColor;
-
- this.icon = builder.icon;
- this.iconRes = builder.iconRes;
-
- this.onClickAction = builder.onClickAction;
- this.onLongClickAction = builder.onLongClickAction;
- }
-
- public MaterialAboutTitleItem(CharSequence text, CharSequence desc, Drawable icon) {
- this.text = text;
- this.desc = desc;
- this.icon = icon;
- }
-
- public MaterialAboutTitleItem(int textRes, int descRes, int iconRes) {
- this.textRes = textRes;
- this.descRes = descRes;
- this.iconRes = iconRes;
- }
-
- public static MaterialAboutItemViewHolder getViewHolder(View view) {
- return new MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder(view);
- }
-
- public static void setupItem(MaterialAboutTitleItemViewHolder holder, MaterialAboutTitleItem item, Context context) {
-
- CharSequence text = item.getText();
- int textRes = item.getTextRes();
-
- holder.text.setVisibility(View.VISIBLE);
- if (text != null) {
- holder.text.setText(text);
- } else if (textRes != 0) {
- holder.text.setText(textRes);
- } else {
- holder.text.setVisibility(GONE);
- }
-
- CharSequence desc = item.getDesc();
- int descRes = item.getDescRes();
-
- holder.desc.setVisibility(View.VISIBLE);
- if (desc != null) {
- holder.desc.setText(desc);
- } else if (descRes != 0) {
- holder.desc.setText(descRes);
- } else {
- holder.desc.setVisibility(GONE);
- }
-
- if (item.getTextColor() != -1) {
- holder.text.setTextColor(item.getTextColor());
- }
- if (item.getDescColor() != -1) {
- holder.desc.setTextColor(item.getDescColor());
- }
-
- Drawable drawable = item.getIcon();
- int drawableRes = item.getIconRes();
- if (drawable != null) {
- holder.icon.setImageDrawable(drawable);
- } else if (drawableRes != 0) {
- holder.icon.setImageResource(drawableRes);
- }
-
- int pL = 0, pT = 0, pR = 0, pB = 0;
- if (Build.VERSION.SDK_INT < 21) {
- pL = holder.view.getPaddingLeft();
- pT = holder.view.getPaddingTop();
- pR = holder.view.getPaddingRight();
- pB = holder.view.getPaddingBottom();
- }
-
- if (item.getOnClickAction() != null || item.getOnLongClickAction() != null) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true);
- holder.view.setBackgroundResource(outValue.resourceId);
- } else {
- holder.view.setBackgroundResource(0);
- }
- holder.setOnClickAction(item.getOnClickAction());
- holder.setOnLongClickAction(item.getOnLongClickAction());
-
- if (Build.VERSION.SDK_INT < 21) {
- holder.view.setPadding(pL, pT, pR, pB);
- }
- }
-
- @Override
- public int getType() {
- return ViewTypeManager.ItemType.TITLE_ITEM;
- }
-
- @Override
- public String getDetailString() {
- return "MaterialAboutTitleItem{" +
- "text=" + text +
- ", textRes=" + textRes +
- ", desc=" + desc +
- ", descRes=" + descRes +
- ", textColor=" + textColor +
- ", descColor=" + descColor +
- ", icon=" + icon +
- ", iconRes=" + iconRes +
- ", onClickAction=" + onClickAction +
- ", onLongClickAction=" + onLongClickAction +
- '}';
- }
-
- public MaterialAboutTitleItem(MaterialAboutTitleItem item) {
- this.id = item.getId();
- this.text = item.getText();
- this.textRes = item.getTextRes();
- this.desc = item.getDesc();
- this.descRes = item.getDescRes();
- this.textColor = item.getTextColor();
- this.descColor = item.getDescColor();
- this.icon = item.getIcon();
- this.iconRes = item.getIconRes();
- this.onClickAction = item.getOnClickAction();
- this.onLongClickAction = item.getOnLongClickAction();
- }
-
- @Override
- public MaterialAboutTitleItem clone() {
- return new MaterialAboutTitleItem(this);
- }
-
- public CharSequence getText() {
- return text;
- }
-
- public MaterialAboutTitleItem setText(CharSequence text) {
- this.textRes = 0;
- this.text = text;
- return this;
- }
-
- public int getTextRes() {
- return textRes;
- }
-
- public MaterialAboutTitleItem setTextRes(int textRes) {
- this.text = null;
- this.textRes = textRes;
- return this;
- }
-
- public CharSequence getDesc() {
- return desc;
- }
-
- public MaterialAboutTitleItem setDesc(CharSequence desc) {
- this.descRes = 0;
- this.desc = desc;
- return this;
- }
-
- public int getDescRes() {
- return descRes;
- }
-
- public MaterialAboutTitleItem setDescRes(int descRes) {
- this.desc = null;
- this.descRes = textRes;
- return this;
- }
-
- public int getTextColor() {
- return textColor;
- }
-
- public MaterialAboutTitleItem setTextColor(int textColor) {
- this.textColor = textColor;
- return this;
- }
-
- public int getDescColor() {
- return descColor;
- }
-
- public MaterialAboutTitleItem setDescColor(int descColor) {
- this.descColor = descColor;
- return this;
- }
-
- public Drawable getIcon() {
- return icon;
- }
-
- public MaterialAboutTitleItem setIcon(Drawable icon) {
- this.iconRes = 0;
- this.icon = icon;
- return this;
- }
-
- public int getIconRes() {
- return iconRes;
- }
-
- public MaterialAboutTitleItem setIconRes(int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnClickAction() {
- return onClickAction;
- }
-
- public MaterialAboutTitleItem setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public MaterialAboutItemOnClickAction getOnLongClickAction() {
- return onLongClickAction;
- }
-
- public MaterialAboutTitleItem setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
- public static class MaterialAboutTitleItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
- public final View view;
- public final ImageView icon;
- public final TextView text;
- public final TextView desc;
- private MaterialAboutItemOnClickAction onClickAction;
- private MaterialAboutItemOnClickAction onLongClickAction;
-
- MaterialAboutTitleItemViewHolder(View view) {
- super(view);
- this.view = view;
- icon = (ImageView) view.findViewById(R.id.mal_item_image);
- text = (TextView) view.findViewById(R.id.mal_item_text);
- desc = (TextView) view.findViewById(R.id.mal_item_desc);
- }
-
- public void setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- if (onClickAction != null) {
- view.setOnClickListener(this);
- } else {
- view.setClickable(false);
- }
- }
-
- public void setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- if (onLongClickAction != null) {
- view.setOnLongClickListener(this);
- } else {
- view.setLongClickable(false);
- }
- }
-
- @Override
- public void onClick(View v) {
- if (onClickAction != null) {
- onClickAction.onClick();
- }
- }
-
- @Override
- public boolean onLongClick(View v) {
- if (onLongClickAction != null) {
- onLongClickAction.onClick();
- return true;
- }
- return false;
- }
- }
-
- public static class Builder {
-
- MaterialAboutItemOnClickAction onClickAction = null;
- MaterialAboutItemOnClickAction onLongClickAction = null;
- private CharSequence text = null;
- @StringRes
- private int textRes = 0;
- private CharSequence desc = null;
- @StringRes
- private int descRes = 0;
- @ColorInt
- private int textColor = -1;
- @ColorInt
- private int descColor = -1;
- private Drawable icon = null;
- @DrawableRes
- private int iconRes = 0;
-
- public MaterialAboutTitleItem.Builder text(CharSequence text) {
- this.text = text;
- this.textRes = 0;
- return this;
- }
-
-
- public MaterialAboutTitleItem.Builder text(@StringRes int text) {
- this.textRes = text;
- this.text = null;
- return this;
- }
-
- public MaterialAboutTitleItem.Builder desc(CharSequence desc) {
- this.desc = desc;
- this.descRes = 0;
- return this;
- }
-
-
- public MaterialAboutTitleItem.Builder desc(@StringRes int desc) {
- this.descRes = desc;
- this.desc = null;
- return this;
- }
-
- public MaterialAboutTitleItem.Builder textColor(@ColorInt int textColor) {
- this.textColor = textColor;
- return this;
- }
-
- public MaterialAboutTitleItem.Builder descColor(@ColorInt int descColor) {
- this.descColor = descColor;
- return this;
- }
-
- public MaterialAboutTitleItem.Builder icon(Drawable icon) {
- this.icon = icon;
- this.iconRes = 0;
- return this;
- }
-
-
- public MaterialAboutTitleItem.Builder icon(@DrawableRes int iconRes) {
- this.icon = null;
- this.iconRes = iconRes;
- return this;
- }
-
- public MaterialAboutTitleItem.Builder setOnClickAction(MaterialAboutItemOnClickAction onClickAction) {
- this.onClickAction = onClickAction;
- return this;
- }
-
- public MaterialAboutTitleItem.Builder setOnLongClickAction(MaterialAboutItemOnClickAction onLongClickAction) {
- this.onLongClickAction = onLongClickAction;
- return this;
- }
-
- public MaterialAboutTitleItem build() {
- return new MaterialAboutTitleItem(this);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutCard.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutCard.java
deleted file mode 100644
index ecbffb18..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutCard.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package com.danielstone.materialaboutlibrary.model;
-
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.StringRes;
-import androidx.annotation.StyleRes;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.danielstone.materialaboutlibrary.items.MaterialAboutItem;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.UUID;
-
-public class MaterialAboutCard {
-
- private String id = "NO-UUID";
-
- private CharSequence title = null;
- private int titleRes = 0;
-
- private int titleColor = 0;
- private int cardColor = 0;
-
- private RecyclerView.Adapter customAdapter = null;
- private ArrayList items = new ArrayList<>();
-
-
- private MaterialAboutCard(Builder builder) {
- this.id = UUID.randomUUID().toString();
- this.title = builder.title;
- this.titleRes = builder.titleRes;
- this.titleColor = builder.titleColor;
- this.cardColor = builder.cardColor;
- this.items = builder.items;
- this.customAdapter = builder.customAdapter;
- }
-
- public MaterialAboutCard(CharSequence title, MaterialAboutItem... materialAboutItems) {
- this.title = title;
- Collections.addAll(items, materialAboutItems);
- }
-
- public MaterialAboutCard(int titleRes, MaterialAboutItem... materialAboutItems) {
- this.titleRes = titleRes;
- Collections.addAll(items, materialAboutItems);
- }
-
- public CharSequence getTitle() {
- return title;
- }
-
- public int getTitleRes() {
- return titleRes;
- }
-
- public int getTitleColor() {
- return titleColor;
- }
-
- public int getCardColor() {
- return cardColor;
- }
-
- public ArrayList getItems() {
- return items;
- }
-
- public static class Builder {
- private CharSequence title = null;
- @StringRes
- private int titleRes = 0;
-
- @ColorInt
- private int titleColor = 0;
-
- @ColorInt
- private int cardColor = 0;
-
- private ArrayList items = new ArrayList<>();
- private RecyclerView.Adapter customAdapter = null;
-
- public Builder title(CharSequence title) {
- this.title = title;
- this.titleRes = 0;
- return this;
- }
-
- public Builder title(@StringRes int titleRes) {
- this.titleRes = titleRes;
- this.title = null;
- return this;
- }
-
- public Builder titleColor(@ColorInt int color) {
- this.titleColor = color;
- return this;
- }
-
- public Builder cardColor(@ColorInt int cardColor) {
- this.cardColor = cardColor;
- return this;
- }
-
- public Builder addItem(MaterialAboutItem item) {
- this.items.add(item);
- return this;
- }
-
- public Builder customAdapter(RecyclerView.Adapter customAdapter) {
- this.customAdapter = customAdapter;
- return this;
- }
-
- public MaterialAboutCard build() {
- return new MaterialAboutCard(this);
- }
- }
-
- public String getId() {
- return id;
- }
-
- public RecyclerView.Adapter getCustomAdapter() {
- return customAdapter;
- }
-
- @Override
- public String toString() {
- String result = "MaterialAboutCard{" +
- "id='" + id + '\'' +
- ", title=" + title +
- ", titleRes=" + titleRes +
- ", titleColor=" + titleColor +
- ", customAdapter=" + customAdapter +
- ", cardColor=" + cardColor + '}';
- return result;
- }
-
- public MaterialAboutCard(MaterialAboutCard card) {
- this.id = card.getId();
- this.title = card.getTitle();
- this.titleRes = card.getTitleRes();
- this.titleColor = card.getTitleColor();
- this.cardColor = card.getCardColor();
- this.items = new ArrayList<>();
- this.customAdapter = card.getCustomAdapter();
- for (MaterialAboutItem item : card.items) {
- this.items.add(item.clone());
- }
- }
- public MaterialAboutCard clone() {
- return new MaterialAboutCard(this);
- }
-
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutList.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutList.java
deleted file mode 100644
index 910dcc53..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/model/MaterialAboutList.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.danielstone.materialaboutlibrary.model;
-
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-public class MaterialAboutList {
-
- private ArrayList cards = new ArrayList<>();
-
- private MaterialAboutList(Builder builder) {
- this.cards = builder.cards;
- }
-
- public MaterialAboutList(MaterialAboutCard... materialAboutCards) {
- Collections.addAll(cards, materialAboutCards);
- }
-
- public MaterialAboutList addCard(MaterialAboutCard card) {
- cards.add(card);
- return this;
- }
-
- public MaterialAboutList clearCards(MaterialAboutCard card) {
- cards.clear();
- return this;
- }
-
- public ArrayList getCards() {
- return cards;
- }
-
- public static class Builder {
- private ArrayList cards = new ArrayList<>();
-
- public Builder addCard(MaterialAboutCard card) {
- this.cards.add(card);
- return this;
- }
-
- public MaterialAboutList build() {
- return new MaterialAboutList(this);
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/DefaultViewTypeManager.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/DefaultViewTypeManager.java
deleted file mode 100644
index 8097c972..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/DefaultViewTypeManager.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.danielstone.materialaboutlibrary.util;
-
-import android.content.Context;
-import android.view.View;
-
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutActionSwitchItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutCheckboxItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutProfileItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutSwitchItem;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem;
-
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.ACTION_LAYOUT;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.ACTION_SWITCH_LAYOUT;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.CHECKBOX_LAYOUT;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.PROFILE_LAYOUT;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.SWITCH_LAYOUT;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemLayout.TITLE_LAYOUT;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.ACTION_ITEM;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.ACTION_SWITCH_ITEM;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.CHECKBOX_ITEM;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.PROFILE_ITEM;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.SWITCH_ITEM;
-import static com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager.ItemType.TITLE_ITEM;
-
-public class DefaultViewTypeManager extends ViewTypeManager {
-
- public static final class ItemType {
- public static final int ACTION_ITEM = ViewTypeManager.ItemType.ACTION_ITEM;
- public static final int TITLE_ITEM = ViewTypeManager.ItemType.TITLE_ITEM;
- public static final int SWITCH_ITEM = ViewTypeManager.ItemType.SWITCH_ITEM;
- public static final int ACTION_SWITCH_ITEM = ViewTypeManager.ItemType.ACTION_SWITCH_ITEM;
- public static final int CHECKBOX_ITEM = ViewTypeManager.ItemType.CHECKBOX_ITEM;
- public static final int PROFILE_ITEM = ViewTypeManager.ItemType.PROFILE_ITEM;
- }
-
- public static final class ItemLayout {
- public static final int ACTION_LAYOUT = ViewTypeManager.ItemLayout.ACTION_LAYOUT;
- public static final int TITLE_LAYOUT = ViewTypeManager.ItemLayout.TITLE_LAYOUT;
- public static final int SWITCH_LAYOUT = ViewTypeManager.ItemLayout.SWITCH_LAYOUT;
- public static final int ACTION_SWITCH_LAYOUT = ViewTypeManager.ItemLayout.ACTION_SWITCH_LAYOUT;
- public static final int CHECKBOX_LAYOUT = ViewTypeManager.ItemLayout.CHECKBOX_LAYOUT;
- public static final int PROFILE_LAYOUT = ViewTypeManager.ItemLayout.PROFILE_LAYOUT;
- }
-
- public int getLayout(int itemType) {
- switch (itemType) {
- case ACTION_ITEM:
- return ACTION_LAYOUT;
- case TITLE_ITEM:
- return TITLE_LAYOUT;
- case SWITCH_ITEM:
- return SWITCH_LAYOUT;
- case ACTION_SWITCH_ITEM:
- return ACTION_SWITCH_LAYOUT;
- case CHECKBOX_ITEM:
- return CHECKBOX_LAYOUT;
- case PROFILE_ITEM:
- return PROFILE_LAYOUT;
- default:
- return -1;
- }
- }
-
- public MaterialAboutItemViewHolder getViewHolder(int itemType, View view) {
- switch (itemType) {
- case ACTION_ITEM:
- return MaterialAboutActionItem.getViewHolder(view);
- case TITLE_ITEM:
- return MaterialAboutTitleItem.getViewHolder(view);
- case SWITCH_ITEM:
- return MaterialAboutSwitchItem.getViewHolder(view);
- case ACTION_SWITCH_ITEM:
- return MaterialAboutActionSwitchItem.getViewHolder(view);
- case CHECKBOX_ITEM:
- return MaterialAboutCheckboxItem.getViewHolder(view);
- case PROFILE_ITEM:
- return MaterialAboutProfileItem.getViewHolder(view);
- default:
- return null;
- }
- }
-
- public void setupItem(int itemType, MaterialAboutItemViewHolder holder, MaterialAboutItem item, Context context) {
- switch (itemType) {
- case ACTION_ITEM:
- MaterialAboutActionItem.setupItem((MaterialAboutActionItem.MaterialAboutActionItemViewHolder) holder, (MaterialAboutActionItem) item, context);
- break;
- case TITLE_ITEM:
- MaterialAboutTitleItem.setupItem((MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder) holder, (MaterialAboutTitleItem) item, context);
- break;
- case SWITCH_ITEM:
- MaterialAboutSwitchItem.setupItem((MaterialAboutSwitchItem.MaterialAboutSwitchItemViewHolder) holder, (MaterialAboutSwitchItem) item, context);
- break;
- case ACTION_SWITCH_ITEM:
- MaterialAboutActionSwitchItem.setupItem((MaterialAboutActionSwitchItem.MaterialAboutActionSwitchItemViewHolder) holder, (MaterialAboutActionSwitchItem) item, context);
- break;
- case CHECKBOX_ITEM:
- MaterialAboutCheckboxItem.setupItem((MaterialAboutCheckboxItem.MaterialAboutCheckboxItemViewHolder) holder, (MaterialAboutCheckboxItem) item, context);
- break;
- case PROFILE_ITEM:
- MaterialAboutProfileItem.setupItem((MaterialAboutProfileItem.MaterialAboutProfileItemViewHolder) holder, (MaterialAboutProfileItem) item, context);
- break;
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/OpenSourceLicense.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/OpenSourceLicense.java
deleted file mode 100644
index c916b2b6..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/OpenSourceLicense.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.danielstone.materialaboutlibrary.util;
-
-import com.danielstone.materialaboutlibrary.R;
-
-public enum OpenSourceLicense {
- APACHE_2, MIT, GNU_GPL_3, BSD;
-
- public int getResourceId() {
- switch (this) {
- case APACHE_2:
- return R.string.license_apache2;
- case MIT:
- return R.string.license_mit;
- case GNU_GPL_3:
- return R.string.license_gpl;
- case BSD:
- return R.string.license_bsd;
- default:
- return -1;
- }
- }
-}
diff --git a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/ViewTypeManager.java b/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/ViewTypeManager.java
deleted file mode 100644
index d496dadd..00000000
--- a/material-about-library/src/main/java/com/danielstone/materialaboutlibrary/util/ViewTypeManager.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.danielstone.materialaboutlibrary.util;
-
-import android.content.Context;
-import android.view.View;
-
-import com.danielstone.materialaboutlibrary.R;
-import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder;
-import com.danielstone.materialaboutlibrary.items.MaterialAboutItem;
-
-public abstract class ViewTypeManager {
-
- public static final class ItemType {
- public static final int ACTION_ITEM = 0;
- public static final int TITLE_ITEM = 1;
- public static final int SWITCH_ITEM = 2;
- public static final int ACTION_SWITCH_ITEM = 3;
- public static final int CHECKBOX_ITEM = 4;
- public static final int PROFILE_ITEM = 5;
- }
-
- public static final class ItemLayout {
- public static final int ACTION_LAYOUT = R.layout.mal_material_about_action_item;
- public static final int TITLE_LAYOUT = R.layout.mal_material_about_title_item;
- public static final int SWITCH_LAYOUT = R.layout.mal_material_about_switch_item;
- public static final int ACTION_SWITCH_LAYOUT = R.layout.mal_material_about_action_switch_item;
- public static final int CHECKBOX_LAYOUT = R.layout.mal_material_about_checkbox_item;
- public static final int PROFILE_LAYOUT = R.layout.mal_material_about_profile_item;
- }
-
- public abstract int getLayout(int itemType);
-
- public abstract MaterialAboutItemViewHolder getViewHolder(int itemType, View view);
-
- public abstract void setupItem(int itemType, MaterialAboutItemViewHolder holder, MaterialAboutItem item, Context context);
-}
diff --git a/material-about-library/src/main/res/layout/mal_material_about_action_item.xml b/material-about-library/src/main/res/layout/mal_material_about_action_item.xml
deleted file mode 100644
index 5edc81d4..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_action_item.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/layout/mal_material_about_action_switch_item.xml b/material-about-library/src/main/res/layout/mal_material_about_action_switch_item.xml
deleted file mode 100644
index 9e1dd978..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_action_switch_item.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/layout/mal_material_about_activity.xml b/material-about-library/src/main/res/layout/mal_material_about_activity.xml
deleted file mode 100644
index 42f77361..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_activity.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/material-about-library/src/main/res/layout/mal_material_about_checkbox_item.xml b/material-about-library/src/main/res/layout/mal_material_about_checkbox_item.xml
deleted file mode 100644
index 659bbd1f..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_checkbox_item.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/layout/mal_material_about_fragment.xml b/material-about-library/src/main/res/layout/mal_material_about_fragment.xml
deleted file mode 100644
index f8bdb8e0..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_fragment.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/layout/mal_material_about_list_card.xml b/material-about-library/src/main/res/layout/mal_material_about_list_card.xml
deleted file mode 100644
index 0d1f73e8..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_list_card.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/layout/mal_material_about_profile_item.xml b/material-about-library/src/main/res/layout/mal_material_about_profile_item.xml
deleted file mode 100644
index a90ccba1..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_profile_item.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/layout/mal_material_about_switch_item.xml b/material-about-library/src/main/res/layout/mal_material_about_switch_item.xml
deleted file mode 100644
index b888bc0f..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_switch_item.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/layout/mal_material_about_title_item.xml b/material-about-library/src/main/res/layout/mal_material_about_title_item.xml
deleted file mode 100644
index e77e04c8..00000000
--- a/material-about-library/src/main/res/layout/mal_material_about_title_item.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/values/attrs.xml b/material-about-library/src/main/res/values/attrs.xml
deleted file mode 100644
index 9d555688..00000000
--- a/material-about-library/src/main/res/values/attrs.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/values/colors.xml b/material-about-library/src/main/res/values/colors.xml
deleted file mode 100644
index 057f6cb3..00000000
--- a/material-about-library/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
- #de000000
- #8a000000
-
- #ff9b9b9b
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/values/dimens.xml b/material-about-library/src/main/res/values/dimens.xml
deleted file mode 100644
index 06796bac..00000000
--- a/material-about-library/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
- 16dp
- 8dp
-
- 24dp
- 32dp
- 40dp
-
- 4dp
- 4dp
-
-
-
\ No newline at end of file
diff --git a/material-about-library/src/main/res/values/strings.xml b/material-about-library/src/main/res/values/strings.xml
deleted file mode 100644
index cbe49a18..00000000
--- a/material-about-library/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
- About
-
- Close
- Send email
-
- No apps to handle action
-
-
- "\nCopyright %1$s %2$s\n"
-
- "\nLicensed under the Apache License, Version 2.0 (the \"License\");"
- "you may not use this file except in compliance with the License."
- "You may obtain a copy of the License at\n"
-
- "\nhttp://www.apache.org/licenses/LICENSE-2.0\n"
-
- "\nUnless required by applicable law or agreed to in writing, software"
- "distributed under the License is distributed on an \"AS IS\" BASIS,"
- "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."
- "See the License for the specific language governing permissions and"
- "limitations under the License."
-
-
-
- "\nMIT License\n"
-
- "\nCopyright © %1$s %2$s\n"
-
- "\nPermission is hereby granted, free of charge, to any person obtaining a copy"
- "of this software and associated documentation files (the "Software"), to deal"
- "in the Software without restriction, including without limitation the rights"
- "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell"
- "copies of the Software, and to permit persons to whom the Software is"
- "furnished to do so, subject to the following conditions:\n"
-
- "\nThe above copyright notice and this permission notice shall be included in all"
- "copies or substantial portions of the Software.\n"
-
- "\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR"
- "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,"
- "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE"
- "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER"
- "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,"
- "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE"
- "SOFTWARE."
-
-
-
- "\nCopyright © %1$s %2$s\n"
-
- "\nThis 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.\n"
-
- "\nThis 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.\n"
-
- "\nYou should have received a copy of the GNU General Public License"
- "along with this program. If not, see http://www.gnu.org/licenses.\n"
-
-
-
- "\nCopyright © %1$s %2$s\n"
-
- "\nRedistribution and use in source and binary forms, with or without"
- "modification, are permitted provided that the following conditions are met:\n"
-
- "\n1. Redistributions of source code must retain the above copyright notice, this"
- " list of conditions and the following disclaimer.\n"
- "2. Redistributions in binary form must reproduce the above copyright notice,"
- " this list of conditions and the following disclaimer in the documentation"
- " and/or other materials provided with the distribution.\n"
-
- "\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND"
- "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED"
- "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE"
- "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR"
- "ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES"
- "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;"
- "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND"
- "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT"
- "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"
- "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-
- "\nThe views and conclusions contained in the software and documentation are those"
- "of the authors and should not be interpreted as representing official policies,"
- "either expressed or implied, of the FreeBSD Project.\n"
-
-
diff --git a/material-about-library/src/main/res/values/styles.xml b/material-about-library/src/main/res/values/styles.xml
deleted file mode 100644
index d0c6188b..00000000
--- a/material-about-library/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/mhttp/build.gradle b/mhttp/build.gradle
deleted file mode 100644
index a17c5b48..00000000
--- a/mhttp/build.gradle
+++ /dev/null
@@ -1,51 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
- compileSdkVersion setup.compileSdk
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion setup.targetSdk
- consumerProguardFiles 'proguard-rules.pro'
- versionCode 1
- versionName PROJ_VERSION
- javaCompileOptions {
- annotationProcessorOptions {
- includeCompileClasspath = true
- }
- }
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- debugMinify {
- debuggable = true
- minifyEnabled = true
- proguardFiles 'proguard-android.txt'
- }
- }
- packagingOptions {
- exclude 'META-INF/services/javax.annotation.processing.Processor'
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- lintOptions {
- textReport true
- textOutput 'stdout'
- }
-}
-
-dependencies {
- compileOnly "androidx.appcompat:appcompat:${versions.appcompat}"
- compileOnly 'io.reactivex.rxjava2:rxjava:2.1.3'
- api 'com.squareup.okhttp3:okhttp:3.12.0'
- api 'com.google.code.gson:gson:2.8.5'
- //api deps.mhttpannotations
-// implementation project(':mhttp-annotations')
-}
-
-//apply from: 'https://raw.githubusercontent.com/motcwang/Utils/master/bintray-publish/bintray.gradle'
\ No newline at end of file
diff --git a/mhttp/gradle.properties b/mhttp/gradle.properties
deleted file mode 100644
index 58145d18..00000000
--- a/mhttp/gradle.properties
+++ /dev/null
@@ -1,31 +0,0 @@
-# Project-wide Gradle settings.
-
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
-
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-PROJ_GROUP=im.wangchao
-PROJ_VERSION=1.10.1
-PROJ_NAME=mhttp
-PROJ_WEBSITEURL=http://wangchao.im/2015/11/22/mhttpadapter-post.html
-PROJ_ISSUETRACKERURL=https://github.com/motcwang/MHttp/issues
-PROJ_VCSURL=git@github.com:motcwang/MHttp.git
-PROJ_DESCRIPTION=
-PROJ_ARTIFACTID=mhttp
-PROJ_PACKAGING=aar
-
-DEVELOPER_ID=mot
-DEVELOPER_NAME=Wang Chao
-DEVELOPER_EMAIL=magician.of.technique@aliyun.com
\ No newline at end of file
diff --git a/mhttp/src/main/AndroidManifest.xml b/mhttp/src/main/AndroidManifest.xml
deleted file mode 100644
index 1c8f0a8f..00000000
--- a/mhttp/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/AbsCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/AbsCallbackHandler.java
deleted file mode 100644
index 32d94c89..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/AbsCallbackHandler.java
+++ /dev/null
@@ -1,256 +0,0 @@
-package im.wangchao.mhttp;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import im.wangchao.mhttp.internal.exception.ParserException;
-import im.wangchao.mhttp.internal.exception.ResponseFailException;
-import okhttp3.Call;
-import okhttp3.internal.Util;
-
-import static im.wangchao.mhttp.Response.IO_EXCEPTION_CODE;
-
-/**
- * Description : AbsResponseHandler.
- * Callback lifecycle as follow:
- * onStart()
- * -------------------------------------------------------
- * |
- * |
- * is canceled --- Y --- onCancel()
- * |
- * N
- * |
- * onFinish()
- * |
- * |
- * is successful --- N --- onFailure() ------------------
- * | |
- * Y |
- * | |
- * backgroundParser() --is download-- onProgress() |
- * | | |
- * | | |
- * onSuccess() onSuccess() |
- * | | |
- * | | |
- * ---------------------------------------------------------
- * onFinally()
- *
- * Author : wangchao.
- * Date : 15/8/17.
- * Time : 下午5:56.
- */
-public abstract class AbsCallbackHandler implements Callback, Converter{
- private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(Util.threadFactory("OkHttp", false));
-
- public final static String DEFAULT_CHARSET = "UTF-8";
-
- private Request request;
- private String responseCharset = DEFAULT_CHARSET;
- private boolean isFinished;
- private boolean isCanceled;
-
- private Executor mExecutor;
-
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public abstract void onSuccess(Parser_Type data, Response response);
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public abstract void onFailure(Response response, Throwable throwable);
- /** Work on the request thread, that is okhttp thread. */
- @Deprecated
- public Parser_Type backgroundParser(Response response) throws Exception{
- return null;
- }
- /** Work on the request thread, that is okhttp thread. */
- @Override public Parser_Type apply(Response response) throws Exception {
- return backgroundParser(response);
- }
-
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public void onStart(){}
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public void onCancel(){}
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public void onProgress(long bytesWritten, long bytesTotal){}
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public void onUploadProgress(int bytesWritten, int bytesTotal){}
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public void onFinish(){}
- /** Working thread depends on {@link #mExecutor}, default UI. */
- public void onFinally(Response response){}
-
-
- @Override final public void onFailure(@NonNull Call call, @NonNull IOException e) {
- if (call.isCanceled()){
- sendCancelEvent();
- return;
- }
- sendFinishEvent();
-
- final Request req = request;
- Response response = Response.error(req,
- IO_EXCEPTION_CODE,
- e.getMessage());
-
- sendFailureEvent(response, e);
- sendFinallyEvent(response);
- }
-
- @Override final public void onResponse(@NonNull Call call, @NonNull okhttp3.Response response) throws IOException {
- if (call.isCanceled()){
- response.close();
- sendCancelEvent();
- return;
- }
- sendFinishEvent();
-
- final Request req = request;
- Response okResponse;
- if (response.isSuccessful() || response.isRedirect()
- || req.allowedErrorCodes().contains(response.code())) {
- try {
- okResponse = Response.newResponse(req, response);
- Parser_Type data = apply(okResponse);
- sendSuccessEvent(data, okResponse);
- } catch (Exception e) {
- sendFailureEvent(okResponse = Response.newResponse(req, response), e);
- }
- } else {
- sendFailureEvent(okResponse = Response.newResponse(req, response), new ResponseFailException());
- }
- // todo response.close()
- sendFinallyEvent(okResponse);
- }
-
- public AbsCallbackHandler(){}
-
- @Override public void initialize(Request request){
- isFinished = false;
- isCanceled = false;
- this.request = request;
- this.mExecutor = request.callbackExecutor();
- if (this.mExecutor == null){
- this.mExecutor = request.callbackThreadMode().executor();
- }
- }
-
- public final boolean isFinished(){
- return isFinished;
- }
-
- /**
- * Sets the charset for the response string. If not set, the default is UTF-8.
- */
- public final void setCharset(@NonNull final String charset) {
- this.responseCharset = charset;
- }
-
- /**
- * subclass can override this method to change charset.
- */
- public String charset() {
- return TextUtils.isEmpty(responseCharset) ? DEFAULT_CHARSET : responseCharset;
- }
-
- /**
- * @return request accept
- */
- @Override public String accept(){
- return Accept.EMPTY;
- }
-
- protected final void print(String message){
- Log.d(AbsCallbackHandler.class.getSimpleName(), message);
- }
-
- @Nullable protected final String byteArrayToString(byte[] bytes){
- try {
- return bytes == null ? null : new String(bytes, charset());
- } catch (UnsupportedEncodingException e) {
- return null;
- }
- }
-
- protected final Request getRequest(){
- return this.request;
- }
-
- public final void sendUploadProgressEvent(final int bytesWritten, final int bytesTotal) {
- execute(()->{
- try {
- onUploadProgress(bytesWritten, bytesTotal);
- } catch (Throwable t) {
- //Silent
- }
- });
- }
-
- public final void sendProgressEvent(final long bytesWritten, final long bytesTotal) {
- execute(()->{
- try {
- onProgress(bytesWritten, bytesTotal);
- } catch (Throwable t) {
- //Silent
- }
- });
- }
-
- /*package*/ final void sendSuccessEvent(final Parser_Type data, final Response response) {
- execute(() -> onSuccess(data, response));
- }
-
- /*package*/ final void sendFailureEvent(final Response response, @Nullable final Throwable throwable) {
- execute(() -> onFailure(response, throwable));
- }
-
- /*package*/ final void sendStartEvent() {
- if (request.callbackThreadMode() == ThreadMode.BACKGROUND){
- DEFAULT_EXECUTOR_SERVICE.execute(this::onStart);
- } else {
- execute(this::onStart);
- }
- }
-
- /*package*/ final void sendFinishEvent() {
- execute(() -> {
- AbsCallbackHandler.this.isFinished = true;
- onFinish();
- });
- }
-
- /*package*/ final void sendFinallyEvent(final Response response) {
- execute(() -> onFinally(response));
- }
-
- /*package*/ final synchronized void sendCancelEvent() {
- if (isCanceled){
- return;
- }
- execute(() -> {
- AbsCallbackHandler.this.isCanceled = true;
- onCancel();
- });
- }
-
- private void execute(Runnable command){
- if (mExecutor == null || threadInterrupted()){
- return;
- }
-
- mExecutor.execute(command);
- }
-
- private boolean threadInterrupted(){
- return Thread.currentThread().isInterrupted();
- }
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Accept.java b/mhttp/src/main/java/im/wangchao/mhttp/Accept.java
deleted file mode 100644
index 161d227e..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/Accept.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package im.wangchao.mhttp;
-
-import androidx.annotation.StringDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Description : Accept.
- * Author : wangchao.
- * Date : 16/4/25.
- * Time : 上午11:06.
- */
-public interface Accept {
- String EMPTY = "";
- String ACCEPT_JSON = "application/json;charset=utf-8";
- String ACCEPT_TEXT = "text/html;charset=utf-8";
- String ACCEPT_DATA = "application/octet-stream";
- String ACCEPT_IMAGE = "image/png,image/jpeg,image/*";
- String ACCEPT_FILE = "application/octet-stream";
-
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({
- Accept.EMPTY,
- Accept.ACCEPT_JSON,
- Accept.ACCEPT_TEXT,
- Accept.ACCEPT_DATA,
- Accept.ACCEPT_IMAGE,
- Accept.ACCEPT_FILE
- })
- public @interface $Accept {
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Android5SSL.java b/mhttp/src/main/java/im/wangchao/mhttp/Android5SSL.java
deleted file mode 100644
index 4ddbc6de..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/Android5SSL.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package im.wangchao.mhttp;
-
-import android.os.Build;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.security.GeneralSecurityException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.X509TrustManager;
-
-/**
- * Description : Android5SSL.
- * Author : wangchao.
- * Date : 2018/3/19.
- * Time : 上午11:09.
- */
-/*package*/ class Android5SSL extends SSLSocketFactory {
- private SSLSocketFactory defaultFactory;
- // Android 5.0+ (API level21) provides reasonable default settings
- // but it still allows SSLv3
- // https://developer.android.com/about/versions/android-5.0-changes.html#ssl
- static String protocols[] = null, cipherSuites[] = null;
-
- static {
- try {
- SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
- if (socket != null) {
- /* set reasonable protocol versions */
- // - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
- // - remove all SSL versions (especially SSLv3) because they're insecure now
- List protocols = new LinkedList<>();
- for (String protocol : socket.getSupportedProtocols())
- if (!protocol.toUpperCase().contains("SSL"))
- protocols.add(protocol);
- Android5SSL.protocols = protocols.toArray(new String[protocols.size()]);
- /* set up reasonable cipher suites */
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- // choose known secure cipher suites
- List allowedCiphers = Arrays.asList(
- // TLS 1.2
- "TLS_RSA_WITH_AES_256_GCM_SHA384",
- "TLS_RSA_WITH_AES_128_GCM_SHA256",
- "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
- "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
- "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
- "TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256",
- // maximum interoperability
- "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
- "TLS_RSA_WITH_AES_128_CBC_SHA",
- // additionally
- "TLS_RSA_WITH_AES_256_CBC_SHA",
- "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
- "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
- List availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());
- // take all allowed ciphers that are available and put them into preferredCiphers
- HashSet preferredCiphers = new HashSet<>(allowedCiphers);
- preferredCiphers.retainAll(availableCiphers);
- /* For maximum security, preferredCiphers should *replace* enabled ciphers (thus disabling
- * ciphers which are enabled by default, but have become unsecure), but I guess for
- * the security level of DAVdroid and maximum compatibility, disabling of insecure
- * ciphers should be a server-side task */
- // add preferred ciphers to enabled ciphers
- HashSet enabledCiphers = preferredCiphers;
- enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));
- Android5SSL.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);
- }
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public Android5SSL(X509TrustManager tm) {
- try {
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, (tm != null) ? new X509TrustManager[]{tm} : null, null);
- defaultFactory = sslContext.getSocketFactory();
- } catch (GeneralSecurityException e) {
- throw new AssertionError(); // The system has no TLS. Just give up.
- }
- }
-
- private void upgradeTLS(SSLSocket ssl) {
- // Android 5.0+ (API level21) provides reasonable default settings
- // but it still allows SSLv3
- // https://developer.android.com/about/versions/android-5.0-changes.html#ssl
- if (protocols != null) {
- ssl.setEnabledProtocols(protocols);
- }
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && cipherSuites != null) {
- ssl.setEnabledCipherSuites(cipherSuites);
- }
- }
-
- @Override public String[] getDefaultCipherSuites() {
- return cipherSuites;
- }
-
- @Override public String[] getSupportedCipherSuites() {
- return cipherSuites;
- }
-
- @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
- Socket ssl = defaultFactory.createSocket(s, host, port, autoClose);
- if (ssl instanceof SSLSocket)
- upgradeTLS((SSLSocket) ssl);
- return ssl;
- }
-
- @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- Socket ssl = defaultFactory.createSocket(host, port);
- if (ssl instanceof SSLSocket)
- upgradeTLS((SSLSocket) ssl);
- return ssl;
- }
-
- @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
- Socket ssl = defaultFactory.createSocket(host, port, localHost, localPort);
- if (ssl instanceof SSLSocket)
- upgradeTLS((SSLSocket) ssl);
- return ssl;
- }
-
- @Override public Socket createSocket(InetAddress host, int port) throws IOException {
- Socket ssl = defaultFactory.createSocket(host, port);
- if (ssl instanceof SSLSocket)
- upgradeTLS((SSLSocket) ssl);
- return ssl;
- }
-
- @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
- Socket ssl = defaultFactory.createSocket(address, port, localAddress, localPort);
- if (ssl instanceof SSLSocket)
- upgradeTLS((SSLSocket) ssl);
- return ssl;
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/BindApi.java b/mhttp/src/main/java/im/wangchao/mhttp/BindApi.java
deleted file mode 100644
index 03f26855..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/BindApi.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package im.wangchao.mhttp;
-
-
-import android.util.Log;
-
-/**
- * Description : BindApi.
- * Author : wangchao.
- * Date : 15/10/19.
- * Time : 上午8:23.
- */
-final class BindApi {
- /** HttpProcessor.SUFFIX */
- private static final String SUFFIX = "_HttpBinder";
-
- @SuppressWarnings("unchecked") public static T bind(Class type) {
- String name = type.getName() + SUFFIX;
- T obj = null;
- try {
- obj = (T)Class.forName(name).newInstance();
- } catch (Exception e) {
- Log.e(BindApi.class.getSimpleName(), e.getMessage(), e);
- }
- return obj;
- }
-
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Callback.java b/mhttp/src/main/java/im/wangchao/mhttp/Callback.java
deleted file mode 100644
index fa617fe2..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/Callback.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package im.wangchao.mhttp;
-
-import java.io.IOException;
-
-import okhttp3.Call;
-import okhttp3.Response;
-
-/**
- * Description : OkCallback.
- * Author : wangchao.
- * Date : 16/6/3.
- * Time : 上午10:16.
- */
-public interface Callback extends okhttp3.Callback {
-
- Callback EMPTY = new Callback() {
- @Override public void initialize(Request request) {}
-
- @Override public String accept() {
- return Accept.EMPTY;
- }
-
- @Override public void onFailure(Call call, IOException e) {}
-
- @Override public void onResponse(Call call, Response response) throws IOException {
- response.close();
- }
- };
-
- /**
- * Initialize the callback.
- */
- void initialize(Request request);
-
- /**
- * Request accept.
- */
- String accept();
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Converter.java b/mhttp/src/main/java/im/wangchao/mhttp/Converter.java
deleted file mode 100644
index c75bf3f0..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/Converter.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package im.wangchao.mhttp;
-
-/**
- * Description : Converter.
- * Author : wangchao.
- * Date : 2018/3/20.
- * Time : 下午10:26.
- */
-public interface Converter {
-
- R apply(T t) throws Exception;
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/HTTPS.java b/mhttp/src/main/java/im/wangchao/mhttp/HTTPS.java
deleted file mode 100644
index c485086f..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/HTTPS.java
+++ /dev/null
@@ -1,179 +0,0 @@
-package im.wangchao.mhttp;
-
-import java.io.InputStream;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-import okhttp3.OkHttpClient;
-import okhttp3.internal.Util;
-
-/**
- * Description : HTTPS.
- * Author : wangchao.
- * Date : 16/9/2.
- * Time : 下午3:58.
- */
-/*package*/ final class HTTPS {
-
- // 信任所有证书的 TrustManager
- private static X509TrustManager TrustAllCertificate = new X509TrustManager() {
- @Override public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
- }
-
- @Override public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
- }
-
- @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return new java.security.cert.X509Certificate[]{};
- }
- };
-
- /**
- * Trust all certificate for debug
- */
- /*package*/ static void trustAllCertificate(OkHttpClient.Builder builder) {
- builder.sslSocketFactory(new Android5SSL(TrustAllCertificate), TrustAllCertificate);
- }
-
- /**
- * Set Certificate
- */
- /*package*/ static void setCertificates(OkHttpClient.Builder builder,
- InputStream... certificates) throws Exception {
- setCertificates(builder, null, certificates, null, null);
- }
-
- /**
- * Set Certificate
- */
- /*package*/ static void setCertificates(OkHttpClient.Builder builder,
- X509TrustManager trustManager,
- InputStream bksFile,
- String password) throws Exception {
- setCertificates(builder, trustManager, null, bksFile, password);
- }
-
- /**
- * Set Certificate
- */
- /*package*/ static void setCertificates(OkHttpClient.Builder builder,
- InputStream[] certificates,
- InputStream bksFile,
- String password) throws Exception {
- setCertificates(builder, null, certificates, bksFile, password);
- }
-
- /**
- * Set Certificate
- */
- /*package*/ static void setCertificates(OkHttpClient.Builder builder,
- X509TrustManager trustManager,
- InputStream[] certificates,
- InputStream bksFile,
- String password) throws Exception {
- TrustManager[] trustManagers = prepareTrustManager(certificates);
- KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
-
- X509TrustManager manager;
- if (trustManager != null) {
- manager = trustManager;
- } else if (trustManagers != null) {
- manager = chooseTrustManager(trustManagers);
- } else {
- manager = TrustAllCertificate;
- }
-
- // 创建TLS类型的SSLContext对象, that uses our finalTrustManager
- SSLContext sslContext = SSLContext.getInstance("TLS");
- // 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书
- // 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书
- sslContext.init(keyManagers, new TrustManager[]{manager}, new SecureRandom());
- builder.sslSocketFactory(sslContext.getSocketFactory(), manager);
- }
-
- /*package*/ static TrustManager[] prepareTrustManager(InputStream... certificates) throws Exception {
- if (certificates == null || certificates.length <= 0) return null;
-
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- // 创建一个默认类型的KeyStore,存储我们信任的证书
- KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
- keyStore.load(null);
- int index = 0;
- for (InputStream certificate : certificates) {
- String certificateAlias = Integer.toString(index++);
- keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
- Util.closeQuietly(certificate);
- }
-
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.
- getInstance(TrustManagerFactory.getDefaultAlgorithm());
- //用我们之前的keyStore实例初始化TrustManagerFactory,使TrustManagerFactory信任keyStore中的证书
- trustManagerFactory.init(keyStore);
- return trustManagerFactory.getTrustManagers();
- }
-
- /*package*/ static KeyManager[] prepareKeyManager(InputStream bksFile, String password) throws Exception{
- if (bksFile == null || password == null) return null;
-
- KeyStore clientKeyStore = KeyStore.getInstance("BKS");
- clientKeyStore.load(bksFile, password.toCharArray());
- KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- keyManagerFactory.init(clientKeyStore, password.toCharArray());
- return keyManagerFactory.getKeyManagers();
- }
-
- /*package*/ static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
- for (TrustManager trustManager : trustManagers) {
- if (trustManager instanceof X509TrustManager) {
- return (X509TrustManager) trustManager;
- }
- }
- return null;
- }
-
- /* X509TrustManager */
- /*package*/ static class MyTrustManager implements X509TrustManager {
- private X509TrustManager defaultTrustManager;
- private X509TrustManager localTrustManager;
-
- /*package*/ MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException {
- TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- var4.init((KeyStore) null);
- defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
- this.localTrustManager = localTrustManager;
- }
-
- @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
-// try {
-// defaultTrustManager.checkClientTrusted(chain, authType);
-// } catch (CertificateException e) {
-// localTrustManager.checkClientTrusted(chain, authType);
-// }
- }
-
- @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- try {
- defaultTrustManager.checkServerTrusted(chain, authType);
- } catch (CertificateException e) {
- localTrustManager.checkServerTrusted(chain, authType);
- }
- }
-
-
- @Override public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/MHttp.java b/mhttp/src/main/java/im/wangchao/mhttp/MHttp.java
deleted file mode 100644
index af46229b..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/MHttp.java
+++ /dev/null
@@ -1,252 +0,0 @@
-package im.wangchao.mhttp;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.StatFs;
-import androidx.annotation.NonNull;
-
-import java.io.File;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.X509TrustManager;
-
-import im.wangchao.mhttp.internal.interceptor.HttpLoggingInterceptor;
-import im.wangchao.mhttp.internal.interceptor.MBridgeInterceptor;
-import im.wangchao.mhttp.internal.log.LoggerImpl;
-import okhttp3.Cache;
-import okhttp3.Call;
-import okhttp3.HttpUrl;
-import okhttp3.OkHttpClient;
-
-/**
- * Description : MHttp.
- * Author : wangchao.
- * Date : 16/6/2.
- * Time : 上午8:40.
- */
-public final class MHttp {
- private static volatile MHttp instance;
-
- private OkHttpClient.Builder mOkBuilder;
- private OkHttpClient mInnerClient;
- private URLInterceptor mURLInterceptor;
- private final HttpLoggingInterceptor mLoggingInterceptor = new HttpLoggingInterceptor(LoggerImpl.instance.get());
-
- public static MHttp instance(){
- if (instance == null) {
- synchronized (MHttp.class){
- instance = new MHttp();
- }
- }
- return instance;
- }
-
- /**
- * Create annotation api
- */
- public static T create(Class api){
- return BindApi.bind(api);
- }
-
- /**
- * OkHttpClient
- */
- public MHttp customOkHttpClient(@NonNull OkHttpClient client){
- mOkBuilder = client.newBuilder()
- .addInterceptor(MBridgeInterceptor.instance.get());
- return this;
- }
-
- /**
- * Set logging level
- */
- public MHttp loggingLevel(HttpLoggingInterceptor.Level level){
- mLoggingInterceptor.setLevel(level);
- LoggerImpl.instance.get().setLevel(level);
- if (!mOkBuilder.interceptors().contains(mLoggingInterceptor)) {
- mOkBuilder.addInterceptor(mLoggingInterceptor);
- }
- return this;
- }
-
- /**
- * Set cache Dir
- */
- public MHttp cache(Context context, String dirName) {
- File cache = new File(context.getApplicationContext().getCacheDir(), dirName);
- if (!cache.exists()) {
- //noinspection ResultOfMethodCallIgnored
- cache.mkdirs();
- }
- long size = 5 * 1024 * 1024;
- try {
- StatFs statFs = new StatFs(cache.getAbsolutePath());
- long count, blockSize;
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1){
- count = statFs.getBlockCountLong();
- blockSize = statFs.getBlockSizeLong();
- } else {
- count = statFs.getBlockCount();
- blockSize = statFs.getBlockSize();
- }
- long available = count * blockSize;
- // Target 2% of the total space.
- size = available / 50;
- } catch (IllegalArgumentException ignored) {
- }
- // Bound inside min/max size for disk cache.
- size = Math.max(Math.min(size, size * 10), size);
-
- mOkBuilder.cache(new Cache(cache, size));
- return this;
- }
-
- /**
- * Set connect, read and write time with {@link TimeUnit#SECONDS}
- */
- public MHttp timeout(int timeout){
- timeout(timeout, TimeUnit.SECONDS);
- return this;
- }
-
- public MHttp timeout(int timeout, TimeUnit unit){
- connectTimeout(timeout, unit);
- readTimeout(timeout, unit);
- writeTimeout(timeout, unit);
- return this;
- }
-
- public MHttp connectTimeout(long timeout, TimeUnit unit){
- mOkBuilder.connectTimeout(timeout, unit);
- return this;
- }
-
- public MHttp readTimeout(long timeout, TimeUnit unit){
- mOkBuilder.readTimeout(timeout, unit);
- return this;
- }
-
- public MHttp writeTimeout(long timeout, TimeUnit unit){
- mOkBuilder.writeTimeout(timeout, unit);
- return this;
- }
-
- public MHttp setURLInterceptor(URLInterceptor interceptor){
- this.mURLInterceptor = interceptor;
- return this;
- }
-
- /**
- * Trust all certificate for debug
- */
- public MHttp trustAllCertificate(){
- HTTPS.trustAllCertificate(mOkBuilder);
- return this;
- }
-
- /**
- * Set Certificate
- */
- public MHttp setCertificates(InputStream... certificates){
- return setCertificates(certificates, null, null);
- }
-
- /**
- * Set Certificate
- */
- public MHttp setCertificates(X509TrustManager trustManager, InputStream bksFile, String password) {
- try {
- HTTPS.setCertificates(mOkBuilder, trustManager, null, bksFile, password);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- return this;
- }
-
- /**
- * Set Certificate
- */
- public MHttp setCertificates(InputStream[] certificates, InputStream bksFile, String password) {
- try {
- HTTPS.setCertificates(mOkBuilder, null, certificates, bksFile, password);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- return this;
- }
-
- public MHttp hostnameVerifier(HostnameVerifier hostnameVerifier){
- mOkBuilder.hostnameVerifier(hostnameVerifier);
- return this;
- }
-
- /**
- * @return Current client.
- */
- public OkHttpClient client(){
- if (mOkBuilder == null){
- throw new IllegalArgumentException("OkHttpClient cannot be null, please call the MHttp#client(OkHttpClient client) method first.");
- }
- if (mInnerClient == null){
- mInnerClient = mOkBuilder.build();
- }
- return mInnerClient;
- }
-
- /**
- * Cancel all request.
- */
- public MHttp cancelAll(){
- client().dispatcher().cancelAll();
- return this;
- }
-
- /**
- * Cancel request with {@code tag}
- */
- public MHttp cancel(Object tag){
- for (Call call : client().dispatcher().queuedCalls()) {
- if (tag.equals(call.request().tag())) {
- call.cancel();
- }
- }
- for (Call call : client().dispatcher().runningCalls()) {
- if (tag.equals(call.request().tag())) {
- call.cancel();
- }
- }
- return this;
- }
-
- /*package*/ String proceedURL(String url){
- if (mURLInterceptor != null){
- return mURLInterceptor.interceptor(url);
- }
- return url;
- }
-
- /*package*/ HttpUrl proceedURL(HttpUrl url){
- if (mURLInterceptor != null){
- return mURLInterceptor.interceptor(url);
- }
- return url;
- }
-
- /*package*/ URL proceedURL(URL url){
- if (mURLInterceptor != null){
- return mURLInterceptor.interceptor(url);
- }
- return url;
- }
-
- //@private
- private MHttp(){
- //default instance
- mOkBuilder = new OkHttpClient.Builder()
- .addInterceptor(MBridgeInterceptor.instance.get());
- }
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Method.java b/mhttp/src/main/java/im/wangchao/mhttp/Method.java
deleted file mode 100644
index f7453aab..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/Method.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package im.wangchao.mhttp;
-
-import androidx.annotation.StringDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Description : Method.
- * Author : wangchao.
- * Date : 16/3/8.
- * Time : 下午4:08.
- */
-public interface Method {
- String POST = "POST";
- String GET = "GET";
- String HEAD = "HEAD";
- String DELETE = "DELETE";
- String PUT = "PUT";
- String PATCH = "PATCH";
-
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({Method.POST, Method.GET, Method.HEAD, Method.DELETE, Method.PUT, Method.PATCH})
- @interface MethodType{}
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Request.java b/mhttp/src/main/java/im/wangchao/mhttp/Request.java
deleted file mode 100644
index 426b0eab..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/Request.java
+++ /dev/null
@@ -1,503 +0,0 @@
-package im.wangchao.mhttp;
-
-import androidx.annotation.NonNull;
-import android.util.Pair;
-import android.util.Log;
-
-import com.google.gson.JsonObject;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-import im.wangchao.mhttp.body.JSONBody;
-import im.wangchao.mhttp.body.MediaTypeUtils;
-import okhttp3.CacheControl;
-import okhttp3.Call;
-import okhttp3.Headers;
-import okhttp3.HttpUrl;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.RequestBody;
-import okio.Buffer;
-import okio.BufferedSink;
-
-/**
- * Description : MRequest.
- * Author : wangchao.
- * Date : 16/6/2.
- * Time : 下午4:16.
- */
-public final class Request {
- public static Builder builder(){
- return new Builder();
- }
-
- private final okhttp3.Request mRawRequest;
- private final RequestParams mRequestParams;
- private final Callback mCallback;
- private final MediaType mMediaType;
- private final Executor mExecutor;
- private final ThreadMode mThreadMode;
- private final JsonObject mJsonBody;
- private final okhttp3.OkHttpClient mOkHttpClient;
- private final List mAllowedErrorCodes;
- private final String mTextBody;
-
- private okhttp3.Call mRawCall;
-
- private Request(Builder builder){
- mRawRequest = builder.mRawRequest;
- mRequestParams = builder.mRequestParams;
- mCallback = builder.mCallback;
- mMediaType = builder.mMediaType;
- mExecutor = builder.mExecutor;
- mThreadMode = builder.mThreadMode;
- mJsonBody = builder.mJsonBody;
- mOkHttpClient = builder.mOkHttpClient;
- mAllowedErrorCodes = builder.mAllowedErrorCodes;
- mTextBody = builder.mTextBody;
- }
-
- public okhttp3.Request raw() {
- return mRawRequest;
- }
-
- public HttpUrl url() {
- return mRawRequest.url();
- }
-
- public String method() {
- return mRawRequest.method();
- }
-
- public Headers headers() {
- return mRawRequest.headers();
- }
-
- public String header(String name) {
- return mRawRequest.header(name);
- }
-
- public List headers(String name) {
- return mRawRequest.headers(name);
- }
-
- public RequestBody body() {
- return mRawRequest.body();
- }
-
- public String bodyToString(){
- try {
- final Buffer buffer = new Buffer();
- body().writeTo(buffer);
- return buffer.readUtf8();
- } catch (final Exception e) {
- return "did not work. "+e.getMessage();
- }
- }
-
- public Object tag() {
- return mRawRequest.tag();
- }
-
- public Builder newBuilder() {
- return new Builder(this);
- }
-
- public Callback callback() {
- return mCallback;
- }
-
- public JsonObject jsonBody() {
- return mJsonBody;
- }
-
- public String textBody() {
- return mTextBody;
- }
-
- public OkHttpClient okHttpClient() {
- return mOkHttpClient;
- }
-
- public List allowedErrorCodes() {
- return mAllowedErrorCodes;
- }
-
- /**
- * Returns the cache control directives for this response. This is never null, even if this
- * response contains no {@code Cache-Control} header.
- */
- public CacheControl cacheControl() {
- return mRawRequest.cacheControl();
- }
-
- public boolean isHttps() {
- return mRawRequest.isHttps();
- }
-
- /**
- * The executor used for {@link Callback} methods on which thread work.
- */
- public Executor callbackExecutor() {
- return mExecutor;
- }
-
- /**
- * {@link Callback} methods on which thread work.
- */
- public ThreadMode callbackThreadMode() {
- return mThreadMode;
- }
-
- public RequestParams requestParams(){
- return mRequestParams;
- }
-
- /**
- * Send the async request.
- */
- public Request enqueue(){
- Callback callback = callback();
- callback.initialize(this);
- if (callback instanceof AbsCallbackHandler){
- ((AbsCallbackHandler) callback).sendStartEvent();
- }
- rawCall().enqueue(callback);
- return this;
- }
-
- /**
- * Send the sync request.
- */
- public Response execute() throws IOException {
- return Response.newResponse(this, rawCall().execute());
- }
-
- /**
- * Cancel this request
- */
- public Request cancel(){
- if (rawCall().isCanceled()){
- return this;
- }
- rawCall().cancel();
- return this;
- }
-
- private Call rawCall(){
- if (mRawCall == null){
- OkHttpClient client;
- if (mOkHttpClient == null) {
- client = MHttp.instance().client();
- }
- else {
- client = mOkHttpClient;
- }
- mRawCall = client.newCall(raw());
- }
- return mRawCall;
- }
-
- @Override public String toString() {
- return mRawRequest.toString();
- }
-
- public static class Builder {
- private static final String TAG = Builder.class.getSimpleName();
-
- okhttp3.Request mRawRequest;
- okhttp3.Request.Builder mRawBuilder;
- RequestParams mRequestParams;
- Callback mCallback;
- String mMethod;
- MediaType mMediaType;
- Executor mExecutor;
- ThreadMode mThreadMode;
- JsonObject mJsonBody;
- OkHttpClient mOkHttpClient;
- List mAllowedErrorCodes;
- String mTextBody;
-
- public Builder() {
- mCallback = Callback.EMPTY;
- mMethod = Method.GET;
- mRawBuilder = new okhttp3.Request.Builder();
- mRequestParams = new RequestParams();
- mThreadMode = ThreadMode.BACKGROUND;
- mJsonBody = null;
- mOkHttpClient = null;
- mAllowedErrorCodes = new ArrayList<>();
- mTextBody = null;
- }
-
- private Builder(Request request) {
- mCallback = request.mCallback;
- mMethod = request.method();
- mRequestParams = request.mRequestParams;
- mRawBuilder = request.mRawRequest.newBuilder();
- mExecutor = request.mExecutor;
- mThreadMode = request.mThreadMode;
- mMediaType = request.mMediaType;
- mJsonBody = request.mJsonBody;
- mOkHttpClient = request.mOkHttpClient;
- mAllowedErrorCodes = request.mAllowedErrorCodes;
- mTextBody = request.mTextBody;
- }
-
- public Builder url(HttpUrl url) {
- mRawBuilder.url(MHttp.instance().proceedURL(url));
- return this;
- }
-
- public Builder url(String url) {
- mRawBuilder.url(MHttp.instance().proceedURL(url));
- return this;
- }
-
- public Builder url(URL url) {
- mRawBuilder.url(MHttp.instance().proceedURL(url));
- return this;
- }
-
- public Builder header(String name, String value) {
- mRawBuilder.header(name, value);
- return this;
- }
-
- public Builder addHeader(String name, String value) {
- mRawBuilder.addHeader(name, value);
- return this;
- }
-
- public Builder removeHeader(String name) {
- mRawBuilder.removeHeader(name);
- return this;
- }
-
- public Builder headers(Headers headers) {
- mRawBuilder.headers(headers);
- return this;
- }
-
- public Builder cacheControl(CacheControl cacheControl) {
- mRawBuilder.cacheControl(cacheControl);
- return this;
- }
-
- public Builder withClient(OkHttpClient okHttpClient) {
- mOkHttpClient = okHttpClient;
- return this;
- }
-
- public Builder get() {
- return method(Method.GET);
- }
-
- public Builder head() {
- return method(Method.HEAD);
- }
-
- public Builder post() {
- return method(Method.POST);
- }
-
- public Builder postJson() {
- return method(Method.POST).contentType(MediaTypeUtils.APPLICATION_JSON);
- }
-
- public Builder delete() {
- return method(Method.DELETE);
- }
-
- public Builder put() {
- return method(Method.PUT);
- }
-
- public Builder patch() {
- return method(Method.PATCH);
- }
-
- public Builder setJsonBody(JsonObject jsonBody) {
- mJsonBody = jsonBody;
- return method(Method.POST).contentType(MediaTypeUtils.APPLICATION_JSON);
- }
-
- public Builder setTextBody(String textBody, String mediaType) {
- mTextBody = textBody;
- return method(Method.POST).contentType(mediaType);
- }
-
- public Builder allowErrorCode(int code) {
- mAllowedErrorCodes.add(code);
- return this;
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, Object value){
- mRequestParams.put(key, value);
- return this;
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, InputStream stream, String name){
- mRequestParams.put(key, stream, name);
- return this;
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, InputStream stream, String name, String contentType){
- mRequestParams.put(key, stream, name, contentType);
- return this;
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, File file, String contentType){
- try {
- mRequestParams.put(key, file, contentType);
- } catch (FileNotFoundException e) {
- Log.e(TAG, e.getMessage(), e);
- }
- return this;
- }
-
- public Builder requestParams(RequestParams params) {
- if (params != null){
- mRequestParams = params;
- }
- return this;
- }
-
- public Builder addParams(List> params) {
- if (params != null){
- mRequestParams.put(params);
- }
- return this;
- }
-
- public Builder method(@NonNull String method) {
- this.mMethod = method;
- return this;
- }
-
- public Builder tag(Object tag) {
- mRawBuilder.tag(tag);
- return this;
- }
-
- public Builder callback(@NonNull Callback callback){
- mCallback = callback;
- return this;
- }
-
- public Builder callbackExecutor(Executor executor){
- mExecutor = executor;
- return this;
- }
-
- public Builder callbackThreadMode(ThreadMode threadMode){
- mThreadMode = threadMode;
- return this;
- }
-
- public Builder userAgent(String ua){
- header("User-Agent", ua);
- return this;
- }
-
- public Builder contentType(@NonNull String contentType){
- this.mMediaType = MediaType.parse(contentType);
- header("Content-Type", contentType);
- return this;
- }
-
- public Builder contentType(@NonNull MediaType mediaType){
- this.mMediaType = mediaType;
- header("Content-Type", this.mMediaType.toString());
- return this;
- }
-
- public Request build() {
- if (mMediaType == null){
- // judgment request header
- List headers = mRawBuilder.build().headers("Content-Type");
- final int len = headers.size();
- if (len != 0){
- StringBuilder mediaType = new StringBuilder();
- for (int i = 0; i < len; i++){
- mediaType.append(headers.get(i));
- }
- mMediaType = MediaType.parse(mediaType.toString());
- if (mMediaType == null){
- mMediaType = MediaTypeUtils.DEFAULT;
- }
- }
- // default is application/x-www-form-urlencoded
- else {
- mMediaType = MediaTypeUtils.DEFAULT;
- }
- }
-
- if (!Accept.EMPTY.equals(mCallback.accept())) {
- addHeader("Accept", mCallback.accept());
- }
-
- switch (mMethod) {
- case Method.GET:
- mRawBuilder.method(mMethod, null);
- mRawRequest = mRawBuilder.build();
- mRawRequest = mRawBuilder.url(mRequestParams.formatURLParams(mRawRequest.url())).build();
- break;
- case Method.HEAD:
- mRawBuilder.method(mMethod, null);
- mRawRequest = mRawBuilder.build();
- break;
- default:
- if (MediaTypeUtils.isJSON(mMediaType) && mJsonBody != null) {
- mRawBuilder.method(mMethod, new JSONBody(mJsonBody.toString()));
- }
- else if (mTextBody != null) {
- mRawBuilder.method(mMethod, new RequestBody() {
- @Override
- public MediaType contentType() {
- return mMediaType;
- }
-
- @Override
- public void writeTo(BufferedSink sink) throws IOException {
- sink.write(mTextBody.getBytes(), 0, mTextBody.getBytes().length);
- }
-
- @Override
- public long contentLength() throws IOException {
- return mTextBody.getBytes().length;
- }
- });
- }
- else {
- // inject callback if exist.
- mRawBuilder.method(mMethod, mRequestParams.requestBody(mMediaType,
- (mCallback instanceof AbsCallbackHandler ? (AbsCallbackHandler) mCallback : null)));
- }
- mRawRequest = mRawBuilder.build();
- break;
- }
-
- return new Request(this);
- }
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/RequestParams.java b/mhttp/src/main/java/im/wangchao/mhttp/RequestParams.java
deleted file mode 100644
index 822338ac..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/RequestParams.java
+++ /dev/null
@@ -1,378 +0,0 @@
-package im.wangchao.mhttp;
-
-import androidx.annotation.NonNull;
-import android.text.TextUtils;
-import android.util.Pair;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import im.wangchao.mhttp.body.FileBody;
-import im.wangchao.mhttp.body.JSONBody;
-import im.wangchao.mhttp.body.MediaTypeUtils;
-import im.wangchao.mhttp.body.OctetStreamBody;
-import im.wangchao.mhttp.body.ProgressRequestBody;
-import okhttp3.FormBody;
-import okhttp3.HttpUrl;
-import okhttp3.MediaType;
-import okhttp3.MultipartBody;
-import okhttp3.RequestBody;
-
-import static im.wangchao.mhttp.body.MediaTypeUtils.APPLICATION_OCTET_STREAM;
-
-/**
- * Description : RequestParams.
- * Author : wangchao.
- * Date : 15/8/17.
- * Time : 下午2:16.
- */
-public class RequestParams{
- final private static String UTF_8_STR = "utf-8";
- final private static Charset UTF_8 = Charset.forName(UTF_8_STR);
-
- //params
- final private List> urlParams = new ArrayList<>();
- final private ConcurrentHashMap streamParams = new ConcurrentHashMap<>();
- final private ConcurrentHashMap fileParams = new ConcurrentHashMap<>();
-
- //default
- private String contentEncoding = UTF_8_STR;
-
- public RequestParams(){
- this((Map)null);
- }
-
- public RequestParams(Map params){
- if (params != null){
- for(Map.Entry entry : params.entrySet()){
- put(entry.getKey(), entry.getValue());
- }
- }
- }
-
- public RequestParams(Object...keysAndValues){
- int len = keysAndValues.length;
- if (len % 2 != 0){
- throw new IllegalArgumentException("Supplied arguments must be even.");
- }
- for (int i = 0; i < len; i += 2){
- String key = String.valueOf(keysAndValues[i]);
- String val = String.valueOf(keysAndValues[i + 1]);
- put(key, val);
- }
- }
-
- public RequestParams(RequestParams params){
- if (params == null){
- return;
- }
- this.urlParams.addAll(params.getUrlParams());
- this.streamParams.putAll(params.getStreamParams());
- this.fileParams.putAll(params.getFileParams());
- this.contentEncoding = params.contentEncoding();
- }
-
- RequestBody requestBody(MediaType mediaType, AbsCallbackHandler callback){
- if (isJSON(mediaType)){
- Charset charset = mediaType.charset();
- if (charset == null){
- charset = UTF_8;
- }
- return new JSONBody(parseJSON(), charset.name());
- }
-
- if (isForm(mediaType)){
- return formBody();
- }
-
- MultipartBody.Builder builder = new MultipartBody.Builder();
- builder.setType(MultipartBody.FORM);
- //form
- for (Pair entry: urlParams){
- builder.addFormDataPart(entry.first, String.valueOf(entry.second));
- }
- //stream
- for (Map.Entry streamEntry: streamParams.entrySet()){
- builder.addPart(
- okhttp3.Headers.of("Content-Disposition",
- String.format("form-data;name=\"%s\";filename=\"%s\"", streamEntry.getKey(), streamEntry.getValue().name),
- "Content-Transfer-Encoding", "binary"),
- uploadProgressRequestBody(
- new OctetStreamBody(streamEntry.getValue().inputStream, streamEntry.getValue().contentType),
- callback));
- }
- //file
- for (Map.Entry file: fileParams.entrySet()){
- builder.addPart(uploadProgressRequestBody(
- new FileBody(file.getValue().file, file.getValue().contentType),
- callback
- ));
- }
-
- return builder.build();
- }
-
- private ProgressRequestBody uploadProgressRequestBody(RequestBody requestBody, AbsCallbackHandler callback){
- return new ProgressRequestBody(requestBody, callback);
- }
-
- private FormBody formBody(){
- FormBody.Builder builder = new FormBody.Builder();
- for (Pair entry: urlParams){
- builder.add(entry.first, String.valueOf(entry.second));
- }
- return builder.build();
- }
-
- /**
- * @return Request body media type is JSON.
- */
- private boolean isJSON(MediaType mediaType){
- return MediaTypeUtils.isJSON(mediaType) && streamParams.size() == 0
- && fileParams.size() == 0;
- }
-
- /**
- * @return Request body media type is Form.
- */
- private boolean isForm(MediaType mediaType){
- return MediaTypeUtils.isFORM(mediaType) && streamParams.size() == 0
- && fileParams.size() == 0;
- }
-
- /**
- * Request body encoding.
- */
- public RequestParams contentEncoding(@NonNull String encoding) {
- if (Charset.isSupported(encoding)){
- this.contentEncoding = encoding;
- }
- return this;
- }
-
- public String contentEncoding(){
- return contentEncoding;
- }
-
- public void put(Map params){
- if (params != null){
- for(Map.Entry entry : params.entrySet()){
- put(entry.getKey(), entry.getValue());
- }
- }
- }
-
- public void put(List> params){
- if (params != null){
- urlParams.addAll(params);
- }
- }
-
- public void put(String key, String value) {
- if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
- urlParams.add(new Pair<>(key, value));
- }
- }
-
- public void put(String key, Object value) {
- if (!TextUtils.isEmpty(key) && (value != null)) {
- if (value instanceof File){
- try {
- put(key, (File)value);
- } catch (FileNotFoundException e) {
- // Silent
- }
- } else {
- urlParams.add(new Pair<>(key, value));
- }
- }
- }
-
-
-
- public void put(String key, InputStream stream){
- put(key, stream, null);
- }
-
- public void put(String key, InputStream stream, String name){
- put(key, stream, name, null);
- }
-
- public void put(String key, InputStream stream, String name, String contentType){
- if (!TextUtils.isEmpty(key) && stream != null){
- streamParams.put(key, StreamWrapper.newInstance(stream, name, contentType));
- }
- }
-
- public void put(File file) throws FileNotFoundException {
- put(file, null);
- }
-
- public void put(File file, String contentType) throws FileNotFoundException {
- put(RequestParams.class.getSimpleName(), file, contentType);
- }
-
- public void put(String key, File file) throws FileNotFoundException {
- put(key, file, null);
- }
-
- public void put(String key, File file, String contentType) throws FileNotFoundException {
- if (file == null || !file.exists()){
- throw new FileNotFoundException();
- }
- if (!TextUtils.isEmpty(key)){
- fileParams.put(key, new FileWrapper(file, contentType));
- }
- }
-
- public void remove(String key){
- Pair removing = null;
- for (Pair entry: urlParams) {
- if (entry.first.equals(key)) {
- removing = entry;
- }
- }
- urlParams.remove(removing);
- streamParams.remove(key);
- fileParams.remove(key);
- }
-
- public boolean has(String key){
- for (Pair entry: urlParams) {
- if (entry.first.equals(key)) {
- return true;
- }
- }
- return (streamParams.containsKey(key) || fileParams.containsKey(key));
- }
-
- public boolean isEmpty(){
- return urlParams.isEmpty() && streamParams.isEmpty() && fileParams.isEmpty();
- }
-
- private String parseJSON(){
- JSONObject json = new JSONObject();
-
- String key;
- Object value;
- for (Pair entry: urlParams){
- key = entry.first;
- value = entry.second;
-
- if (key.isEmpty() || value == null){
- continue;
- }
-
- try {
- json.put(key, value);
- } catch (JSONException e) {
- // Silent
- }
- }
-
- return json.toString();
- }
-
- public ConcurrentHashMap getStreamParams() {
- return streamParams;
- }
-
- public ConcurrentHashMap getFileParams() {
- return fileParams;
- }
-
- public List> getUrlParams() {
- return urlParams;
- }
-
- public HttpUrl formatURLParams(HttpUrl url) {
- HttpUrl.Builder builder = url.newBuilder();
- if (urlParams.size() != 0) {
- for (Pair entry : urlParams) {
- try {
- builder.addEncodedQueryParameter(URLEncoder.encode(entry.first, contentEncoding),
- URLEncoder.encode(String.valueOf(entry.second), contentEncoding));
- } catch (UnsupportedEncodingException e) {
- //Silent
- }
- }
- }
- return builder.build();
- }
-
- /**
- * Format get params.
- */
- public String formatURLParams() {
- StringBuilder sb = new StringBuilder();
- if (urlParams.size() != 0) {
- for (Pair entry : urlParams) {
- String encode = "";
- try {
- encode = URLEncoder.encode(String.valueOf(entry.second), contentEncoding);
- } catch (UnsupportedEncodingException e) {
- //Silent
- }
- sb.append(entry.first).append("=").append(encode);
- sb.append("&");
- }
- sb.deleteCharAt(sb.length() - 1);
- }
-
- return sb.toString().replace(" ", "%20");
- }
-
- /**
- * Url params convert to {@link List}.
- */
- public List> getParamsList(){
- List> params = new LinkedList<>();
-
- for (Pair entry : urlParams) {
- params.add(new Pair<>(entry.first, entry.second));
- }
-
- return params;
- }
-
- public static class FileWrapper {
- public final File file;
- public final String contentType;
-
- public FileWrapper(File file, String contentType) {
- this.file = file;
- this.contentType = contentType;
- }
- }
-
- public static class StreamWrapper {
- public final InputStream inputStream;
- public final String name;
- public final String contentType;
-
- public StreamWrapper(InputStream inputStream, String name, String contentType) {
- this.inputStream = inputStream;
- this.name = name;
- this.contentType = contentType;
- }
-
- static StreamWrapper newInstance(InputStream inputStream, String name, String contentType) {
- return new StreamWrapper(
- inputStream,
- name,
- TextUtils.isEmpty(contentType) ? APPLICATION_OCTET_STREAM : contentType);
- }
- }
-}
\ No newline at end of file
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/Response.java b/mhttp/src/main/java/im/wangchao/mhttp/Response.java
deleted file mode 100644
index 8d1e16d7..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/Response.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package im.wangchao.mhttp;
-
-import okhttp3.Headers;
-import okhttp3.Protocol;
-
-/**
- * Description : MResponse.
- * Author : wangchao.
- * Date : 16/6/3.
- * Time : 下午3:03.
- */
-public final class Response {
- public final static int IO_EXCEPTION_CODE = 1000;
-
- public static Response error(Request request, int code, String message){
- if (message == null){
- message = "unknown exception.";
- }
- return new Response(request, new okhttp3.Response.Builder()
- .request(request.raw())
- .protocol(Protocol.HTTP_1_1)
- .code(code)
- .message(message)
- .build());
- }
-
- public static Response newResponse(Request request, okhttp3.Response raw){
- return new Response(request, raw);
- }
-
- private final Request request;
- private final okhttp3.Response rawResponse;
- public String parserErrorBody = null;
-
- private Response(Request request, okhttp3.Response rawResponse){
- this.request = request;
- this.rawResponse = rawResponse;
- }
-
- public Request request() {
- return request;
- }
-
- public okhttp3.Response raw() {
- return rawResponse;
- }
-
- /** HTTP status code. */
- public int code() {
- return rawResponse.code();
- }
-
- /** HTTP status message or null if unknown. */
- public String message() {
- return rawResponse.message();
- }
-
- /** HTTP headers. */
- public Headers headers() {
- return rawResponse.headers();
- }
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/ThreadMode.java b/mhttp/src/main/java/im/wangchao/mhttp/ThreadMode.java
deleted file mode 100644
index 49a23195..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/ThreadMode.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package im.wangchao.mhttp;
-
-import java.util.concurrent.Executor;
-
-import im.wangchao.mhttp.executor.BACKGROUND;
-import im.wangchao.mhttp.executor.MAIN;
-import im.wangchao.mhttp.executor.SENDING;
-
-/**
- * Description : ThreadMode.
- * Author : wangchao.
- * Date : 16/8/3.
- * Time : 下午12:44.
- */
-public enum ThreadMode {
- /**
- * Callback will be called in the same thread, which is sending the request.
- */
- SENDING{
- @Override public Executor executor() {
- return new SENDING();
- }
- },
- /**
- * Callback will be called in Android's main thread (UI thread).
- */
- MAIN{
- @Override public Executor executor() {
- return new MAIN();
- }
- },
-
- /**
- * Callback will be called in a background thread. That is, work on the request thread(okhttp thread).
- */
- BACKGROUND{
- @Override public Executor executor() {
- return new BACKGROUND();
- }
- };
-
- public abstract Executor executor();
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/URLInterceptor.java b/mhttp/src/main/java/im/wangchao/mhttp/URLInterceptor.java
deleted file mode 100644
index 739a24f2..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/URLInterceptor.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package im.wangchao.mhttp;
-
-import java.net.URL;
-
-import okhttp3.HttpUrl;
-
-/**
- * Description : URLInterceptor.
- * Author : wangchao.
- * Date : 2018/1/15.
- * Time : 上午11:01.
- */
-public interface URLInterceptor {
-
- String interceptor(String origin);
-
- HttpUrl interceptor(HttpUrl origin);
-
- URL interceptor(URL origin);
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/FileBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/FileBody.java
deleted file mode 100644
index 051dce2c..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/body/FileBody.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package im.wangchao.mhttp.body;
-
-import androidx.annotation.NonNull;
-import android.text.TextUtils;
-
-import java.io.File;
-import java.io.IOException;
-
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-import okhttp3.internal.Util;
-import okio.BufferedSink;
-import okio.Okio;
-import okio.Source;
-
-/**
- * Description : FileBody.
- * Author : wangchao.
- * Date : 16/3/8.
- * Time : 下午6:10.
- */
-public final class FileBody extends RequestBody{
- private final static MediaType CONTENT_TYPE = MediaTypeUtils.OCTET;
- private final MediaType contentType;
- private final File file;
-
- public FileBody(File file){
- this(file, null);
- }
-
- public FileBody(File file, String contentType){
- this.file = file;
- this.contentType = TextUtils.isEmpty(contentType) ? CONTENT_TYPE : MediaType.parse(contentType);
- }
-
- @Override public MediaType contentType() {
- return contentType;
- }
-
- @Override public long contentLength() throws IOException {
- return file.length();
- }
-
- @Override public void writeTo(@NonNull BufferedSink sink) throws IOException {
- Source source = null;
- try {
- source = Okio.source(file);
- sink.writeAll(source);
- } finally {
- Util.closeQuietly(source);
- }
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/JSONBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/JSONBody.java
deleted file mode 100644
index 8449625c..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/body/JSONBody.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package im.wangchao.mhttp.body;
-
-import androidx.annotation.NonNull;
-import android.text.TextUtils;
-
-import java.io.IOException;
-
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-import okio.BufferedSink;
-
-/**
- * Description : JSONBody.
- * Author : wangchao.
- * Date : 16/3/8.
- * Time : 下午4:31.
- */
-public final class JSONBody extends RequestBody{
- private final static MediaType CONTENT_TYPE = MediaTypeUtils.JSON;
- private final MediaType contentType;
- private final byte[] bytes;
-
- public JSONBody(String content){
- this(content, null);
- }
-
- public JSONBody(String content, String charset){
- if (TextUtils.isEmpty(content)){
- throw new NullPointerException("content == null");
- }
- if (TextUtils.isEmpty(charset)){
- charset = "utf-8";
- }
- this.contentType = TextUtils.isEmpty(charset) ? CONTENT_TYPE : MediaType.parse("application/json; charset=" + charset);
- bytes = content.getBytes(contentType.charset());
- }
-
- @Override public MediaType contentType() {
- return contentType;
- }
-
- @Override public long contentLength() throws IOException {
- return bytes.length;
- }
-
- @Override public void writeTo(@NonNull BufferedSink sink) throws IOException {
- sink.write(bytes, 0, bytes.length);
- }
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/MediaTypeUtils.java b/mhttp/src/main/java/im/wangchao/mhttp/body/MediaTypeUtils.java
deleted file mode 100644
index ff665962..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/body/MediaTypeUtils.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package im.wangchao.mhttp.body;
-
-import androidx.annotation.NonNull;
-import android.text.TextUtils;
-
-import okhttp3.MediaType;
-
-/**
- * Description : MediaType.
- * Author : wangchao.
- * Date : 2017/6/23.
- * Time : 下午2:15.
- */
-public final class MediaTypeUtils {
- /** MediaType String */
- public static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
- public static final String APPLICATION_JSON = "application/json; charset=utf-8";
- public static final String APPLICATION_FORM = "application/x-www-form-urlencoded";
- public static final String APPLICATION_XML = "application/xml";
-
- /** MediaType */
- public static final MediaType JSON = MediaType.parse(APPLICATION_JSON);
- public static final MediaType OCTET = MediaType.parse(APPLICATION_OCTET_STREAM);
- public static final MediaType FORM = MediaType.parse(APPLICATION_FORM);
- public static final MediaType XML = MediaType.parse(APPLICATION_XML);
- public static final MediaType DEFAULT = FORM;
-
- /**
- * 判断两个 MediaType 是否相等,只判断 type 和 subType。
- */
- public static boolean equals(@NonNull MediaType first, @NonNull MediaType second){
- String first_type_subType = first.type().concat(first.subtype());
- String second_type_subType = second.type().concat(second.subtype());
-
- return TextUtils.equals(first_type_subType, second_type_subType);
- }
-
- public static boolean isJSON(@NonNull MediaType mediaType){
- return equals(mediaType, JSON);
- }
-
- public static boolean isOCTET(@NonNull MediaType mediaType){
- return equals(mediaType, OCTET);
- }
-
- public static boolean isFORM(@NonNull MediaType mediaType){
- return equals(mediaType, FORM);
- }
-
- public static boolean isXML(@NonNull MediaType mediaType){
- return equals(mediaType, XML);
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/OctetStreamBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/OctetStreamBody.java
deleted file mode 100644
index faf1c113..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/body/OctetStreamBody.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package im.wangchao.mhttp.body;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import android.text.TextUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-import okhttp3.internal.Util;
-import okio.Buffer;
-import okio.BufferedSink;
-import okio.Okio;
-import okio.Source;
-
-/**
- * Description : OctetStreamBody.
- * Author : wangchao.
- * Date : 16/3/8.
- * Time : 下午4:31.
- */
-public final class OctetStreamBody extends RequestBody{
- private final static MediaType CONTENT_TYPE = MediaTypeUtils.OCTET;
- private final MediaType contentType;
- private final InputStream stream;
- private long contentLength = -1L;
- private Buffer buffer;
-
- public OctetStreamBody(InputStream stream){
- this(stream, null);
- }
-
- public OctetStreamBody(InputStream stream, String contentType){
- this.stream = stream;
- this.contentType = TextUtils.isEmpty(contentType) ? CONTENT_TYPE : MediaType.parse(contentType);
- }
-
- @Override public MediaType contentType() {
- return contentType;
- }
-
- @Override public long contentLength() throws IOException {
- long result = contentLength;
- if (result != -1L) return result;
- return contentLength = writeOrCountBytes(null, true);
- }
-
- @Override public void writeTo(@NonNull BufferedSink sink) throws IOException {
- contentLength = writeOrCountBytes(sink, false);
- }
-
- private long writeOrCountBytes(@Nullable BufferedSink sink, boolean countBytes) throws IOException{
- long byteCount = 0L;
-
- if (countBytes) {
- buffer = new Buffer();
- Source source = null;
- try {
- source = Okio.source(stream);
- buffer.writeAll(source);
- } finally {
- Util.closeQuietly(source);
- }
-
- byteCount = buffer.size();
-
- return byteCount;
- } else {
- if (sink == null){
- return byteCount;
- }
- Source source = null;
- try {
- source = Okio.source(buffer == null ? stream : buffer.inputStream());
- return sink.writeAll(source);
- } finally {
- if (buffer != null){
- buffer.clear();
- }
- Util.closeQuietly(source);
- }
- }
-
- }
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/body/ProgressRequestBody.java b/mhttp/src/main/java/im/wangchao/mhttp/body/ProgressRequestBody.java
deleted file mode 100644
index 2ea2b901..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/body/ProgressRequestBody.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package im.wangchao.mhttp.body;
-
-import androidx.annotation.NonNull;
-
-import java.io.IOException;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-import okio.Buffer;
-import okio.BufferedSink;
-import okio.ForwardingSink;
-import okio.Okio;
-import okio.Sink;
-
-/**
- * Description : ProgressRequestBody.
- * Author : wangchao.
- * Date : 2018/1/30.
- * Time : 下午8:25.
- */
-public class ProgressRequestBody extends RequestBody {
-
- private final RequestBody mRequestBody;
- private final AbsCallbackHandler mCallback;
- private BufferedSink mBufferedSink;
-
- public ProgressRequestBody(RequestBody requestBody, AbsCallbackHandler callback){
- this.mRequestBody = requestBody;
- this.mCallback = callback;
- }
-
- @Override public MediaType contentType() {
- return mRequestBody.contentType();
- }
-
- @Override public long contentLength() throws IOException {
- return mRequestBody.contentLength();
- }
-
- @Override public void writeTo(@NonNull BufferedSink sink) throws IOException {
- if (mCallback == null){
- mRequestBody.writeTo(sink);
- return;
- }
- if (mBufferedSink == null){
- mBufferedSink = Okio.buffer(forward(sink));
- }
-
- mRequestBody.writeTo(mBufferedSink);
- mBufferedSink.flush();
- }
-
- private Sink forward(Sink sink){
- return new ForwardingSink(sink) {
- private long bytesWritten = 0L;
- private long contentLength = 0L;
-
- @Override public void write(@NonNull Buffer source, long byteCount) throws IOException {
- super.write(source, byteCount);
- if (contentLength == 0) {
- contentLength = contentLength();
- }
- bytesWritten += byteCount;
-
- mCallback.sendUploadProgressEvent((int) bytesWritten, (int) contentLength);
- }
- };
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/BinaryCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/BinaryCallbackHandler.java
deleted file mode 100644
index 05b763b9..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/callback/BinaryCallbackHandler.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package im.wangchao.mhttp.callback;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Accept;
-import im.wangchao.mhttp.Response;
-
-/**
- * Description : BinaryResponseHandler.
- * Author : wangchao.
- * Date : 15/10/18.
- * Time : 下午2:49.
- */
-public class BinaryCallbackHandler extends AbsCallbackHandler {
-
- @Override public void onSuccess(byte[] data, Response response) {
-
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
-
- }
-
- @Override public byte[] backgroundParser(Response response) throws Exception {
- return response.raw().body().bytes();
- }
-
- @Override public String accept() {
- return Accept.ACCEPT_DATA;
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/BitmapCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/BitmapCallbackHandler.java
deleted file mode 100644
index 3193703f..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/callback/BitmapCallbackHandler.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package im.wangchao.mhttp.callback;
-
-import android.graphics.Bitmap;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Accept;
-import im.wangchao.mhttp.Response;
-
-/**
- * Description : ImageResponseHandler.
- * Author : wangchao.
- * Date : 15/10/18.
- * Time : 下午2:49.
- */
-public abstract class BitmapCallbackHandler extends AbsCallbackHandler {
- @Override public void onSuccess(Bitmap bitmap, Response response) {
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
-
- }
-
- @Override public String accept() {
- return Accept.ACCEPT_IMAGE;
- }
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/CustomCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/CustomCallbackHandler.java
deleted file mode 100644
index 537cb735..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/callback/CustomCallbackHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package im.wangchao.mhttp.callback;
-
-import im.wangchao.mhttp.Response;
-import im.wangchao.mhttp.internal.exception.ParserException;
-
-/**
- * Description : GSONResponseHandler.
- * Author : wangchao.
- * Date : 16/3/20.
- * Time : 上午9:06.
- */
-public abstract class CustomCallbackHandler extends TextCallbackHandler {
-
- @Override final public void onSuccess(String data, Response response) {
- if (data != null) {
- onSuccess(parser(data));
- }
- else {
- onFailure(response, new ParserException());
- }
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
-
- }
-
- /** parser Json to T */
- protected abstract T parser(String data);
-
- public void onSuccess(T t){
-
- }
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/FileCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/FileCallbackHandler.java
deleted file mode 100644
index 796ec1cf..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/callback/FileCallbackHandler.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package im.wangchao.mhttp.callback;
-
-import android.content.Context;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URLDecoder;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Accept;
-import im.wangchao.mhttp.Response;
-import okhttp3.internal.Util;
-
-/**
- * Description : FileResponseHandler.
- * Author : wangchao.
- * Date : 15/10/18.
- * Time : 下午2:39.
- */
-public class FileCallbackHandler extends AbsCallbackHandler {
- private File file;
- final private static int BUFFER_SIZE = 4096;
-
- public FileCallbackHandler(Context context){
- this.file = getTempFile(context);
- }
-
- public FileCallbackHandler(File file){
- this.file = file;
- }
-
- protected File getFile(){
- return file;
- }
-
- @Override public void onSuccess(File file, Response response){
-
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
-
- }
-
- @Override public File backgroundParser(Response response) throws IOException{
- writeFile(response.raw(), file);
- return file;
- }
-
- @Override public String accept() {
- return Accept.ACCEPT_FILE;
- }
-
- private File getTempFile(Context context){
- try {
- return File.createTempFile("temp", "_handled", context.getCacheDir());
- } catch (IOException e) {
- return null;
- }
- }
-
- /**
- * write file , send progress message
- */
- protected void writeFile(okhttp3.Response response, File file) throws IOException {
- if (file == null){
- throw new IllegalArgumentException("File == null");
- }
- if (this.file.isDirectory()) {
- String contentDisposition = response.header("content-disposition");
- if (contentDisposition != null) {
- if (contentDisposition.contains("*=UTF-8")) {
- contentDisposition = contentDisposition.replace("*=UTF-8''", "\"") + "\"";
- contentDisposition = URLDecoder.decode(contentDisposition, "UTF-8");
- }
- String filename = contentDisposition.substring(contentDisposition.indexOf("\"") + 1, contentDisposition.lastIndexOf("\""));
- this.file = new File(file, filename);
- file = this.file;
- }
- }
- InputStream instream = response.body().byteStream();
- long contentLength = response.body().contentLength();
- FileOutputStream buffer = new FileOutputStream(file);
- if (instream != null) {
- try {
- byte[] tmp = new byte[BUFFER_SIZE];
- int l;
- long count = 0;
- while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) {
- count += l;
- buffer.write(tmp, 0, l);
-
- sendProgressEvent(count, contentLength);
- }
- } finally {
- Util.closeQuietly(instream);
- buffer.flush();
- Util.closeQuietly(buffer);
- }
- }
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonArrayCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonArrayCallbackHandler.java
deleted file mode 100644
index c417e097..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonArrayCallbackHandler.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package im.wangchao.mhttp.callback;
-
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Accept;
-import im.wangchao.mhttp.Response;
-
-public class JsonArrayCallbackHandler extends AbsCallbackHandler {
-
- @Override public void onSuccess(JsonArray data, Response response) {
-
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
-
- }
-
- @Override public JsonArray backgroundParser(Response response) throws Exception {
- try {
- byte[] body = response.raw().body().bytes();
- String bodyString = byteArrayToString(body);
- JsonArray object = new JsonParser().parse(bodyString).getAsJsonArray();
- return object;
- }
- catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override public String accept() {
- return Accept.ACCEPT_JSON;
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonCallbackHandler.java
deleted file mode 100644
index 2c16e9eb..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/callback/JsonCallbackHandler.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package im.wangchao.mhttp.callback;
-
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Accept;
-import im.wangchao.mhttp.Response;
-
-/**
- * Description : JSONResponseHandler.
- * Author : wangchao.
- * Date : 15/10/18.
- * Time : 下午2:25.
- */
-public class JsonCallbackHandler extends AbsCallbackHandler {
-
- @Override public void onSuccess(JsonObject data, Response response) {
-
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
-
- }
-
- @Override public JsonObject backgroundParser(Response response) throws Exception {
- try {
- byte[] body = response.raw().body().bytes();
- String bodyString = byteArrayToString(body);
- try {
- return new JsonParser().parse(bodyString).getAsJsonObject();
- }
- catch (Exception e) {
- e.printStackTrace();
- response.parserErrorBody = bodyString;
- return null;
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override public String accept() {
- return Accept.ACCEPT_JSON;
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/callback/TextCallbackHandler.java b/mhttp/src/main/java/im/wangchao/mhttp/callback/TextCallbackHandler.java
deleted file mode 100644
index a7781c2e..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/callback/TextCallbackHandler.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package im.wangchao.mhttp.callback;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Accept;
-import im.wangchao.mhttp.Response;
-
-/**
- * Description : TextResponseHandler.
- * Author : wangchao.
- * Date : 15/10/18.
- * Time : 下午2:41.
- */
-public class TextCallbackHandler extends AbsCallbackHandler {
- @Override public void onSuccess(String data, Response response) {
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
- }
-
- @Override public String backgroundParser(Response response) throws Exception {
- return byteArrayToString(response.raw().body().bytes());
- }
-
- @Override public String accept() {
- return Accept.ACCEPT_TEXT;
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/executor/BACKGROUND.java b/mhttp/src/main/java/im/wangchao/mhttp/executor/BACKGROUND.java
deleted file mode 100644
index 20eecd41..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/executor/BACKGROUND.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package im.wangchao.mhttp.executor;
-
-import androidx.annotation.NonNull;
-
-import java.util.concurrent.Executor;
-
-/**
- * Description : BACKGROUND.
- * Author : wangchao.
- * Date : 16/9/2.
- * Time : 下午4:50.
- */
-public final class BACKGROUND implements Executor {
- @Override public void execute(@NonNull Runnable command) {
- command.run();
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/executor/MAIN.java b/mhttp/src/main/java/im/wangchao/mhttp/executor/MAIN.java
deleted file mode 100644
index 57785d2d..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/executor/MAIN.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package im.wangchao.mhttp.executor;
-
-import android.os.Handler;
-import android.os.Looper;
-import androidx.annotation.NonNull;
-
-import java.util.concurrent.Executor;
-
-/**
- * Description : MainThread.
- * Author : wangchao.
- * Date : 16/9/2.
- * Time : 下午4:45.
- */
-public final class MAIN implements Executor{
- private final Handler handler = new Handler(Looper.getMainLooper());
-
- @Override public void execute(@NonNull Runnable command) {
- handler.post(command);
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/executor/SENDING.java b/mhttp/src/main/java/im/wangchao/mhttp/executor/SENDING.java
deleted file mode 100644
index 5960bf4e..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/executor/SENDING.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package im.wangchao.mhttp.executor;
-
-import android.os.Handler;
-import android.os.Looper;
-import androidx.annotation.NonNull;
-
-import java.util.concurrent.Executor;
-
-/**
- * Description : SENDING.
- * Author : wangchao.
- * Date : 16/9/2.
- * Time : 下午4:47.
- */
-public final class SENDING implements Executor {
- private final Handler handler;
- public SENDING(){
- if (Looper.myLooper() == null){
- throw new RuntimeException("The Looper of the current thread is null, please call Looper.prepare() on your thread.");
- }
- handler = new Handler(Looper.myLooper());
- }
-
- @Override public void execute(@NonNull Runnable command) {
- handler.post(command);
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/Singleton.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/Singleton.java
deleted file mode 100644
index 2a351d6f..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/Singleton.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package im.wangchao.mhttp.internal;
-
-/**
- * Description : Singleton.
- * Author : wangchao.
- * Date : 16/8/25.
- * Time : 上午10:37.
- */
-public abstract class Singleton {
- private T instance;
-
- protected abstract T create();
-
- public T get(){
- if (instance == null){
- synchronized (this){
- if (instance == null){
- instance = create();
- }
- }
- }
-
- return instance;
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/Version.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/Version.java
deleted file mode 100644
index 847fe87e..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/Version.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package im.wangchao.mhttp.internal;
-
-/**
- * Description : Version.
- * Author : wangchao.
- * Date : 16/8/24.
- * Time : 下午2:47.
- */
-public class Version {
- private Version(){
- throw new AssertionError();
- }
-
- public static String userAgent() {
- return moduleName().concat("1.10.1");
- }
-
- public static String moduleName() {
- return "mhttp";
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/ClearableCookieJar.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/ClearableCookieJar.java
deleted file mode 100644
index 61c6e2ae..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/ClearableCookieJar.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie;
-
-import okhttp3.CookieJar;
-
-public interface ClearableCookieJar extends CookieJar {
-
- void clear();
- void clearForDomain(String domain);
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/MemoryCookieJar.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/MemoryCookieJar.java
deleted file mode 100644
index 34ff5235..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/MemoryCookieJar.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package im.wangchao.mhttp.internal.cookie;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import im.wangchao.mhttp.internal.cookie.cache.CookieCache;
-import okhttp3.Cookie;
-import okhttp3.HttpUrl;
-
-/**
- * Description : MemeryCookieJar.
- * Author : wangchao.
- * Date : 16/3/18.
- * Time : 下午2:20.
- */
-public class MemoryCookieJar implements ClearableCookieJar {
-
- private CookieCache cache;
-
- public MemoryCookieJar(CookieCache cache) {
- this.cache = cache;
- }
-
- @Override
- synchronized public void saveFromResponse(HttpUrl url, List cookies) {
- cache.addAll(cookies);
- }
-
- @Override
- synchronized public List loadForRequest(HttpUrl url) {
- List validCookies = new ArrayList<>();
-
- for (Iterator it = cache.iterator(); it.hasNext(); ) {
- Cookie currentCookie = it.next();
-
- if (isCookieExpired(currentCookie)) {
- it.remove();
-
- } else if (currentCookie.matches(url)) {
- validCookies.add(currentCookie);
- }
- }
-
-
- return validCookies;
- }
-
- private static boolean isCookieExpired(Cookie cookie) {
- return cookie.expiresAt() < System.currentTimeMillis();
- }
-
- synchronized public void clear() {
- cache.clear();
- }
-
- synchronized public void clearForDomain(String domain) {
- cache.clearForDomain(domain);
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java
deleted file mode 100644
index 3a6b5a8c..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie;
-
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import im.wangchao.mhttp.internal.cookie.cache.CookieCache;
-import im.wangchao.mhttp.internal.cookie.persistence.CookiePersistor;
-import okhttp3.Cookie;
-import okhttp3.HttpUrl;
-
-public class PersistentCookieJar implements ClearableCookieJar {
-
- private CookieCache cache;
- private CookiePersistor persistor;
-
- public PersistentCookieJar(CookieCache cache, CookiePersistor persistor) {
- this.cache = cache;
- this.persistor = persistor;
-
- this.cache.addAll(persistor.loadAll());
- }
-
- @Override
- synchronized public void saveFromResponse(@Nullable HttpUrl url, List cookies) {
- // cookies need to be reversed, in order to replace old cookies with these coming later
- // (if there are duplicate cookies in the same response)
- List reverseCookies = new ArrayList<>(cookies);
- Collections.reverse(reverseCookies);
- cache.addAll(reverseCookies);
- persistor.saveAll(reverseCookies);
- }
-
- @NonNull
- @Override
- synchronized public List loadForRequest(HttpUrl url) {
- List removedCookies = new ArrayList<>();
- List validCookies = new ArrayList<>();
-
- for (Iterator it = cache.iterator(); it.hasNext(); ) {
- Cookie currentCookie = it.next();
- if (isCookieExpired(currentCookie)) {
- removedCookies.add(currentCookie);
- it.remove();
-
- } else if (currentCookie.matches(url)) {
- validCookies.add(currentCookie);
- }
- }
-
- persistor.removeAll(removedCookies);
-
- return validCookies;
- }
-
- @NonNull
- synchronized public List getForDomain(String domain) {
- List removedCookies = new ArrayList<>();
- List validCookies = new ArrayList<>();
-
- for (Iterator it = cache.iterator(); it.hasNext(); ) {
- Cookie currentCookie = it.next();
- if (isCookieExpired(currentCookie)) {
- removedCookies.add(currentCookie);
- it.remove();
-
- } else if (domain.equals(currentCookie.domain())) {
- validCookies.add(currentCookie);
- }
- }
-
- persistor.removeAll(removedCookies);
-
- return validCookies;
- }
-
- @Nullable
- synchronized public String getCookie(String domain, String name) {
- String cookieValue = null;
- List removedCookies = new ArrayList<>();
-
- for (Iterator it = cache.iterator(); it.hasNext(); ) {
- Cookie currentCookie = it.next();
- if (isCookieExpired(currentCookie)) {
- removedCookies.add(currentCookie);
- it.remove();
-
- } else if (domain.equals(currentCookie.domain()) && name.equals(currentCookie.name())) {
- cookieValue = currentCookie.value();
- break;
- }
- }
-
- persistor.removeAll(removedCookies);
-
- return cookieValue;
- }
-
- private static boolean isCookieExpired(Cookie cookie) {
- return cookie.expiresAt() < System.currentTimeMillis();
- }
-
- synchronized public void clear() {
- cache.clear();
- persistor.clear();
- }
-
- synchronized public void clearForDomain(String domain) {
- cache.clearForDomain(domain);
- persistor.clearForDomain(domain);
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/CookieCache.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/CookieCache.java
deleted file mode 100644
index 5b1de024..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/CookieCache.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie.cache;
-
-import java.util.Collection;
-
-import okhttp3.Cookie;
-
-public interface CookieCache extends Iterable {
-
- /**
- * Add all the new cookies to the session, existing cookies will be overwritten.
- *
- * @param cookies
- */
- void addAll(Collection cookies);
-
- /**
- * Clear all the cookies from the session.
- */
- void clear();
-
- void clearForDomain(String domain);
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/IdentifiableCookie.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/IdentifiableCookie.java
deleted file mode 100644
index e10d269b..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/IdentifiableCookie.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie.cache;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import okhttp3.Cookie;
-
-/**
- * This class decorates a Cookie to re-implements equals() and hashcode() methods in order to identify
- * the cookie by the following attributes: name, domain, path, secure & hostOnly.
- *
- * This new behaviour will be useful in determining when an already existing cookie in session must be overwritten.
- */
-class IdentifiableCookie {
-
- private Cookie cookie;
-
- static List decorateAll(Collection cookies) {
- List identifiableCookies = new ArrayList<>(cookies.size());
- for (Cookie cookie : cookies) {
- identifiableCookies.add(new IdentifiableCookie(cookie));
- }
- return identifiableCookies;
- }
-
- IdentifiableCookie(Cookie cookie) {
- this.cookie = cookie;
- }
-
- Cookie getCookie() {
- return cookie;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof IdentifiableCookie)) return false;
- IdentifiableCookie that = (IdentifiableCookie) other;
- return that.cookie.name().equals(this.cookie.name())
- && that.cookie.domain().equals(this.cookie.domain())
- && that.cookie.path().equals(this.cookie.path())
- && that.cookie.secure() == this.cookie.secure()
- && that.cookie.hostOnly() == this.cookie.hostOnly();
- }
-
- @Override
- public int hashCode() {
- int hash = 17;
- if (cookie == null)
- return hash;
- hash = 31 * hash + cookie.name().hashCode();
- hash = 31 * hash + cookie.domain().hashCode();
- hash = 31 * hash + cookie.path().hashCode();
- hash = 31 * hash + (cookie.secure() ? 0 : 1);
- hash = 31 * hash + (cookie.hostOnly() ? 0 : 1);
- return hash;
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/SetCookieCache.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/SetCookieCache.java
deleted file mode 100644
index 136df502..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/cache/SetCookieCache.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie.cache;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import okhttp3.Cookie;
-
-public class SetCookieCache implements CookieCache {
-
- private Set cookies;
-
- public SetCookieCache() {
- cookies = new HashSet<>();
- }
-
- @Override
- public void addAll(Collection newCookies) {
- updateCookies(IdentifiableCookie.decorateAll(newCookies));
- }
-
- /**
- * All cookies will be added to the collection, already existing cookies will be overwritten by the new ones.
- *
- * @param cookies
- */
- private void updateCookies(Collection cookies) {
- this.cookies.removeAll(cookies);
- this.cookies.addAll(cookies);
- }
-
- @Override
- public void clear() {
- cookies.clear();
- }
-
- @Override
- public void clearForDomain(String domain) {
- Collection removeCookies = new ArrayList<>();
- for (IdentifiableCookie cookie: cookies) {
- if (cookie.getCookie().domain().equals(domain)) {
- removeCookies.add(cookie);
- }
- }
- cookies.removeAll(removeCookies);
- }
-
- @Override
- public Iterator iterator() {
- return new SetCookieCacheIterator();
- }
-
- private class SetCookieCacheIterator implements Iterator {
-
- private Iterator iterator;
-
- public SetCookieCacheIterator() {
- iterator = cookies.iterator();
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
-
- @Override
- public Cookie next() {
- return iterator.next().getCookie();
- }
-
- @Override
- public void remove() {
- iterator.remove();
- }
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/CookiePersistor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/CookiePersistor.java
deleted file mode 100644
index 1346c662..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/CookiePersistor.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie.persistence;
-
-import java.util.Collection;
-import java.util.List;
-
-import okhttp3.Cookie;
-
-public interface CookiePersistor {
-
- List loadAll();
-
- /**
- * Persist all cookies, existing cookies will be overwritten.
- *
- * @param cookies cookies persist
- */
- void saveAll(Collection cookies);
-
- /**
- * Removes indicated cookies from persistence.
- *
- * @param cookies cookies to remove from persistence
- */
- void removeAll(Collection cookies);
-
- /**
- * Clear all cookies from persistence.
- */
- void clear();
-
- /**
- * Clear all cookies from persistence for specified url.
- *
- * @param domain domain name
- */
- void clearForDomain(String domain);
-
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SerializableCookie.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SerializableCookie.java
deleted file mode 100644
index bce2efe8..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SerializableCookie.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie.persistence;
-
-import android.util.Log;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-
-import okhttp3.Cookie;
-
-public class SerializableCookie implements Serializable {
- private static final String TAG = SerializableCookie.class
- .getSimpleName();
-
- private transient Cookie cookie;
-
- public String encode(Cookie cookie) {
- this.cookie = cookie;
-
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- try {
- ObjectOutputStream outputStream = new ObjectOutputStream(os);
- outputStream.writeObject(this);
- } catch (IOException e) {
- Log.d(TAG, "IOException in encodeCookie", e);
- return null;
- }
-
- return byteArrayToHexString(os.toByteArray());
- }
-
- /**
- * Using some super basic byte array <-> hex conversions so we don't
- * have to rely on any large Base64 libraries. Can be overridden if you
- * like!
- *
- * @param bytes byte array to be converted
- * @return string containing hex values
- */
- private static String byteArrayToHexString(byte[] bytes) {
- StringBuilder sb = new StringBuilder(bytes.length * 2);
- for (byte element : bytes) {
- int v = element & 0xff;
- if (v < 16) {
- sb.append('0');
- }
- sb.append(Integer.toHexString(v));
- }
- return sb.toString();
- }
-
- public Cookie decode(String encodedCookie) {
- byte[] bytes = hexStringToByteArray(encodedCookie);
- ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
- bytes);
- Cookie cookie = null;
- try {
- ObjectInputStream objectInputStream = new ObjectInputStream(
- byteArrayInputStream);
- cookie = ((SerializableCookie) objectInputStream.readObject()).cookie;
- } catch (IOException e) {
- Log.d(TAG, "IOException in decodeCookie", e);
- } catch (ClassNotFoundException e) {
- Log.d(TAG, "ClassNotFoundException in decodeCookie", e);
- }
- return cookie;
- }
-
- /**
- * Converts hex values from strings to byte array
- *
- * @param hexString string of hex-encoded values
- * @return decoded byte array
- */
- private static byte[] hexStringToByteArray(String hexString) {
- int len = hexString.length();
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
- .digit(hexString.charAt(i + 1), 16));
- }
- return data;
- }
-
- private static long NON_VALID_EXPIRES_AT = -1l;
-
- private void writeObject(ObjectOutputStream out) throws IOException {
- out.writeObject(cookie.name());
- out.writeObject(cookie.value());
- out.writeLong(cookie.persistent() ? cookie.expiresAt() : NON_VALID_EXPIRES_AT);
- out.writeObject(cookie.domain());
- out.writeObject(cookie.path());
- out.writeBoolean(cookie.secure());
- out.writeBoolean(cookie.httpOnly());
- out.writeBoolean(cookie.hostOnly());
- }
-
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- Cookie.Builder builder = new Cookie.Builder();
-
- builder.name((String) in.readObject());
-
- builder.value((String) in.readObject());
-
- long expiresAt = in.readLong();
- if (expiresAt != NON_VALID_EXPIRES_AT) {
- builder.expiresAt(expiresAt);
- }
-
- final String domain = (String) in.readObject();
- builder.domain(domain);
-
- builder.path((String) in.readObject());
-
- if (in.readBoolean())
- builder.secure();
-
- if (in.readBoolean())
- builder.httpOnly();
-
- if (in.readBoolean())
- builder.hostOnlyDomain(domain);
-
- cookie = builder.build();
- }
-
-}
\ No newline at end of file
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SharedPrefsCookiePersistor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SharedPrefsCookiePersistor.java
deleted file mode 100644
index b1f82a09..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/persistence/SharedPrefsCookiePersistor.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 Francisco José Montiel Navarro.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.wangchao.mhttp.internal.cookie.persistence;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import okhttp3.Cookie;
-
-public class SharedPrefsCookiePersistor implements CookiePersistor {
-
- private SharedPreferences sharedPreferences;
-
- public SharedPrefsCookiePersistor(Context context) {
- final String SHARED_PREFERENCES_NAME = "cookies";
-
- sharedPreferences =
- context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
- }
-
- @Override
- public List loadAll() {
- List cookies = new ArrayList<>();
-
- for (Map.Entry entry : sharedPreferences.getAll().entrySet()) {
- String serializedCookie = (String) entry.getValue();
- Cookie cookie = new SerializableCookie().decode(serializedCookie);
- cookies.add(cookie);
- }
- return cookies;
- }
-
- @Override
- public void saveAll(Collection cookies) {
- SharedPreferences.Editor editor = sharedPreferences.edit();
- for (Cookie cookie : cookies) {
- if (cookie.persistent()) {
- editor.putString(createCookieKey(cookie), new SerializableCookie().encode(cookie));
- }
- }
- editor.apply();
- }
-
- @Override
- public void removeAll(Collection cookies) {
- SharedPreferences.Editor editor = sharedPreferences.edit();
- for (Cookie cookie : cookies) {
- editor.remove(createCookieKey(cookie));
- }
- editor.apply();
- }
-
- private static String createCookieKey(Cookie cookie) {
- return (cookie.secure() ? "https" : "http") + "://" + cookie.domain() + cookie.path() + "|" + cookie.name();
- }
-
- @Override
- public void clear() {
- sharedPreferences.edit().clear().apply();
- }
-
- @Override
- public void clearForDomain(String domain) {
- List cookies = loadAll();
- SharedPreferences.Editor editor = sharedPreferences.edit();
- for (Cookie cookie : cookies) {
- if (cookie.domain().equals(domain))
- editor.remove(createCookieKey(cookie));
- }
- editor.apply();
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ParserException.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ParserException.java
deleted file mode 100644
index 2b12087a..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ParserException.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package im.wangchao.mhttp.internal.exception;
-
-/**
- * Description : ParserException.
- * Author : wangchao.
- * Date : 16/4/26.
- * Time : 下午8:38.
- */
-public class ParserException extends Exception{
- public ParserException(){
- super("Response parse exception.");
- }
-
- public ParserException(Throwable cause) {
- super("Response parse exception.", cause);
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ResponseFailException.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ResponseFailException.java
deleted file mode 100644
index bb985e37..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/exception/ResponseFailException.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package im.wangchao.mhttp.internal.exception;
-
-/**
- * Description : ResponseFailException.
- * Author : wangchao.
- * Date : 16/4/25.
- * Time : 下午4:06.
- */
-public class ResponseFailException extends Exception{
- //Response Non Successful
- public ResponseFailException(){
- super("Response failure exception.");
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/HttpLoggingInterceptor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/HttpLoggingInterceptor.java
deleted file mode 100644
index 0ba2658a..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/HttpLoggingInterceptor.java
+++ /dev/null
@@ -1,320 +0,0 @@
-package im.wangchao.mhttp.internal.interceptor;
-
-/*
- * Copyright (C) 2015 Square, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.concurrent.TimeUnit;
-
-import okhttp3.Connection;
-import okhttp3.Headers;
-import okhttp3.Interceptor;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import okhttp3.ResponseBody;
-import okhttp3.internal.http.HttpHeaders;
-import okhttp3.internal.platform.Platform;
-import okio.Buffer;
-import okio.BufferedSource;
-import okio.GzipSource;
-
-import static okhttp3.internal.platform.Platform.INFO;
-
-/**
- * An OkHttp interceptor which logs request and response information. Can be applied as an
- * {@linkplain OkHttpClient#interceptors() application interceptor} or as a {@linkplain
- * OkHttpClient#networkInterceptors() network interceptor}. The format of the logs created by
- * this class should not be considered stable and may change slightly between releases. If you need
- * a stable logging format, use your own interceptor.
- */
-public final class HttpLoggingInterceptor implements Interceptor {
- private static final Charset UTF8 = Charset.forName("UTF-8");
-
- public enum Level {
- /** No logs. */
- NONE,
- /**
- * Logs request and response lines.
- *
- *
Example:
- *
{@code
- * --> POST /greeting http/1.1 (3-byte body)
- *
- * <-- 200 OK (22ms, 6-byte body)
- * }
- */
- BASIC,
- /**
- * Logs request and response lines and their respective headers.
- *
- * Example:
- *
{@code
- * --> POST /greeting http/1.1
- * Host: example.com
- * Content-Type: plain/text
- * Content-Length: 3
- * --> END POST
- *
- * <-- 200 OK (22ms)
- * Content-Type: plain/text
- * Content-Length: 6
- * <-- END HTTP
- * }
- */
- HEADERS,
- /**
- * Logs request and response lines and their respective headers and bodies (if present).
- *
- * Example:
- *
{@code
- * --> POST /greeting http/1.1
- * Host: example.com
- * Content-Type: plain/text
- * Content-Length: 3
- *
- * Hi?
- * --> END POST
- *
- * <-- 200 OK (22ms)
- * Content-Type: plain/text
- * Content-Length: 6
- *
- * Hello!
- * <-- END HTTP
- * }
- */
- BODY
- }
-
- public interface Logger {
- void log(String message);
-
- /** A {@link Logger} defaults output appropriate for the current platform. */
- Logger DEFAULT = new Logger() {
- @Override public void log(String message) {
- Platform.get().log(INFO, message, null);
- }
- };
- }
-
- public HttpLoggingInterceptor() {
- this(Logger.DEFAULT);
- }
-
- public HttpLoggingInterceptor(Logger logger) {
- this.logger = logger;
- }
-
- private final Logger logger;
-
- private volatile Level level = Level.NONE;
-
- /** Change the level at which this interceptor logs. */
- public HttpLoggingInterceptor setLevel(Level level) {
- if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead.");
- this.level = level;
- return this;
- }
-
- public Level getLevel() {
- return level;
- }
-
- @Override public Response intercept(Chain chain) throws IOException {
- Level level = this.level;
-
- Request request = chain.request();
- if (level == Level.NONE) {
- return chain.proceed(request);
- }
-
- boolean logBody = level == Level.BODY;
- boolean logHeaders = logBody || level == Level.HEADERS;
-
- RequestBody requestBody = request.body();
- boolean hasRequestBody = requestBody != null;
-
- Connection connection = chain.connection();
- String requestStartMessage = "--> "
- + request.method()
- + ' ' + request.url()
- + (connection != null ? " " + connection.protocol() : "");
- if (!logHeaders && hasRequestBody) {
- requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
- }
- logger.log(requestStartMessage);
-
- if (logHeaders) {
- if (hasRequestBody) {
- // Request body headers are only present when installed as a network interceptor. Force
- // them to be included (when available) so there values are known.
- if (requestBody.contentType() != null) {
- logger.log("Content-Type: " + requestBody.contentType());
- }
- if (requestBody.contentLength() != -1) {
- logger.log("Content-Length: " + requestBody.contentLength());
- }
- }
-
- Headers headers = request.headers();
- for (int i = 0, count = headers.size(); i < count; i++) {
- String name = headers.name(i);
- // Skip headers from the request body as they are explicitly logged above.
- if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
- logger.log(name + ": " + headers.value(i));
- }
- }
-
- if (!logBody || !hasRequestBody) {
- logger.log("--> END " + request.method());
- } else if (bodyHasUnknownEncoding(request.headers())) {
- logger.log("--> END " + request.method() + " (encoded body omitted)");
- } else {
- Buffer buffer = new Buffer();
- requestBody.writeTo(buffer);
-
- Charset charset = UTF8;
- MediaType contentType = requestBody.contentType();
- if (contentType != null) {
- charset = contentType.charset(UTF8);
- }
-
- logger.log("");
- if (isPlaintext(buffer)) {
- logger.log(buffer.readString(charset));
- logger.log("--> END " + request.method()
- + " (" + requestBody.contentLength() + "-byte body)");
- } else {
- logger.log("--> END " + request.method() + " (binary "
- + requestBody.contentLength() + "-byte body omitted)");
- }
- }
- }
-
- long startNs = System.nanoTime();
- Response response;
- try {
- response = chain.proceed(request);
- } catch (Exception e) {
- logger.log("<-- HTTP FAILED: " + e);
- throw e;
- }
- long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
-
- ResponseBody responseBody = response.body();
- long contentLength = responseBody.contentLength();
- String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
- logger.log("<-- "
- + response.code()
- + (response.message().isEmpty() ? "" : ' ' + response.message())
- + ' ' + response.request().url()
- + " (" + tookMs + "ms" + (!logHeaders ? ", " + bodySize + " body" : "") + ')');
-
- if (logHeaders) {
- Headers headers = response.headers();
- for (int i = 0, count = headers.size(); i < count; i++) {
- logger.log(headers.name(i) + ": " + headers.value(i));
- }
-
- if (!logBody || !HttpHeaders.hasBody(response)) {
- logger.log("<-- END HTTP");
- } else if (bodyHasUnknownEncoding(response.headers())) {
- logger.log("<-- END HTTP (encoded body omitted)");
- } else {
- BufferedSource source = responseBody.source();
- source.request(Long.MAX_VALUE); // Buffer the entire body.
- Buffer buffer = source.buffer();
-
- Long gzippedLength = null;
- if ("gzip".equalsIgnoreCase(headers.get("Content-Encoding"))) {
- gzippedLength = buffer.size();
- GzipSource gzippedResponseBody = null;
- try {
- gzippedResponseBody = new GzipSource(buffer.clone());
- buffer = new Buffer();
- buffer.writeAll(gzippedResponseBody);
- } finally {
- if (gzippedResponseBody != null) {
- gzippedResponseBody.close();
- }
- }
- }
-
- Charset charset = UTF8;
- MediaType contentType = responseBody.contentType();
- if (contentType != null) {
- charset = contentType.charset(UTF8);
- }
-
- if (!isPlaintext(buffer)) {
- logger.log("");
- logger.log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)");
- return response;
- }
-
- if (contentLength != 0) {
- logger.log("");
- logger.log(buffer.clone().readString(charset));
- }
-
- if (gzippedLength != null) {
- logger.log("<-- END HTTP (" + buffer.size() + "-byte, "
- + gzippedLength + "-gzipped-byte body)");
- } else {
- logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");
- }
- }
- }
-
- return response;
- }
-
- /**
- * Returns true if the body in question probably contains human readable text. Uses a small sample
- * of code points to detect unicode control characters commonly used in binary file signatures.
- */
- static boolean isPlaintext(Buffer buffer) {
- try {
- Buffer prefix = new Buffer();
- long byteCount = buffer.size() < 64 ? buffer.size() : 64;
- buffer.copyTo(prefix, 0, byteCount);
- for (int i = 0; i < 16; i++) {
- if (prefix.exhausted()) {
- break;
- }
- int codePoint = prefix.readUtf8CodePoint();
- if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
- return false;
- }
- }
- return true;
- } catch (EOFException e) {
- return false; // Truncated UTF-8 sequence.
- }
- }
-
- private boolean bodyHasUnknownEncoding(Headers headers) {
- String contentEncoding = headers.get("Content-Encoding");
- return contentEncoding != null
- && !contentEncoding.equalsIgnoreCase("identity")
- && !contentEncoding.equalsIgnoreCase("gzip");
- }
-}
\ No newline at end of file
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/MBridgeInterceptor.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/MBridgeInterceptor.java
deleted file mode 100644
index cd354e97..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/interceptor/MBridgeInterceptor.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package im.wangchao.mhttp.internal.interceptor;
-
-import java.io.IOException;
-
-import im.wangchao.mhttp.internal.Singleton;
-import im.wangchao.mhttp.internal.Version;
-import okhttp3.Interceptor;
-import okhttp3.Request;
-import okhttp3.Response;
-
-/**
- * Description : MBridgeInterceptors.
- * Author : wangchao.
- * Date : 16/8/24.
- * Time : 下午4:32.
- */
-public final class MBridgeInterceptor implements Interceptor {
- private MBridgeInterceptor(){}
-
- public static Singleton instance = new Singleton() {
- @Override protected MBridgeInterceptor create() {
- return new MBridgeInterceptor();
- }
- };
-
- @Override public Response intercept(Chain chain) throws IOException {
- Request request = chain.request();
- Request.Builder builder = request.newBuilder();
-
- if (request.header("User-Agent") == null) {
- builder.header("User-Agent", Version.userAgent());
- }
-
- return chain.proceed(builder.build());
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/log/LoggerImpl.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/log/LoggerImpl.java
deleted file mode 100644
index d54fe9ce..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/internal/log/LoggerImpl.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package im.wangchao.mhttp.internal.log;
-
-import android.util.Log;
-
-import im.wangchao.mhttp.internal.Singleton;
-import im.wangchao.mhttp.internal.Version;
-import im.wangchao.mhttp.internal.interceptor.HttpLoggingInterceptor;
-
-/**
- * Description : Logger.
- * Author : wangchao.
- * Date : 2018/3/20.
- * Time : 下午5:36.
- */
-public class LoggerImpl implements HttpLoggingInterceptor.Logger{
- private static final String TAG = Version.moduleName();
- private HttpLoggingInterceptor.Level mLevel;
-
- public static Singleton instance = new Singleton() {
- @Override protected LoggerImpl create() {
- return new LoggerImpl();
- }
- };
-
- public void setLevel(HttpLoggingInterceptor.Level level){
- mLevel = level;
- }
-
- @Override public void log(String message) {
- if (mLevel == HttpLoggingInterceptor.Level.NONE){
- return;
- }
- Log.e(TAG, message);
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseEnqueueObservable.java b/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseEnqueueObservable.java
deleted file mode 100644
index b61ab6d4..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseEnqueueObservable.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package im.wangchao.mhttp.rxjava2;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Request;
-import im.wangchao.mhttp.Response;
-import io.reactivex.Observable;
-import io.reactivex.Observer;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.exceptions.CompositeException;
-import io.reactivex.exceptions.Exceptions;
-import io.reactivex.plugins.RxJavaPlugins;
-
-/**
- * Description : ResponseEnqueueObservable.
- * Author : wangchao.
- * Date : 2018/3/19.
- * Time : 下午4:45.
- */
-public class ResponseEnqueueObservable extends Observable {
- private final RxRequest request;
-
- public ResponseEnqueueObservable(RxRequest request){
- this.request = request;
- }
-
- @Override protected void subscribeActual(Observer super T> observer) {
-
- AbsCallbackHandler callback = request.callback();
- EnqueueDisposable disposable = new EnqueueDisposable<>(observer, callback);
-
- observer.onSubscribe(disposable);
- request.request().newBuilder().callback(disposable).build().enqueue();
- }
-
- private static final class EnqueueDisposable extends AbsCallbackHandler implements Disposable{
- private final AbsCallbackHandler originCallback;
- private final Observer super T> observer;
- private volatile boolean disposed;
- boolean terminated = false;
-
- EnqueueDisposable(Observer super T> observer, AbsCallbackHandler callbackHandler){
- this.observer = observer;
- this.originCallback = callbackHandler;
- }
-
- @Override public void dispose() {
- disposed = true;
- Request request = getRequest();
- request.cancel();
- }
-
- @Override public boolean isDisposed() {
- return disposed;
- }
-
-
- @Override public String charset() {
- return originCallback.charset();
- }
-
- @Override public String accept() {
- return originCallback.accept();
- }
-
- @Override public void onStart() {
- originCallback.onStart();
- }
-
- @Override public void onUploadProgress(int bytesWritten, int bytesTotal) {
- originCallback.onUploadProgress(bytesWritten, bytesTotal);
- }
-
- @Override public void onProgress(long bytesWritten, long bytesTotal) {
- originCallback.onProgress(bytesWritten, bytesTotal);
- }
-
- @Override public void onFinish() {
- originCallback.onFinish();
- }
-
- @Override public void onCancel() {
- originCallback.onCancel();
- if (!disposed){
- dispose();
- }
- }
-
- @Override public T apply(Response response) throws Exception {
- return originCallback.apply(response);
- }
-
- @Override public void onSuccess(T data, Response response) {
- if (disposed) return;
-
- try {
- originCallback.onSuccess(data, response);
-
- observer.onNext(data);
-
- if (!disposed) {
- terminated = true;
- observer.onComplete();
- }
- } catch (Throwable t) {
- if (terminated) {
- RxJavaPlugins.onError(t);
- } else if (!disposed) {
- try {
- observer.onError(t);
- } catch (Throwable inner) {
- Exceptions.throwIfFatal(inner);
- RxJavaPlugins.onError(new CompositeException(t, inner));
- }
- }
- }
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
- try {
- originCallback.onFailure(response, throwable);
-
- observer.onError(throwable);
- } catch (Throwable inner) {
- Exceptions.throwIfFatal(inner);
- RxJavaPlugins.onError(new CompositeException(throwable, inner));
- }
- }
-
- @Override public void onFinally(Response response) {
- originCallback.onFinally(response);
- }
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseExecuteObservable.java b/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseExecuteObservable.java
deleted file mode 100644
index e68dfd2b..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/ResponseExecuteObservable.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package im.wangchao.mhttp.rxjava2;
-
-import im.wangchao.mhttp.Converter;
-import im.wangchao.mhttp.Request;
-import im.wangchao.mhttp.Response;
-import io.reactivex.Observable;
-import io.reactivex.Observer;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.exceptions.CompositeException;
-import io.reactivex.exceptions.Exceptions;
-import io.reactivex.plugins.RxJavaPlugins;
-
-/**
- * Description : ResponseExecuteObservable.
- * Author : wangchao.
- * Date : 2018/3/19.
- * Time : 下午4:46.
- */
-public class ResponseExecuteObservable extends Observable {
- private final RxRequest request;
- private final Converter converter;
-
- public ResponseExecuteObservable(RxRequest request, Converter converter){
- this.request = request;
- this.converter = converter;
- }
-
- @Override protected void subscribeActual(Observer super T> observer) {
-
- ExecuteDisposable disposable = new ExecuteDisposable(request.request());
- observer.onSubscribe(disposable);
-
- boolean terminated = false;
- try {
- T response = converter.apply(request.request().execute());
- if (!disposable.isDisposed()) {
- observer.onNext(response);
- }
- if (!disposable.isDisposed()) {
- terminated = true;
- observer.onComplete();
- }
- } catch (Throwable t) {
- Exceptions.throwIfFatal(t);
- if (terminated) {
- RxJavaPlugins.onError(t);
- } else if (!disposable.isDisposed()) {
- try {
- observer.onError(t);
- } catch (Throwable inner) {
- Exceptions.throwIfFatal(inner);
- RxJavaPlugins.onError(new CompositeException(t, inner));
- }
- }
- }
-
- }
-
- private static final class ExecuteDisposable implements Disposable {
- private final Request request;
- private volatile boolean disposed;
-
- ExecuteDisposable(Request request) {
- this.request = request;
- }
-
- @Override public void dispose() {
- disposed = true;
- request.cancel();
- }
-
- @Override public boolean isDisposed() {
- return disposed;
- }
- }
-}
diff --git a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/RxRequest.java b/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/RxRequest.java
deleted file mode 100644
index ef648ea0..00000000
--- a/mhttp/src/main/java/im/wangchao/mhttp/rxjava2/RxRequest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package im.wangchao.mhttp.rxjava2;
-
-import androidx.annotation.NonNull;
-
-import java.io.File;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.concurrent.Executor;
-
-import im.wangchao.mhttp.AbsCallbackHandler;
-import im.wangchao.mhttp.Converter;
-import im.wangchao.mhttp.Method;
-import im.wangchao.mhttp.Request;
-import im.wangchao.mhttp.RequestParams;
-import im.wangchao.mhttp.Response;
-import im.wangchao.mhttp.ThreadMode;
-import io.reactivex.Observable;
-import okhttp3.CacheControl;
-import okhttp3.Headers;
-import okhttp3.HttpUrl;
-import okhttp3.MediaType;
-
-/**
- * Description : RxRequest.
- * Author : wangchao.
- * Date : 2018/3/26.
- * Time : 下午5:40.
- */
-public class RxRequest {
- public static RxRequest.Builder builder(){
- return new RxRequest.Builder<>();
- }
-
- private Request request;
- private AbsCallbackHandler callback;
-
- private RxRequest(Builder builder){
- request = builder.request;
- callback = builder.callback;
- }
-
- public Request request(){
- return request;
- }
-
- public AbsCallbackHandler callback(){
- return callback;
- }
-
- public RxRequest.Builder newBuilder() {
- return new Builder<>(this);
- }
-
- public Observable execute(Converter converter){
- return new ResponseExecuteObservable<>(this, converter);
- }
-
- public Observable enqueue(){
- return new ResponseEnqueueObservable<>(this);
- }
-
- public static final class Builder {
-
- Request request;
- Request.Builder requestBuilder;
- AbsCallbackHandler callback;
-
- public Builder() {
- requestBuilder = new Request.Builder();
- callback = new AbsCallbackHandler() {
- @Override public void onSuccess(T data, Response response) {
-
- }
-
- @Override public void onFailure(Response response, Throwable throwable) {
-
- }
- };
- }
-
- private Builder(RxRequest request) {
- requestBuilder = request.request.newBuilder();
- callback = request.callback;
- }
-
- public Builder url(HttpUrl url) {
- requestBuilder.url(url);
- return this;
- }
-
- public Builder url(String url) {
- requestBuilder.url(url);
- return this;
- }
-
- public Builder url(URL url) {
- requestBuilder.url(url);
- return this;
- }
-
- public Builder header(String name, String value) {
- requestBuilder.header(name, value);
- return this;
- }
-
- public Builder addHeader(String name, String value) {
- requestBuilder.header(name, value);
- return this;
- }
-
- public Builder removeHeader(String name) {
- requestBuilder.removeHeader(name);
- return this;
- }
-
- public Builder headers(Headers headers) {
- requestBuilder.headers(headers);
- return this;
- }
-
- public Builder cacheControl(CacheControl cacheControl) {
- requestBuilder.cacheControl(cacheControl);
- return this;
- }
-
- public Builder get() {
- return method(Method.GET);
- }
-
- public Builder head() {
- return method(Method.HEAD);
- }
-
- public Builder post() {
- return method(Method.POST);
- }
-
- public Builder delete() {
- return method(Method.DELETE);
- }
-
- public Builder put() {
- return method(Method.PUT);
- }
-
- public Builder patch() {
- return method(Method.PATCH);
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, Object value){
- requestBuilder.addParameter(key, value);
- return this;
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, InputStream stream, String name){
- requestBuilder.addParameter(key, stream, name);
- return this;
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, InputStream stream, String name, String contentType){
- requestBuilder.addParameter(key, stream, name, contentType);
- return this;
- }
-
- /**
- * Simple to add request parameter
- */
- public Builder addParameter(String key, File file, String contentType) {
- requestBuilder.addParameter(key, file, contentType);
- return this;
- }
-
- public Builder requestParams(RequestParams params) {
- requestBuilder.requestParams(params);
- return this;
- }
-
- public Builder method(@NonNull String method) {
- requestBuilder.method(method);
- return this;
- }
-
- public Builder tag(Object tag) {
- requestBuilder.tag(tag);
- return this;
- }
-
- public Builder callback(@NonNull AbsCallbackHandler callback){
- this.callback = callback;
- return this;
- }
-
- public Builder callbackExecutor(Executor executor){
- requestBuilder.callbackExecutor(executor);
- return this;
- }
-
- public Builder callbackThreadMode(ThreadMode threadMode){
- requestBuilder.callbackThreadMode(threadMode);
- return this;
- }
-
- public Builder userAgent(String ua){
- requestBuilder.userAgent(ua);
- return this;
- }
-
- public Builder contentType(@NonNull String contentType){
- requestBuilder.contentType(contentType);
- return this;
- }
-
- public Builder contentType(@NonNull MediaType mediaType){
- requestBuilder.contentType(mediaType);
- return this;
- }
-
- public RxRequest build() {
- request = requestBuilder.build();
-
- return new RxRequest<>(this);
- }
- }
-}
diff --git a/nachos/build.gradle b/nachos/build.gradle
deleted file mode 100644
index 821a4a83..00000000
--- a/nachos/build.gradle
+++ /dev/null
@@ -1,23 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
- compileSdkVersion setup.compileSdk
-
- defaultConfig {
- minSdkVersion 15
- targetSdkVersion setup.targetSdk
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation "com.android.support:support-compat:28.0.0"
-}
\ No newline at end of file
diff --git a/nachos/maven_push.gradle b/nachos/maven_push.gradle
deleted file mode 100644
index 946f7859..00000000
--- a/nachos/maven_push.gradle
+++ /dev/null
@@ -1,111 +0,0 @@
-apply plugin: 'maven'
-apply plugin: 'signing'
-
-def isReleaseBuild() {
- return VERSION_NAME.contains("SNAPSHOT") == false
-}
-
-def getReleaseRepositoryUrl() {
- return ARTIFACT_REPO
-}
-
-def getSnapshotRepositoryUrl() {
- return ARTIFACT_SNAPSHOT_REPO
-}
-
-def getRepositoryUsername() {
- return System.properties['username']
-}
-
-def getRepositoryPassword() {
- return System.properties['password']
-}
-
-afterEvaluate { project ->
- uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
-
- pom.groupId = GROUP
- pom.artifactId = POM_ARTIFACT_ID
- pom.version = VERSION_NAME
-
- repository(url: getReleaseRepositoryUrl()) {
- authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
- }
- snapshotRepository(url: getSnapshotRepositoryUrl()) {
- authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
- }
-
- pom.project {
- name POM_NAME
- packaging POM_PACKAGING
- description POM_DESCRIPTION
- url POM_URL
-
- scm {
- url POM_SCM_URL
- connection POM_SCM_CONNECTION
- developerConnection POM_SCM_DEV_CONNECTION
- }
-
- licenses {
- license {
- name POM_LICENCE_NAME
- url POM_LICENCE_URL
- distribution POM_LICENCE_DIST
- }
- }
-
- developers {
- developer {
- id POM_DEVELOPER_ID
- name POM_DEVELOPER_NAME
- }
- }
- }
- }
- }
- }
-
- task installArchives(type: Upload) {
- description "Installs the artifacts to the local Maven repository."
- configuration = configurations['archives']
- repositories {
- mavenDeployer {
- pom.groupId = GROUP
- pom.artifactId = POM_ARTIFACT_ID
- pom.version = VERSION_NAME
-
- repository url: "file://${System.properties['user.home']}/.m2/repository"
- }
- }
- }
-
- signing {
- required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
- sign configurations.archives
- }
-
- task androidJavadocs(type: Javadoc) {
- source = android.sourceSets.main.java.srcDirs
- classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
- failOnError = false
- }
-
- task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
- classifier = 'javadoc'
- from androidJavadocs.destinationDir
- }
-
- task androidSourcesJar(type: Jar) {
- classifier = 'sources'
- from android.sourceSets.main.java.srcDirs
- }
-
- artifacts {
- archives androidSourcesJar
- archives androidJavadocsJar
- }
-}
\ No newline at end of file
diff --git a/nachos/src/main/AndroidManifest.xml b/nachos/src/main/AndroidManifest.xml
deleted file mode 100644
index ad3cc65f..00000000
--- a/nachos/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/nachos/src/main/java/com/hootsuite/nachos/ChipConfiguration.java b/nachos/src/main/java/com/hootsuite/nachos/ChipConfiguration.java
deleted file mode 100644
index 0b8fb3b7..00000000
--- a/nachos/src/main/java/com/hootsuite/nachos/ChipConfiguration.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.hootsuite.nachos;
-
-import android.content.res.ColorStateList;
-
-public class ChipConfiguration {
-
- private final int mChipHorizontalSpacing;
- private final ColorStateList mChipBackground;
- private final int mChipCornerRadius;
- private final int mChipTextColor;
- private final int mChipTextSize;
- private final int mChipHeight;
- private final int mChipVerticalSpacing;
- private final int mMaxAvailableWidth;
-
- /**
- * Creates a new ChipConfiguration. You can pass in {@code -1} or {@code null} for any of the parameters to indicate that parameter should be
- * ignored.
- *
- * @param chipHorizontalSpacing the amount of horizontal space (in pixels) to put between consecutive chips
- * @param chipBackground the {@link ColorStateList} to set as the background of the chips
- * @param chipCornerRadius the corner radius of the chip background, in pixels
- * @param chipTextColor the color to set as the text color of the chips
- * @param chipTextSize the font size (in pixels) to use for the text of the chips
- * @param chipHeight the height (in pixels) of each chip
- * @param chipVerticalSpacing the amount of vertical space (in pixels) to put between chips on consecutive lines
- * @param maxAvailableWidth the maximum available with for a chip (the width of a full line of text in the text view)
- */
- ChipConfiguration(int chipHorizontalSpacing,
- ColorStateList chipBackground,
- int chipCornerRadius,
- int chipTextColor,
- int chipTextSize,
- int chipHeight,
- int chipVerticalSpacing,
- int maxAvailableWidth) {
- mChipHorizontalSpacing = chipHorizontalSpacing;
- mChipBackground = chipBackground;
- mChipCornerRadius = chipCornerRadius;
- mChipTextColor = chipTextColor;
- mChipTextSize = chipTextSize;
- mChipHeight = chipHeight;
- mChipVerticalSpacing = chipVerticalSpacing;
- mMaxAvailableWidth = maxAvailableWidth;
- }
-
- public int getChipHorizontalSpacing() {
- return mChipHorizontalSpacing;
- }
-
- public ColorStateList getChipBackground() {
- return mChipBackground;
- }
-
- public int getChipCornerRadius() {
- return mChipCornerRadius;
- }
-
- public int getChipTextColor() {
- return mChipTextColor;
- }
-
- public int getChipTextSize() {
- return mChipTextSize;
- }
-
- public int getChipHeight() {
- return mChipHeight;
- }
-
- public int getChipVerticalSpacing() {
- return mChipVerticalSpacing;
- }
-
- public int getMaxAvailableWidth() {
- return mMaxAvailableWidth;
- }
-}
diff --git a/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java b/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java
deleted file mode 100644
index b2cb81ab..00000000
--- a/nachos/src/main/java/com/hootsuite/nachos/NachoTextView.java
+++ /dev/null
@@ -1,1165 +0,0 @@
-package com.hootsuite.nachos;
-
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.text.Editable;
-import android.text.Layout;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Pair;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.widget.Adapter;
-import android.widget.AdapterView;
-import android.widget.AutoCompleteTextView;
-import android.widget.ListAdapter;
-import android.widget.MultiAutoCompleteTextView;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.ColorRes;
-import androidx.annotation.DimenRes;
-import androidx.annotation.Dimension;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-
-import com.hootsuite.nachos.chip.Chip;
-import com.hootsuite.nachos.chip.ChipInfo;
-import com.hootsuite.nachos.chip.ChipSpan;
-import com.hootsuite.nachos.chip.ChipSpanChipCreator;
-import com.hootsuite.nachos.terminator.ChipTerminatorHandler;
-import com.hootsuite.nachos.terminator.DefaultChipTerminatorHandler;
-import com.hootsuite.nachos.tokenizer.ChipTokenizer;
-import com.hootsuite.nachos.tokenizer.SpanChipTokenizer;
-import com.hootsuite.nachos.validator.ChipifyingNachoValidator;
-import com.hootsuite.nachos.validator.IllegalCharacterIdentifier;
-import com.hootsuite.nachos.validator.NachoValidator;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * An editable TextView extending {@link MultiAutoCompleteTextView} that supports "chipifying" pieces of text and displaying suggestions for segments of the text.
- * The ChipTokenizer
- * To customize chipifying with this class you can provide a custom {@link ChipTokenizer} by calling {@link #setChipTokenizer(ChipTokenizer)}.
- * By default the {@link SpanChipTokenizer} is used.
- * Chip Terminators
- * To set which characters trigger the creation of a chip, call {@link #addChipTerminator(char, int)} or {@link #setChipTerminators(Map)}.
- * For example if tapping enter should cause all unchipped text to become chipped, call
- * {@code chipSuggestionTextView.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);}
- * To completely customize how chips are created when text is entered in this text view you can provide a custom {@link ChipTerminatorHandler}
- * through {@link #setChipTerminatorHandler(ChipTerminatorHandler)}
- * Illegal Characters
- * To prevent a character from being typed you can call {@link #setIllegalCharacterIdentifier(IllegalCharacterIdentifier)}} to identify characters
- * that should be considered illegal.
- * Suggestions
- * To provide suggestions you must provide an {@link android.widget.Adapter} by calling {@link #setAdapter(ListAdapter)}
- * UI Customization
- * This view defines six custom attributes (all of which are optional):
- *
- * chipHorizontalSpacing - the horizontal space between chips
- * chipBackground - the background color of the chip
- * chipCornerRadius - the corner radius of the chip background
- * chipTextColor - the color of the chip text
- * chipTextSize - the font size of the chip text
- * chipHeight - the height of a single chip
- * chipVerticalSpacing - the vertical space between chips on consecutive lines
- *
- * Note: chipVerticalSpacing is only used if a chipHeight is also set
- *
- *
- *
- * The values of these attributes will be passed to the ChipTokenizer through {@link ChipTokenizer#applyConfiguration(Editable, ChipConfiguration)}
- * Validation
- * This class can perform validation when certain events occur (such as losing focus). When the validation occurs is decided by
- * {@link AutoCompleteTextView}. To perform validation, set a {@link NachoValidator}:
- *
- * nachoTextView.setNachoValidator(new ChipifyingNachoValidator());
- *
- * Note: The NachoValidator will be ignored if a ChipTokenizer is not set. To perform validation without a ChipTokenizer you can use
- * {@link AutoCompleteTextView}'s built-in {@link AutoCompleteTextView.Validator Validator} through {@link #setValidator(Validator)}
- * Editing Chips
- * This class also supports editing chips on touch. To enable this behavior call {@link #enableEditChipOnTouch(boolean, boolean)}. To disable this
- * behavior you can call {@link #disableEditChipOnTouch()}
- * Example Setup:
- * A standard setup for this class could look something like the following:
- *
- * String[] suggestions = new String[]{"suggestion 1", "suggestion 2"};
- * ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, suggestions);
- * nachoTextView.setAdapter(adapter);
- * nachoTextView.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);
- * nachoTextView.addChipTerminator(' ', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_TO_TERMINATOR);
- * nachoTextView.setIllegalCharacters('@');
- * nachoTextView.setNachoValidator(new ChipifyingNachoValidator());
- * nachoTextView.enableEditChipOnTouch(true, true);
- * nachoTextView.setOnChipClickListener(new NachoTextView.OnChipClickListener() {
- * {@literal @Override}
- * public void onChipClick(Chip chip, MotionEvent motionEvent) {
- * // Handle click event
- * }
- * });
- * nachoTextView.setOnChipRemoveListener(new NachoTextView.OnChipRemoveListener() {
- * {@literal @Override}
- * public void onChipRemove(Chip chip) {
- * // Handle remove event
- * }
- * });
- *
- *
- * @see SpanChipTokenizer
- * @see DefaultChipTerminatorHandler
- * @see ChipifyingNachoValidator
- */
-public class NachoTextView extends MultiAutoCompleteTextView implements TextWatcher, AdapterView.OnItemClickListener {
-
- // UI Attributes
- private int mChipHorizontalSpacing = -1;
- private ColorStateList mChipBackground = null;
- private int mChipCornerRadius = -1;
- private int mChipTextColor = Color.TRANSPARENT;
- private int mChipTextSize = -1;
- private int mChipHeight = -1;
- private int mChipVerticalSpacing = -1;
-
- private int mDefaultPaddingTop = 0;
- private int mDefaultPaddingBottom = 0;
- /**
- * Flag to keep track of the padding state so we only update the padding when necessary
- */
- private boolean mUsingDefaultPadding = true;
-
- // Touch events
- @Nullable
- private OnChipClickListener mOnChipClickListener;
- private GestureDetector singleTapDetector;
- private boolean mEditChipOnTouchEnabled;
- private boolean mMoveChipToEndOnEdit;
- private boolean mChipifyUnterminatedTokensOnEdit;
-
- // Text entry
- @Nullable
- private ChipTokenizer mChipTokenizer;
- @Nullable
- private ChipTerminatorHandler mChipTerminatorHandler;
- @Nullable
- private NachoValidator mNachoValidator;
- @Nullable
- private IllegalCharacterIdentifier illegalCharacterIdentifier;
-
- @Nullable
- private OnChipRemoveListener mOnChipRemoveListener;
- private List mChipsToRemove = new ArrayList<>();
- private boolean mIgnoreTextChangedEvents;
- private int mTextChangedStart;
- private int mTextChangedEnd;
- private boolean mIsPasteEvent;
-
- // Measurement
- private boolean mMeasured;
-
- // Layout
- private boolean mLayoutComplete;
-
- public NachoTextView(Context context) {
- super(context);
- init(null);
- }
-
- public NachoTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs);
- }
-
- public NachoTextView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(attrs);
- }
-
- private void init(@Nullable AttributeSet attrs) {
- Context context = getContext();
-
- if (attrs != null) {
- TypedArray attributes = context.getTheme().obtainStyledAttributes(
- attrs,
- R.styleable.NachoTextView,
- 0,
- R.style.DefaultChipSuggestionTextView);
-
- try {
- mChipHorizontalSpacing = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipHorizontalSpacing, -1);
- mChipBackground = attributes.getColorStateList(R.styleable.NachoTextView_chipBackground);
- mChipCornerRadius = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipCornerRadius, -1);
- mChipTextColor = attributes.getColor(R.styleable.NachoTextView_chipTextColor, Color.TRANSPARENT);
- mChipTextSize = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipTextSize, -1);
- mChipHeight = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipHeight, -1);
- mChipVerticalSpacing = attributes.getDimensionPixelSize(R.styleable.NachoTextView_chipVerticalSpacing, -1);
- } finally {
- attributes.recycle();
- }
- }
-
- mDefaultPaddingTop = getPaddingTop();
- mDefaultPaddingBottom = getPaddingBottom();
-
- singleTapDetector = new GestureDetector(getContext(), new SingleTapListener());
-
- setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN);
- addTextChangedListener(this);
- setChipTokenizer(new SpanChipTokenizer<>(context, new ChipSpanChipCreator(), ChipSpan.class));
- setChipTerminatorHandler(new DefaultChipTerminatorHandler());
- setOnItemClickListener(this);
-
- updatePadding();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (!mMeasured && getWidth() > 0) {
- // Refresh the tokenizer for width changes
- invalidateChips();
- mMeasured = true;
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- if (!mLayoutComplete) {
- invalidateChips();
- mLayoutComplete = true;
- }
- }
-
- /**
- * Updates the padding based on whether or not any chips are present to avoid the view from changing heights when chips are inserted/deleted.
- * Extra padding is added when there are no chips. When there are chips the padding is reverted to its defaults. This only affects top and bottom
- * padding because the chips only affect the height of the view.
- */
- private void updatePadding() {
- if (mChipHeight != -1) {
- boolean chipsArePresent = !getAllChips().isEmpty();
- if (!chipsArePresent && mUsingDefaultPadding) {
- mUsingDefaultPadding = false;
- Paint paint = getPaint();
- Paint.FontMetricsInt fm = paint.getFontMetricsInt();
- int textHeight = fm.descent - fm.ascent;
- // Calculate how tall the view should be if there were chips
- int newTextHeight = mChipHeight + (mChipVerticalSpacing != -1 ? mChipVerticalSpacing : 0);
- // We need to add half our missing height above and below the text by increasing top and bottom padding
- int paddingAdjustment = (newTextHeight - textHeight) / 2;
- super.setPadding(getPaddingLeft(), mDefaultPaddingTop + paddingAdjustment, getPaddingRight(), mDefaultPaddingBottom + paddingAdjustment);
- } else if (chipsArePresent && !mUsingDefaultPadding) {
- // If there are chips we can revert to default padding
- mUsingDefaultPadding = true;
- super.setPadding(getPaddingLeft(), mDefaultPaddingTop, getPaddingRight(), mDefaultPaddingBottom);
- }
- }
- }
-
- /**
- * Sets the padding on this View. The left and right padding will be handled as they normally would in a TextView. The top and bottom padding passed
- * here will be the padding that is used when there are one or more chips in the text view. When there are no chips present, the padding will be
- * increased to make sure the overall height of the text view stays the same, since chips take up more vertical space than plain text.
- *
- * @param left the left padding in pixels
- * @param top the top padding in pixels
- * @param right the right padding in pixels
- * @param bottom the bottom padding in pixels
- */
- @Override
- public void setPadding(int left, int top, int right, int bottom) {
- // Call the super method so that left and right padding are updated
- // top and bottom padding will be handled in updatePadding()
- super.setPadding(left, top, right, bottom);
- mDefaultPaddingTop = top;
- mDefaultPaddingBottom = bottom;
- updatePadding();
- }
-
- public int getChipHorizontalSpacing() {
- return mChipHorizontalSpacing;
- }
-
- public void setChipHorizontalSpacing(@DimenRes int chipHorizontalSpacingResId) {
- mChipHorizontalSpacing = getContext().getResources().getDimensionPixelSize(chipHorizontalSpacingResId);
- invalidateChips();
- }
-
- public ColorStateList getChipBackground() {
- return mChipBackground;
- }
-
- public void setChipBackgroundResource(@ColorRes int chipBackgroundResId) {
- setChipBackground(ContextCompat.getColorStateList(getContext(), chipBackgroundResId));
- }
-
- public void setChipBackground(ColorStateList chipBackground) {
- mChipBackground = chipBackground;
- invalidateChips();
- }
-
- /**
- * @return The chip background corner radius value, in pixels.
- */
- @Dimension
- public int getChipCornerRadius() {
- return mChipCornerRadius;
- }
-
- /**
- * Sets the chip background corner radius.
- *
- * @param chipCornerRadiusResId The dimension resource with the corner radius value.
- */
- public void setChipCornerRadiusResource(@DimenRes int chipCornerRadiusResId) {
- setChipCornerRadius(getContext().getResources().getDimensionPixelSize(chipCornerRadiusResId));
- }
-
- /**
- * Sets the chip background corner radius.
- *
- * @param chipCornerRadius The corner radius value, in pixels.
- */
- public void setChipCornerRadius(@Dimension int chipCornerRadius) {
- mChipCornerRadius = chipCornerRadius;
- invalidateChips();
- }
-
-
- public int getChipTextColor() {
- return mChipTextColor;
- }
-
- public void setChipTextColorResource(@ColorRes int chipTextColorResId) {
- setChipTextColor(ContextCompat.getColor(getContext(), chipTextColorResId));
- }
-
- public void setChipTextColor(@ColorInt int chipTextColor) {
- mChipTextColor = chipTextColor;
- invalidateChips();
- }
-
- public int getChipTextSize() {
- return mChipTextSize;
- }
-
- public void setChipTextSize(@DimenRes int chipTextSizeResId) {
- mChipTextSize = getContext().getResources().getDimensionPixelSize(chipTextSizeResId);
- invalidateChips();
- }
-
- public int getChipHeight() {
- return mChipHeight;
- }
-
- public void setChipHeight(@DimenRes int chipHeightResId) {
- mChipHeight = getContext().getResources().getDimensionPixelSize(chipHeightResId);
- invalidateChips();
- }
-
- public int getChipVerticalSpacing() {
- return mChipVerticalSpacing;
- }
-
- public void setChipVerticalSpacing(@DimenRes int chipVerticalSpacingResId) {
- mChipVerticalSpacing = getContext().getResources().getDimensionPixelSize(chipVerticalSpacingResId);
- invalidateChips();
- }
-
- @Nullable
- public ChipTokenizer getChipTokenizer() {
- return mChipTokenizer;
- }
-
- /**
- * Sets the {@link ChipTokenizer} to be used by this ChipSuggestionTextView.
- * Note that a Tokenizer set here will override any Tokenizer set by {@link #setTokenizer(Tokenizer)}
- *
- * @param chipTokenizer the {@link ChipTokenizer} to set
- */
- public void setChipTokenizer(@Nullable ChipTokenizer chipTokenizer) {
- mChipTokenizer = chipTokenizer;
- if (mChipTokenizer != null) {
- setTokenizer(new ChipTokenizerWrapper(mChipTokenizer));
- } else {
- setTokenizer(null);
- }
- invalidateChips();
- }
-
- public void setOnChipClickListener(@Nullable OnChipClickListener onChipClickListener) {
- mOnChipClickListener = onChipClickListener;
- }
-
- public void setOnChipRemoveListener(@Nullable OnChipRemoveListener onChipRemoveListener) {
- mOnChipRemoveListener = onChipRemoveListener;
- }
-
- public void setChipTerminatorHandler(@Nullable ChipTerminatorHandler chipTerminatorHandler) {
- mChipTerminatorHandler = chipTerminatorHandler;
- }
-
- public void setNachoValidator(@Nullable NachoValidator nachoValidator) {
- mNachoValidator = nachoValidator;
- }
-
- /**
- * @see ChipTerminatorHandler#setChipTerminators(Map)
- */
- public void setChipTerminators(@Nullable Map chipTerminators) {
- if (mChipTerminatorHandler != null) {
- mChipTerminatorHandler.setChipTerminators(chipTerminators);
- }
- }
-
- /**
- * @see ChipTerminatorHandler#addChipTerminator(char, int)
- */
- public void addChipTerminator(char character, int behavior) {
- if (mChipTerminatorHandler != null) {
- mChipTerminatorHandler.addChipTerminator(character, behavior);
- }
- }
-
- /**
- * @see ChipTerminatorHandler#setPasteBehavior(int)
- */
- public void setPasteBehavior(int pasteBehavior) {
- if (mChipTerminatorHandler != null) {
- mChipTerminatorHandler.setPasteBehavior(pasteBehavior);
- }
- }
-
- /**
- * Sets the {@link IllegalCharacterIdentifier} that will identify characters that should
- * not show up in the field when typed (i.e. they will be deleted as soon as they are entered).
- * If a character is listed as both a chip terminator character and an illegal character,
- * it will be treated as an illegal character.
- *
- * @param illegalCharacterIdentifier the identifier to use
- */
- public void setIllegalCharacterIdentifier(@Nullable IllegalCharacterIdentifier illegalCharacterIdentifier) {
- this.illegalCharacterIdentifier = illegalCharacterIdentifier;
- }
-
- /**
- * Applies any updated configuration parameters to any existing chips and all future chips in the text view.
- *
- * @see ChipTokenizer#applyConfiguration(Editable, ChipConfiguration)
- */
- public void invalidateChips() {
- beginUnwatchedTextChange();
-
- if (mChipTokenizer != null) {
- Editable text = getText();
- int availableWidth = getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight();
- ChipConfiguration configuration = new ChipConfiguration(
- mChipHorizontalSpacing,
- mChipBackground,
- mChipCornerRadius,
- mChipTextColor,
- mChipTextSize,
- mChipHeight,
- mChipVerticalSpacing,
- availableWidth);
-
- mChipTokenizer.applyConfiguration(text, configuration);
- }
-
- endUnwatchedTextChange();
- }
-
- /**
- * Enables editing chips on touch events. When a touch event occurs, the touched chip will be put in editing mode. To later disable this behavior
- * call {@link #disableEditChipOnTouch()}.
- *
- * Note: If an {@link OnChipClickListener} is set it's behavior will override the behavior described here if it's
- * {@link OnChipClickListener#onChipClick(Chip, MotionEvent)} method returns true. If that method returns false, the touched chip will be put
- * in editing mode as expected.
- *
- *
- * @param moveChipToEnd if true, the chip will also be moved to the end of the text when it is put in editing mode
- * @param chipifyUnterminatedTokens if true, all unterminated tokens will be chipified before the touched chip is put in editing mode
- * @see #disableEditChipOnTouch()
- */
- public void enableEditChipOnTouch(boolean moveChipToEnd, boolean chipifyUnterminatedTokens) {
- mEditChipOnTouchEnabled = true;
- mMoveChipToEndOnEdit = moveChipToEnd;
- mChipifyUnterminatedTokensOnEdit = chipifyUnterminatedTokens;
- }
-
- /**
- * Disables editing chips on touch events. To re-enable this behavior call {@link #enableEditChipOnTouch(boolean, boolean)}.
- *
- * @see #enableEditChipOnTouch(boolean, boolean)
- */
- public void disableEditChipOnTouch() {
- mEditChipOnTouchEnabled = false;
- }
-
- /**
- * Puts the provided Chip in editing mode (i.e. reverts it to an unchipified token whose text can be edited).
- *
- * @param chip the chip to edit
- * @param moveChipToEnd if true, the chip will also be moved to the end of the text
- */
- public void setEditingChip(Chip chip, boolean moveChipToEnd) {
- if (mChipTokenizer == null) {
- return;
- }
-
- beginUnwatchedTextChange();
-
- Editable text = getText();
- if (moveChipToEnd) {
- // Move the chip text to the end of the text
- text.append(chip.getText());
- // Delete the existing chip
- mChipTokenizer.deleteChipAndPadding(chip, text);
- // Move the cursor to the end of the text
- setSelection(text.length());
- } else {
- int chipStart = mChipTokenizer.findChipStart(chip, text);
- mChipTokenizer.revertChipToToken(chip, text);
- setSelection(mChipTokenizer.findTokenEnd(text, chipStart));
- }
-
- endUnwatchedTextChange();
- }
-
- @Override
- public boolean onTouchEvent(@NonNull MotionEvent event) {
- boolean wasHandled = false;
- clearChipStates();
- Chip touchedChip = findTouchedChip(event);
- if (touchedChip != null && isFocused() && singleTapDetector.onTouchEvent(event)) {
- touchedChip.setState(View.PRESSED_SELECTED_STATE_SET);
- if (onChipClicked(touchedChip)) {
- wasHandled = true;
- }
- if (mOnChipClickListener != null) {
- mOnChipClickListener.onChipClick(touchedChip, event);
- }
- }
-
- // Getting NullPointerException inside Editor.updateFloatingToolbarVisibility (Editor.java:1520)
- // primarily seen in Samsung Nougat devices.
- boolean superOnTouch = false;
- try {
- superOnTouch = super.onTouchEvent(event);
- } catch (NullPointerException e) {
- Log.w("Nacho", String.format("Error during touch event of type [%d]", event.getAction()), e);
- // can't handle or reproduce, but will monitor the error
- }
-
- return wasHandled || superOnTouch;
- }
-
- @Nullable
- private Chip findTouchedChip(MotionEvent event) {
- if (mChipTokenizer == null) {
- return null;
- }
-
- Editable text = getText();
- int offset = getOffsetForPosition(event.getX(), event.getY());
- List chips = getAllChips();
- for (Chip chip : chips) {
- int chipStart = mChipTokenizer.findChipStart(chip, text);
- int chipEnd = mChipTokenizer.findChipEnd(chip, text); // This is actually the index of the character just past the end of the chip
- // When a touch event occurs getOffsetForPosition will either return the index of the first character of the span or the index of the
- // character one past the end of the span
- // This matches up perfectly with chipStart and chipEnd so we can just directly compare them...
- if (chipStart <= offset && offset <= chipEnd) {
- float startX = getXForIndex(chipStart);
- float endX = getXForIndex(chipEnd - 1);
- float eventX = event.getX();
- // ... however, when comparing the x coordinate we need to use (chipEnd - 1) because chipEnd will give us the x coordinate of the
- // beginning of the next span since that is actually what chipEnd holds. We want the x coordinate of the end of the current span so
- // we use (chipEnd - 1)
- if (startX <= eventX && eventX <= endX) {
- return chip;
- }
- }
- }
- return null;
- }
-
- /**
- * Implement this method to handle chip clicked events.
- *
- * @param chip the chip that was clicked
- * @return true if the event was handled, otherwise false
- */
- public boolean onChipClicked(Chip chip) {
- boolean wasHandled = false;
- if (mEditChipOnTouchEnabled) {
- if (mChipifyUnterminatedTokensOnEdit) {
- chipifyAllUnterminatedTokens();
- }
- setEditingChip(chip, mMoveChipToEndOnEdit);
- wasHandled = true;
- }
- return wasHandled;
- }
-
- private float getXForIndex(int index) {
- Layout layout = getLayout();
- return layout.getPrimaryHorizontal(index);
- }
-
- private void clearChipStates() {
- for (Chip chip : getAllChips()) {
- chip.setState(View.EMPTY_STATE_SET);
- }
- }
-
- @Override
- public boolean onTextContextMenuItem(int id) {
- int start = getSelectionStart();
- int end = getSelectionEnd();
- switch (id) {
- case android.R.id.cut:
- try {
- setClipboardData(ClipData.newPlainText(null, getTextWithPlainTextSpans(start, end)));
- } catch (StringIndexOutOfBoundsException e) {
- throw new StringIndexOutOfBoundsException(
- String.format(
- "%s \nError cutting text index [%s, %s] for text [%s] and substring [%s]",
- e.getMessage(),
- start,
- end,
- getText().toString(),
- getText().subSequence(start, end)));
- }
- getText().delete(getSelectionStart(), getSelectionEnd());
- return true;
- case android.R.id.copy:
- try {
- setClipboardData(ClipData.newPlainText(null, getTextWithPlainTextSpans(start, end)));
- } catch (StringIndexOutOfBoundsException e) {
- throw new StringIndexOutOfBoundsException(
- String.format(
- "%s \nError copying text index [%s, %s] for text [%s] and substring [%s]",
- e.getMessage(),
- start,
- end,
- getText().toString(),
- getText().subSequence(start, end)));
- }
- return true;
- case android.R.id.paste:
- mIsPasteEvent = true;
- boolean returnValue = super.onTextContextMenuItem(id);
- mIsPasteEvent = false;
- return returnValue;
- default:
- return super.onTextContextMenuItem(id);
- }
- }
-
- private void setClipboardData(ClipData clip) {
- ClipboardManager clipboard = (ClipboardManager) getContext().
- getSystemService(Context.CLIPBOARD_SERVICE);
- clipboard.setPrimaryClip(clip);
- }
-
- /**
- * If a {@link android.widget.AutoCompleteTextView.Validator Validator} was set, this method will validate the entire text.
- * (Overrides the superclass method which only validates the current token)
- */
- @Override
- public void performValidation() {
- if (mNachoValidator == null || mChipTokenizer == null) {
- super.performValidation();
- return;
- }
-
- CharSequence text = getText();
- if (!TextUtils.isEmpty(text) && !mNachoValidator.isValid(mChipTokenizer, text)) {
- setRawText(mNachoValidator.fixText(mChipTokenizer, text));
- }
- }
-
- /**
- * From the point this method is called to when {@link #endUnwatchedTextChange()} is called, all TextChanged events will be ignored
- */
- private void beginUnwatchedTextChange() {
- mIgnoreTextChangedEvents = true;
- }
-
- /**
- * After this method is called TextChanged events will resume being handled.
- * This method also calls {@link #updatePadding()} in case the unwatched changed created/destroyed chips
- */
- private void endUnwatchedTextChange() {
- updatePadding();
- mIgnoreTextChangedEvents = false;
- }
-
- /**
- * Sets the contents of this text view without performing any processing (nothing will be chipified, no characters will be removed etc.)
- *
- * @param text the text to set
- */
- private void setRawText(CharSequence text) {
- beginUnwatchedTextChange();
- super.setText(text);
- endUnwatchedTextChange();
- }
-
- /**
- * Sets the contents of this text view to contain the provided list of strings. The text view will be cleared then each string in the list will
- * be chipified and appended to the text.
- *
- * @param chipValues the list of strings to chipify and set as the contents of the text view or null to clear the text view
- */
- public void setText(@Nullable List chipValues) {
- if (mChipTokenizer == null) {
- return;
- }
- beginUnwatchedTextChange();
-
- Editable text = getText();
- text.clear();
-
- if (chipValues != null) {
- for (String chipValue : chipValues) {
- CharSequence chippedText = mChipTokenizer.terminateToken(chipValue, null);
- text.append(chippedText);
- }
- }
- setSelection(text.length());
-
- endUnwatchedTextChange();
- }
-
- public void setTextWithChips(@Nullable List chips) {
- if (mChipTokenizer == null) {
- return;
- }
- beginUnwatchedTextChange();
-
- Editable text = getText();
- text.clear();
-
- if (chips != null) {
- for (ChipInfo chipInfo : chips) {
- CharSequence chippedText = mChipTokenizer.terminateToken(chipInfo.getText(), chipInfo.getData());
- text.append(chippedText);
- }
- }
- setSelection(text.length());
- endUnwatchedTextChange();
- }
-
- public void addTextWithChips(@Nullable List chips) {
- if (mChipTokenizer == null) {
- return;
- }
- beginUnwatchedTextChange();
-
- Editable text = getText();
-
- if (chips != null) {
- for (ChipInfo chipInfo : chips) {
- CharSequence chippedText = mChipTokenizer.terminateToken(chipInfo.getText(), chipInfo.getData());
- text.append(chippedText);
- }
- }
- setSelection(text.length());
- endUnwatchedTextChange();
- }
-
- @Override
- public void onItemClick(AdapterView> adapterView, View view, int position, long id) {
- if (mChipTokenizer == null) {
- return;
- }
- Adapter adapter = getAdapter();
- if (adapter == null) {
- return;
- }
- beginUnwatchedTextChange();
-
- Object data = getDataForSuggestion(adapter, position);
- CharSequence text = getFilter().convertResultToString(adapter.getItem(position));
-
- clearComposingText();
- int end = getSelectionEnd();
- Editable editable = getText();
- int start = mChipTokenizer.findTokenStart(editable, end);
-
- // guard against java.lang.StringIndexOutOfBoundsException
- start = Math.min(Math.max(0, start), editable.length());
- end = Math.min(Math.max(0, end), editable.length());
- if (end < start) {
- end = start;
- }
-
- editable.replace(start, end, mChipTokenizer.terminateToken(text, data));
-
- endUnwatchedTextChange();
- }
-
- /**
- * Returns a object that will be associated with a chip that is about to be created for the item at {@code position} in {@code adapter} because that
- * item was just tapped.
- *
- * @param adapter the adapter supplying the suggestions
- * @param position the position of the suggestion that was tapped
- * @return the data object
- */
- protected Object getDataForSuggestion(@NonNull Adapter adapter, int position) {
- return adapter.getItem(position);
- }
-
- /**
- * If there is a ChipTokenizer set, this method will do nothing. Instead we wait until the OnItemClickListener is triggered to actually perform
- * the text replacement so we can also associate the suggestion data with it.
- *
- * If there is no ChipTokenizer set, we call through to the super method.
- *
- * @param text the text to be chipified
- */
- @Override
- protected void replaceText(CharSequence text) {
- // If we have a ChipTokenizer, this will be handled by our OnItemClickListener so we can do nothing here.
- // If we don't have a ChipTokenizer, we'll use the default behavior
- if (mChipTokenizer == null) {
- super.replaceText(text);
- }
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- if (mIgnoreTextChangedEvents) {
- return;
- }
-
- mTextChangedStart = start;
- mTextChangedEnd = start + after;
-
- // Check for backspace
- if (mChipTokenizer != null) {
- if (count > 0 && after < count) {
- int end = start + count;
- Editable message = getText();
- Chip[] chips = mChipTokenizer.findAllChips(start, end, message);
-
- for (Chip chip : chips) {
- int spanStart = mChipTokenizer.findChipStart(chip, message);
- int spanEnd = mChipTokenizer.findChipEnd(chip, message);
- if ((spanStart < end) && (spanEnd > start)) {
- // Add to remove list
- mChipsToRemove.add(chip);
- }
- }
- }
- }
- }
-
- @Override
- public void onTextChanged(@NonNull CharSequence textChanged, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable message) {
- if (mIgnoreTextChangedEvents) {
- return;
- }
-
- // Avoid triggering text changed events from changes we make in this method
- beginUnwatchedTextChange();
-
- // Handle backspace key
- if (mChipTokenizer != null) {
- Iterator iterator = mChipsToRemove.iterator();
- while (iterator.hasNext()) {
- Chip chip = iterator.next();
- iterator.remove();
- mChipTokenizer.deleteChip(chip, message);
- if (mOnChipRemoveListener != null) {
- mOnChipRemoveListener.onChipRemove(chip);
- }
- }
- }
-
- // Handle an illegal or chip terminator character
- if (message.length() >= mTextChangedEnd && message.length() >= mTextChangedStart) {
- handleTextChanged(mTextChangedStart, mTextChangedEnd);
- }
-
- endUnwatchedTextChange();
- }
-
- private void handleTextChanged(int start, int end) {
- if (start == end) {
- // If start and end are the same there was text deleted, so this type of event can be ignored
- return;
- }
-
- // First remove any illegal characters
- Editable text = getText();
- CharSequence subText = text.subSequence(start, end);
- CharSequence withoutIllegalCharacters = removeIllegalCharacters(subText);
-
- // Check if illegal characters were found
- if (withoutIllegalCharacters.length() < subText.length()) {
- text.replace(start, end, withoutIllegalCharacters);
- end = start + withoutIllegalCharacters.length();
- clearComposingText();
- }
-
- if (start == end) {
- // If start and end are the same here, it means only illegal characters were inserted so there's nothing left to do
- return;
- }
-
- // Then handle chip terminator characters
- if (mChipTokenizer != null && mChipTerminatorHandler != null) {
- int newSelectionIndex = mChipTerminatorHandler.findAndHandleChipTerminators(mChipTokenizer, getText(), start, end, mIsPasteEvent);
- if (newSelectionIndex > 0) {
- setSelection(newSelectionIndex);
- }
- }
- }
-
- private CharSequence removeIllegalCharacters(CharSequence text) {
- StringBuilder newText = new StringBuilder();
-
- for (int i = 0; i < text.length(); i++) {
- char theChar = text.charAt(i);
- if (!isIllegalCharacter(theChar)) {
- newText.append(theChar);
- }
- }
-
- return newText;
- }
-
- private boolean isIllegalCharacter(char character) {
- if (illegalCharacterIdentifier != null) {
- return illegalCharacterIdentifier.isCharacterIllegal(character);
- }
- return false;
- }
-
- /**
- * Chipifies all existing plain text in the field
- */
- public void chipifyAllUnterminatedTokens() {
- beginUnwatchedTextChange();
- chipifyAllUnterminatedTokens(getText());
- endUnwatchedTextChange();
- }
-
- private void chipifyAllUnterminatedTokens(Editable text) {
- if (mChipTokenizer != null) {
- mChipTokenizer.terminateAllTokens(text);
- }
- }
-
- /**
- * Replaces the text from start (inclusive) to end (exclusive) with a chip
- * containing the same text
- *
- * @param start the index of the first character to replace
- * @param end one more than the index of the last character to replace
- */
- public void chipify(int start, int end) {
- beginUnwatchedTextChange();
- chipify(start, end, getText(), null);
- endUnwatchedTextChange();
- }
-
- private void chipify(int start, int end, Editable text, Object data) {
- if (mChipTokenizer != null) {
- CharSequence textToChip = text.subSequence(start, end);
- CharSequence chippedText = mChipTokenizer.terminateToken(textToChip, data);
- text.replace(start, end, chippedText);
- }
- }
-
- private CharSequence getTextWithPlainTextSpans(int start, int end) {
- Editable editable = getText();
- String selectedText = editable.subSequence(start, end).toString();
-
- if (mChipTokenizer != null) {
- List chips = Arrays.asList(mChipTokenizer.findAllChips(start, end, editable));
- Collections.reverse(chips);
- for (Chip chip : chips) {
- String chipText = chip.getText().toString();
- int chipStart = mChipTokenizer.findChipStart(chip, editable) - start;
- int chipEnd = mChipTokenizer.findChipEnd(chip, editable) - start;
- selectedText = selectedText.substring(0, chipStart) + chipText + selectedText.substring(chipEnd, selectedText.length());
- }
- }
- return selectedText;
- }
-
- /**
- * @return all of the chips currently in the text view - this does not include any unchipped text
- */
- @NonNull
- public List getAllChips() {
- Editable text = getText();
- return mChipTokenizer != null ? Arrays.asList(mChipTokenizer.findAllChips(0, text.length(), text)) : new ArrayList();
- }
-
- /**
- * Returns a List of the string values of all the chips in the text (obtained through {@link Chip#getText()}).
- * This does not include the text of any unterminated tokens.
- *
- * @return the List of chip values
- */
- @NonNull
- public List getChipValues() {
- List chipValues = new ArrayList<>();
-
- List chips = getAllChips();
- for (Chip chip : chips) {
- chipValues.add(chip.getText().toString());
- }
-
- return chipValues;
- }
-
- /**
- * Returns a List of the string values of all the tokens (unchipped text) in the text
- * (obtained through {@link ChipTokenizer#findAllTokens(CharSequence)}). This does not include any chipped text.
- *
- * @return the List of token values
- */
- @NonNull
- public List getTokenValues() {
- List