8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.5)
5 | rexml
6 | addressable (2.8.0)
7 | public_suffix (>= 2.0.2, < 5.0)
8 | artifactory (3.0.15)
9 | atomos (0.1.3)
10 | aws-eventstream (1.2.0)
11 | aws-partitions (1.574.0)
12 | aws-sdk-core (3.130.0)
13 | aws-eventstream (~> 1, >= 1.0.2)
14 | aws-partitions (~> 1, >= 1.525.0)
15 | aws-sigv4 (~> 1.1)
16 | jmespath (~> 1.0)
17 | aws-sdk-kms (1.55.0)
18 | aws-sdk-core (~> 3, >= 3.127.0)
19 | aws-sigv4 (~> 1.1)
20 | aws-sdk-s3 (1.113.0)
21 | aws-sdk-core (~> 3, >= 3.127.0)
22 | aws-sdk-kms (~> 1)
23 | aws-sigv4 (~> 1.4)
24 | aws-sigv4 (1.4.0)
25 | aws-eventstream (~> 1, >= 1.0.2)
26 | babosa (1.0.4)
27 | claide (1.1.0)
28 | colored (1.2)
29 | colored2 (3.1.2)
30 | commander (4.6.0)
31 | highline (~> 2.0.0)
32 | declarative (0.0.20)
33 | digest-crc (0.6.4)
34 | rake (>= 12.0.0, < 14.0.0)
35 | domain_name (0.5.20190701)
36 | unf (>= 0.0.5, < 1.0.0)
37 | dotenv (2.7.6)
38 | emoji_regex (3.2.3)
39 | excon (0.92.2)
40 | faraday (1.10.0)
41 | faraday-em_http (~> 1.0)
42 | faraday-em_synchrony (~> 1.0)
43 | faraday-excon (~> 1.1)
44 | faraday-httpclient (~> 1.0)
45 | faraday-multipart (~> 1.0)
46 | faraday-net_http (~> 1.0)
47 | faraday-net_http_persistent (~> 1.0)
48 | faraday-patron (~> 1.0)
49 | faraday-rack (~> 1.0)
50 | faraday-retry (~> 1.0)
51 | ruby2_keywords (>= 0.0.4)
52 | faraday-cookie_jar (0.0.7)
53 | faraday (>= 0.8.0)
54 | http-cookie (~> 1.0.0)
55 | faraday-em_http (1.0.0)
56 | faraday-em_synchrony (1.0.0)
57 | faraday-excon (1.1.0)
58 | faraday-httpclient (1.0.1)
59 | faraday-multipart (1.0.3)
60 | multipart-post (>= 1.2, < 3)
61 | faraday-net_http (1.0.1)
62 | faraday-net_http_persistent (1.2.0)
63 | faraday-patron (1.0.0)
64 | faraday-rack (1.0.0)
65 | faraday-retry (1.0.3)
66 | faraday_middleware (1.2.0)
67 | faraday (~> 1.0)
68 | fastimage (2.2.6)
69 | fastlane (2.205.1)
70 | CFPropertyList (>= 2.3, < 4.0.0)
71 | addressable (>= 2.8, < 3.0.0)
72 | artifactory (~> 3.0)
73 | aws-sdk-s3 (~> 1.0)
74 | babosa (>= 1.0.3, < 2.0.0)
75 | bundler (>= 1.12.0, < 3.0.0)
76 | colored
77 | commander (~> 4.6)
78 | dotenv (>= 2.1.1, < 3.0.0)
79 | emoji_regex (>= 0.1, < 4.0)
80 | excon (>= 0.71.0, < 1.0.0)
81 | faraday (~> 1.0)
82 | faraday-cookie_jar (~> 0.0.6)
83 | faraday_middleware (~> 1.0)
84 | fastimage (>= 2.1.0, < 3.0.0)
85 | gh_inspector (>= 1.1.2, < 2.0.0)
86 | google-apis-androidpublisher_v3 (~> 0.3)
87 | google-apis-playcustomapp_v1 (~> 0.1)
88 | google-cloud-storage (~> 1.31)
89 | highline (~> 2.0)
90 | json (< 3.0.0)
91 | jwt (>= 2.1.0, < 3)
92 | mini_magick (>= 4.9.4, < 5.0.0)
93 | multipart-post (~> 2.0.0)
94 | naturally (~> 2.2)
95 | optparse (~> 0.1.1)
96 | plist (>= 3.1.0, < 4.0.0)
97 | rubyzip (>= 2.0.0, < 3.0.0)
98 | security (= 0.1.3)
99 | simctl (~> 1.6.3)
100 | terminal-notifier (>= 2.0.0, < 3.0.0)
101 | terminal-table (>= 1.4.5, < 2.0.0)
102 | tty-screen (>= 0.6.3, < 1.0.0)
103 | tty-spinner (>= 0.8.0, < 1.0.0)
104 | word_wrap (~> 1.0.0)
105 | xcodeproj (>= 1.13.0, < 2.0.0)
106 | xcpretty (~> 0.3.0)
107 | xcpretty-travis-formatter (>= 0.0.3)
108 | gh_inspector (1.1.3)
109 | google-apis-androidpublisher_v3 (0.18.0)
110 | google-apis-core (>= 0.4, < 2.a)
111 | google-apis-core (0.4.2)
112 | addressable (~> 2.5, >= 2.5.1)
113 | googleauth (>= 0.16.2, < 2.a)
114 | httpclient (>= 2.8.1, < 3.a)
115 | mini_mime (~> 1.0)
116 | representable (~> 3.0)
117 | retriable (>= 2.0, < 4.a)
118 | rexml
119 | webrick
120 | google-apis-iamcredentials_v1 (0.10.0)
121 | google-apis-core (>= 0.4, < 2.a)
122 | google-apis-playcustomapp_v1 (0.7.0)
123 | google-apis-core (>= 0.4, < 2.a)
124 | google-apis-storage_v1 (0.12.0)
125 | google-apis-core (>= 0.4, < 2.a)
126 | google-cloud-core (1.6.0)
127 | google-cloud-env (~> 1.0)
128 | google-cloud-errors (~> 1.0)
129 | google-cloud-env (1.6.0)
130 | faraday (>= 0.17.3, < 3.0)
131 | google-cloud-errors (1.2.0)
132 | google-cloud-storage (1.36.1)
133 | addressable (~> 2.8)
134 | digest-crc (~> 0.4)
135 | google-apis-iamcredentials_v1 (~> 0.1)
136 | google-apis-storage_v1 (~> 0.1)
137 | google-cloud-core (~> 1.6)
138 | googleauth (>= 0.16.2, < 2.a)
139 | mini_mime (~> 1.0)
140 | googleauth (1.1.2)
141 | faraday (>= 0.17.3, < 3.a)
142 | jwt (>= 1.4, < 3.0)
143 | memoist (~> 0.16)
144 | multi_json (~> 1.11)
145 | os (>= 0.9, < 2.0)
146 | signet (>= 0.16, < 2.a)
147 | highline (2.0.3)
148 | http-cookie (1.0.4)
149 | domain_name (~> 0.5)
150 | httpclient (2.8.3)
151 | jmespath (1.6.1)
152 | json (2.6.1)
153 | jwt (2.3.0)
154 | memoist (0.16.2)
155 | mini_magick (4.11.0)
156 | mini_mime (1.1.2)
157 | multi_json (1.15.0)
158 | multipart-post (2.0.0)
159 | nanaimo (0.3.0)
160 | naturally (2.2.1)
161 | optparse (0.1.1)
162 | os (1.1.4)
163 | plist (3.6.0)
164 | public_suffix (4.0.6)
165 | rake (13.0.6)
166 | representable (3.1.1)
167 | declarative (< 0.1.0)
168 | trailblazer-option (>= 0.1.1, < 0.2.0)
169 | uber (< 0.2.0)
170 | retriable (3.1.2)
171 | rexml (3.2.5)
172 | rouge (2.0.7)
173 | ruby2_keywords (0.0.5)
174 | rubyzip (2.3.2)
175 | security (0.1.3)
176 | signet (0.16.1)
177 | addressable (~> 2.8)
178 | faraday (>= 0.17.5, < 3.0)
179 | jwt (>= 1.5, < 3.0)
180 | multi_json (~> 1.10)
181 | simctl (1.6.8)
182 | CFPropertyList
183 | naturally
184 | terminal-notifier (2.0.0)
185 | terminal-table (1.8.0)
186 | unicode-display_width (~> 1.1, >= 1.1.1)
187 | trailblazer-option (0.1.2)
188 | tty-cursor (0.7.1)
189 | tty-screen (0.8.1)
190 | tty-spinner (0.9.3)
191 | tty-cursor (~> 0.7)
192 | uber (0.1.0)
193 | unf (0.1.4)
194 | unf_ext
195 | unf_ext (0.0.8.1)
196 | unicode-display_width (1.8.0)
197 | webrick (1.7.0)
198 | word_wrap (1.0.0)
199 | xcodeproj (1.21.0)
200 | CFPropertyList (>= 2.3.3, < 4.0)
201 | atomos (~> 0.1.3)
202 | claide (>= 1.0.2, < 2.0)
203 | colored2 (~> 3.1)
204 | nanaimo (~> 0.3.0)
205 | rexml (~> 3.2.4)
206 | xcpretty (0.3.0)
207 | rouge (~> 2.0.7)
208 | xcpretty-travis-formatter (1.0.1)
209 | xcpretty (~> 0.2, >= 0.0.7)
210 |
211 | PLATFORMS
212 | x86_64-linux
213 |
214 | DEPENDENCIES
215 | fastlane
216 |
217 | BUNDLED WITH
218 | 2.2.5
219 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a colorful, text-based calendar widget for Android.
2 |
3 | The color coding is intended to be especially useful for people who must
4 | coordinate multiple calendars.
5 |
6 | It is relatively simple, at least by Android project standards, and attempts
7 | to use the standard practices for each part. By default, it has no calendar
8 | permissions, and so it will be in "screenshot mode" (which was also used to
9 | prepare the app widget preview).
10 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 31
5 |
6 | defaultConfig {
7 | applicationId "com.gyorog.polycal"
8 | minSdkVersion 24
9 | targetSdkVersion 31
10 | versionCode 7
11 | versionName "1.7"
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | implementation fileTree(dir: "libs", include: ["*.jar"])
24 | implementation 'androidx.appcompat:appcompat:1.4.1'
25 | implementation 'androidx.preference:preference:1.2.0'
26 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
27 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/release/app-release.aab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/release/app-release.aab
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/gyorog/polycal/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.polycal;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.example.polycal", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
55 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gyorog/polycal/CalendarRemoteViewsFactory.java:
--------------------------------------------------------------------------------
1 | package com.gyorog.polycal;
2 |
3 | import android.appwidget.AppWidgetManager;
4 | import android.content.ContentUris;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.SharedPreferences;
8 | import android.database.Cursor;
9 | import android.graphics.Color;
10 | import android.net.Uri;
11 | import android.os.Binder;
12 | import android.os.Bundle;
13 | import android.provider.CalendarContract;
14 | import android.text.TextUtils;
15 | import android.util.Log;
16 | import android.util.TypedValue;
17 | import android.widget.AdapterView;
18 | import android.widget.RemoteViews;
19 | import android.widget.RemoteViewsService;
20 |
21 | import java.text.DateFormatSymbols;
22 | import java.text.SimpleDateFormat;
23 | import java.util.Calendar;
24 | import java.util.Date;
25 | import java.util.HashSet;
26 | import java.util.Locale;
27 | import java.util.Set;
28 | import java.util.TimeZone;
29 |
30 | public class CalendarRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
31 | public static final String EVENT_ID = "com.gyorog.polycal.EVENT_ID";
32 | public static final String EVENT_BEGIN = "com.gyorog.polycal.EVENT_BEGIN";
33 | private static final String TAG = "CalendarRemoteViewsFactory";
34 | private Context mContext;
35 | private Cursor mCursor;
36 | private int widget_id;
37 | private int text_size;
38 | private String date_format;
39 | private String date_format_allday;
40 |
41 | public CalendarRemoteViewsFactory(Context applicationContext, Intent intent) {
42 | mContext = applicationContext;
43 | //widget_id = Integer.parseInt(intent.getData().getSchemeSpecificPart());
44 | widget_id = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
45 | Log.d(TAG, "wID " + widget_id + " created.");
46 | }
47 |
48 | @Override
49 | public void onCreate() { }
50 |
51 | @Override
52 | public void onDataSetChanged() {
53 | final long identityToken = Binder.clearCallingIdentity();
54 | Log.d(TAG, "wID " + widget_id + " got identityToken " + identityToken);
55 |
56 | // SharedPreferences SharePref = PreferenceManager.getDefaultSharedPreferences(mContext);
57 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
58 | SharedPreferences SharePref = mContext.getSharedPreferences(pref_file_name , 0);
59 |
60 | text_size = SharePref.getInt("text_size", 12);
61 | date_format = SharePref.getString("date_format", (String) PolyCalDateFormats.getFormatsParseable()[0]);
62 | date_format_allday = SharePref.getString("date_format_allday", (String) PolyCalDateFormats.getFormatsParseableAllday()[0]);
63 | Log.d(TAG, "wID " + widget_id + " got date_format='" + date_format + "' and date_format_allday='" + date_format_allday + "'");
64 |
65 | Set EnabledCalendarIDs = SharePref.getStringSet("calendar_selection", new HashSet() );
66 | Log.d(TAG, "wID " + widget_id + " got calendar_selection='" + EnabledCalendarIDs.toString() + "'" );
67 |
68 | GetCalendarEvents(EnabledCalendarIDs);
69 | Log.d(TAG, "wID " + widget_id + " found " + getCount() + " calendar events.");
70 |
71 | Binder.restoreCallingIdentity(identityToken);
72 | }
73 |
74 |
75 | @Override
76 | public void onDestroy() {
77 | if (mCursor != null) {
78 | mCursor.close();
79 | }
80 | }
81 |
82 | @Override
83 | public int getCount() {
84 | return mCursor == null ? 0 : mCursor.getCount();
85 | }
86 |
87 | @Override
88 | public RemoteViews getViewAt(int position) {
89 | Log.d(TAG, "RemoteViews getViewAt(" + position + ")");
90 | if (position == AdapterView.INVALID_POSITION || mCursor == null || !mCursor.moveToPosition(position)) {
91 | return null;
92 | }
93 |
94 | SimpleDateFormat formatter;
95 | if ( 1 == mCursor.getInt(EVENT_INDEX_ALLDAY) ) {
96 | formatter = new SimpleDateFormat(date_format_allday, Locale.US);
97 | } else {
98 | formatter = new SimpleDateFormat(date_format, Locale.US);
99 | }
100 | DateFormatSymbols symbols = new DateFormatSymbols(Locale.getDefault());
101 | symbols.setAmPmStrings(new String[] { "am", "pm" });
102 | formatter.setDateFormatSymbols(symbols);
103 | Date StartDate = new Date( mCursor.getLong(EVENT_INDEX_BEGIN) );
104 | formatter.setTimeZone(TimeZone.getTimeZone( mCursor.getString(EVENT_INDEX_EVENT_TIMEZONE) ));
105 |
106 | RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.appwidget_item);
107 |
108 | Bundle extras = new Bundle();
109 | //extras.putLong(EVENT_ID, mCursor.getLong(EVENT_INDEX_EVENTID));
110 | extras.putLong(EVENT_BEGIN, mCursor.getLong(EVENT_INDEX_BEGIN));
111 | Intent fillInIntent = new Intent();
112 | fillInIntent.putExtras(extras);
113 | rv.setOnClickFillInIntent(R.id.item_layout, fillInIntent);
114 |
115 | int other_color = Color.LTGRAY;
116 |
117 | rv.setTextViewText(R.id.event_time, formatter.format(StartDate) );
118 | rv.setTextColor(R.id.event_time, other_color);
119 | rv.setTextViewTextSize(R.id.event_time, TypedValue.COMPLEX_UNIT_SP, text_size);
120 |
121 | String title_raw = mCursor.getString(EVENT_INDEX_TITLE);
122 | if (title_raw != null) {
123 | rv.setTextViewText(R.id.event_title, title_raw.replaceAll("[\\t\\n\\r]+", " "));
124 | } else {
125 | rv.setTextViewText(R.id.event_title, "");
126 | }
127 | rv.setTextColor(R.id.event_title, mCursor.getInt(EVENT_INDEX_DISPLAY_COLOR));
128 | rv.setTextViewTextSize(R.id.event_title, TypedValue.COMPLEX_UNIT_SP, text_size);
129 |
130 | String location_raw = mCursor.getString(EVENT_INDEX_LOCATION);
131 | if (location_raw != null) {
132 | rv.setTextViewText(R.id.event_location, location_raw.replaceAll("[\\t\\n\\r]+", " "));
133 | } else {
134 | rv.setTextViewText(R.id.event_location, "" );
135 | }
136 | rv.setTextColor(R.id.event_location, other_color);
137 | rv.setTextViewTextSize(R.id.event_location, TypedValue.COMPLEX_UNIT_SP, text_size);
138 |
139 | return rv;
140 | }
141 |
142 | @Override
143 | public RemoteViews getLoadingView() {
144 | return null;
145 | }
146 |
147 | @Override
148 | public int getViewTypeCount() {
149 | return 1;
150 | }
151 |
152 | @Override
153 | public long getItemId(int position) {
154 | return mCursor.moveToPosition(position) ? mCursor.getLong(0) : position;
155 | }
156 |
157 | @Override
158 | public boolean hasStableIds() {
159 | return true;
160 | }
161 |
162 |
163 | public static final String[] EVENT_COLUMN_LIST = new String[] {
164 | CalendarContract.Instances.EVENT_ID,
165 | CalendarContract.Instances.BEGIN,
166 | CalendarContract.Events.ALL_DAY,
167 | CalendarContract.Events.EVENT_TIMEZONE,
168 | CalendarContract.Events.DISPLAY_COLOR,
169 | CalendarContract.Events.TITLE,
170 | CalendarContract.Events.EVENT_LOCATION,
171 | CalendarContract.Instances.END
172 | };
173 | private static final int EVENT_INDEX_EVENTID = 0;
174 | private static final int EVENT_INDEX_BEGIN = 1;
175 | private static final int EVENT_INDEX_ALLDAY = 2;
176 | private static final int EVENT_INDEX_EVENT_TIMEZONE = 3;
177 | private static final int EVENT_INDEX_DISPLAY_COLOR = 4;
178 | private static final int EVENT_INDEX_TITLE = 5;
179 | private static final int EVENT_INDEX_LOCATION = 6;
180 | private static final int EVENT_INDEX_END = 7;
181 |
182 | private void GetCalendarEvents(Set EnabledCalendarIDs) {
183 | long now_ms = System.currentTimeMillis();
184 |
185 | Calendar cal_end = Calendar.getInstance();
186 | cal_end.add(Calendar.YEAR, 1);
187 | long end_ms = cal_end.getTimeInMillis();
188 |
189 | Uri.Builder instancesUriBuilder = CalendarContract.Instances.CONTENT_URI.buildUpon();
190 | ContentUris.appendId(instancesUriBuilder, now_ms );
191 | ContentUris.appendId(instancesUriBuilder, end_ms );
192 | Uri instancesUri = instancesUriBuilder.build();
193 |
194 | String[] selectionArgs = new String[0];
195 | String selectionString = "";
196 | if( EnabledCalendarIDs.isEmpty() ) {
197 | selectionString = "( " + CalendarContract.Instances.CALENDAR_ID + " != " + CalendarContract.Instances.CALENDAR_ID + " )";
198 | } else {
199 | // selectionArgs = EnabledCalendarIDs.toArray(new String[EnabledCalendarIDs.size()]);
200 | selectionArgs = EnabledCalendarIDs.toArray(new String[0]);
201 |
202 | String[] query_list = new String[selectionArgs.length];
203 | for(int i=0; i " + intent.toString() );
143 | for (String key : intent.getExtras().keySet())
144 | Log.d(TAG, "(extra) " + key + " = " + intent.getExtras().get(key));
145 | }
146 |
147 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/gyorog/polycal/ScreenshotRemoteViewsFactory.java:
--------------------------------------------------------------------------------
1 | package com.gyorog.polycal;
2 |
3 | import android.appwidget.AppWidgetManager;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.graphics.Color;
8 | import android.os.Binder;
9 | import android.util.Log;
10 | import android.util.TypedValue;
11 | import android.widget.AdapterView;
12 | import android.widget.RemoteViews;
13 | import android.widget.RemoteViewsService;
14 |
15 | import java.text.DateFormatSymbols;
16 | import java.text.ParseException;
17 | import java.text.SimpleDateFormat;
18 | import java.util.Date;
19 | import java.util.Locale;
20 |
21 | public class ScreenshotRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
22 | private static final String TAG = "ScreenshotRemoteViewsFactory";
23 | private Context mContext;
24 | private int widget_id;
25 | private int text_size;
26 | private String date_format;
27 | private String date_format_allday;
28 |
29 | private static class EventEntry{
30 | public String color;
31 | public Boolean allday;
32 | public Date begin;
33 | public String title;
34 | public String location;
35 | EventEntry(String set_color, Boolean set_allday, Date set_begin, String set_title, String set_location){
36 | color = set_color;
37 | allday = set_allday;
38 | begin = set_begin;
39 | title = set_title;
40 | location = set_location;
41 | }
42 | }
43 |
44 | private static SimpleDateFormat formatter = new SimpleDateFormat("MMM dd hh:mm a", Locale.US);
45 | private static EventEntry fake_events[] = new EventEntry[0];
46 | static {
47 | try {
48 | fake_events = new EventEntry[]{
49 | new EventEntry("#ff8888", false, formatter.parse("Jun 1 10:00 pm"), "Date with Sam", ""),
50 | new EventEntry("#00aaaa", false, formatter.parse("Jun 3 8:00 am"), "Receive award for PolyCal", ""),
51 | new EventEntry("#00aaaa", false, formatter.parse("Jun 6 2:30 pm"), "Honorary Doctorate review", ""),
52 | new EventEntry("#00aaaa", false, formatter.parse("Jun 8 10:00 am"), "Nobel Awards ceremony", ""),
53 | new EventEntry("#ffff00", true, formatter.parse("Jun 12 12:00 am"), "Loving Day", ""),
54 | new EventEntry("#ff8888", false, formatter.parse("Jun 15 8:00 pm"), "Date with Pat", ""),
55 | new EventEntry("#ffff00", true, formatter.parse("Jun 19 12:00 am"), "Juneteenth", ""),
56 | new EventEntry("#00aaaa", false, formatter.parse("Jun 25 5:00 pm"), "Receive Medal of Honor", ""),
57 | new EventEntry("#ffff00", true, formatter.parse("Jun 28 12:00 am"), "Stonewall Riots Anniversary", ""),
58 | new EventEntry("#00aaaa", false, formatter.parse("Jun 29 8:00 am"), "Booker Prize review", "")
59 | };
60 | } catch (ParseException e) {
61 | e.printStackTrace();
62 | }
63 | }
64 |
65 | public ScreenshotRemoteViewsFactory(Context applicationContext, Intent intent) {
66 | mContext = applicationContext;
67 | //LogIntent("ScreenshotRemoteViewsFactoy()", intent);
68 | widget_id = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
69 | Log.d(TAG, "wID " + widget_id + " new ScreenshotRemoteViewsFactory()");
70 | }
71 |
72 | @Override
73 | public void onCreate() { }
74 |
75 | @Override
76 | public void onDataSetChanged() {
77 | final long identityToken = Binder.clearCallingIdentity();
78 |
79 | // SharedPreferences SharePref = PreferenceManager.getDefaultSharedPreferences(mContext);
80 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
81 | SharedPreferences SharePref = mContext.getSharedPreferences(pref_file_name , 0);
82 |
83 | text_size = SharePref.getInt("text_size", 12);
84 | date_format = SharePref.getString("date_format", (String) PolyCalDateFormats.getFormatsParseable()[0]);
85 | date_format_allday = SharePref.getString("date_format_allday", (String) PolyCalDateFormats.getFormatsParseableAllday()[0]);
86 | Log.d(TAG, "wID " + widget_id + " got date_format='" + date_format + "' and date_format_allday='" + date_format_allday + "'");
87 |
88 | Binder.restoreCallingIdentity(identityToken);
89 | }
90 |
91 | @Override
92 | public void onDestroy() {}
93 |
94 | @Override
95 | public int getCount() {
96 | return fake_events.length;
97 | }
98 |
99 | @Override
100 | public RemoteViews getViewAt(int position) {
101 | if (position == AdapterView.INVALID_POSITION){
102 | return null;
103 | }
104 |
105 | int other_color = Color.LTGRAY;
106 | EventEntry my_entry = fake_events[position];
107 |
108 | SimpleDateFormat formatter;
109 | if ( my_entry.allday ) {
110 | formatter = new SimpleDateFormat(date_format_allday, Locale.US);
111 | } else {
112 | formatter = new SimpleDateFormat(date_format, Locale.US);
113 | }
114 | DateFormatSymbols symbols = new DateFormatSymbols(Locale.getDefault());
115 | symbols.setAmPmStrings(new String[] { "am", "pm" });
116 | formatter.setDateFormatSymbols(symbols);
117 |
118 | RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.appwidget_item);
119 |
120 | Intent settings_intent = new Intent(mContext, SettingsActivity.class);
121 | settings_intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget_id);
122 | settings_intent.putExtra("from", "Screenshot.UserClick");
123 | rv.setOnClickFillInIntent(R.id.item_layout, settings_intent);
124 |
125 | rv.setTextViewText(R.id.event_time, formatter.format(my_entry.begin));
126 | rv.setTextColor(R.id.event_time, other_color);
127 | rv.setTextViewTextSize(R.id.event_time, TypedValue.COMPLEX_UNIT_SP, text_size);
128 |
129 | rv.setTextViewText(R.id.event_title, my_entry.title);
130 | rv.setTextColor(R.id.event_title, Color.parseColor(my_entry.color) );
131 | rv.setTextViewTextSize(R.id.event_title, TypedValue.COMPLEX_UNIT_SP, text_size);
132 |
133 | rv.setTextViewText(R.id.event_location, my_entry.location);
134 | rv.setTextColor(R.id.event_location, other_color);
135 | rv.setTextViewTextSize(R.id.event_location, TypedValue.COMPLEX_UNIT_SP, text_size);
136 |
137 | return rv;
138 | }
139 |
140 | @Override
141 | public RemoteViews getLoadingView() {
142 | return null;
143 | }
144 |
145 | @Override
146 | public int getViewTypeCount() {
147 | return 1;
148 | }
149 |
150 | @Override
151 | public long getItemId(int position) {
152 | return position;
153 | }
154 |
155 | @Override
156 | public boolean hasStableIds() {
157 | return true;
158 | }
159 | /*
160 | public void LogIntent(String extra_tag, Intent intent){
161 | Log.d(TAG, extra_tag + " -> " + intent.toString() );
162 | for (String key : intent.getExtras().keySet())
163 | Log.d(TAG, "(extra) " + key + " = " + intent.getExtras().get(key));
164 | }
165 | */
166 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/gyorog/polycal/ScreenshotRemoteViewsService.java:
--------------------------------------------------------------------------------
1 | package com.gyorog.polycal;
2 |
3 | import android.content.Intent;
4 | import android.os.IBinder;
5 | import android.util.Log;
6 | import android.widget.RemoteViewsService;
7 |
8 | public class ScreenshotRemoteViewsService extends RemoteViewsService {
9 | private static final String TAG = "ScreenshotRemoteViewService";
10 |
11 | @Override
12 | public RemoteViewsFactory onGetViewFactory(Intent intent) {
13 | //LogIntent("onGetViewFactory()", intent);
14 | return new ScreenshotRemoteViewsFactory(this.getApplicationContext(), intent);
15 | }
16 | /*
17 | public IBinder onBind(Intent intent) {
18 | LogIntent("onBind()", intent);
19 | return super.onBind(intent);
20 | }
21 | */
22 | /*
23 | public void LogIntent(String extra_tag, Intent intent){
24 | Log.d(TAG, extra_tag + " Received " + intent.toString() );
25 | for (String key : intent.getExtras().keySet())
26 | Log.d(TAG, "(extra) " + key + " = " + intent.getExtras().get(key));
27 | }
28 | */
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/gyorog/polycal/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.gyorog.polycal;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.appwidget.AppWidgetManager;
6 | import android.content.ContentResolver;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.content.pm.PackageManager;
10 | import android.database.Cursor;
11 | import android.net.Uri;
12 | import android.os.Bundle;
13 | import android.provider.CalendarContract.Calendars;
14 | import android.util.Log;
15 | import android.view.View;
16 | import android.widget.Button;
17 |
18 | import androidx.appcompat.app.AppCompatActivity;
19 | import androidx.core.app.ActivityCompat;
20 | import androidx.preference.ListPreference;
21 | import androidx.preference.MultiSelectListPreference;
22 | import androidx.preference.Preference;
23 | import androidx.preference.PreferenceFragmentCompat;
24 | import androidx.preference.SeekBarPreference;
25 | import androidx.preference.SwitchPreference;
26 |
27 | import java.util.Arrays;
28 | import java.util.HashSet;
29 | import java.util.LinkedList;
30 | import java.util.List;
31 | import java.util.Set;
32 |
33 | public class SettingsActivity extends AppCompatActivity {
34 | private static final String TAG = "com.gyorog.polycal.SettingsActivity";
35 | private List CalendarIDs = new LinkedList<>();
36 | private List CalendarDisplayNames = new LinkedList<>();
37 | static public int widget_id;
38 | Boolean requireReturnCode = false;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 |
44 | Bundle extras = getIntent().getExtras();
45 | if ( extras != null ){
46 | widget_id = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
47 | Log.d(TAG, "wID " + widget_id + " (from " + AppWidgetManager.EXTRA_APPWIDGET_ID + ")");
48 |
49 | String intent_from = extras.getString("from");
50 | if (intent_from == null) {
51 | Log.d(TAG, "No 'from' extra. Assuming needs return code.");
52 | requireReturnCode = true;
53 | } else if ( intent_from.equals("WidgetProvider") ){
54 | Log.d(TAG, "Detected 'from' extra as 'WidgetProvider'");
55 | requireReturnCode = false;
56 | } else {
57 | Log.d(TAG, "Detected 'from' extra as '" + intent_from + "'");
58 | requireReturnCode = false;
59 | }
60 | } else {
61 | finish();
62 | Log.e(TAG, "COULD NOT DETERMINE WIDGET ID for SettingsActivity");
63 | }
64 |
65 | // Set up preferences screen
66 |
67 |
68 | if (! requireReturnCode) {
69 | setContentView(R.layout.settings_activity);
70 | } else {
71 | setContentView(R.layout.settings_activity_button);
72 |
73 | Button accept_button = findViewById(R.id.accept_button);
74 | accept_button.setText("Add Widget to Home Screen");
75 | accept_button.setOnClickListener(new View.OnClickListener() {
76 | public void onClick(View v) {
77 | setResult(Activity.RESULT_OK);
78 | finish();
79 | }
80 | });
81 |
82 | }
83 |
84 | }
85 |
86 |
87 | public static class SettingsFragment extends PreferenceFragmentCompat {
88 | private final int READ_CALENDAR_CONSTANT=1;
89 |
90 | @Override
91 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
92 | setPreferencesFromResource(R.xml.preference_screen, rootKey);
93 |
94 | Log.d(TAG, "wID " + widget_id + " onCreatePreferences()");
95 |
96 | findPreference("calendar_permission").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
97 | @Override
98 | public boolean onPreferenceClick(Preference preference){
99 | requestPermissions(new String[]{Manifest.permission.READ_CALENDAR}, READ_CALENDAR_CONSTANT);
100 | return true;
101 | }
102 | });
103 |
104 | findPreference("screenshot_mode").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
105 | @Override
106 | public boolean onPreferenceChange(Preference preference, Object newSetting) {
107 | if ( (boolean) newSetting ){
108 | findPreference("calendar_select").setEnabled(false);
109 | } else {
110 | findPreference("calendar_select").setEnabled(true);
111 | }
112 |
113 | Log.d(TAG, "wID " + widget_id + " onPreferenceChange(screenshotmode=" + newSetting + ")");
114 |
115 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
116 | SharedPreferences SharePref = preference.getContext().getSharedPreferences(pref_file_name , 0);
117 | SharedPreferences.Editor editor = SharePref.edit();
118 | editor.putBoolean("screenshot_mode", (boolean) newSetting);
119 | editor.apply();
120 |
121 | Intent redraw = new Intent("com.gyorog.polycal.CHANGE_SOURCE");
122 | redraw.setPackage(getContext().getPackageName());
123 | getContext().sendBroadcast(redraw);
124 |
125 | return true;
126 | }
127 | });
128 |
129 | //String calendar_select_pref = String.format("%d calendar_select", widget_id);
130 | findPreference("calendar_select").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
131 | @Override
132 | public boolean onPreferenceChange(Preference preference, Object newVal) {
133 | Log.d(TAG, "wID " + widget_id + " onPreferenceChange(calendar_selection=" + newVal.toString() + ")");
134 |
135 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
136 | SharedPreferences SharePref = preference.getContext().getSharedPreferences(pref_file_name , 0);
137 | SharedPreferences.Editor editor = SharePref.edit();
138 | editor.putStringSet("calendar_selection", (Set) newVal);
139 | editor.apply();
140 |
141 | Intent redraw = new Intent("com.gyorog.polycal.RELOAD_EVENTS");
142 | redraw.setPackage(getContext().getPackageName());
143 | getContext().sendBroadcast(redraw);
144 |
145 | return true;
146 | }
147 | });
148 |
149 | SeekBarPreference seek_bar = findPreference("text_size");
150 | if (seek_bar != null) {
151 | seek_bar.setShowSeekBarValue(true);
152 | seek_bar.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
153 | @Override
154 | public boolean onPreferenceChange(Preference preference, Object newVal) {
155 | Log.d(TAG, "wID " + widget_id + " onPreferenceChange(text_size=" + newVal.toString() + ")");
156 |
157 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
158 | SharedPreferences SharePref = preference.getContext().getSharedPreferences(pref_file_name, 0);
159 | SharedPreferences.Editor editor = SharePref.edit();
160 | editor.putInt("text_size", (int) newVal);
161 | editor.apply();
162 |
163 | Intent redraw = new Intent("com.gyorog.polycal.RELOAD_EVENTS");
164 | redraw.setPackage(getContext().getPackageName());
165 | getContext().sendBroadcast(redraw);
166 |
167 | return true;
168 | }
169 | });
170 | }
171 |
172 | findPreference("date_format").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
173 | @Override
174 | public boolean onPreferenceChange(Preference preference, Object newVal) {
175 | Log.d(TAG, "wID " + widget_id + " onPreferenceChange(date_format=" + newVal.toString() + ")");
176 |
177 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
178 | SharedPreferences SharePref = preference.getContext().getSharedPreferences(pref_file_name , 0);
179 | SharedPreferences.Editor editor = SharePref.edit();
180 | editor.putString("date_format", (String) newVal);
181 | editor.apply();
182 |
183 | Intent redraw = new Intent("com.gyorog.polycal.RELOAD_EVENTS");
184 | redraw.setPackage(getContext().getPackageName());
185 | getContext().sendBroadcast(redraw);
186 |
187 | return true;
188 | }
189 | });
190 |
191 | findPreference("date_format_allday").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
192 | @Override
193 | public boolean onPreferenceChange(Preference preference, Object newVal) {
194 | Log.d(TAG, "wID " + widget_id + " onPreferenceChange(date_format_allday=" + newVal.toString() + ")" );
195 |
196 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
197 | SharedPreferences SharePref = preference.getContext().getSharedPreferences(pref_file_name , 0);
198 | SharedPreferences.Editor editor = SharePref.edit();
199 | editor.putString("date_format_allday", (String) newVal);
200 | editor.apply();
201 |
202 | Intent redraw = new Intent("com.gyorog.polycal.RELOAD_EVENTS");
203 | redraw.setPackage(getContext().getPackageName());
204 | getContext().sendBroadcast(redraw);
205 |
206 | return true;
207 | }
208 | });
209 |
210 | UpdatePreferences();
211 | }
212 |
213 | public void UpdatePreferences() {
214 | boolean gotCalendarPermission = ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED;
215 |
216 | String pref_file_name = String.format("com.gyorog.PolyCal.prefs_for_widget_%d", widget_id);
217 | SharedPreferences SharePref = getContext().getSharedPreferences(pref_file_name , 0);
218 |
219 | if (gotCalendarPermission) {
220 | Preference CalendarPermissionPref = findPreference("calendar_permission");
221 | CalendarPermissionPref.setEnabled(false);
222 | CalendarPermissionPref.setSummary("Calendar permission has been granted.");
223 |
224 | ((SettingsActivity) getActivity()).FillCalendarLists();
225 | int CalendarCount = ((SettingsActivity) getActivity()).CalendarDisplayNames.size();
226 | CharSequence[] entries_array = ((SettingsActivity) getActivity()).CalendarDisplayNames.toArray(new CharSequence[CalendarCount]);
227 | CharSequence[] values_array = ((SettingsActivity) getActivity()).CalendarIDs.toArray(new CharSequence[CalendarCount]);
228 |
229 | Boolean screenshot_mode = SharePref.getBoolean("screenshot_mode", true);
230 | SwitchPreference ScreenshotModePref = findPreference("screenshot_mode");
231 | ScreenshotModePref.setEnabled(true);
232 | ScreenshotModePref.setChecked(screenshot_mode);
233 |
234 | Set current_calendar_selection = SharePref.getStringSet("calendar_selection", null );
235 | if(current_calendar_selection == null){
236 | current_calendar_selection = new HashSet<>();
237 | for(int i=0; i
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/text_outline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/widget_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/widget_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/drawable/widget_preview.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/appwidget.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
15 |
16 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/appwidget_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
17 |
18 |
19 |
26 |
27 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/settings_activity.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/settings_activity_button.xml:
--------------------------------------------------------------------------------
1 |
8 |
15 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/polycal_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/polycal_icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/polycal_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-hdpi/polycal_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/polycal_icon_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-hdpi/polycal_icon_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/polycal_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-hdpi/polycal_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/polycal_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-hdpi/polycal_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/polycal_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-mdpi/polycal_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/polycal_icon_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-mdpi/polycal_icon_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/polycal_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-mdpi/polycal_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/polycal_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-mdpi/polycal_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/polycal_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xhdpi/polycal_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/polycal_icon_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xhdpi/polycal_icon_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/polycal_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xhdpi/polycal_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/polycal_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xhdpi/polycal_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/polycal_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxhdpi/polycal_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/polycal_icon_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxhdpi/polycal_icon_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/polycal_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxhdpi/polycal_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/polycal_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxhdpi/polycal_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/polycal_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxxhdpi/polycal_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/polycal_icon_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxxhdpi/polycal_icon_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/polycal_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxxhdpi/polycal_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/polycal_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/app/src/main/res/mipmap-xxxhdpi/polycal_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PolyCal
3 | Settings
4 |
5 |
6 | Calendar Permission
7 | Tap to request. Without calendar permission, only Screenshot Mode can be used.
8 |
9 | Screenshot Mode
10 | This mode populates the widget with fake entries.
11 |
12 | Select Calendars
13 | Only entries from selected calendars will be displayed.
14 |
15 | Date/Time Format
16 | Select a date and time format for events with a starting time.
17 |
18 | Date Format
19 | Select a date format for "all day" events.
20 |
21 | This app is a home screen widget. For this version of Android, you must add widgets to your home screen by first navigating to the screen where you want the widget. Then, long-press on the screeen where you want the widget.
22 | Multiple widget instances found. Please choose one to configure:
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/appwidget_provider.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preference_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
13 |
18 |
19 |
20 |
26 |
30 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/test/java/com/gyorog/polycal/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.polycal;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:7.1.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | tasks.withType(JavaCompile) {
21 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | json_key_file("/home/yoda/AndroidStore-PlayStore/pc-api-6859567652060244258-307-11ba2d372a11.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
2 | package_name("com.gyorog.polycal") # e.g. com.krausefx.app
3 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:android)
17 |
18 | platform :android do
19 | desc "Deploy a new version to the Google Play"
20 | lane :deploy do
21 | gradle(task: "clean assembleRelease")
22 | upload_to_play_store
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/5.txt:
--------------------------------------------------------------------------------
1 | Clicking an event now launches the calendar to that date.
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/6.txt:
--------------------------------------------------------------------------------
1 | Fixed a few bugs with the help of the F-Droid team.
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/7.txt:
--------------------------------------------------------------------------------
1 | Added text size slider.
2 | Added FLAG_IMMUTABLE to prevent a crash on Android 12.
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | The color coding is intended to be especially useful for people who must coordinate multiple calendars. Multiple widgets can be added, and they will have separate calendar selection settings.
2 |
3 | It is relatively simple, at least by Android project standards, and attempts to use the standard practices for each part. By default, it has no calendar permissions, and so it will be in "screenshot mode" (which was also used to prepare the app widget preview).
4 |
5 | Source Code (GPLv2): https://github.com/jasongyorog/PolyCal
6 | Privacy Policy: http://gyorog.com/PolyCal-privacy.html
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/featureGraphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/fastlane/metadata/android/en-US/images/featureGraphic.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | colorful, text-based calendar widget
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | PolyCal
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Oct 20 19:04:51 CDT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/imported_images/PolyCal_background_1296.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/PolyCal_background_1296.png
--------------------------------------------------------------------------------
/imported_images/PolyCal_background_1296.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/PolyCal_background_1296.xcf
--------------------------------------------------------------------------------
/imported_images/PolyCal_foreground_1296.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/PolyCal_foreground_1296.png
--------------------------------------------------------------------------------
/imported_images/PolyCal_foreground_1296.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/PolyCal_foreground_1296.xcf
--------------------------------------------------------------------------------
/imported_images/PolyCal_ori_portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/PolyCal_ori_portrait.png
--------------------------------------------------------------------------------
/imported_images/Poly_Settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/Poly_Settings.png
--------------------------------------------------------------------------------
/imported_images/Polyamory_Pride_Flag.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/imported_images/attribution.txt:
--------------------------------------------------------------------------------
1 | The preview image was created using the Widget Preview app on an emulated Nexus 5 running API 24.
2 |
3 |
4 |
5 |
6 | I made the PolyCal icon in GIMP, using two images (attribution below) as source material. I
7 | noticed that the "Asset Studio" application built-in to Android Studio creates icon sizes at
8 | 108, 162, 216, 324, and 432. To accommodate all these sizes, I worked at 1296x1296, which
9 | is the least common multiple of that list of numbers.
10 |
11 |
12 |
13 | https://www.flaticon.com/free-icon/june-16-daily-calendar-page_42328
14 | Icon made by Freepik from www.flaticon.com
15 | - This SVG was edited in a text editor, to remove the numerals, then imported into GIMP.
16 |
17 |
18 |
19 | "Polyamory Pride Flag"
20 | https://commons.wikimedia.org/wiki/File:Polyamory_Pride_Flag.svg
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/imported_images/calendar.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
87 |
--------------------------------------------------------------------------------
/imported_images/calendar2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
41 |
--------------------------------------------------------------------------------
/imported_images/polycal_github_social_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/polycal_github_social_preview.png
--------------------------------------------------------------------------------
/imported_images/polycal_playstore_feature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasongyorog/PolyCal/a3c474ea5ebb92e92e5354c316c2ff50e6a3fb6e/imported_images/polycal_playstore_feature.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "PolyCal"
--------------------------------------------------------------------------------