Merge pull request #1 from SimpleMobileTools/master

update from source
This commit is contained in:
Xose M 2020-06-06 10:25:23 +02:00 committed by GitHub
commit 1fe5610697
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
621 changed files with 33286 additions and 19350 deletions

View file

@ -15,3 +15,9 @@ root = true
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
continuation_indent_size = 8
[*.xml]
continuation_indent_size = 4

3
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,3 @@
github: [tibbi]
patreon: tiborkaputa
custom: ["https://www.paypal.me/SimpleMobileTools", "https://www.simplemobiletools.com/donate"]

21
.gitignore vendored
View file

@ -1,25 +1,10 @@
# Temp files
*~
*.bak
*.backup
\#*
.\#*
*\#
*.swp
*.swap
*.sav
*.save
*.autosav
*.autosave
*.iml
*.aab
.gradle
/local.properties
/gradle.properties
/.idea/
.DS_Store
/build
/captures
debug.keystore
release.keystore
signing.properties
keystore.jks
keystore.properties

View file

@ -1,6 +1,502 @@
Changelog
==========
Version 6.9.4 *(2020-05-25)*
----------------------------
* Allow landscape orientation on any device
* Use the nicer new app icon on lower Android versions
* Some UI, stability and translation improvements
Version 6.9.3 *(2020-05-05)*
----------------------------
* Added a 1x1 widget showing the current date
* Made all widget corners round to make them nicer
* Added some translation and other smaller improvements here and there
Version 6.9.2 *(2020-04-17)*
----------------------------
* Fixed some .ics file importing related glitches
* Corrected and added some UK holidays
* Added many UI and translation improvements
Version 6.9.1 *(2020-03-25)*
----------------------------
* Allow zooming the weekly view with vertical gestures
* Allow scrolling through the whole weeky view, use Start time only as the default time
* Updating the app icon
* Other stability, translation and UX improvements
Version 6.9.0 *(2020-03-18)*
----------------------------
* Remember the last used folder at ics exporting
* Do not request the Storage permission on Android 10+, use Scoped Storage
Version 6.8.5 *(2020-03-08)*
----------------------------
* Added a Go To Today menu button at the event list view too
* Some translation and stability improvements
Version 6.8.4 *(2020-02-07)*
----------------------------
* Added many translation and stability improvements
Version 6.8.3 *(2019-12-29)*
----------------------------
* Fixed a glitch at events repeating every X weeks
* Added an extra check to avoid showing reminders of deleted event repetition instances
* Some stability and translation improvements
Version 6.8.2 *(2019-12-18)*
----------------------------
* Improved some holidays
* Added a few stability and translation improvements
Version 6.8.1 *(2019-12-11)*
----------------------------
* Adding some time zone related crashfixes
Version 6.8.0 *(2019-12-11)*
----------------------------
* Added time zone support (customization has to be enabled in the app settings)
* Some UI improvements here and there
* Some stability and translation improvements
Version 6.7.2 *(2019-12-02)*
----------------------------
* Fixed some glitches at importing events from .ics files
* Improved the user experience of Simple Event List view
* Added some initial things under the hood for proper timezone support
* Couple stability and translation improvements
Version 6.7.1 *(2019-11-18)*
----------------------------
* Fixed a glitch at rechecking CalDAV synced calendars too often
Version 6.7.0 *(2019-11-17)*
----------------------------
* Fixed some repeating CalDAV synced events not showing up properly
* Improved the event sorting at the monthly widget
* Properly refresh CalDAV synced events in the background
* Some translation and stability improvements
Version 6.6.5 *(2019-11-06)*
----------------------------
* Fixed a glitch with small letters in some cases
* Some translation improvements
Version 6.6.4 *(2019-10-27)*
----------------------------
* Never show the Add New Event button over the yearly view
* Some stability and translation improvements
Version 6.6.3 *(2019-10-13)*
----------------------------
* Fixed a glitch with small letters and not being able to force English in some cases
Version 6.6.2 *(2019-10-09)*
----------------------------
* Added some stability and translation improvements
Version 6.6.1 *(2019-09-17)*
----------------------------
* Fixed a glitch with syncing all-day events via Radicale (by ddast)
* Use better messages at birthday/anniversary importing
* Fixed some UK holidays
Version 6.6.0 *(2019-08-28)*
----------------------------
* Use separate channels per event type reminders for more control
* Added some extra German and UK holidays
* Apply the Event List past limitation in the in-app view too, not just widget
* Fixing some glitches at importing events from .ics files
* Added some theming improvements
Version 6.5.7 *(2019-08-07)*
----------------------------
* Properly use the selected default event calendar, even at CalDAV synced ones
* Fixing invisible buttons at the date/time pickers with light theme
* Fixed a couple other smaller glitches and added some translation improvements
Version 6.5.6 *(2019-07-26)*
----------------------------
* Properly handle birthday and anniversary updating
* Fixed a widget list related glitch
Version 6.5.5 *(2019-07-25)*
----------------------------
* Added some dark theme related improvements
* Allow customizing the bottom navigation bar color
* Added a Go To Today button at the event list widget
Version 6.5.4 *(2019-07-01)*
----------------------------
* Adding some stability improvements
Version 6.5.3 *(2019-06-30)*
----------------------------
* Added some translation and stability improvements
Version 6.5.2 *(2019-06-28)*
----------------------------
* Don't show events that end at 00:00 as multi day event (by archibishop)
* Properly handle opening files with type application/ics
* Some other stability, translation and performance improvements
Version 6.5.1 *(2019-06-13)*
----------------------------
* Fixed a glitch related to CalDAV synced events reappearing after deletion
* Many translation improvements
Version 6.5.0 *(2019-05-04)*
----------------------------
* Show a more specific message if no new event has been found at importing
* Fixed an Event list widget glitch with overlapping event type indicator colors
* Misc smaller improvements
Version 6.4.3 *(2019-04-10)*
----------------------------
* Fixed some third party intent handling
* Some stability and translation improvements
Version 6.4.2 *(2019-04-03)*
----------------------------
* Added holidays in Taiwan
* Added an explanation dialog at upgrading from Free version
* Some stability and translation improvements
Version 6.4.1 *(2019-03-23)*
----------------------------
* Fixed a CalDAV sync related glitch with missing events
* Fixed adding reminders to birthdays and anniversaries
Version 6.4.0 *(2019-03-20)*
----------------------------
* Added email reminders and attendees in CalDAV synced events
* Improved CalDAV event syncing in the background
* Fixed some sorting related glitches
* Some other stability and UX improvements
Version 6.3.2 *(2019-03-07)*
----------------------------
* Added a "Go to date" to most views for easy jumping between dates
* Added an app shortcut for creating new events quickly, from Android 7.1+
Version 6.3.1 *(2019-02-23)*
----------------------------
* Allow adding event reminders to birthdays/anniversaries
* Filled content description of some views to improve the UX of visually impaired people
* A few more stability and UX improvements here and there
Version 6.3.0 *(2019-02-14)*
----------------------------
* Allow setting default start time/duration/event type for new events
* Allow exporting/importing settings
* Fixed a glitch with repeating events older than from year 2001
* Fixed some glitches related to overlapping events on the monthly and weekly view
Version 6.2.2 *(2019-01-25)*
----------------------------
* Fixed some CalDAV sync glitches
* Increase the visibility of dimmed events on the monthly view
Version 6.2.1 *(2019-01-08)*
----------------------------
* Fixed a CalDAV sync related glitches
* Fixed a glitch at showing notifications below Android Oreo
Version 6.2.0 *(2019-01-07)*
----------------------------
* Fixed a few CalDAV sync related glitches
* Properly handle reminder vibrations
Version 6.1.2 *(2018-12-25)*
----------------------------
* Fixed "Duplicate Event" not working
* Fixed a glitch with weekly view sometimes being blank
Version 6.1.1 *(2018-12-19)*
----------------------------
* Fixed one more case of CalDAV events getting duplicated
* Fixed the "New event" button sometimes not working properly
* Fixed some cases of empty weekly views at app launch
* Few other UX and stability improvements
Version 6.1.0 *(2018-12-05)*
----------------------------
* Many bugfixed related to CalDAV sync and event importing via .ics files
* Fixed a couple weekly view related glitches
* Open specific event details on clicking it from Event list widget
* Fix a glitch related to events repeating by X weeks for a long time
* Many other smaller fixes and performance/stability improvements
Version 6.0.1 *(2018-11-18)*
----------------------------
* Fixed some crashes and UX glitches
Version 6.0.0 *(2018-11-16)*
----------------------------
* Initial Pro version
* Fully rewrote the database storing events
* Fixed some issues related to importing events from .ics files and CalDAV sync
Version 5.1.3 *(2018-11-29)*
----------------------------
* This version of the app is no longer maintained, please upgrade to the Pro version. You can find the Upgrade button at the top of the app Settings.
Version 5.1.2 *(2018-11-09)*
----------------------------
* Couple smaller UX improvements
Version 5.1.1 *(2018-10-25)*
----------------------------
* Fixing a crash related to pull-to-refresh swiping
Version 5.1.0 *(2018-10-24)*
----------------------------
* Add optional pull-to-refresh for refreshing CalDAV events on some views (by azisuazusa)
* Allow setting a default view to be opened from the Event List widget (by knusprjg)
* Apply selected filters on all views, including widgets
* Allow changing any CalDAV calendars color, even if only locally
* Fix some glitches related to saving CalDAV events in a wrong calendar
* Some performance improvements related to fetching events
* Couple other smaller stability/ux improvements
Version 5.0.1 *(2018-10-17)*
----------------------------
* Fixed transparent date/time picker backgrounds
Version 5.0.0 *(2018-10-16)*
----------------------------
* Increased the minimal required Android OS version to 5
* Some translation and stability improvements
Version 4.2.1 *(2018-09-22)*
----------------------------
* Fixed some crashes related to specific invalid times in some timezones
* Added some holidays in Malaysia and Australia by youdly
* Added a new warning if the app notifications are disabled by the system
* Some other translation improvements and bugfixes
Version 4.2.0 *(2018-09-10)*
----------------------------
* Replaced colored event type dots with bars for better visibility
* Fixed some wrong reminder date data
* Properly highlight running all-day events
* Fix a glitch with CalDAV events being saved in the wrong calendar
* Couple other smaller UX and translation improvements
Version 4.1.3 *(2018-08-06)*
----------------------------
* Added a Go To Today button at the monthly widget
* Increase the allowed length of event titles, locations, descriptions
* Couple other stability and UX improvements
Version 4.1.2 *(2018-07-14)*
----------------------------
* Made reminder sounds more reliable on Android Oreo
* Properly fetch running events at reboot, notify only if needed
* Couple UX and stability improvements
Version 4.1.1 *(2018-07-04)*
----------------------------
* Allow customizing the audio stream used by reminders
* Show the time remaining till the reminder appears
* Couple other UX and stability improvements
Version 4.1.0 *(2018-06-13)*
----------------------------
* Make reminders on Android Oreo more reliable
* Allow deleting only future occurrences of repeating events
* Fixed some visual glitches at the weekly view
* Multiple CalDAV event related improvements
Version 4.0.4 *(2018-05-27)*
----------------------------
* Make sure the alarm rings properly at DND mode
* Improved the UK holidays and added Singapore ones
* Make Event list items more compact when possible
* Couple other UX improvements and bugfixes
Version 4.0.3 *(2018-05-15)*
----------------------------
* Fixing some widget related crashes
Version 4.0.2 *(2018-05-14)*
----------------------------
* Make sure we store the proper calendar ID at events
Version 4.0.1 *(2018-05-14)*
----------------------------
* Fix app not opening at clicking widgets
* Couple stability improvements
Version 4.0.0 *(2018-05-10)*
----------------------------
* Allow changing the app launcher color
* Allow setting reminder looping till dismissed
* Added a button in Settings for changing widget colors without recreating them
* Added optional dimming of past events
* Make Event List view an endless scrollview
* Added some more advanced yearly repetition rules
* Improved some country holidays
* Many CalDAV related improvements
* Many other smaller bugfixes and performance/UX improvements
Version 3.4.2 *(2018-04-13)*
----------------------------
* Hide public notification content if desired so (by fraang)
* Added optional grid on the monthly view
* Allow exporting events on SD cards
* Allow selecting No Sound as a reminder sound
* Set default event status for CalDAV events as Confirmed
Version 3.4.1 *(2018-03-30)*
----------------------------
* Reworked custom notification sound, should be more reliable
* Fixed some glitches related to the monthly view
* Misc smaller bugfixes and stability improvements
Version 3.4.0 *(2018-02-28)*
----------------------------
* Rewrote the monthly view
* Improved the performance at importing events from ics files
* Added many new country holidays
* Handle some new third party intents
Version 3.3.2 *(2018-02-21)*
----------------------------
* Try fixing the off-by-one issue at CalDAV syncing all-day events
* Couple stability improvements
Version 3.3.1 *(2018-02-19)*
----------------------------
* Improved CalDAV all-day event importing (by angelsl)
* Added a FAQ section with a couple initial items
* Once again fixed some cases of blank or duplicate views
Version 3.3.0 *(2018-02-10)*
----------------------------
* Fixed blank or duplicate views in some cases (yes, again)
* Fixed off-by-one day error at syncing all-day events via Nextcloud
* Make default filenames at export more user-friendly
* Improved the performance by removing some unnecessary redraws
* Added a toggle for switching between default snooze interval or always showing an interval picker
Version 3.2.4 *(2018-02-05)*
----------------------------
* Fixed blank screens in some cases
* Misc smaller improvements
Version 3.2.3 *(2018-02-01)*
----------------------------
* Fixed blank screens in some cases
* Make sure the Add New Event button works when opening the app from a widget
* Removed the "Default event reminder" from settings, remember last used values
* Allow selecting Snooze interval at pressing Snooze
* Allow disabling displaying of What's New
* Add a Back button at the actionmenu when opening a subview
* Allow deleting all events at once without reseting event types and other settings
Version 3.2.2 *(2018-01-27)*
----------------------------
* Fixed some cases of reminders not triggering
* Properly handle importing events with multiple lines long description
* Properly show the New Event button whenever appropriate
Version 3.2.1 *(2018-01-22)*
----------------------------
* Misc minor fixes
Version 3.2.0 *(2018-01-22)*
----------------------------
* Added an initial implementation of Search
* Fixed an off-by-one issue at syncing all-day CalDAV events
* Added a Daily View
* Allow importing events from .ics files directly in a CalDAV account
* Try parsing latitude and longitude coordinates from the Location field
Version 3.1.0 *(2018-01-11)*
----------------------------
* Made some CalDAV sync improvements, especially related to repeatable event exceptions
* Added a Map button to event location, to display the location in a third party map
* Handle INSERT and EDIT intent
* Made Dark theme the default
* Updated both event list and monthly widget, hopelly making them more reliable
* Added holidays in Australia
* Hopefully fixed the off-by-one error at importing/syncing all-day events/holidays
Version 3.0.1 *(2017-12-06)*
----------------------------

809
LICENSE
View file

@ -1,201 +1,674 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
1. Definitions.
Preamble
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
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.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
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.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
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.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
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.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
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.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
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.
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
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.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
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.
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
The precise terms and conditions for copying, distribution and
modification follow.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
TERMS AND CONDITIONS
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
0. Definitions.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
"This License" refers to version 3 of the GNU General Public License.
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
"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.
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
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.
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
A "covered work" means either the unmodified Program or a work based
on the Program.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
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.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
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.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
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.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
1. Source Code.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
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.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
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
APPENDIX: How to apply the Apache License to your work.
How to Apply These Terms to Your New Programs
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
Copyright 2017 SimpleMobileTools
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
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
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
https://www.apache.org/licenses/LICENSE-2.0
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View file

@ -1,37 +1,25 @@
# Simple Calendar
<img alt="Logo" src="app/src/main/res/mipmap-xxxhdpi/ic_launcher.png" width="80" />
<img alt="Logo" src="fastlane/metadata/android/en-US/images/icon.png" width="120" />
A simple calendar with events and a customizable widget.
An offline calendar without any other calendar integration. You can easily create recurring events and setup reminders, it can also display week numbers.
A simple calendar with optional CalDAV synchronization. You can easily create recurring events and setup reminders, it can also display week numbers.
Contains a resizable 4x4 widget where you can customize the color of the text, as well as the alpha and the color of the background.
Contains a monthly view and an event list widget where you can customize the color of the text, as well as the alpha and the color of the background.
Contains no ads or unnecessary permissions. It is fully open-source, provides customizable colors.
Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors.
The Storage permission is needed only for exporting or importing events from .ics files.
This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
The Contacts permission is used only at importing contact birthdays and anniversaries.
<a href='https://play.google.com/store/apps/details?id=com.simplemobiletools.calendar'><img src='http://simplemobiletools.github.io/assets/public/google-play.png' alt='Get it on Google Play' height='45' /></a>
<a href='https://f-droid.org/app/com.simplemobiletools.calendar'><img src='http://simplemobiletools.github.io/assets/public/f-droid.png' alt='Get it on F-Droid' height='45' /></a>
This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
<img alt="App image" src="screenshots/app_2.png" width="250" />
<img alt="App image" src="screenshots/app_4.png" width="250" />
<img alt="App image" src="screenshots/app.png" width="250" />
<a href='https://play.google.com/store/apps/details?id=com.simplemobiletools.calendar.pro'><img src='https://simplemobiletools.com/assets/images/google-play.png' alt='Get it on Google Play' height='45' /></a>
<a href='https://f-droid.org/packages/com.simplemobiletools.calendar.pro'><img src='https://simplemobiletools.com/assets/images/f-droid.png' alt='Get it on F-Droid' height='45' /></a>
License
-------
Copyright 2017 SimpleMobileTools
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
https://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.
<div style="display:flex;">
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app_1.jpg" width="30%">
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app_2.jpg" width="30%">
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app_3.jpg" width="30%">
</div>

View file

@ -1,31 +1,53 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'de.timfreiheit.resourceplaceholders'
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 27
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.simplemobiletools.calendar"
minSdkVersion 16
targetSdkVersion 27
versionCode 106
versionName "3.0.1"
applicationId "com.simplemobiletools.calendar.pro"
minSdkVersion 21
targetSdkVersion 29
versionCode 177
versionName "6.9.4"
multiDexEnabled true
setProperty("archivesBaseName", "calendar")
vectorDrawables.useSupportLibrary = true
}
signingConfigs {
release
if (keystorePropertiesFile.exists()) {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
}
buildTypes {
debug {
applicationIdSuffix ".debug"
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
if (keystorePropertiesFile.exists()) {
signingConfig signingConfigs.release
}
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@ -35,38 +57,19 @@ android {
checkReleaseBuilds false
abortOnError false
}
}
ext {
leakCanaryVersion = '1.5.4'
resourcePlaceholders {
files = ['xml/shortcuts.xml']
}
}
dependencies {
implementation 'com.simplemobiletools:commons:3.4.12'
implementation 'joda-time:joda-time:2.9.9'
implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'com.android.support:multidex:1.0.2'
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.simplemobiletools:commons:5.28.23'
implementation 'joda-time:joda-time:2.10.1'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
}
Properties props = new Properties()
def propFile = new File('signing.properties')
if (propFile.canRead()) {
props.load(new FileInputStream(propFile))
if (props != null && props.containsKey('STORE_FILE') && props.containsKey('KEY_ALIAS') && props.containsKey('PASSWORD')) {
android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
android.signingConfigs.release.storePassword = props['PASSWORD']
android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
android.signingConfigs.release.keyPassword = props['PASSWORD']
} else {
println 'signing.properties found but some entries are missing'
android.buildTypes.release.signingConfig = null
}
} else {
println 'signing.properties not found'
android.buildTypes.release.signingConfig = null
kapt 'androidx.room:room-compiler:2.2.5'
implementation 'androidx.room:room-runtime:2.2.5'
annotationProcessor 'androidx.room:room-compiler:2.2.5'
}

View file

@ -1,7 +1 @@
-keep class com.simplemobiletools.calendar.models.** { *; }
# Joda
-dontwarn org.joda.convert.**
-dontwarn org.joda.time.**
-keep class org.joda.time.** { *; }
-keep interface org.joda.time.** { *; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="leak_canary_display_activity_label">Calendar Leaks</string>
<string name="app_launcher_name">Calendar_debug</string>
</resources>

View file

@ -1,40 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.simplemobiletools.calendar"
package="com.simplemobiletools.calendar.pro"
android:installLocation="auto">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name='android.permission.WAKE_LOCK'/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission
android:name="android.permission.USE_FINGERPRINT"
tools:node="remove" />
<uses-feature
android:name="android.hardware.faketouch"
android:required="false" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_launcher_name"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".activities.SplashActivity"
android:theme="@style/SplashTheme">
android:launchMode="singleTask"
android:theme="@style/SplashTheme" />
<activity
android:name=".activities.MainActivity"
android:launchMode="singleTask">
<meta-data
android:name="android.app.default_searchable"
android:resource="@xml/searchable" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
<activity android:name=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
@ -43,6 +56,7 @@
<data android:scheme="file" />
<data android:mimeType="text/x-vcalendar" />
<data android:mimeType="text/calendar" />
<data android:mimeType="application/ics" />
</intent-filter>
<intent-filter>
@ -53,6 +67,12 @@
<data android:host="com.android.calendar" />
<data android:scheme="content" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/event" />
</intent-filter>
</activity>
<activity
@ -73,6 +93,15 @@
</intent-filter>
</activity>
<activity
android:name=".activities.WidgetDateConfigureActivity"
android:screenOrientation="portrait"
android:theme="@style/MyWidgetConfigTheme">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<activity
android:name="com.simplemobiletools.commons.activities.AboutActivity"
android:label="@string/about"
@ -89,14 +118,43 @@
android:parentActivityName="com.simplemobiletools.commons.activities.AboutActivity" />
<activity
android:name=".activities.DayActivity"
android:label="@string/details"
android:parentActivityName=".activities.MainActivity"/>
android:name="com.simplemobiletools.commons.activities.FAQActivity"
android:label="@string/frequently_asked_questions"
android:parentActivityName="com.simplemobiletools.commons.activities.AboutActivity" />
<activity
android:name=".activities.EventActivity"
android:label="@string/event"
android:parentActivityName=".activities.DayActivity"/>
android:launchMode="singleTask"
android:parentActivityName=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.INSERT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/event" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.INSERT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/event" />
</intent-filter>
</activity>
<activity
android:name=".activities.SelectTimeZoneActivity"
android:parentActivityName=".activities.EventActivity">
<meta-data
android:name="android.app.default_searchable"
android:resource="@xml/searchable" />
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
<activity
android:name=".activities.SettingsActivity"
@ -108,6 +166,10 @@
android:label="@string/event_types"
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".activities.SnoozeReminderActivity"
android:theme="@style/Theme.Transparent" />
<receiver
android:name=".helpers.MyWidgetMonthlyProvider"
android:icon="@drawable/img_widget_monthly_preview"
@ -134,12 +196,34 @@
android:resource="@xml/widget_list_info" />
</receiver>
<receiver
android:name=".helpers.MyWidgetDateProvider"
android:icon="@drawable/img_widget_date_preview"
android:label="@string/widget_todays_date">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_date_info" />
</receiver>
<service
android:name=".services.WidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<service
android:name=".services.WidgetServiceEmpty"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<service android:name=".services.SnoozeService" />
<service
android:name=".jobs.CalDAVUpdateListener"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<receiver android:name=".receivers.NotificationReceiver" />
<receiver android:name=".receivers.CalDAVSyncReceiver" />
@ -148,11 +232,12 @@
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<provider
android:name="android.support.v4.content.FileProvider"
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
@ -160,5 +245,251 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<activity-alias
android:name=".activities.SplashActivity.Red"
android:enabled="false"
android:icon="@mipmap/ic_launcher_red"
android:roundIcon="@mipmap/ic_launcher_red"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Pink"
android:enabled="false"
android:icon="@mipmap/ic_launcher_pink"
android:roundIcon="@mipmap/ic_launcher_pink"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Purple"
android:enabled="false"
android:icon="@mipmap/ic_launcher_purple"
android:roundIcon="@mipmap/ic_launcher_purple"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Deep_purple"
android:enabled="false"
android:icon="@mipmap/ic_launcher_deep_purple"
android:roundIcon="@mipmap/ic_launcher_deep_purple"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Indigo"
android:enabled="false"
android:icon="@mipmap/ic_launcher_indigo"
android:roundIcon="@mipmap/ic_launcher_indigo"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Blue"
android:enabled="false"
android:icon="@mipmap/ic_launcher_blue"
android:roundIcon="@mipmap/ic_launcher_blue"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Light_blue"
android:enabled="false"
android:icon="@mipmap/ic_launcher_light_blue"
android:roundIcon="@mipmap/ic_launcher_light_blue"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Cyan"
android:enabled="false"
android:icon="@mipmap/ic_launcher_cyan"
android:roundIcon="@mipmap/ic_launcher_cyan"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Teal"
android:enabled="false"
android:icon="@mipmap/ic_launcher_teal"
android:roundIcon="@mipmap/ic_launcher_teal"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Green"
android:enabled="false"
android:icon="@mipmap/ic_launcher_green"
android:roundIcon="@mipmap/ic_launcher_green"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Light_green"
android:enabled="false"
android:icon="@mipmap/ic_launcher_light_green"
android:roundIcon="@mipmap/ic_launcher_light_green"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Lime"
android:enabled="false"
android:icon="@mipmap/ic_launcher_lime"
android:roundIcon="@mipmap/ic_launcher_lime"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Yellow"
android:enabled="false"
android:icon="@mipmap/ic_launcher_yellow"
android:roundIcon="@mipmap/ic_launcher_yellow"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Amber"
android:enabled="false"
android:icon="@mipmap/ic_launcher_amber"
android:roundIcon="@mipmap/ic_launcher_amber"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Orange"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Deep_orange"
android:enabled="false"
android:icon="@mipmap/ic_launcher_deep_orange"
android:roundIcon="@mipmap/ic_launcher_deep_orange"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Brown"
android:enabled="false"
android:icon="@mipmap/ic_launcher_brown"
android:roundIcon="@mipmap/ic_launcher_brown"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Blue_grey"
android:enabled="false"
android:icon="@mipmap/ic_launcher_blue_grey"
android:roundIcon="@mipmap/ic_launcher_blue_grey"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Grey_black"
android:enabled="false"
android:icon="@mipmap/ic_launcher_grey_black"
android:roundIcon="@mipmap/ic_launcher_grey_black"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
</manifest>

358
app/src/main/assets/australia.ics Executable file
View file

@ -0,0 +1,358 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
UID:20180101_60o30chhcgo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:New Year's Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180126
DTEND;VALUE=DATE:20180127
UID:20180126_60o30chhcko30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Australia Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180507
DTEND;VALUE=DATE:20180508
UID:20180507_60o30chicko36e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=5;BYDAY=1MO
SUMMARY:May Day (Northern Territory)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180312
DTEND;VALUE=DATE:20180313
UID:20180312_60o30chicko3ie1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2MO
SUMMARY:Labour Day (Victoria)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180305
DTEND;VALUE=DATE:20180306
UID:20180305_60o30chicko3ge1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=1MO
SUMMARY:Labour Day (Western Australia)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181001
DTEND;VALUE=DATE:20181002
UID:20181001_60o30chicko3ec1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=10;BYDAY=1MO
SUMMARY:Labour Day (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180507
DTEND;VALUE=DATE:20180508
UID:20180507_60o30chicko38e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=5;BYDAY=1MO
SUMMARY:Labour Day (Queensland)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180312
DTEND;VALUE=DATE:20180313
UID:20180312_60o30chicko62e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2MO
SUMMARY:Eight Hours Day (Tasmania)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180425
DTEND;VALUE=DATE:20180426
UID:20180425_60o30chi6so32c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:ANZAC Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181001
DTEND;VALUE=DATE:20181002
UID:20181001_60o30chhcoo38c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=10;BYDAY=1MO
SUMMARY:Queen's Birthday (Queensland)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180611
DTEND;VALUE=DATE:20180612
UID:20180611_60o30chhcoo32e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=6;BYDAY=2MO
SUMMARY:Queen's Birthday (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180212
DTEND;VALUE=DATE:20180213
UID:20180212_60o30e1pcko30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=2;BYDAY=2MO
SUMMARY:Royal Hobart Regatta (Tasmania)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180312
DTEND;VALUE=DATE:20180313
UID:20180312_60o30chj64o30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2MO
SUMMARY:Canberra Day (Australian Capital Territory)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180806
DTEND;VALUE=DATE:20180807
UID:20180806_60o30chicgo30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=8;BYDAY=1MO
SUMMARY:Northern Territory Picnic Day (Northern Territory)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180604
DTEND;VALUE=DATE:20180605
UID:20180604_60o30chj60o30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=6;BYDAY=1MO
SUMMARY:Western Australia Day (Western Australia)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181105
DTEND;VALUE=DATE:20181106
UID:20181105_60o30chj6ko30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=1MO
SUMMARY:Recreation Day (Tasmania)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181106
DTEND;VALUE=DATE:20181107
UID:20181106_60o30chj6oo30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=1TU
SUMMARY:Melbourne Cup Day (Victoria)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180806
DTEND;VALUE=DATE:20180807
UID:20180806_60o30chicco30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=8;BYDAY=1MO
SUMMARY:New South Wales Bank Holiday (New South Wales)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180312
DTEND;VALUE=DATE:20180313
UID:20180312_60o30chicoo30e1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2MO
SUMMARY:Adelaide Cup (South Australia)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181007
DTEND;VALUE=DATE:20181008
UID:20181007_60o30c9o60o30dpl6ooj0dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=10;BYDAY=1SU
SUMMARY:Daylight Saving Time starts
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
UID:20180401_60o30c9o64o30dpl6ooj0dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=4;BYDAY=1SU
SUMMARY:Daylight Saving Time ends
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180321
DTEND;VALUE=DATE:20180322
UID:20180321_60o30opo64o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Harmony Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181111
DTEND;VALUE=DATE:20181112
UID:20181111_60o30chj6so30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Remembrance Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181224
DTEND;VALUE=DATE:20181225
UID:20181224_60o30chi60o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Christmas Eve
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
UID:20181225_60o30chi64o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Christmas Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
UID:20181226_60o30chi68o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Boxing Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181231
DTEND;VALUE=DATE:20190101
UID:20181231_60o30chhcco30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:New Year's Eve
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200127
DTEND;VALUE=DATE:20200128
UID:20200127_60o30chhcko30e1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Australia Day observed
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
UID:20200412_60o30chi6ko36c1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Easter Sunday (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210404
DTEND;VALUE=DATE:20210405
UID:20210404_60o30chi6ko3ac1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Easter Sunday (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
UID:20200413_60o30chi6oo30c1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Easter Monday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210405
DTEND;VALUE=DATE:20210406
UID:20210405_60o30chi6oo30c1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Easter Monday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200414
DTEND;VALUE=DATE:20200415
UID:20200414_60o30chj6co30c1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Easter Tuesday (Tasmania)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210406
DTEND;VALUE=DATE:20210407
UID:20210406_60o30chj6co30c1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Easter Tuesday (Tasmania)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
UID:20200410_60o30chi6co30c1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Good Friday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210402
DTEND;VALUE=DATE:20210403
UID:20210402_60o30chi6co30c1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Good Friday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200411
DTEND;VALUE=DATE:20200412
UID:20200411_60o30chi6go32c1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Holy Saturday (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210403
DTEND;VALUE=DATE:20210404
UID:20210403_60o30chi6go32c1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Holy Saturday (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200601
DTEND;VALUE=DATE:20200602
UID:20200601_60o32dr3cgo30e1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Reconciliation Day (Australian Capital Territory)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210531
DTEND;VALUE=DATE:20210601
UID:20210531_60o32dr3cgo30e1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Reconciliation Day (Australian Capital Territory)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200812
DTEND;VALUE=DATE:20200813
UID:20200812_60o30chj6go30c1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Royal National Agricultural Show Day Queensland (Queensland)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210811
DTEND;VALUE=DATE:20210812
UID:20210811_60o30chj6go30c1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Royal National Agricultural Show Day Queensland (Queensland)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200928
DTEND;VALUE=DATE:20200929
UID:20200928_60o30chhcoo36e1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Queen's Birthday (Western Australia)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210927
DTEND;VALUE=DATE:20210928
UID:20210927_60o30chhcoo36e1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Queen's Birthday (Western Australia)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20201228
DTEND;VALUE=DATE:20201229
UID:20201228_60o30chic8o30c1g60o30dr56g@google.com
STATUS:CONFIRMED
SUMMARY:Christmas/Boxing Day Holiday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20211227
DTEND;VALUE=DATE:20211228
UID:20211227_60o30chic4o30c1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Christmas/Boxing Day Holiday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20211228
DTEND;VALUE=DATE:20211229
UID:20211228_60o32o9hc4o30e1g60o30dr56k@google.com
STATUS:CONFIRMED
SUMMARY:Christmas/Boxing Day Holiday
END:VEVENT
END:VCALENDAR

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,149 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-chn-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:元旦
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20180215@kayaposoft.com
DTSTART;VALUE=DATE:20180215
DTEND;VALUE=DATE:20180222
SUMMARY:春节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20180405@kayaposoft.com
DTSTART;VALUE=DATE:20180405
DTEND;VALUE=DATE:20180408
SUMMARY:清明节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20180429@kayaposoft.com
DTSTART;VALUE=DATE:20180429
DTEND;VALUE=DATE:20180502
SUMMARY:劳动节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20180616@kayaposoft.com
DTSTART;VALUE=DATE:20180616
DTEND;VALUE=DATE:20180619
SUMMARY:端午节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20180922@kayaposoft.com
DTSTART;VALUE=DATE:20180922
DTEND;VALUE=DATE:20180925
SUMMARY:中秋节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20181001@kayaposoft.com
DTSTART;VALUE=DATE:20181001
DTEND;VALUE=DATE:20181008
SUMMARY:国庆节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:元旦
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20190205@kayaposoft.com
DTSTART;VALUE=DATE:20190205
DTEND;VALUE=DATE:20190206
SUMMARY:春节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20190405@kayaposoft.com
DTSTART;VALUE=DATE:20190405
DTEND;VALUE=DATE:20190406
SUMMARY:清明节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:劳动节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20190607@kayaposoft.com
DTSTART;VALUE=DATE:20190607
DTEND;VALUE=DATE:20190608
SUMMARY:端午节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20190913@kayaposoft.com
DTSTART;VALUE=DATE:20190913
DTEND;VALUE=DATE:20190914
SUMMARY:中秋节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20191001@kayaposoft.com
DTSTART;VALUE=DATE:20191001
DTEND;VALUE=DATE:20191002
SUMMARY:国庆节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:元旦
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20200125@kayaposoft.com
DTSTART;VALUE=DATE:20200125
DTEND;VALUE=DATE:20200126
SUMMARY:春节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20200404@kayaposoft.com
DTSTART;VALUE=DATE:20200404
DTEND;VALUE=DATE:20200405
SUMMARY:清明节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:劳动节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20200625@kayaposoft.com
DTSTART;VALUE=DATE:20200625
DTEND;VALUE=DATE:20200626
SUMMARY:端午节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20201001@kayaposoft.com
DTSTART;VALUE=DATE:20201001
DTEND;VALUE=DATE:20201002
SUMMARY:国庆节
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-chn-20201001-529562@kayaposoft.com
DTSTART;VALUE=DATE:20201001
DTEND;VALUE=DATE:20201002
SUMMARY:中秋节
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,422 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-col-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Año Nuevo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180108@kayaposoft.com
DTSTART;VALUE=DATE:20180108
DTEND;VALUE=DATE:20180109
SUMMARY:Día de los Reyes Magos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180319@kayaposoft.com
DTSTART;VALUE=DATE:20180319
DTEND;VALUE=DATE:20180320
SUMMARY:Día de San José
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180325@kayaposoft.com
DTSTART;VALUE=DATE:20180325
DTEND;VALUE=DATE:20180326
SUMMARY:Domingo de Ramos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180329@kayaposoft.com
DTSTART;VALUE=DATE:20180329
DTEND;VALUE=DATE:20180330
SUMMARY:Jueves Santo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180330@kayaposoft.com
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
SUMMARY:Viernes Santo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180401@kayaposoft.com
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
SUMMARY:Domingo de Pascuas o Resurrección
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Día del Trabajo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180514@kayaposoft.com
DTSTART;VALUE=DATE:20180514
DTEND;VALUE=DATE:20180515
SUMMARY:Día de la Ascensión
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180604@kayaposoft.com
DTSTART;VALUE=DATE:20180604
DTEND;VALUE=DATE:20180605
SUMMARY:Corpus Christi
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180611@kayaposoft.com
DTSTART;VALUE=DATE:20180611
DTEND;VALUE=DATE:20180612
SUMMARY:Sagrado Corazón de Jesús
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180702@kayaposoft.com
DTSTART;VALUE=DATE:20180702
DTEND;VALUE=DATE:20180703
SUMMARY:San Pedro y San Pablo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180720@kayaposoft.com
DTSTART;VALUE=DATE:20180720
DTEND;VALUE=DATE:20180721
SUMMARY:Declaracion de la Independencia de Colombia
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180807@kayaposoft.com
DTSTART;VALUE=DATE:20180807
DTEND;VALUE=DATE:20180808
SUMMARY:Batalla de Boyacá
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20180820@kayaposoft.com
DTSTART;VALUE=DATE:20180820
DTEND;VALUE=DATE:20180821
SUMMARY:Asunción de la Virgen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20181015@kayaposoft.com
DTSTART;VALUE=DATE:20181015
DTEND;VALUE=DATE:20181016
SUMMARY:Día de la Raza
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20181105@kayaposoft.com
DTSTART;VALUE=DATE:20181105
DTEND;VALUE=DATE:20181106
SUMMARY:Día de todos los Santos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20181112@kayaposoft.com
DTSTART;VALUE=DATE:20181112
DTEND;VALUE=DATE:20181113
SUMMARY:Independencia de Cartagena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20181208@kayaposoft.com
DTSTART;VALUE=DATE:20181208
DTEND;VALUE=DATE:20181209
SUMMARY:Día de la Inmaculada Concepción
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Navidad
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Año Nuevo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190107@kayaposoft.com
DTSTART;VALUE=DATE:20190107
DTEND;VALUE=DATE:20190108
SUMMARY:Día de los Reyes Magos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190325@kayaposoft.com
DTSTART;VALUE=DATE:20190325
DTEND;VALUE=DATE:20190326
SUMMARY:Día de San José
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190414@kayaposoft.com
DTSTART;VALUE=DATE:20190414
DTEND;VALUE=DATE:20190415
SUMMARY:Domingo de Ramos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190418@kayaposoft.com
DTSTART;VALUE=DATE:20190418
DTEND;VALUE=DATE:20190419
SUMMARY:Jueves Santo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190419@kayaposoft.com
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:Viernes Santo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190421@kayaposoft.com
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
SUMMARY:Domingo de Pascuas o Resurrección
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Día del Trabajo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190603@kayaposoft.com
DTSTART;VALUE=DATE:20190603
DTEND;VALUE=DATE:20190604
SUMMARY:Día de la Ascensión
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190624@kayaposoft.com
DTSTART;VALUE=DATE:20190624
DTEND;VALUE=DATE:20190625
SUMMARY:Corpus Christi
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190701@kayaposoft.com
DTSTART;VALUE=DATE:20190701
DTEND;VALUE=DATE:20190702
SUMMARY:Sagrado Corazón de Jesús
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190701-289927@kayaposoft.com
DTSTART;VALUE=DATE:20190701
DTEND;VALUE=DATE:20190702
SUMMARY:San Pedro y San Pablo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190720@kayaposoft.com
DTSTART;VALUE=DATE:20190720
DTEND;VALUE=DATE:20190721
SUMMARY:Declaracion de la Independencia de Colombia
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190807@kayaposoft.com
DTSTART;VALUE=DATE:20190807
DTEND;VALUE=DATE:20190808
SUMMARY:Batalla de Boyacá
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20190819@kayaposoft.com
DTSTART;VALUE=DATE:20190819
DTEND;VALUE=DATE:20190820
SUMMARY:Asunción de la Virgen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20191014@kayaposoft.com
DTSTART;VALUE=DATE:20191014
DTEND;VALUE=DATE:20191015
SUMMARY:Día de la Raza
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20191104@kayaposoft.com
DTSTART;VALUE=DATE:20191104
DTEND;VALUE=DATE:20191105
SUMMARY:Día de todos los Santos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20191111@kayaposoft.com
DTSTART;VALUE=DATE:20191111
DTEND;VALUE=DATE:20191112
SUMMARY:Independencia de Cartagena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20191208@kayaposoft.com
DTSTART;VALUE=DATE:20191208
DTEND;VALUE=DATE:20191209
SUMMARY:Día de la Inmaculada Concepción
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Navidad
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Año Nuevo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200106@kayaposoft.com
DTSTART;VALUE=DATE:20200106
DTEND;VALUE=DATE:20200107
SUMMARY:Día de los Reyes Magos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200323@kayaposoft.com
DTSTART;VALUE=DATE:20200323
DTEND;VALUE=DATE:20200324
SUMMARY:Día de San José
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200405@kayaposoft.com
DTSTART;VALUE=DATE:20200405
DTEND;VALUE=DATE:20200406
SUMMARY:Domingo de Ramos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200409@kayaposoft.com
DTSTART;VALUE=DATE:20200409
DTEND;VALUE=DATE:20200410
SUMMARY:Jueves Santo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200410@kayaposoft.com
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
SUMMARY:Viernes Santo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200412@kayaposoft.com
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
SUMMARY:Domingo de Pascuas o Resurrección
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Día del Trabajo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200525@kayaposoft.com
DTSTART;VALUE=DATE:20200525
DTEND;VALUE=DATE:20200526
SUMMARY:Día de la Ascensión
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200615@kayaposoft.com
DTSTART;VALUE=DATE:20200615
DTEND;VALUE=DATE:20200616
SUMMARY:Corpus Christi
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200622@kayaposoft.com
DTSTART;VALUE=DATE:20200622
DTEND;VALUE=DATE:20200623
SUMMARY:Sagrado Corazón de Jesús
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200629@kayaposoft.com
DTSTART;VALUE=DATE:20200629
DTEND;VALUE=DATE:20200630
SUMMARY:San Pedro y San Pablo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200720@kayaposoft.com
DTSTART;VALUE=DATE:20200720
DTEND;VALUE=DATE:20200721
SUMMARY:Declaracion de la Independencia de Colombia
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200807@kayaposoft.com
DTSTART;VALUE=DATE:20200807
DTEND;VALUE=DATE:20200808
SUMMARY:Batalla de Boyacá
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20200817@kayaposoft.com
DTSTART;VALUE=DATE:20200817
DTEND;VALUE=DATE:20200818
SUMMARY:Asunción de la Virgen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20201012@kayaposoft.com
DTSTART;VALUE=DATE:20201012
DTEND;VALUE=DATE:20201013
SUMMARY:Día de la Raza
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20201102@kayaposoft.com
DTSTART;VALUE=DATE:20201102
DTEND;VALUE=DATE:20201103
SUMMARY:Día de todos los Santos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20201116@kayaposoft.com
DTSTART;VALUE=DATE:20201116
DTEND;VALUE=DATE:20201117
SUMMARY:Independencia de Cartagena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20201208@kayaposoft.com
DTSTART;VALUE=DATE:20201208
DTEND;VALUE=DATE:20201209
SUMMARY:Día de la Inmaculada Concepción
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-col-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Navidad
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,296 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-hrv-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180106@kayaposoft.com
DTSTART;VALUE=DATE:20180106
DTEND;VALUE=DATE:20180107
SUMMARY:Bogojavljanje ili Sveta tri kralja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180401@kayaposoft.com
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
SUMMARY:Uskrs
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180402@kayaposoft.com
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
SUMMARY:Uskrsni ponedjeljak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180531@kayaposoft.com
DTSTART;VALUE=DATE:20180531
DTEND;VALUE=DATE:20180601
SUMMARY:Tijelovo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180622@kayaposoft.com
DTSTART;VALUE=DATE:20180622
DTEND;VALUE=DATE:20180623
SUMMARY:Dan antifašističke borbe
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180625@kayaposoft.com
DTSTART;VALUE=DATE:20180625
DTEND;VALUE=DATE:20180626
SUMMARY:Dan državnosti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180805@kayaposoft.com
DTSTART;VALUE=DATE:20180805
DTEND;VALUE=DATE:20180806
SUMMARY:Dan pobjede i domovinske zahvalnosti i Dan hrvatskih branitelja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20180815@kayaposoft.com
DTSTART;VALUE=DATE:20180815
DTEND;VALUE=DATE:20180816
SUMMARY:Velika Gospa
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20181008@kayaposoft.com
DTSTART;VALUE=DATE:20181008
DTEND;VALUE=DATE:20181009
SUMMARY:Dan neovisnosti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20181101@kayaposoft.com
DTSTART;VALUE=DATE:20181101
DTEND;VALUE=DATE:20181102
SUMMARY:Svi sveti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Božić
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:Prvi dan po Božiću\, Sveti Stjepan
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190106@kayaposoft.com
DTSTART;VALUE=DATE:20190106
DTEND;VALUE=DATE:20190107
SUMMARY:Bogojavljanje ili Sveta tri kralja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190421@kayaposoft.com
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
SUMMARY:Uskrs
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190422@kayaposoft.com
DTSTART;VALUE=DATE:20190422
DTEND;VALUE=DATE:20190423
SUMMARY:Uskrsni ponedjeljak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190620@kayaposoft.com
DTSTART;VALUE=DATE:20190620
DTEND;VALUE=DATE:20190621
SUMMARY:Tijelovo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190622@kayaposoft.com
DTSTART;VALUE=DATE:20190622
DTEND;VALUE=DATE:20190623
SUMMARY:Dan antifašističke borbe
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190625@kayaposoft.com
DTSTART;VALUE=DATE:20190625
DTEND;VALUE=DATE:20190626
SUMMARY:Dan državnosti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190805@kayaposoft.com
DTSTART;VALUE=DATE:20190805
DTEND;VALUE=DATE:20190806
SUMMARY:Dan pobjede i domovinske zahvalnosti i Dan hrvatskih branitelja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20190815@kayaposoft.com
DTSTART;VALUE=DATE:20190815
DTEND;VALUE=DATE:20190816
SUMMARY:Velika Gospa
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20191008@kayaposoft.com
DTSTART;VALUE=DATE:20191008
DTEND;VALUE=DATE:20191009
SUMMARY:Dan neovisnosti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20191101@kayaposoft.com
DTSTART;VALUE=DATE:20191101
DTEND;VALUE=DATE:20191102
SUMMARY:Svi sveti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Božić
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:Prvi dan po Božiću\, Sveti Stjepan
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200106@kayaposoft.com
DTSTART;VALUE=DATE:20200106
DTEND;VALUE=DATE:20200107
SUMMARY:Bogojavljanje ili Sveta tri kralja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200412@kayaposoft.com
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
SUMMARY:Uskrs
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200413@kayaposoft.com
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:Uskrsni ponedjeljak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200611@kayaposoft.com
DTSTART;VALUE=DATE:20200611
DTEND;VALUE=DATE:20200612
SUMMARY:Tijelovo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200622@kayaposoft.com
DTSTART;VALUE=DATE:20200622
DTEND;VALUE=DATE:20200623
SUMMARY:Dan antifašističke borbe
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200625@kayaposoft.com
DTSTART;VALUE=DATE:20200625
DTEND;VALUE=DATE:20200626
SUMMARY:Dan državnosti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200805@kayaposoft.com
DTSTART;VALUE=DATE:20200805
DTEND;VALUE=DATE:20200806
SUMMARY:Dan pobjede i domovinske zahvalnosti i Dan hrvatskih branitelja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20200815@kayaposoft.com
DTSTART;VALUE=DATE:20200815
DTEND;VALUE=DATE:20200816
SUMMARY:Velika Gospa
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20201008@kayaposoft.com
DTSTART;VALUE=DATE:20201008
DTEND;VALUE=DATE:20201009
SUMMARY:Dan neovisnosti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20201101@kayaposoft.com
DTSTART;VALUE=DATE:20201101
DTEND;VALUE=DATE:20201102
SUMMARY:Svi sveti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Božić
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-hrv-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:Prvi dan po Božiću\, Sveti Stjepan
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,254 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-dnk-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Nytårsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180325@kayaposoft.com
DTSTART;VALUE=DATE:20180325
DTEND;VALUE=DATE:20180326
SUMMARY:Palmesøndag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180329@kayaposoft.com
DTSTART;VALUE=DATE:20180329
DTEND;VALUE=DATE:20180330
SUMMARY:Skærtorsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180330@kayaposoft.com
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
SUMMARY:Langfredag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180401@kayaposoft.com
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
SUMMARY:1. Påskedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180402@kayaposoft.com
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
SUMMARY:2. Påskedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180427@kayaposoft.com
DTSTART;VALUE=DATE:20180427
DTEND;VALUE=DATE:20180428
SUMMARY:Store Bededag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180510@kayaposoft.com
DTSTART;VALUE=DATE:20180510
DTEND;VALUE=DATE:20180511
SUMMARY:Kristi Himmelfartsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180520@kayaposoft.com
DTSTART;VALUE=DATE:20180520
DTEND;VALUE=DATE:20180521
SUMMARY:1. Pinsedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20180521@kayaposoft.com
DTSTART;VALUE=DATE:20180521
DTEND;VALUE=DATE:20180522
SUMMARY:2. Pinsedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:1. Juledag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:2. Juledag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Nytårsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190414@kayaposoft.com
DTSTART;VALUE=DATE:20190414
DTEND;VALUE=DATE:20190415
SUMMARY:Palmesøndag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190418@kayaposoft.com
DTSTART;VALUE=DATE:20190418
DTEND;VALUE=DATE:20190419
SUMMARY:Skærtorsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190419@kayaposoft.com
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:Langfredag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190421@kayaposoft.com
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
SUMMARY:1. Påskedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190422@kayaposoft.com
DTSTART;VALUE=DATE:20190422
DTEND;VALUE=DATE:20190423
SUMMARY:2. Påskedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190517@kayaposoft.com
DTSTART;VALUE=DATE:20190517
DTEND;VALUE=DATE:20190518
SUMMARY:Store Bededag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190530@kayaposoft.com
DTSTART;VALUE=DATE:20190530
DTEND;VALUE=DATE:20190531
SUMMARY:Kristi Himmelfartsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190609@kayaposoft.com
DTSTART;VALUE=DATE:20190609
DTEND;VALUE=DATE:20190610
SUMMARY:1. Pinsedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20190610@kayaposoft.com
DTSTART;VALUE=DATE:20190610
DTEND;VALUE=DATE:20190611
SUMMARY:2. Pinsedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:1. Juledag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:2. Juledag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Nytårsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200405@kayaposoft.com
DTSTART;VALUE=DATE:20200405
DTEND;VALUE=DATE:20200406
SUMMARY:Palmesøndag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200409@kayaposoft.com
DTSTART;VALUE=DATE:20200409
DTEND;VALUE=DATE:20200410
SUMMARY:Skærtorsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200410@kayaposoft.com
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
SUMMARY:Langfredag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200412@kayaposoft.com
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
SUMMARY:1. Påskedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200413@kayaposoft.com
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:2. Påskedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200508@kayaposoft.com
DTSTART;VALUE=DATE:20200508
DTEND;VALUE=DATE:20200509
SUMMARY:Store Bededag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200521@kayaposoft.com
DTSTART;VALUE=DATE:20200521
DTEND;VALUE=DATE:20200522
SUMMARY:Kristi Himmelfartsdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200531@kayaposoft.com
DTSTART;VALUE=DATE:20200531
DTEND;VALUE=DATE:20200601
SUMMARY:1. Pinsedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20200601@kayaposoft.com
DTSTART;VALUE=DATE:20200601
DTEND;VALUE=DATE:20200602
SUMMARY:2. Pinsedag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:1. Juledag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-dnk-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:2. Juledag
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -1,219 +1,254 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
SUMMARY:Leheristipäev
UID:87aea25e-f592-47eb-b603-81640c074097
DTSTART;VALUE=DATE:20170518
DTEND;VALUE=DATE:20170519
UID:enrico-est-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:uusaasta
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Taevaminemispüha
UID:6e5e0af9-0230-427b-97f3-e799ddad9294
DTSTART;VALUE=DATE:20170525
DTEND;VALUE=DATE:20170526
UID:enrico-est-20180224@kayaposoft.com
DTSTART;VALUE=DATE:20180224
DTEND;VALUE=DATE:20180225
SUMMARY:iseseisvuspäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:1. nelipüha
UID:496869e4-af27-425b-ac0d-67c6dcb01adc
DTSTART;VALUE=DATE:20170604
DTEND;VALUE=DATE:20170605
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:2. nelipüha
UID:b70ead8d-fad3-484a-bf67-5a52632c579d
DTSTART;VALUE=DATE:20170605
DTEND;VALUE=DATE:20170606
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Suve algus kell 07:24
UID:328ecee3-576a-44e8-9c1e-2f3a5e357f83
DTSTART;VALUE=DATE:20170621
DTEND;VALUE=DATE:20170622
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Sügise algus kell 23:02
UID:afc4d254-2139-497a-a8d8-38df0bbaea0d
DTSTART;VALUE=DATE:20170922
DTEND;VALUE=DATE:20170923
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Kohaliku omavalitsuse volikogu valimised
UID:8da59f54-176f-446e-a270-c111ea3e18dd
DTSTART;VALUE=DATE:20171015
DTEND;VALUE=DATE:20171016
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:1. advent
UID:47dc3b6a-d95b-44b5-bfc7-1b3a35f7205d
DTSTART;VALUE=DATE:20171203
DTEND;VALUE=DATE:20171204
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:2. advent
UID:4864b353-09b9-4efa-83d0-a972392b84bb
DTSTART;VALUE=DATE:20171210
DTEND;VALUE=DATE:20171211
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:3. advent
UID:329a9209-d449-4bbf-a34c-ad1d5a5c614b
DTSTART;VALUE=DATE:20171217
DTEND;VALUE=DATE:20171218
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Talve algus kell 18:28
UID:8f789507-7ebb-43a0-98c3-7d43e02383ab
DTSTART;VALUE=DATE:20171221
DTEND;VALUE=DATE:20171222
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:4. advent
UID:b2be7f14-42d6-4315-ae41-a8e70cc0389d
DTSTART;VALUE=DATE:20171224
DTEND;VALUE=DATE:20171225
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vastlapäev
UID:a95dc427-9bc3-42c2-bf73-e28475488119
DTSTART;VALUE=DATE:20180213
DTEND;VALUE=DATE:20180214
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Tuhkapäev
UID:f154d202-d199-47d7-8c9b-2f7e9b6ee566
DTSTART;VALUE=DATE:20180214
DTEND;VALUE=DATE:20180215
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Kevade algus kell 18:15
UID:bf16eef0-f725-4bad-8f08-782b799d3c23
DTSTART;VALUE=DATE:20180320
DTEND;VALUE=DATE:20180321
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Suur reede
UID:c6622440-ffcb-4ac1-b74e-9585bbd4201f
UID:enrico-est-20180330@kayaposoft.com
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
SUMMARY:suur reede
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:1. ülestõusmispüha
UID:e2b4326b-a759-4139-983c-010e11c00ed6
UID:enrico-est-20180401@kayaposoft.com
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
SUMMARY:ülestõusmispühade 1. püha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:2. ülestõusmispüha
UID:7953c329-b375-453d-aa22-3178ab4c8635
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
UID:enrico-est-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:kevadpüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Tuuleristipäev
UID:3bcd442c-cfb7-4ce2-b094-5c8faa2eb6e3
DTSTART;VALUE=DATE:20180419
DTEND;VALUE=DATE:20180420
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Linnuristipäev
UID:ed690184-a077-404a-9898-526fc30c0edd
DTSTART;VALUE=DATE:20180426
DTEND;VALUE=DATE:20180427
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Leheristipäev
UID:3ee1e9ca-4a0f-4b50-95e2-9d6f0df602b4
DTSTART;VALUE=DATE:20180503
DTEND;VALUE=DATE:20180504
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Taevaminemispüha
UID:77e33601-6e4a-451d-8f05-f0e32aae10e8
DTSTART;VALUE=DATE:20180510
DTEND;VALUE=DATE:20180511
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:1. nelipüha
UID:b1ec19e5-7aad-4c68-9b57-afb2fdc443d7
UID:enrico-est-20180520@kayaposoft.com
DTSTART;VALUE=DATE:20180520
DTEND;VALUE=DATE:20180521
SUMMARY:nelipühade 1. püha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:2. nelipüha
UID:fbd7814f-0b3b-4916-94de-3c20d7a32fae
DTSTART;VALUE=DATE:20180521
DTEND;VALUE=DATE:20180522
UID:enrico-est-20180623@kayaposoft.com
DTSTART;VALUE=DATE:20180623
DTEND;VALUE=DATE:20180624
SUMMARY:võidupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Suve algus kell 13:07
UID:2c96272e-c227-46ba-8219-54e5ae360ffd
DTSTART;VALUE=DATE:20180621
DTEND;VALUE=DATE:20180622
UID:enrico-est-20180624@kayaposoft.com
DTSTART;VALUE=DATE:20180624
DTEND;VALUE=DATE:20180625
SUMMARY:jaanipäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Sügise algus kell 04:54
UID:5f22d789-9b4b-4aeb-9691-f813e2a01aa8
DTSTART;VALUE=DATE:20180923
DTEND;VALUE=DATE:20180924
UID:enrico-est-20180820@kayaposoft.com
DTSTART;VALUE=DATE:20180820
DTEND;VALUE=DATE:20180821
SUMMARY:taasiseseisvumispäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:1. advent
UID:ec10f2a1-aa5f-44d3-afe1-a6d1cf3e5a9e
DTSTART;VALUE=DATE:20181202
DTEND;VALUE=DATE:20181203
UID:enrico-est-20181224@kayaposoft.com
DTSTART;VALUE=DATE:20181224
DTEND;VALUE=DATE:20181225
SUMMARY:jõululaupäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:2. advent
UID:c29c4c4a-6905-4864-9bb9-ebf6c1ed394e
DTSTART;VALUE=DATE:20181209
DTEND;VALUE=DATE:20181210
UID:enrico-est-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:esimene jõulupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:3. advent
UID:fc82eb9d-15b2-4182-9e7c-30096371decc
DTSTART;VALUE=DATE:20181216
DTEND;VALUE=DATE:20181217
UID:enrico-est-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:teine jõulupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Talve algus kell 00:23
UID:89ae6fc6-699f-4189-80db-c118f2aca9c4
DTSTART;VALUE=DATE:20181222
DTEND;VALUE=DATE:20181223
UID:enrico-est-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:uusaasta
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:4. advent
UID:6b3cd6d7-77ab-4d12-97c8-92fbe78264a8
DTSTART;VALUE=DATE:20181223
DTEND;VALUE=DATE:20181224
UID:enrico-est-20190224@kayaposoft.com
DTSTART;VALUE=DATE:20190224
DTEND;VALUE=DATE:20190225
SUMMARY:iseseisvuspäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20190419@kayaposoft.com
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:suur reede
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20190421@kayaposoft.com
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
SUMMARY:ülestõusmispühade 1. püha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:kevadpüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20190609@kayaposoft.com
DTSTART;VALUE=DATE:20190609
DTEND;VALUE=DATE:20190610
SUMMARY:nelipühade 1. püha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20190623@kayaposoft.com
DTSTART;VALUE=DATE:20190623
DTEND;VALUE=DATE:20190624
SUMMARY:võidupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20190624@kayaposoft.com
DTSTART;VALUE=DATE:20190624
DTEND;VALUE=DATE:20190625
SUMMARY:jaanipäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20190820@kayaposoft.com
DTSTART;VALUE=DATE:20190820
DTEND;VALUE=DATE:20190821
SUMMARY:taasiseseisvumispäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20191224@kayaposoft.com
DTSTART;VALUE=DATE:20191224
DTEND;VALUE=DATE:20191225
SUMMARY:jõululaupäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:esimene jõulupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:teine jõulupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:uusaasta
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200224@kayaposoft.com
DTSTART;VALUE=DATE:20200224
DTEND;VALUE=DATE:20200225
SUMMARY:iseseisvuspäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200410@kayaposoft.com
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
SUMMARY:suur reede
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200412@kayaposoft.com
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
SUMMARY:ülestõusmispühade 1. püha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:kevadpüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200531@kayaposoft.com
DTSTART;VALUE=DATE:20200531
DTEND;VALUE=DATE:20200601
SUMMARY:nelipühade 1. püha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200623@kayaposoft.com
DTSTART;VALUE=DATE:20200623
DTEND;VALUE=DATE:20200624
SUMMARY:võidupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200624@kayaposoft.com
DTSTART;VALUE=DATE:20200624
DTEND;VALUE=DATE:20200625
SUMMARY:jaanipäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20200820@kayaposoft.com
DTSTART;VALUE=DATE:20200820
DTEND;VALUE=DATE:20200821
SUMMARY:taasiseseisvumispäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20201224@kayaposoft.com
DTSTART;VALUE=DATE:20201224
DTEND;VALUE=DATE:20201225
SUMMARY:jõululaupäev
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:esimene jõulupüha
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-est-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:teine jõulupüha
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -65,16 +65,16 @@ END:VEVENT
BEGIN:VEVENT
SUMMARY:Naistenpäivä
UID:55954496-9c99-4eeb-871e-b015d0f8ce40
DTSTART;VALUE=DATE:19750308
DTEND;VALUE=DATE:19750309
DTSTART;VALUE=DATE:20170308
DTEND;VALUE=DATE:20170309
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ruotsalaisuuden päivä
UID:ac081b74-6737-49a2-aeaf-4993eec75d0e
DTSTART;VALUE=DATE:19801106
DTEND;VALUE=DATE:19801107
DTSTART;VALUE=DATE:20171106
DTEND;VALUE=DATE:20171107
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT

View file

@ -7,13 +7,6 @@ DTEND;VALUE=DATE:20170526
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:55d7b48b-f4ac-4d4f-9f7a-c750cd836fb9
DTSTART;VALUE=DATE:20170604
DTEND;VALUE=DATE:20170605
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:0763c01f-245e-4ebf-acff-45597e999a01
DTSTART;VALUE=DATE:20170605
@ -35,13 +28,6 @@ DTEND;VALUE=DATE:20171120
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:e2e10823-b9cd-4c10-931c-38f2b0853844
DTSTART;VALUE=DATE:20171122
DTEND;VALUE=DATE:20171123
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:3d292c6c-c482-4a6a-8ec3-18dae2c57aa0
DTSTART;VALUE=DATE:20171126
@ -49,48 +35,6 @@ DTEND;VALUE=DATE:20171127
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:f31f4c45-3d27-4992-88b7-8ed6e269069a
DTSTART;VALUE=DATE:20171203
DTEND;VALUE=DATE:20171204
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:4f5ceb8a-4fdf-471b-873d-7b6d74ce1527
DTSTART;VALUE=DATE:20171210
DTEND;VALUE=DATE:20171211
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:13fc6d4f-c378-478e-b4d1-98578060b359
DTSTART;VALUE=DATE:20171217
DTEND;VALUE=DATE:20171218
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:71807f5d-ea0a-4c85-954d-301490a4db78
DTSTART;VALUE=DATE:20171224
DTEND;VALUE=DATE:20171225
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:16a1f889-913e-4d6c-ae41-63d05096af02
DTSTART;VALUE=DATE:20180212
DTEND;VALUE=DATE:20180213
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:553ebbee-4e98-4979-9fb4-f16de19b78c9
DTSTART;VALUE=DATE:20180214
DTEND;VALUE=DATE:20180215
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:00fa1ea2-c91d-4d5b-89c5-1102259e1d24
DTSTART;VALUE=DATE:20180330
@ -98,13 +42,6 @@ DTEND;VALUE=DATE:20180331
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostern
UID:3a6ff1ad-1215-462e-bc6e-31ff03cab1fe
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostermontag
UID:0ab12047-4716-4307-9d41-025db2534867
DTSTART;VALUE=DATE:20180402
@ -119,20 +56,6 @@ DTEND;VALUE=DATE:20180511
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:01e33d81-7688-4b5f-a448-8f30936d53c5
DTSTART;VALUE=DATE:20180513
DTEND;VALUE=DATE:20180514
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:e6891ff2-4e97-4163-8b68-2711a9395a2b
DTSTART;VALUE=DATE:20180520
DTEND;VALUE=DATE:20180521
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:01da1f59-2a95-4528-84b7-45c420d73130
DTSTART;VALUE=DATE:20180521
@ -154,13 +77,6 @@ DTEND;VALUE=DATE:20181119
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:8f011c35-0bc0-4ce7-983c-3f5107105089
DTSTART;VALUE=DATE:20181121
DTEND;VALUE=DATE:20181122
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:5ce3351e-8a46-4a6a-86c1-9d6a4691d69c
DTSTART;VALUE=DATE:20181125
@ -168,55 +84,6 @@ DTEND;VALUE=DATE:20181126
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:54af4894-22f2-4d6f-afec-b41a4773a7c1
DTSTART;VALUE=DATE:20181202
DTEND;VALUE=DATE:20181203
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:075866e7-e5a4-4e28-9e7b-da1668457f12
DTSTART;VALUE=DATE:20181209
DTEND;VALUE=DATE:20181210
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:859543e9-8310-4c39-a953-55d01afb95d5
DTSTART;VALUE=DATE:20181216
DTEND;VALUE=DATE:20181217
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:86472732-c54c-454c-8c46-60dc8d872f22
DTSTART;VALUE=DATE:20181223
DTEND;VALUE=DATE:20181224
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:d37799d7-4c4e-49a1-8132-3b41ffdc650e
DTSTART;VALUE=DATE:20190304
DTEND;VALUE=DATE:20190305
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:59874060-e592-493d-beb3-7710a4c8a4c4
DTSTART;VALUE=DATE:20190306
DTEND;VALUE=DATE:20190307
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palmsonntag
UID:f69b0d53-6039-4f44-993e-dfed2988dbbb
DTSTART;VALUE=DATE:20190414
DTEND;VALUE=DATE:20190415
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:0aaa7d21-c168-4dbb-a9ca-311c83c0840d
DTSTART;VALUE=DATE:20190419
@ -224,13 +91,6 @@ DTEND;VALUE=DATE:20190420
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostern
UID:c6ae2cd0-f9dc-4936-ac69-7f43a8d5c454
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostermontag
UID:b0300aa9-c14b-482c-b9d9-be81d9475123
DTSTART;VALUE=DATE:20190422
@ -238,13 +98,6 @@ DTEND;VALUE=DATE:20190423
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:1cbb64eb-c8c1-4f49-bc4e-e11190c37f42
DTSTART;VALUE=DATE:20190512
DTEND;VALUE=DATE:20190513
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christi Himmelfahrt
UID:54b3d09c-99f7-4f27-9253-d1fe8e358c50
DTSTART;VALUE=DATE:20190530
@ -252,13 +105,6 @@ DTEND;VALUE=DATE:20190531
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:4154d812-6a09-4bb1-9b39-9654af771086
DTSTART;VALUE=DATE:20190609
DTEND;VALUE=DATE:20190610
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:68095b69-e62a-4a0a-be4a-c9a68844a341
DTSTART;VALUE=DATE:20190610
@ -280,13 +126,6 @@ DTEND;VALUE=DATE:20191118
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:29bcda47-bb53-40ef-8d23-5f96e87d7b11
DTSTART;VALUE=DATE:20191120
DTEND;VALUE=DATE:20191121
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:55f73cbf-979c-4947-9245-1f39720f017a
DTSTART;VALUE=DATE:20191124
@ -294,55 +133,6 @@ DTEND;VALUE=DATE:20191125
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:f88e5652-cc2c-4e29-8d7a-aaf2b839ca87
DTSTART;VALUE=DATE:20191201
DTEND;VALUE=DATE:20191202
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:6a1e6f6b-4a86-45cf-ae59-e73968a4f094
DTSTART;VALUE=DATE:20191208
DTEND;VALUE=DATE:20191209
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:59ab9870-918f-49ef-a3c5-ac1b79c12e43
DTSTART;VALUE=DATE:20191215
DTEND;VALUE=DATE:20191216
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:cc5ff7ef-7d49-49ab-ab20-b2fcfb9d5c8a
DTSTART;VALUE=DATE:20191222
DTEND;VALUE=DATE:20191223
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:f10cb9c7-e9c6-40da-9799-e9f7defc8706
DTSTART;VALUE=DATE:20200224
DTEND;VALUE=DATE:20200225
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:d263556d-11f7-41dd-9b87-e7e33b5e0cd7
DTSTART;VALUE=DATE:20200226
DTEND;VALUE=DATE:20200227
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palmsonntag
UID:e7d82cc8-29d3-4b46-8c64-6d0514ff01a3
DTSTART;VALUE=DATE:20200405
DTEND;VALUE=DATE:20200406
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:84fb596d-f62c-4f0c-be11-7d96e7883e97
DTSTART;VALUE=DATE:20200410
@ -350,8 +140,8 @@ DTEND;VALUE=DATE:20200411
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostern
UID:b65c108f-5eea-4065-a4cd-8f5cc869666b
SUMMARY:Ostersonntag
UID:84fb596d-f62c-4f0c-be11-7d96e7884567
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
STATUS:CONFIRMED
@ -364,13 +154,6 @@ DTEND;VALUE=DATE:20200414
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:b3a25d49-3ae0-4941-a0a3-605a0aa013a3
DTSTART;VALUE=DATE:20200510
DTEND;VALUE=DATE:20200511
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christi Himmelfahrt
UID:20b3805d-d325-478b-bcee-c8f1f87f7e2d
DTSTART;VALUE=DATE:20200521
@ -378,8 +161,8 @@ DTEND;VALUE=DATE:20200522
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:b394de73-9c84-425c-8f43-acb3f08988fb
SUMMARY:Pfingstsonntag
UID:12013b62-6924-4457-89ff-3a8ba947778
DTSTART;VALUE=DATE:20200531
DTEND;VALUE=DATE:20200601
STATUS:CONFIRMED
@ -406,13 +189,6 @@ DTEND;VALUE=DATE:20201116
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:fbda2175-0043-463e-9559-75846f246604
DTSTART;VALUE=DATE:20201118
DTEND;VALUE=DATE:20201119
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:0cc4f56c-7eb8-4de7-ae2a-99b293b25f97
DTSTART;VALUE=DATE:20201122
@ -420,48 +196,6 @@ DTEND;VALUE=DATE:20201123
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:af547b9d-c9fb-4b2c-a9ee-1883a246fb4a
DTSTART;VALUE=DATE:20201129
DTEND;VALUE=DATE:20201130
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:9be17f09-8386-4d4a-b611-ea5b8aaca4d1
DTSTART;VALUE=DATE:20201206
DTEND;VALUE=DATE:20201207
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:7b494bd1-ed8b-4278-985e-f974481b1574
DTSTART;VALUE=DATE:20201213
DTEND;VALUE=DATE:20201214
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:1b11acb7-0340-4958-9225-cfc14f4a478f
DTSTART;VALUE=DATE:20201220
DTEND;VALUE=DATE:20201221
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:2a024898-6e15-448b-83f5-c994fb1e4aa1
DTSTART;VALUE=DATE:20210215
DTEND;VALUE=DATE:20210216
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:82dc191a-e513-407e-99e3-9cb98483715d
DTSTART;VALUE=DATE:20210217
DTEND;VALUE=DATE:20210218
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:4c8899f1-6694-4804-bdaf-dd13f837c8d5
DTSTART;VALUE=DATE:20210402
@ -469,13 +203,6 @@ DTEND;VALUE=DATE:20210403
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostern
UID:7de1ada4-4e88-417e-91a1-86a219184830
DTSTART;VALUE=DATE:20210404
DTEND;VALUE=DATE:20210405
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostermontag
UID:3ab2214a-92e4-4fca-87b6-77d92c142631
DTSTART;VALUE=DATE:20210405
@ -483,13 +210,6 @@ DTEND;VALUE=DATE:20210406
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:d6cfc602-b0ec-4cb7-a066-4fed1804dc2e
DTSTART;VALUE=DATE:20210509
DTEND;VALUE=DATE:20210510
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christi Himmelfahrt
UID:65fd8793-c12f-4c51-b392-a40b8b434fee
DTSTART;VALUE=DATE:20210513
@ -497,13 +217,6 @@ DTEND;VALUE=DATE:20210514
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:6b058d52-a7c5-40e4-9c49-9b2cf6994053
DTSTART;VALUE=DATE:20210523
DTEND;VALUE=DATE:20210524
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:8a560aec-1ad3-4116-b0c0-f345345f8112
DTSTART;VALUE=DATE:20210524
@ -525,13 +238,6 @@ DTEND;VALUE=DATE:20211115
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:b495650e-002d-4c02-b9d3-52c26b204bf0
DTSTART;VALUE=DATE:20211117
DTEND;VALUE=DATE:20211118
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:f0a7eadd-30e7-46c1-bce0-37616e68ac13
DTSTART;VALUE=DATE:20211121
@ -539,55 +245,6 @@ DTEND;VALUE=DATE:20211122
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:03e79870-f2e5-414e-ac71-a41f73acd5c8
DTSTART;VALUE=DATE:20211128
DTEND;VALUE=DATE:20211129
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:79ba8671-3780-461a-a884-c23a64cf7930
DTSTART;VALUE=DATE:20211205
DTEND;VALUE=DATE:20211206
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:7128bd77-e61e-48ec-baca-adc12c869c87
DTSTART;VALUE=DATE:20211212
DTEND;VALUE=DATE:20211213
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:b73f7d0d-0d10-4d42-96d7-d3256415d1b9
DTSTART;VALUE=DATE:20211219
DTEND;VALUE=DATE:20211220
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:28273646-1658-430a-836f-90b3079ab56c
DTSTART;VALUE=DATE:20220228
DTEND;VALUE=DATE:20220301
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:642134b6-db26-4c84-9055-88f1e350ef4e
DTSTART;VALUE=DATE:20220302
DTEND;VALUE=DATE:20220303
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palmsonntag
UID:70683648-440f-45aa-9460-10d1ffced6e1
DTSTART;VALUE=DATE:20220410
DTEND;VALUE=DATE:20220411
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:018fdbdd-e2c5-48aa-bf6e-4f802d757d52
DTSTART;VALUE=DATE:20220415
@ -595,13 +252,6 @@ DTEND;VALUE=DATE:20220416
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostern
UID:fca22c3c-3e5a-4aec-b1f8-14b146ec71ef
DTSTART;VALUE=DATE:20220417
DTEND;VALUE=DATE:20220418
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostermontag
UID:402857cd-1eb5-48ef-9b8c-fd0eb188dec6
DTSTART;VALUE=DATE:20220418
@ -609,13 +259,6 @@ DTEND;VALUE=DATE:20220419
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:ff344166-2d62-43c5-9ded-53a300f684b9
DTSTART;VALUE=DATE:20220508
DTEND;VALUE=DATE:20220509
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christi Himmelfahrt
UID:c90fd01f-5521-4973-b0bb-11c3b16dd9ff
DTSTART;VALUE=DATE:20220526
@ -623,13 +266,6 @@ DTEND;VALUE=DATE:20220527
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:0d0106e9-1335-464e-b463-5cb142db5f1a
DTSTART;VALUE=DATE:20220605
DTEND;VALUE=DATE:20220606
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:a22fa187-185b-4cf1-93c1-82bdca14fd0e
DTSTART;VALUE=DATE:20220606
@ -651,13 +287,6 @@ DTEND;VALUE=DATE:20221114
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:590b067f-31f8-4c6f-bafb-accf22a6cf89
DTSTART;VALUE=DATE:20221116
DTEND;VALUE=DATE:20221117
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:f3b740a9-5fe6-42f8-8ea1-0a24c3b7947c
DTSTART;VALUE=DATE:20221120
@ -665,55 +294,6 @@ DTEND;VALUE=DATE:20221121
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:9b5a13c3-6abe-458e-bcbe-f1d6cdcdd02d
DTSTART;VALUE=DATE:20221127
DTEND;VALUE=DATE:20221128
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:1a7f91ae-5850-4e72-bdd1-1108c812d6fb
DTSTART;VALUE=DATE:20221204
DTEND;VALUE=DATE:20221205
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:a7d53387-8173-4a44-8d67-b64563dff278
DTSTART;VALUE=DATE:20221211
DTEND;VALUE=DATE:20221212
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:220094a1-08c4-4a0d-bd30-40d071682395
DTSTART;VALUE=DATE:20221218
DTEND;VALUE=DATE:20221219
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:5f7513bd-0978-4ed8-8022-7280645c3186
DTSTART;VALUE=DATE:20230220
DTEND;VALUE=DATE:20230221
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:956d4b66-1b2c-418e-ae7d-3cffad30eae7
DTSTART;VALUE=DATE:20230222
DTEND;VALUE=DATE:20230223
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palmsonntag
UID:0b5571a1-a813-4f47-bef7-dc28569de753
DTSTART;VALUE=DATE:20230402
DTEND;VALUE=DATE:20230403
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:ffaf8199-f853-45c8-b635-5f0e302f13fe
DTSTART;VALUE=DATE:20230407
@ -721,13 +301,6 @@ DTEND;VALUE=DATE:20230408
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostern
UID:a379dcf3-85eb-401f-b8cf-7f02da344d11
DTSTART;VALUE=DATE:20230409
DTEND;VALUE=DATE:20230410
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostermontag
UID:bb40c59f-7f00-44b7-98fc-e5fd5e0c9c27
DTSTART;VALUE=DATE:20230410
@ -735,13 +308,6 @@ DTEND;VALUE=DATE:20230411
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:8a0d77ba-30f9-4238-83b5-adcab7a3badb
DTSTART;VALUE=DATE:20230514
DTEND;VALUE=DATE:20230515
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christi Himmelfahrt
UID:f91d0e50-3550-46f4-959e-4c0837d122b3
DTSTART;VALUE=DATE:20230518
@ -749,13 +315,6 @@ DTEND;VALUE=DATE:20230519
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:888f86d6-9809-4b2c-948b-1443edac5e8e
DTSTART;VALUE=DATE:20230528
DTEND;VALUE=DATE:20230529
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:4eebf391-9bab-4c47-9828-9f102779600a
DTSTART;VALUE=DATE:20230529
@ -777,13 +336,6 @@ DTEND;VALUE=DATE:20231120
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:ba67b1dd-5db8-4536-af86-5ac01e6db382
DTSTART;VALUE=DATE:20231122
DTEND;VALUE=DATE:20231123
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:0eae032b-ae56-42ba-9d9b-42893d74dfb2
DTSTART;VALUE=DATE:20231126
@ -791,55 +343,6 @@ DTEND;VALUE=DATE:20231127
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:42a5ae0f-030c-4e61-a16a-168e3644c61a
DTSTART;VALUE=DATE:20231203
DTEND;VALUE=DATE:20231204
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:3568cc04-205f-43ce-981f-5f695f0ffb89
DTSTART;VALUE=DATE:20231210
DTEND;VALUE=DATE:20231211
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:c706891d-2560-4b11-b165-01b1810f36a3
DTSTART;VALUE=DATE:20231217
DTEND;VALUE=DATE:20231218
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:966f4e2f-a485-4617-be7b-fc1bfed38d05
DTSTART;VALUE=DATE:20231224
DTEND;VALUE=DATE:20231225
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:28ff27ae-6c43-4241-8e19-b859d3bacbbd
DTSTART;VALUE=DATE:20240212
DTEND;VALUE=DATE:20240213
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:99af362f-b9b1-4452-896d-648906ae4920
DTSTART;VALUE=DATE:20240214
DTEND;VALUE=DATE:20240215
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palmsonntag
UID:aabf87df-8b3b-469d-b731-fd8ee5c851da
DTSTART;VALUE=DATE:20240324
DTEND;VALUE=DATE:20240325
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:179a8a7f-6ebc-427f-89c8-dfd87f770bf9
DTSTART;VALUE=DATE:20240329
@ -861,20 +364,6 @@ DTEND;VALUE=DATE:20240510
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:23fa06d1-ccfe-40bf-81e8-d558ed1bf420
DTSTART;VALUE=DATE:20240512
DTEND;VALUE=DATE:20240513
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:7075eb28-7dde-4b96-8aad-76083ac8682b
DTSTART;VALUE=DATE:20240519
DTEND;VALUE=DATE:20240520
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:aa76019e-b3b6-4488-8bbf-31dc09fb1764
DTSTART;VALUE=DATE:20240520
@ -896,13 +385,6 @@ DTEND;VALUE=DATE:20241118
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:dcf3f9a7-086c-4e3e-805f-adaaec6fda2e
DTSTART;VALUE=DATE:20241120
DTEND;VALUE=DATE:20241121
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:546e46fb-ec99-4ddd-aa9d-6ec619b96dc0
DTSTART;VALUE=DATE:20241124
@ -910,55 +392,6 @@ DTEND;VALUE=DATE:20241125
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Erster Advent
UID:0b6285cb-89f9-4b85-8de0-a42bd18589c9
DTSTART;VALUE=DATE:20241201
DTEND;VALUE=DATE:20241202
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Zweiter Advent
UID:4ad38de2-8fce-4344-a208-979f1916b835
DTSTART;VALUE=DATE:20241208
DTEND;VALUE=DATE:20241209
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Dritter Advent
UID:b49431ca-7be4-4b79-bbb2-5f6a1248ef93
DTSTART;VALUE=DATE:20241215
DTEND;VALUE=DATE:20241216
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Vierter Advent
UID:6b46edc1-b54b-430b-9028-759a11d582c7
DTSTART;VALUE=DATE:20241222
DTEND;VALUE=DATE:20241223
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Rosenmontag
UID:749e7d53-b90e-4e4c-8375-10bc41996985
DTSTART;VALUE=DATE:20250303
DTEND;VALUE=DATE:20250304
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Aschermittwoch
UID:0c4a90fc-4651-4a12-886c-0659eb26d299
DTSTART;VALUE=DATE:20250305
DTEND;VALUE=DATE:20250306
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palmsonntag
UID:1c33e111-bb08-4f3d-992e-4e4712ab7118
DTSTART;VALUE=DATE:20250413
DTEND;VALUE=DATE:20250414
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Karfreitag
UID:e9a51e52-0956-4d0f-be18-c5ce39dae024
DTSTART;VALUE=DATE:20250418
@ -966,13 +399,6 @@ DTEND;VALUE=DATE:20250419
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostern
UID:efacb91a-6c19-4f00-bda9-cd6b8cfc4ce0
DTSTART;VALUE=DATE:20250420
DTEND;VALUE=DATE:20250421
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ostermontag
UID:457982d2-a038-49d2-9b27-6f9708a16206
DTSTART;VALUE=DATE:20250421
@ -980,13 +406,6 @@ DTEND;VALUE=DATE:20250422
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Muttertag
UID:1b9ecb65-b7ff-4388-b20c-64a5f90ff83f
DTSTART;VALUE=DATE:20250511
DTEND;VALUE=DATE:20250512
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christi Himmelfahrt
UID:0705f107-eef7-4929-ac93-a9d7a645e7f8
DTSTART;VALUE=DATE:20250529
@ -994,13 +413,6 @@ DTEND;VALUE=DATE:20250530
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingsten
UID:49fa3924-037e-46aa-985b-29f0f886ef8c
DTSTART;VALUE=DATE:20250608
DTEND;VALUE=DATE:20250609
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pfingstmontag
UID:082092fe-3345-4652-b5f9-d5aeee66328f
DTSTART;VALUE=DATE:20250609
@ -1022,13 +434,6 @@ DTEND;VALUE=DATE:20251117
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:b2e0c62b-d371-414a-9f14-bdd0fa5a3eb9
DTSTART;VALUE=DATE:20251119
DTEND;VALUE=DATE:20251120
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Totensonntag
UID:54c731a4-2052-44f7-be17-7976de70f144
DTSTART;VALUE=DATE:20251123
@ -1080,14 +485,6 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Valentinstag
UID:959125914
DTSTART;VALUE=DATE:20060214
DTEND;VALUE=DATE:20060215
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Tag der Arbeit
UID:999463355
DTSTART;VALUE=DATE:20060501
@ -1104,7 +501,7 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Mariä Himmelfahrt
SUMMARY:Maria Himmelfahrt
UID:948278340
DTSTART;VALUE=DATE:20060815
DTEND;VALUE=DATE:20060816
@ -1120,14 +517,6 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Reformationstag
UID:996398531
DTSTART;VALUE=DATE:20061031
DTEND;VALUE=DATE:20061101
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Allerheiligen
UID:970745861
DTSTART;VALUE=DATE:20061101
@ -1136,22 +525,6 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nikolaus
UID:915905148
DTSTART;VALUE=DATE:20061206
DTEND;VALUE=DATE:20061207
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Heiliger Abend
UID:031bd550-c8d9-11da-9d0c-a4805e40b203
DTSTART;VALUE=DATE:20061224
DTEND;VALUE=DATE:20061225
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:1. Weihnachtstag
UID:982967580
DTSTART;VALUE=DATE:20061225
@ -1175,4 +548,62 @@ DTEND;VALUE=DATE:20070101
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Internationaler Frauentag
UID:4694f46a-aef0-49a0-a8eb-asdasd
DTSTART;VALUE=DATE:20170308
DTEND;VALUE=DATE:20170309
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Reformationstag
UID:4694f46a-aef0-49a0-a8eb-reform
DTSTART;VALUE=DATE:20171031
DTEND;VALUE=DATE:20171101
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:4694f46a-aef0-49a0-a8eb-b1
DTSTART;VALUE=DATE:20181121
DTEND;VALUE=DATE:20181122
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:4694f46a-aef0-49a0-a8eb-b2
DTSTART;VALUE=DATE:20191120
DTEND;VALUE=DATE:20191121
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:4694f46a-aef0-49a0-a8eb-b3
DTSTART;VALUE=DATE:20201118
DTEND;VALUE=DATE:20201119
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:4694f46a-aef0-49a0-a8eb-b4
DTSTART;VALUE=DATE:20211117
DTEND;VALUE=DATE:20211118
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:4694f46a-aef0-49a0-a8eb-b5
DTSTART;VALUE=DATE:20221116
DTEND;VALUE=DATE:20221117
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Buß- und Bettag
UID:4694f46a-aef0-49a0-a8eb-b6
DTSTART;VALUE=DATE:20231122
DTEND;VALUE=DATE:20231123
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -300,8 +300,8 @@ END:VEVENT
BEGIN:VEVENT
SUMMARY:ID-I-Milad-un-Nabi [Barah-Wafat]
UID:2002-05-25-1
DTSTART;VALUE=DATE:20161213
DTEND;VALUE=DATE:20161214
DTSTART;VALUE=DATE:20161110
DTEND;VALUE=DATE:20161111
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT

View file

@ -0,0 +1,300 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:20171212T045342Z-268948299@marudot.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180101
SUMMARY:New Year's Day 2018
DESCRIPTION:Tahun Baru 2018
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-601964501@marudot.com
DTSTART;VALUE=DATE:20180216
DTEND;VALUE=DATE:20180216
SUMMARY:Chinese New Year
DESCRIPTION:Tahun Baru Imlek 2569
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-417357037@marudot.com
DTSTART;VALUE=DATE:20180228
DTEND;VALUE=DATE:20180228
SUMMARY:Coming to Indonesia-Cross Cultural Training
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-578292563@marudot.com
DTSTART;VALUE=DATE:20180301
DTEND;VALUE=DATE:20180301
SUMMARY:Working in Indonesia-Cross Cultural Workshop for Expats
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1099619811@marudot.com
DTSTART;VALUE=DATE:20180313
DTEND;VALUE=DATE:20180313
SUMMARY:Living in Indonesia-Cross Cultural Workshop for Spouses
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-894503703@marudot.com
DTSTART;VALUE=DATE:20180314
DTEND;VALUE=DATE:20180314
SUMMARY:Management in Indonesia-Cross Cultural Workshop
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-791851244@marudot.com
DTSTART;VALUE=DATE:20180317
DTEND;VALUE=DATE:20180317
SUMMARY:Balinese New Year
DESCRIPTION:Hari Raya Nyepi 1940
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-329618688@marudot.com
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180330
SUMMARY:Good Friday
DESCRIPTION:Wafat Isa Al-Masih
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-190146881@marudot.com
DTSTART;VALUE=DATE:20180414
DTEND;VALUE=DATE:20180414
SUMMARY:Ascension of Prophet Muhammad SAW
DESCRIPTION:Isra Miraj Nabi Muhammad SAW
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-435386496@marudot.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180501
SUMMARY:Labor Day
DESCRIPTION:Hari Buruh Internasional
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-418653428@marudot.com
DTSTART;VALUE=DATE:20180510
DTEND;VALUE=DATE:20180510
SUMMARY:Waisak Day (“Buddhas Birthday” 2562)
DESCRIPTION:Hari Waisak 2562
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-2110293750@marudot.com
DTSTART;VALUE=DATE:20180510
DTEND;VALUE=DATE:20180510
SUMMARY:Ascension Day of Jesus Christ
DESCRIPTION:Kenaikan Isa Almasih
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-119842090@marudot.com
DTSTART;VALUE=DATE:20180601
DTEND;VALUE=DATE:20180601
SUMMARY:Birthday of Pancasila
DESCRIPTION:Hari Lahir Pancasila
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1166612864@marudot.com
DTSTART;VALUE=DATE:20180615
DTEND;VALUE=DATE:20180615
SUMMARY:End of Ramadan Eid-al-Fitr 1439H (1st of Shawwal)
DESCRIPTION:Hari Raya Idul Fitri 1439H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-640873938@marudot.com
DTSTART;VALUE=DATE:20180616
DTEND;VALUE=DATE:20180616
SUMMARY:End of Ramadan Eid-al-Fitr 1439H (2nd of Shawwal)
DESCRIPTION:Hari Raya Idul Fitri 1439H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1948724575@marudot.com
DTSTART;VALUE=DATE:20180808
DTEND;VALUE=DATE:20180808
SUMMARY:Working in Indonesia-Cross Cultural Workshop for Expats
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1926764224@marudot.com
DTSTART;VALUE=DATE:20180814
DTEND;VALUE=DATE:20180814
SUMMARY:Management in Indonesia-Cross Cultural Workshop
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-828431129@marudot.com
DTSTART;VALUE=DATE:20180817
DTEND;VALUE=DATE:20180817
SUMMARY:Indonesia Independence Day
DESCRIPTION:Hari Kemerdekaan Republik Indonesia ke-73
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1713949044@marudot.com
DTSTART;VALUE=DATE:20180822
DTEND;VALUE=DATE:20180822
SUMMARY:Islamic feast of Sacrifice (Bakr-Eid) 1439H
DESCRIPTION:Hari Raya Idul Adha 1439H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1202137034@marudot.com
DTSTART;VALUE=DATE:20180911
DTEND;VALUE=DATE:20180911
SUMMARY:Islamic New Year (1st Muharram 1440H)
DESCRIPTION:Tahun Baru Islam 1440H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-209129850@marudot.com
DTSTART;VALUE=DATE:20181120
DTEND;VALUE=DATE:20181120
SUMMARY:Birth of the Prophet Muhammad SAW
DESCRIPTION:Maulid Nabi
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-946856460@marudot.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181225
SUMMARY:Christmas Day
DESCRIPTION:Hari Raya Natal
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-2689482992@marudot.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190101
SUMMARY:New Year's Day 2019
DESCRIPTION:Tahun Baru 2019
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-6019645012@marudot.com
DTSTART;VALUE=DATE:20190205
DTEND;VALUE=DATE:20190205
SUMMARY:Chinese New Year
DESCRIPTION:Tahun Baru Imlek 2569
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-7918512442@marudot.com
DTSTART;VALUE=DATE:20190307
DTEND;VALUE=DATE:20190307
SUMMARY:Balinese New Year
DESCRIPTION:Hari Raya Nyepi 1940
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-3296186882@marudot.com
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190419
SUMMARY:Good Friday
DESCRIPTION:Wafat Isa Al-Masih
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1901468812@marudot.com
DTSTART;VALUE=DATE:20190530
DTEND;VALUE=DATE:20190530
SUMMARY:Ascension of Prophet Muhammad SAW
DESCRIPTION:Isra Miraj Nabi Muhammad SAW
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-4353864962@marudot.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190501
SUMMARY:Labor Day
DESCRIPTION:Hari Buruh Internasional
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-4186534282@marudot.com
DTSTART;VALUE=DATE:20190519
DTEND;VALUE=DATE:20190519
SUMMARY:Waisak Day (“Buddhas Birthday” 2562)
DESCRIPTION:Hari Waisak 2562
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-21102937502@marudot.com
DTSTART;VALUE=DATE:20190530
DTEND;VALUE=DATE:20190530
SUMMARY:Ascension Day of Jesus Christ
DESCRIPTION:Kenaikan Isa Almasih
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-1198420902@marudot.com
DTSTART;VALUE=DATE:20190601
DTEND;VALUE=DATE:20190601
SUMMARY:Birthday of Pancasila
DESCRIPTION:Hari Lahir Pancasila
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-11666128642@marudot.com
DTSTART;VALUE=DATE:20180605
DTEND;VALUE=DATE:20180605
SUMMARY:End of Ramadan Eid-al-Fitr 1439H (1st of Shawwal)
DESCRIPTION:Hari Raya Idul Fitri 1439H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-6408739382@marudot.com
DTSTART;VALUE=DATE:20180606
DTEND;VALUE=DATE:20180606
SUMMARY:End of Ramadan Eid-al-Fitr 1439H (2nd of Shawwal)
DESCRIPTION:Hari Raya Idul Fitri 1439H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-8284311292@marudot.com
DTSTART;VALUE=DATE:20190817
DTEND;VALUE=DATE:20190817
SUMMARY:Indonesia Independence Day
DESCRIPTION:Hari Kemerdekaan Republik Indonesia ke-73
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-17139490442@marudot.com
DTSTART;VALUE=DATE:20180812
DTEND;VALUE=DATE:20180812
SUMMARY:Islamic feast of Sacrifice (Bakr-Eid) 1439H
DESCRIPTION:Hari Raya Idul Adha 1439H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-12021370342@marudot.com
DTSTART;VALUE=DATE:20180901
DTEND;VALUE=DATE:20180901
SUMMARY:Islamic New Year (1st Muharram 1440H)
DESCRIPTION:Tahun Baru Islam 1440H
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-2091298502@marudot.com
DTSTART;VALUE=DATE:20181110
DTEND;VALUE=DATE:20181110
SUMMARY:Birth of the Prophet Muhammad SAW
DESCRIPTION:Maulid Nabi
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:20171212T045342Z-9468564602@marudot.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181225
SUMMARY:Christmas Day
DESCRIPTION:Hari Raya Natal
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -152,10 +152,10 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:天皇誕生日 / Tennō tanjōbi / Emperor Akihito's Birthday
SUMMARY:天皇誕生日 / Tennō tanjōbi / The Emperor Naruhito's Birthday
UID:0f5a4799-4082-4921-95e5-183652982b2d
DTSTART;VALUE=DATE:20071223
DTEND;VALUE=DATE:20071224
DTSTART;VALUE=DATE:20190223
DTEND;VALUE=DATE:20190224
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT

View file

@ -0,0 +1,326 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-lva-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Jaungada dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180330@kayaposoft.com
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
SUMMARY:Lielo Piektdienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180401@kayaposoft.com
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
SUMMARY:Pirmās Lieldienas
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180402@kayaposoft.com
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
SUMMARY:Otro Lieldienu dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180430@kayaposoft.com
DTSTART;VALUE=DATE:20180430
DTEND;VALUE=DATE:20180501
SUMMARY:Darba svētkus
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Darba svētkus
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180504@kayaposoft.com
DTSTART;VALUE=DATE:20180504
DTEND;VALUE=DATE:20180505
SUMMARY:Latvijas Republikas Neatkarības atjaunošanas dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180513@kayaposoft.com
DTSTART;VALUE=DATE:20180513
DTEND;VALUE=DATE:20180514
SUMMARY:Mātes diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180520@kayaposoft.com
DTSTART;VALUE=DATE:20180520
DTEND;VALUE=DATE:20180521
SUMMARY:Vasarsvētkus
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180623@kayaposoft.com
DTSTART;VALUE=DATE:20180623
DTEND;VALUE=DATE:20180624
SUMMARY:Līgo dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20180624@kayaposoft.com
DTSTART;VALUE=DATE:20180624
DTEND;VALUE=DATE:20180625
SUMMARY:Jāņu dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20181119@kayaposoft.com
DTSTART;VALUE=DATE:20181119
DTEND;VALUE=DATE:20181120
SUMMARY:Latvijas Republikas proklamēšanas diena
DESCRIPTION:Holiday in lieu of 18 Nov 2018
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20181224@kayaposoft.com
DTSTART;VALUE=DATE:20181224
DTEND;VALUE=DATE:20181225
SUMMARY:Ziemassvētku vakars
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Ziemassvētki
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:2. Ziemassvētki
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20181231@kayaposoft.com
DTSTART;VALUE=DATE:20181231
DTEND;VALUE=DATE:20190101
SUMMARY:Vecgada vakars
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Jaungada dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190419@kayaposoft.com
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:Lielo Piektdienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190421@kayaposoft.com
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
SUMMARY:Pirmās Lieldienas
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190422@kayaposoft.com
DTSTART;VALUE=DATE:20190422
DTEND;VALUE=DATE:20190423
SUMMARY:Otro Lieldienu dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Darba svētkus
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190506@kayaposoft.com
DTSTART;VALUE=DATE:20190506
DTEND;VALUE=DATE:20190507
SUMMARY:Latvijas Republikas Neatkarības atjaunošanas dienu
DESCRIPTION:Holiday in lieu of 4 May 2019
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190512@kayaposoft.com
DTSTART;VALUE=DATE:20190512
DTEND;VALUE=DATE:20190513
SUMMARY:Mātes diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190609@kayaposoft.com
DTSTART;VALUE=DATE:20190609
DTEND;VALUE=DATE:20190610
SUMMARY:Vasarsvētkus
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190623@kayaposoft.com
DTSTART;VALUE=DATE:20190623
DTEND;VALUE=DATE:20190624
SUMMARY:Līgo dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20190624@kayaposoft.com
DTSTART;VALUE=DATE:20190624
DTEND;VALUE=DATE:20190625
SUMMARY:Jāņu dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20191118@kayaposoft.com
DTSTART;VALUE=DATE:20191118
DTEND;VALUE=DATE:20191119
SUMMARY:Latvijas Republikas proklamēšanas diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20191224@kayaposoft.com
DTSTART;VALUE=DATE:20191224
DTEND;VALUE=DATE:20191225
SUMMARY:Ziemassvētku vakars
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Ziemassvētki
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:2. Ziemassvētki
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20191231@kayaposoft.com
DTSTART;VALUE=DATE:20191231
DTEND;VALUE=DATE:20200101
SUMMARY:Vecgada vakars
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Jaungada dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200410@kayaposoft.com
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
SUMMARY:Lielo Piektdienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200412@kayaposoft.com
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
SUMMARY:Pirmās Lieldienas
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200413@kayaposoft.com
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:Otro Lieldienu dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Darba svētkus
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200504@kayaposoft.com
DTSTART;VALUE=DATE:20200504
DTEND;VALUE=DATE:20200505
SUMMARY:Latvijas Republikas Neatkarības atjaunošanas dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200510@kayaposoft.com
DTSTART;VALUE=DATE:20200510
DTEND;VALUE=DATE:20200511
SUMMARY:Mātes diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200531@kayaposoft.com
DTSTART;VALUE=DATE:20200531
DTEND;VALUE=DATE:20200601
SUMMARY:Vasarsvētkus
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200623@kayaposoft.com
DTSTART;VALUE=DATE:20200623
DTEND;VALUE=DATE:20200624
SUMMARY:Līgo dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20200624@kayaposoft.com
DTSTART;VALUE=DATE:20200624
DTEND;VALUE=DATE:20200625
SUMMARY:Jāņu dienu
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20201118@kayaposoft.com
DTSTART;VALUE=DATE:20201118
DTEND;VALUE=DATE:20201119
SUMMARY:Latvijas Republikas proklamēšanas diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20201224@kayaposoft.com
DTSTART;VALUE=DATE:20201224
DTEND;VALUE=DATE:20201225
SUMMARY:Ziemassvētku vakars
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Ziemassvētki
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:2. Ziemassvētki
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lva-20201231@kayaposoft.com
DTSTART;VALUE=DATE:20201231
DTEND;VALUE=DATE:20210101
SUMMARY:Vecgada vakars
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,317 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-ltu-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Naujieji metai
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180216@kayaposoft.com
DTSTART;VALUE=DATE:20180216
DTEND;VALUE=DATE:20180217
SUMMARY:Lietuvos valstybės atkūrimo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180311@kayaposoft.com
DTSTART;VALUE=DATE:20180311
DTEND;VALUE=DATE:20180312
SUMMARY:Lietuvos nepriklausomybės atkūrimo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180401@kayaposoft.com
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
SUMMARY:Velykos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180402@kayaposoft.com
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
SUMMARY:Velykos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Tarptautinė darbo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180506@kayaposoft.com
DTSTART;VALUE=DATE:20180506
DTEND;VALUE=DATE:20180507
SUMMARY:Motinos diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180603@kayaposoft.com
DTSTART;VALUE=DATE:20180603
DTEND;VALUE=DATE:20180604
SUMMARY:Tėvo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180624@kayaposoft.com
DTSTART;VALUE=DATE:20180624
DTEND;VALUE=DATE:20180625
SUMMARY:Rasos (Joninės)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180706@kayaposoft.com
DTSTART;VALUE=DATE:20180706
DTEND;VALUE=DATE:20180707
SUMMARY:Valstybės (Lietuvos karaliaus Mindaugo karūnavimo) diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20180815@kayaposoft.com
DTSTART;VALUE=DATE:20180815
DTEND;VALUE=DATE:20180816
SUMMARY:Žolinė (Švč. Mergelės Marijos ėmimo į dangų diena)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20181101@kayaposoft.com
DTSTART;VALUE=DATE:20181101
DTEND;VALUE=DATE:20181102
SUMMARY:Visų šventųjų diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20181224@kayaposoft.com
DTSTART;VALUE=DATE:20181224
DTEND;VALUE=DATE:20181225
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Naujieji metai
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190216@kayaposoft.com
DTSTART;VALUE=DATE:20190216
DTEND;VALUE=DATE:20190217
SUMMARY:Lietuvos valstybės atkūrimo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190311@kayaposoft.com
DTSTART;VALUE=DATE:20190311
DTEND;VALUE=DATE:20190312
SUMMARY:Lietuvos nepriklausomybės atkūrimo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190421@kayaposoft.com
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
SUMMARY:Velykos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190422@kayaposoft.com
DTSTART;VALUE=DATE:20190422
DTEND;VALUE=DATE:20190423
SUMMARY:Velykos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Tarptautinė darbo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190505@kayaposoft.com
DTSTART;VALUE=DATE:20190505
DTEND;VALUE=DATE:20190506
SUMMARY:Motinos diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190602@kayaposoft.com
DTSTART;VALUE=DATE:20190602
DTEND;VALUE=DATE:20190603
SUMMARY:Tėvo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190624@kayaposoft.com
DTSTART;VALUE=DATE:20190624
DTEND;VALUE=DATE:20190625
SUMMARY:Rasos (Joninės)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190706@kayaposoft.com
DTSTART;VALUE=DATE:20190706
DTEND;VALUE=DATE:20190707
SUMMARY:Valstybės (Lietuvos karaliaus Mindaugo karūnavimo) diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20190815@kayaposoft.com
DTSTART;VALUE=DATE:20190815
DTEND;VALUE=DATE:20190816
SUMMARY:Žolinė (Švč. Mergelės Marijos ėmimo į dangų diena)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20191101@kayaposoft.com
DTSTART;VALUE=DATE:20191101
DTEND;VALUE=DATE:20191102
SUMMARY:Visų šventųjų diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20191224@kayaposoft.com
DTSTART;VALUE=DATE:20191224
DTEND;VALUE=DATE:20191225
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Naujieji metai
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200216@kayaposoft.com
DTSTART;VALUE=DATE:20200216
DTEND;VALUE=DATE:20200217
SUMMARY:Lietuvos valstybės atkūrimo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200311@kayaposoft.com
DTSTART;VALUE=DATE:20200311
DTEND;VALUE=DATE:20200312
SUMMARY:Lietuvos nepriklausomybės atkūrimo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200412@kayaposoft.com
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
SUMMARY:Velykos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200413@kayaposoft.com
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:Velykos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Tarptautinė darbo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200503@kayaposoft.com
DTSTART;VALUE=DATE:20200503
DTEND;VALUE=DATE:20200504
SUMMARY:Motinos diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200607@kayaposoft.com
DTSTART;VALUE=DATE:20200607
DTEND;VALUE=DATE:20200608
SUMMARY:Tėvo diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200624@kayaposoft.com
DTSTART;VALUE=DATE:20200624
DTEND;VALUE=DATE:20200625
SUMMARY:Rasos (Joninės)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200706@kayaposoft.com
DTSTART;VALUE=DATE:20200706
DTEND;VALUE=DATE:20200707
SUMMARY:Valstybės (Lietuvos karaliaus Mindaugo karūnavimo) diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20200815@kayaposoft.com
DTSTART;VALUE=DATE:20200815
DTEND;VALUE=DATE:20200816
SUMMARY:Žolinė (Švč. Mergelės Marijos ėmimo į dangų diena)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20201101@kayaposoft.com
DTSTART;VALUE=DATE:20201101
DTEND;VALUE=DATE:20201102
SUMMARY:Visų šventųjų diena
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20201224@kayaposoft.com
DTSTART;VALUE=DATE:20201224
DTEND;VALUE=DATE:20201225
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ltu-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:Šv. Kalėdos
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,212 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-lux-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Neijoerschdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20180402@kayaposoft.com
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
SUMMARY:Ouschterméindeg
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Dag vun der Aarbecht
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20180510@kayaposoft.com
DTSTART;VALUE=DATE:20180510
DTEND;VALUE=DATE:20180511
SUMMARY:Christi Himmelfaart
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20180521@kayaposoft.com
DTSTART;VALUE=DATE:20180521
DTEND;VALUE=DATE:20180522
SUMMARY:Péngschtméindeg
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20180623@kayaposoft.com
DTSTART;VALUE=DATE:20180623
DTEND;VALUE=DATE:20180624
SUMMARY:Nationalfeierdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20180815@kayaposoft.com
DTSTART;VALUE=DATE:20180815
DTEND;VALUE=DATE:20180816
SUMMARY:Mariä Himmelfaart
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20181101@kayaposoft.com
DTSTART;VALUE=DATE:20181101
DTEND;VALUE=DATE:20181102
SUMMARY:Allerhellgen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Chrëschtdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:Stiefesdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Neijoerschdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20190422@kayaposoft.com
DTSTART;VALUE=DATE:20190422
DTEND;VALUE=DATE:20190423
SUMMARY:Ouschterméindeg
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Dag vun der Aarbecht
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20190530@kayaposoft.com
DTSTART;VALUE=DATE:20190530
DTEND;VALUE=DATE:20190531
SUMMARY:Christi Himmelfaart
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20190610@kayaposoft.com
DTSTART;VALUE=DATE:20190610
DTEND;VALUE=DATE:20190611
SUMMARY:Péngschtméindeg
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20190623@kayaposoft.com
DTSTART;VALUE=DATE:20190623
DTEND;VALUE=DATE:20190624
SUMMARY:Nationalfeierdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20190815@kayaposoft.com
DTSTART;VALUE=DATE:20190815
DTEND;VALUE=DATE:20190816
SUMMARY:Mariä Himmelfaart
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20191101@kayaposoft.com
DTSTART;VALUE=DATE:20191101
DTEND;VALUE=DATE:20191102
SUMMARY:Allerhellgen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Chrëschtdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:Stiefesdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Neijoerschdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20200413@kayaposoft.com
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:Ouschterméindeg
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Dag vun der Aarbecht
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20200521@kayaposoft.com
DTSTART;VALUE=DATE:20200521
DTEND;VALUE=DATE:20200522
SUMMARY:Christi Himmelfaart
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20200601@kayaposoft.com
DTSTART;VALUE=DATE:20200601
DTEND;VALUE=DATE:20200602
SUMMARY:Péngschtméindeg
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20200623@kayaposoft.com
DTSTART;VALUE=DATE:20200623
DTEND;VALUE=DATE:20200624
SUMMARY:Nationalfeierdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20200815@kayaposoft.com
DTSTART;VALUE=DATE:20200815
DTEND;VALUE=DATE:20200816
SUMMARY:Mariä Himmelfaart
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20201101@kayaposoft.com
DTSTART;VALUE=DATE:20201101
DTEND;VALUE=DATE:20201102
SUMMARY:Allerhellgen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Chrëschtdag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-lux-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:Stiefesdag
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,239 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-mkd-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Нова Година\, Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20180108@kayaposoft.com
DTSTART;VALUE=DATE:20180108
DTEND;VALUE=DATE:20180109
SUMMARY:Прв ден Божик\, Prv den Božik
DESCRIPTION:Holiday in lieu of 7 Jan 2018
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20180409@kayaposoft.com
DTSTART;VALUE=DATE:20180409
DTEND;VALUE=DATE:20180410
SUMMARY:Втор ден Велигден\, Vtor den Veligden
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Ден на трудот\, Den na trudot
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20180524@kayaposoft.com
DTSTART;VALUE=DATE:20180524
DTEND;VALUE=DATE:20180525
SUMMARY:Св. Кирил и Методиј\, Ден на сèсловенските просветители; Sv. Kiril i Metodij\, Den na sèslovenskite prosvetiteli
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20180615@kayaposoft.com
DTSTART;VALUE=DATE:20180615
DTEND;VALUE=DATE:20180616
SUMMARY:Рамазан Бајрам\, Ramazan Bajram
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20180802@kayaposoft.com
DTSTART;VALUE=DATE:20180802
DTEND;VALUE=DATE:20180803
SUMMARY:Ден на Републиката\, Den na Republikata
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20180908@kayaposoft.com
DTSTART;VALUE=DATE:20180908
DTEND;VALUE=DATE:20180909
SUMMARY:Ден на независноста\, Den na nezavisnosta
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20181011@kayaposoft.com
DTSTART;VALUE=DATE:20181011
DTEND;VALUE=DATE:20181012
SUMMARY:Ден на востанието\, Den na vostanieto
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20181023@kayaposoft.com
DTSTART;VALUE=DATE:20181023
DTEND;VALUE=DATE:20181024
SUMMARY:Ден на македонската револуционерна борба\, Den na makedonskata revolucionarna borba
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20181208@kayaposoft.com
DTSTART;VALUE=DATE:20181208
DTEND;VALUE=DATE:20181209
SUMMARY:Св. Климент Охридски\, Sv. Kliment Ohridski
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Нова Година\, Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190107@kayaposoft.com
DTSTART;VALUE=DATE:20190107
DTEND;VALUE=DATE:20190108
SUMMARY:Прв ден Божик\, Prv den Božik
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190429@kayaposoft.com
DTSTART;VALUE=DATE:20190429
DTEND;VALUE=DATE:20190430
SUMMARY:Втор ден Велигден\, Vtor den Veligden
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Ден на трудот\, Den na trudot
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190524@kayaposoft.com
DTSTART;VALUE=DATE:20190524
DTEND;VALUE=DATE:20190525
SUMMARY:Св. Кирил и Методиј\, Ден на сèсловенските просветители; Sv. Kiril i Metodij\, Den na sèslovenskite prosvetiteli
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190604@kayaposoft.com
DTSTART;VALUE=DATE:20190604
DTEND;VALUE=DATE:20190605
SUMMARY:Рамазан Бајрам\, Ramazan Bajram
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190802@kayaposoft.com
DTSTART;VALUE=DATE:20190802
DTEND;VALUE=DATE:20190803
SUMMARY:Ден на Републиката\, Den na Republikata
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20190909@kayaposoft.com
DTSTART;VALUE=DATE:20190909
DTEND;VALUE=DATE:20190910
SUMMARY:Ден на независноста\, Den na nezavisnosta
DESCRIPTION:Holiday in lieu of 8 Sep 2019
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20191011@kayaposoft.com
DTSTART;VALUE=DATE:20191011
DTEND;VALUE=DATE:20191012
SUMMARY:Ден на востанието\, Den na vostanieto
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20191023@kayaposoft.com
DTSTART;VALUE=DATE:20191023
DTEND;VALUE=DATE:20191024
SUMMARY:Ден на македонската револуционерна борба\, Den na makedonskata revolucionarna borba
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20191209@kayaposoft.com
DTSTART;VALUE=DATE:20191209
DTEND;VALUE=DATE:20191210
SUMMARY:Св. Климент Охридски\, Sv. Kliment Ohridski
DESCRIPTION:Holiday in lieu of 8 Dec 2019
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Нова Година\, Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200107@kayaposoft.com
DTSTART;VALUE=DATE:20200107
DTEND;VALUE=DATE:20200108
SUMMARY:Прв ден Божик\, Prv den Božik
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200420@kayaposoft.com
DTSTART;VALUE=DATE:20200420
DTEND;VALUE=DATE:20200421
SUMMARY:Втор ден Велигден\, Vtor den Veligden
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Ден на трудот\, Den na trudot
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200524@kayaposoft.com
DTSTART;VALUE=DATE:20200524
DTEND;VALUE=DATE:20200525
SUMMARY:Рамазан Бајрам\, Ramazan Bajram
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200525@kayaposoft.com
DTSTART;VALUE=DATE:20200525
DTEND;VALUE=DATE:20200526
SUMMARY:Св. Кирил и Методиј\, Ден на сèсловенските просветители; Sv. Kiril i Metodij\, Den na sèslovenskite prosvetiteli
DESCRIPTION:Holiday in lieu of 24 May 2020
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200803@kayaposoft.com
DTSTART;VALUE=DATE:20200803
DTEND;VALUE=DATE:20200804
SUMMARY:Ден на Републиката\, Den na Republikata
DESCRIPTION:Holiday in lieu of 2 Aug 2020
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20200908@kayaposoft.com
DTSTART;VALUE=DATE:20200908
DTEND;VALUE=DATE:20200909
SUMMARY:Ден на независноста\, Den na nezavisnosta
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20201012@kayaposoft.com
DTSTART;VALUE=DATE:20201012
DTEND;VALUE=DATE:20201013
SUMMARY:Ден на востанието\, Den na vostanieto
DESCRIPTION:Holiday in lieu of 11 Oct 2020
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20201023@kayaposoft.com
DTSTART;VALUE=DATE:20201023
DTEND;VALUE=DATE:20201024
SUMMARY:Ден на македонската револуционерна борба\, Den na makedonskata revolucionarna borba
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mkd-20201208@kayaposoft.com
DTSTART;VALUE=DATE:20201208
DTEND;VALUE=DATE:20201209
SUMMARY:Св. Климент Охридски\, Sv. Kliment Ohridski
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,429 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190713
DTEND;VALUE=DATE:20190714
UID:20190713_60o30pb3cgo30e1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Penang Governor's Birthday (Penang)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
UID:20180101_60o30db16oo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:New Year's Day (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180531
DTEND;VALUE=DATE:20180601
UID:20180531_60o30p9k6oo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Harvest Festival Day 2 (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190605
DTEND;VALUE=DATE:20190606
UID:20190605_60o30db260o30c1g60o30db160@google.com
STATUS:CONFIRMED
SUMMARY:Hari Raya Puasa
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
UID:20190419_60o30db26so30c1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Good Friday (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180707
DTEND;VALUE=DATE:20180708
UID:20180707_60o30pb3cco30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:George Town World Heritage City Day (Penang)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191027
DTEND;VALUE=DATE:20191028
UID:20191027_60o30db268o30c1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Diwali/Deepavali (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190506
DTEND;VALUE=DATE:20190507
UID:20190506_60o30ob5c4o30c1g60o30db160@google.com
STATUS:CONFIRMED
SUMMARY:Ramadan begins (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180530
DTEND;VALUE=DATE:20180531
UID:20180530_60o30p9k6ko30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Harvest Festival (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181015
DTEND;VALUE=DATE:20181016
UID:20181015_60o32e1icgo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Almarhum Sultan Iskandar Hol Day (Johor)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190603
DTEND;VALUE=DATE:20190604
UID:20190603_60o32e1i64o30e1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Gawai Dayak Holiday observed (Sarawak)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181211
DTEND;VALUE=DATE:20181212
UID:20181211_60o32e1j68o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Sultan of Selangor (Selangor)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181024
DTEND;VALUE=DATE:20181025
UID:20181024_60o32e1icko30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Sultan of Pahang (Pahang)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181111
DTEND;VALUE=DATE:20181112
UID:20181111_60o32e1j60o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Sultan of Kelantan (Kelantan)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180323
DTEND;VALUE=DATE:20180324
UID:20180323_60o32e1i6go30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Sultan of Johor (Johor)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181013
DTEND;VALUE=DATE:20181014
UID:20181013_60o32e1icco30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Governor of Sarawak (Sarawak)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191007
DTEND;VALUE=DATE:20191008
UID:20191007_60o32e1ic4o30e1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Birthday of the Governor of Sabah observed (Sabah)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180507
DTEND;VALUE=DATE:20180508
UID:20180507_60o32e1i6oo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Pahang State Holiday (Pahang)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190522
DTEND;VALUE=DATE:20190523
UID:20190522_60o30ob5c8o30c1g60o30db160@google.com
STATUS:CONFIRMED
SUMMARY:Nuzul Al-Quran (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190403
DTEND;VALUE=DATE:20190404
UID:20190403_60o30ob574o30c1g60o30db160@google.com
STATUS:CONFIRMED
SUMMARY:Isra and Mi'raj (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180415
DTEND;VALUE=DATE:20180416
UID:20180415_60o32e1i6so30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Declaration of Malacca as Historical City (Malacca)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180114
DTEND;VALUE=DATE:20180115
UID:20180114_60o32e1i6co30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of Yang di-Pertuan Besar (Negeri Sembilan)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180426
DTEND;VALUE=DATE:20180427
UID:20180426_60o32e1i70o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Sultan of Terengganu (Terengganu)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180517
DTEND;VALUE=DATE:20180518
UID:20180517_60o32e1i68o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Raja of Perlis (Perlis)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181012
DTEND;VALUE=DATE:20181013
UID:20181012_60o32e1ic8o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Governor of Malacca (Malacca)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180304
DTEND;VALUE=DATE:20180305
UID:20180304_60o32e1i6ko30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Anniversary of the coronation of the Sultan of Terengganu (Terengga
nu)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181120
DTEND;VALUE=DATE:20181121
UID:20181120_60o30db1c8o30c1g60o30dr568@google.com
STATUS:CONFIRMED
SUMMARY:The Prophet Muhammad's Birthday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180722
DTEND;VALUE=DATE:20180723
UID:20180722_60o32e1i74o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Sarawak Independence Day (Sarawak)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180917
DTEND;VALUE=DATE:20180918
UID:20180917_60o30db274o34c1g60o30dr568@google.com
STATUS:CONFIRMED
SUMMARY:Malaysia Day (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180916
DTEND;VALUE=DATE:20180917
UID:20180916_60o30db274o32c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Malaysia Day (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190813
DTEND;VALUE=DATE:20190814
UID:20190813_60o32e1hcko30c1g60o30db160@google.com
STATUS:CONFIRMED
SUMMARY:Hari Raya Haji (Day 2) (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180601
DTEND;VALUE=DATE:20180602
UID:20180601_60o32e1i60o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Gawai Dayak (Sarawak)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180602
DTEND;VALUE=DATE:20180603
UID:20180602_60o32e1i64o30c1g60o30dr568@google.com
CREATED:20180731T230440Z
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Gawai Dayak Holiday (Sarawak)
TRANSP:TRANSPARENT
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190603
DTEND;VALUE=DATE:20190604
UID:20190603_60o32e1i64o30e1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Gawai Dayak Holiday observed (Sarawak)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181106
DTEND;VALUE=DATE:20181107
UID:20181106_60o30db268o30c1g60o30dr568@google.com
STATUS:CONFIRMED
SUMMARY:Diwali/Deepavali (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181112
DTEND;VALUE=DATE:20181113
UID:20181112_60o32e1j64o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Sultan of Kelantan (Day 2) (Kelantan)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180909
DTEND;VALUE=DATE:20180910
UID:20180909_60o30db1cko32c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:The Yang di-Pertuan Agong's Birthday (regional holiday)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190427
DTEND;VALUE=DATE:20190428
UID:20190427_60o32e1i70o30c1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Birthday of the Sultan of Terengganu (Terengganu)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181102
DTEND;VALUE=DATE:20181103
UID:20181102_60o32e1icoo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Sultan of Perak (Perak)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191014
DTEND;VALUE=DATE:20191015
UID:20191014_60o32e1icco30e1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Birthday of the Governor of Sarawak observed (Sarawak)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181006
DTEND;VALUE=DATE:20181007
UID:20181006_60o32e1ic4o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Birthday of the Governor of Sabah (Sabah)
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180214
DTEND;VALUE=DATE:20180215
UID:20180214_60o32dpo68o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Valentine's Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190901
DTEND;VALUE=DATE:20190902
UID:20190901_60o30or46oo30c1g60o30db164@google.com
STATUS:CONFIRMED
SUMMARY:Muharram/New Year
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190206
DTEND;VALUE=DATE:20190207
UID:20190206_60o30db170o30c1g60o32chmcc@google.com
STATUS:CONFIRMED
SUMMARY:Second day of Chinese Lunar New Year
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180831
DTEND;VALUE=DATE:20180901
UID:20180831_60o30db1coo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Malaysia's National Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
UID:20180501_60o30db1cco30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Labour Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181224
DTEND;VALUE=DATE:20181225
UID:20181224_60o30db26oo30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Christmas Eve
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
UID:20181225_60o30db26ko30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Christmas Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190205
DTEND;VALUE=DATE:20190206
UID:20190205_60o30db16so30c1g60o32chmcc@google.com
STATUS:CONFIRMED
SUMMARY:Chinese Lunar New Year's Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191110
DTEND;VALUE=DATE:20191111
UID:20191110_60o30db1c8o30c1g60o30db164@google.com
STATUS:CONFIRMED
SUMMARY:The Prophet Muhammad's Birthday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180201
DTEND;VALUE=DATE:20180202
UID:20180201_60o30db174o30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Federal Territory Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190812
DTEND;VALUE=DATE:20190813
UID:20190812_60o30db26co30c1g60o30db160@google.com
STATUS:CONFIRMED
SUMMARY:Hari Raya Haji
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190606
DTEND;VALUE=DATE:20190607
UID:20190606_60o30db264o30c1g60o30db160@google.com
STATUS:CONFIRMED
SUMMARY:Hari Raya Puasa Day 2
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181231
DTEND;VALUE=DATE:20190101
UID:20181231_60o30db16ko30c1g60o30dr568@google.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:New Year's Eve
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
UID:20190421_60o30db270o30c1g60o30dr56c@google.com
STATUS:CONFIRMED
SUMMARY:Easter Sunday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190519
DTEND;VALUE=DATE:20190520
UID:20190519_60o30db1cgo30c1g60o30dr568@google.com
STATUS:CONFIRMED
SUMMARY:Wesak Day
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,156 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-mex-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Año Nuevo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20180205@kayaposoft.com
DTSTART;VALUE=DATE:20180205
DTEND;VALUE=DATE:20180206
SUMMARY:Día de la Constitución Mexicana
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20180319@kayaposoft.com
DTSTART;VALUE=DATE:20180319
DTEND;VALUE=DATE:20180320
SUMMARY:Natalicio de Benito Juárez
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Día del Trabajo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20180916@kayaposoft.com
DTSTART;VALUE=DATE:20180916
DTEND;VALUE=DATE:20180917
SUMMARY:Día de la Independencia
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20181119@kayaposoft.com
DTSTART;VALUE=DATE:20181119
DTEND;VALUE=DATE:20181120
SUMMARY:Revolución Mexicana
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20181201@kayaposoft.com
DTSTART;VALUE=DATE:20181201
DTEND;VALUE=DATE:20181202
SUMMARY:Transmisión del Poder Ejecutivo Federal
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Día de Navidad
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Año Nuevo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20190204@kayaposoft.com
DTSTART;VALUE=DATE:20190204
DTEND;VALUE=DATE:20190205
SUMMARY:Día de la Constitución Mexicana
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20190318@kayaposoft.com
DTSTART;VALUE=DATE:20190318
DTEND;VALUE=DATE:20190319
SUMMARY:Natalicio de Benito Juárez
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Día del Trabajo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20190916@kayaposoft.com
DTSTART;VALUE=DATE:20190916
DTEND;VALUE=DATE:20190917
SUMMARY:Día de la Independencia
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20191118@kayaposoft.com
DTSTART;VALUE=DATE:20191118
DTEND;VALUE=DATE:20191119
SUMMARY:Revolución Mexicana
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Día de Navidad
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Año Nuevo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20200203@kayaposoft.com
DTSTART;VALUE=DATE:20200203
DTEND;VALUE=DATE:20200204
SUMMARY:Día de la Constitución Mexicana
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20200316@kayaposoft.com
DTSTART;VALUE=DATE:20200316
DTEND;VALUE=DATE:20200317
SUMMARY:Natalicio de Benito Juárez
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Día del Trabajo
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20200916@kayaposoft.com
DTSTART;VALUE=DATE:20200916
DTEND;VALUE=DATE:20200917
SUMMARY:Día de la Independencia
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20201116@kayaposoft.com
DTSTART;VALUE=DATE:20201116
DTEND;VALUE=DATE:20201117
SUMMARY:Revolución Mexicana
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-mex-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Día de Navidad
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,70 @@
BEGIN:VCALENDER
BEGIN:VEVENT
SUMMARY:New Year's Day
UID:nig-20200101
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
DTEND;VALUE=DATE:20200414
DTSTART;VALUE=DATE:20200413
SUMMARY:Easter Monday
UID:nig-20200413
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
DTEND;VALUE=DATE:20200411
DTSTART;VALUE=DATE:20200410
SUMMARY:Good Friday
UID:nig-20200410
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christmas Day
UID:nig-20201225
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Democracy Day
UID:nig-20200612
DTEND;VALUE=DATE:20200613
DTSTART;VALUE=DATE:20200612
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Sallah
UID:nig-20200525
DTEND;VALUE=DATE:20200526
DTSTART;VALUE=DATE:20200525
END:VEVENT
BEGIN:VEVENT
SUMMARY: Worker's Day
UID:nig-20200501
DTEND;VALUE=DATE:20200502
DTSTART;VALUE=DATE:20200501
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Independence Day
UID:nig-20201001
DTEND;VALUE=DATE:20201002
DTSTART;VALUE=DATE:20201001
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Boxing Day
UID:nig-20201226
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
END:VCALENDER

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,296 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-rou-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Anul nou
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180102@kayaposoft.com
DTSTART;VALUE=DATE:20180102
DTEND;VALUE=DATE:20180103
SUMMARY:Anul nou
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180124@kayaposoft.com
DTSTART;VALUE=DATE:20180124
DTEND;VALUE=DATE:20180125
SUMMARY:Unirea Principatelor Române/Mica Unire
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180408@kayaposoft.com
DTSTART;VALUE=DATE:20180408
DTEND;VALUE=DATE:20180409
SUMMARY:Paştele
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180409@kayaposoft.com
DTSTART;VALUE=DATE:20180409
DTEND;VALUE=DATE:20180410
SUMMARY:Doua zi de Pasti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Ziua muncii
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180527@kayaposoft.com
DTSTART;VALUE=DATE:20180527
DTEND;VALUE=DATE:20180528
SUMMARY:Rusaliile
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180528@kayaposoft.com
DTSTART;VALUE=DATE:20180528
DTEND;VALUE=DATE:20180529
SUMMARY:Doua zi de Rusaliile
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180601@kayaposoft.com
DTSTART;VALUE=DATE:20180601
DTEND;VALUE=DATE:20180602
SUMMARY:Ziua Copilului
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20180815@kayaposoft.com
DTSTART;VALUE=DATE:20180815
DTEND;VALUE=DATE:20180816
SUMMARY:Adormirea Maicii Domnului/Sfânta Maria Mare
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20181130@kayaposoft.com
DTSTART;VALUE=DATE:20181130
DTEND;VALUE=DATE:20181201
SUMMARY:Sfântul Andrei
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20181201@kayaposoft.com
DTSTART;VALUE=DATE:20181201
DTEND;VALUE=DATE:20181202
SUMMARY:Ziua Națională/Marea Unire
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Crăciunul
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:Crăciunul
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Anul nou
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190102@kayaposoft.com
DTSTART;VALUE=DATE:20190102
DTEND;VALUE=DATE:20190103
SUMMARY:Anul nou
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190124@kayaposoft.com
DTSTART;VALUE=DATE:20190124
DTEND;VALUE=DATE:20190125
SUMMARY:Unirea Principatelor Române/Mica Unire
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190428@kayaposoft.com
DTSTART;VALUE=DATE:20190428
DTEND;VALUE=DATE:20190429
SUMMARY:Paştele
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190429@kayaposoft.com
DTSTART;VALUE=DATE:20190429
DTEND;VALUE=DATE:20190430
SUMMARY:Doua zi de Pasti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Ziua muncii
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190601@kayaposoft.com
DTSTART;VALUE=DATE:20190601
DTEND;VALUE=DATE:20190602
SUMMARY:Ziua Copilului
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190616@kayaposoft.com
DTSTART;VALUE=DATE:20190616
DTEND;VALUE=DATE:20190617
SUMMARY:Rusaliile
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190617@kayaposoft.com
DTSTART;VALUE=DATE:20190617
DTEND;VALUE=DATE:20190618
SUMMARY:Doua zi de Rusaliile
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20190815@kayaposoft.com
DTSTART;VALUE=DATE:20190815
DTEND;VALUE=DATE:20190816
SUMMARY:Adormirea Maicii Domnului/Sfânta Maria Mare
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20191130@kayaposoft.com
DTSTART;VALUE=DATE:20191130
DTEND;VALUE=DATE:20191201
SUMMARY:Sfântul Andrei
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20191201@kayaposoft.com
DTSTART;VALUE=DATE:20191201
DTEND;VALUE=DATE:20191202
SUMMARY:Ziua Națională/Marea Unire
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Crăciunul
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:Crăciunul
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Anul nou
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200102@kayaposoft.com
DTSTART;VALUE=DATE:20200102
DTEND;VALUE=DATE:20200103
SUMMARY:Anul nou
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200124@kayaposoft.com
DTSTART;VALUE=DATE:20200124
DTEND;VALUE=DATE:20200125
SUMMARY:Unirea Principatelor Române/Mica Unire
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200419@kayaposoft.com
DTSTART;VALUE=DATE:20200419
DTEND;VALUE=DATE:20200420
SUMMARY:Paştele
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200420@kayaposoft.com
DTSTART;VALUE=DATE:20200420
DTEND;VALUE=DATE:20200421
SUMMARY:Doua zi de Pasti
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Ziua muncii
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200601@kayaposoft.com
DTSTART;VALUE=DATE:20200601
DTEND;VALUE=DATE:20200602
SUMMARY:Ziua Copilului
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200607@kayaposoft.com
DTSTART;VALUE=DATE:20200607
DTEND;VALUE=DATE:20200608
SUMMARY:Rusaliile
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200608@kayaposoft.com
DTSTART;VALUE=DATE:20200608
DTEND;VALUE=DATE:20200609
SUMMARY:Doua zi de Rusaliile
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20200815@kayaposoft.com
DTSTART;VALUE=DATE:20200815
DTEND;VALUE=DATE:20200816
SUMMARY:Adormirea Maicii Domnului/Sfânta Maria Mare
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20201130@kayaposoft.com
DTSTART;VALUE=DATE:20201130
DTEND;VALUE=DATE:20201201
SUMMARY:Sfântul Andrei
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20201201@kayaposoft.com
DTSTART;VALUE=DATE:20201201
DTEND;VALUE=DATE:20201202
SUMMARY:Ziua Națională/Marea Unire
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Crăciunul
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-rou-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:Crăciunul
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,247 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-srb-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180102@kayaposoft.com
DTSTART;VALUE=DATE:20180102
DTEND;VALUE=DATE:20180103
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180107@kayaposoft.com
DTSTART;VALUE=DATE:20180107
DTEND;VALUE=DATE:20180108
SUMMARY:Božić
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180215@kayaposoft.com
DTSTART;VALUE=DATE:20180215
DTEND;VALUE=DATE:20180216
SUMMARY:Dan državnosti Srbije
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180216@kayaposoft.com
DTSTART;VALUE=DATE:20180216
DTEND;VALUE=DATE:20180217
SUMMARY:Dan državnosti Srbije
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180406@kayaposoft.com
DTSTART;VALUE=DATE:20180406
DTEND;VALUE=DATE:20180407
SUMMARY:Veliki petak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180408@kayaposoft.com
DTSTART;VALUE=DATE:20180408
DTEND;VALUE=DATE:20180409
SUMMARY:Vaskrs
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180409@kayaposoft.com
DTSTART;VALUE=DATE:20180409
DTEND;VALUE=DATE:20180410
SUMMARY:Vaskrsni ponedeljak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20180502@kayaposoft.com
DTSTART;VALUE=DATE:20180502
DTEND;VALUE=DATE:20180503
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20181111@kayaposoft.com
DTSTART;VALUE=DATE:20181111
DTEND;VALUE=DATE:20181112
SUMMARY:Dan primirja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20181112@kayaposoft.com
DTSTART;VALUE=DATE:20181112
DTEND;VALUE=DATE:20181113
SUMMARY:Dan primirja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190102@kayaposoft.com
DTSTART;VALUE=DATE:20190102
DTEND;VALUE=DATE:20190103
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190107@kayaposoft.com
DTSTART;VALUE=DATE:20190107
DTEND;VALUE=DATE:20190108
SUMMARY:Božić
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190215@kayaposoft.com
DTSTART;VALUE=DATE:20190215
DTEND;VALUE=DATE:20190216
SUMMARY:Dan državnosti Srbije
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190216@kayaposoft.com
DTSTART;VALUE=DATE:20190216
DTEND;VALUE=DATE:20190217
SUMMARY:Dan državnosti Srbije
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190426@kayaposoft.com
DTSTART;VALUE=DATE:20190426
DTEND;VALUE=DATE:20190427
SUMMARY:Veliki petak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190428@kayaposoft.com
DTSTART;VALUE=DATE:20190428
DTEND;VALUE=DATE:20190429
SUMMARY:Vaskrs
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190429@kayaposoft.com
DTSTART;VALUE=DATE:20190429
DTEND;VALUE=DATE:20190430
SUMMARY:Vaskrsni ponedeljak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20190502@kayaposoft.com
DTSTART;VALUE=DATE:20190502
DTEND;VALUE=DATE:20190503
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20191111@kayaposoft.com
DTSTART;VALUE=DATE:20191111
DTEND;VALUE=DATE:20191112
SUMMARY:Dan primirja
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200102@kayaposoft.com
DTSTART;VALUE=DATE:20200102
DTEND;VALUE=DATE:20200103
SUMMARY:Nova Godina
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200107@kayaposoft.com
DTSTART;VALUE=DATE:20200107
DTEND;VALUE=DATE:20200108
SUMMARY:Božić
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200215@kayaposoft.com
DTSTART;VALUE=DATE:20200215
DTEND;VALUE=DATE:20200216
SUMMARY:Dan državnosti Srbije
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200216@kayaposoft.com
DTSTART;VALUE=DATE:20200216
DTEND;VALUE=DATE:20200217
SUMMARY:Dan državnosti Srbije
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200217@kayaposoft.com
DTSTART;VALUE=DATE:20200217
DTEND;VALUE=DATE:20200218
SUMMARY:Dan državnosti Srbije
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200417@kayaposoft.com
DTSTART;VALUE=DATE:20200417
DTEND;VALUE=DATE:20200418
SUMMARY:Veliki petak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200419@kayaposoft.com
DTSTART;VALUE=DATE:20200419
DTEND;VALUE=DATE:20200420
SUMMARY:Vaskrs
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200420@kayaposoft.com
DTSTART;VALUE=DATE:20200420
DTEND;VALUE=DATE:20200421
SUMMARY:Vaskrsni ponedeljak
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20200502@kayaposoft.com
DTSTART;VALUE=DATE:20200502
DTEND;VALUE=DATE:20200503
SUMMARY:Praznik rada
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-srb-20201111@kayaposoft.com
DTSTART;VALUE=DATE:20201111
DTEND;VALUE=DATE:20201112
SUMMARY:Dan primirja
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

125
app/src/main/assets/singapore.ics Executable file
View file

@ -0,0 +1,125 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
UID:20181225-christmas-day@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Christmas Day
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181106
DTEND;VALUE=DATE:20181107
UID:20181106-deepavali@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Deepavali
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191027
DTEND;VALUE=DATE:20191028
UID:20191027-deepavali@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Deepavali
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180822
DTEND;VALUE=DATE:20180823
UID:20180822-hari-raya-haji@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Hari Raya Haji
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190811
DTEND;VALUE=DATE:20190812
UID:20190811-hari-raya-haji@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Hari Raya Haji
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180809
DTEND;VALUE=DATE:20180810
UID:20180809-national-day@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:National Day
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180615
DTEND;VALUE=DATE:20180616
UID:20180615-hari-raya-puasa@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Hari Raya Puasa
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190605
DTEND;VALUE=DATE:20190606
UID:20190605-hari-raya-puasa@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Hari Raya Puasa
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180529
DTEND;VALUE=DATE:20180530
UID:20180529-vesak-day@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Vesak Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190519
DTEND;VALUE=DATE:20190520
UID:20190519-vesak-day@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Vesak Day
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
UID:20180501-labour-day@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Labour Day
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
UID:20180330-good-friday@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Good Friday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
UID:20190419-good-friday@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Good Friday
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180217
DTEND;VALUE=DATE:20180218
UID:20180217-chinese-new-year@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Chinese New Year
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180216
DTEND;VALUE=DATE:20180217
UID:20180216-chinese-new-year@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Chinese New Year
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
UID:20180101-new-years-day@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:New Year's Day
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190205
DTEND;VALUE=DATE:20190206
UID:20190205-chinese-new-year@www.mom.gov.sg
STATUS:CONFIRMED
SUMMARY:Chinese New Year
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,275 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-zaf-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:New Year's Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180321@kayaposoft.com
DTSTART;VALUE=DATE:20180321
DTEND;VALUE=DATE:20180322
SUMMARY:Human Rights Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180330@kayaposoft.com
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
SUMMARY:Good Friday
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180402@kayaposoft.com
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
SUMMARY:Family Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180427@kayaposoft.com
DTSTART;VALUE=DATE:20180427
DTEND;VALUE=DATE:20180428
SUMMARY:Freedom Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Workers' Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180616@kayaposoft.com
DTSTART;VALUE=DATE:20180616
DTEND;VALUE=DATE:20180617
SUMMARY:Youth Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180809@kayaposoft.com
DTSTART;VALUE=DATE:20180809
DTEND;VALUE=DATE:20180810
SUMMARY:National Women's Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20180924@kayaposoft.com
DTSTART;VALUE=DATE:20180924
DTEND;VALUE=DATE:20180925
SUMMARY:Heritage Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20181216@kayaposoft.com
DTSTART;VALUE=DATE:20181216
DTEND;VALUE=DATE:20181217
SUMMARY:Day of Reconciliation
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20181217@kayaposoft.com
DTSTART;VALUE=DATE:20181217
DTEND;VALUE=DATE:20181218
SUMMARY:Day of Reconciliation
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Christmas Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:Day of Goodwill
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:New Year's Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190321@kayaposoft.com
DTSTART;VALUE=DATE:20190321
DTEND;VALUE=DATE:20190322
SUMMARY:Human Rights Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190419@kayaposoft.com
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:Good Friday
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190422@kayaposoft.com
DTSTART;VALUE=DATE:20190422
DTEND;VALUE=DATE:20190423
SUMMARY:Family Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190427@kayaposoft.com
DTSTART;VALUE=DATE:20190427
DTEND;VALUE=DATE:20190428
SUMMARY:Freedom Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Workers' Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190616@kayaposoft.com
DTSTART;VALUE=DATE:20190616
DTEND;VALUE=DATE:20190617
SUMMARY:Youth Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190617@kayaposoft.com
DTSTART;VALUE=DATE:20190617
DTEND;VALUE=DATE:20190618
SUMMARY:Youth Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190809@kayaposoft.com
DTSTART;VALUE=DATE:20190809
DTEND;VALUE=DATE:20190810
SUMMARY:National Women's Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20190924@kayaposoft.com
DTSTART;VALUE=DATE:20190924
DTEND;VALUE=DATE:20190925
SUMMARY:Heritage Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20191216@kayaposoft.com
DTSTART;VALUE=DATE:20191216
DTEND;VALUE=DATE:20191217
SUMMARY:Day of Reconciliation
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Christmas Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:Day of Goodwill
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:New Year's Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200321@kayaposoft.com
DTSTART;VALUE=DATE:20200321
DTEND;VALUE=DATE:20200322
SUMMARY:Human Rights Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200410@kayaposoft.com
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
SUMMARY:Good Friday
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200413@kayaposoft.com
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:Family Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200427@kayaposoft.com
DTSTART;VALUE=DATE:20200427
DTEND;VALUE=DATE:20200428
SUMMARY:Freedom Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Workers' Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200616@kayaposoft.com
DTSTART;VALUE=DATE:20200616
DTEND;VALUE=DATE:20200617
SUMMARY:Youth Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200809@kayaposoft.com
DTSTART;VALUE=DATE:20200809
DTEND;VALUE=DATE:20200810
SUMMARY:National Women's Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200810@kayaposoft.com
DTSTART;VALUE=DATE:20200810
DTEND;VALUE=DATE:20200811
SUMMARY:National Women's Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20200924@kayaposoft.com
DTSTART;VALUE=DATE:20200924
DTEND;VALUE=DATE:20200925
SUMMARY:Heritage Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20201216@kayaposoft.com
DTSTART;VALUE=DATE:20201216
DTEND;VALUE=DATE:20201217
SUMMARY:Day of Reconciliation
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Christmas Day
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-zaf-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:Day of Goodwill
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -23,8 +23,8 @@ END:VEVENT
BEGIN:VEVENT
SUMMARY:설날 Lunar New Year's Day
UID:3d064a26-70f2-431a-985a-ffd27be9e210
DTSTART;VALUE=DATE:20190205
DTEND;VALUE=DATE:20190206
DTSTART;VALUE=DATE:20190204
DTEND;VALUE=DATE:20190207
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
@ -44,8 +44,15 @@ END:VEVENT
BEGIN:VEVENT
SUMMARY:추석(한가위) Harvest Festival
UID:14bd697c-a319-47fd-9abc-fdff74be58e5
DTSTART;VALUE=DATE:20201001
DTEND;VALUE=DATE:20201002
DTSTART;VALUE=DATE:20200930
DTEND;VALUE=DATE:20201003
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:추석(한가위) Harvest Festival
UID:14bd697c-a319-47fd-9abc-fdffse58aa
DTSTART;VALUE=DATE:20210920
DTEND;VALUE=DATE:20210923
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
@ -65,14 +72,6 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:식목일 Arbor Day
UID:5ae39a0f-5ef9-44d9-9dd5-e90049578e07
DTSTART;VALUE=DATE:20000405
DTEND;VALUE=DATE:20000406
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:어린이 날 Children's Day
UID:5a0c39c0-da3b-407d-824b-890c6b82bd95
DTSTART;VALUE=DATE:20000505
@ -81,22 +80,6 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:어버이 날 Paren't Day
UID:741d7127-995f-43e0-a014-04280dcbb661
DTSTART;VALUE=DATE:20000510
DTEND;VALUE=DATE:20000511
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:스승의 날 Teacher's Day
UID:5309e45c-acca-4b4f-b7c4-fe7b3ddd545f
DTSTART;VALUE=DATE:20000515
DTEND;VALUE=DATE:20000516
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:현충일 Memorial Day
UID:c67d164c-c91c-4b46-a0fa-bff756119cde
DTSTART;VALUE=DATE:20000606
@ -105,22 +88,6 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:6-25 사변일 6/25 War Memorial
UID:c5907e9d-4314-423f-9441-d7309d39db45
DTSTART;VALUE=DATE:20000625
DTEND;VALUE=DATE:20000626
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:제헌절 Constitution Day
UID:4f97c701-816b-4c23-a71e-13d2d2419c8f
DTSTART;VALUE=DATE:20000717
DTEND;VALUE=DATE:20000718
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:광복절 Liberation Day
UID:1aba5d05-a8a7-4253-a6d2-66665bd2490d
DTSTART;VALUE=DATE:20000815
@ -129,14 +96,6 @@ STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:국군의 날 Armed Forces Day
UID:99c12465-6366-4c9e-99c8-8635969cc7ee
DTSTART;VALUE=DATE:20001001
DTEND;VALUE=DATE:20001002
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:개천절 Foundation Day
UID:220f5ee6-10a6-4227-87ca-197628adb976
DTSTART;VALUE=DATE:20001003

385
app/src/main/assets/sweden.ics Executable file → Normal file
View file

@ -1,380 +1,275 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
SUMMARY:Kristi himmelfärdsdag
UID:uuid1211149223742
DTSTART;VALUE=DATE:20170525
DTEND;VALUE=DATE:20170526
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pingstafton
UID:uuid1211149223743
DTSTART;VALUE=DATE:20170603
DTEND;VALUE=DATE:20170604
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pingstdagen
UID:uuid1211149223744
DTSTART;VALUE=DATE:20170604
DTEND;VALUE=DATE:20170605
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nationaldagen
UID:uuid1211149223745
DTSTART;VALUE=DATE:20170606
DTEND;VALUE=DATE:20170607
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Midsommarafton
UID:a076d1a7-69bb-4af5-9a60-89a3c533e6bf
DTSTART;VALUE=DATE:20170623
DTEND;VALUE=DATE:20170624
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Midsommardagen
UID:uuid1211149223746
DTSTART;VALUE=DATE:20170624
DTEND;VALUE=DATE:20170625
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Övergång till vintertid
UID:uuid1211149223747
DTSTART;VALUE=DATE:20171029
DTEND;VALUE=DATE:20171030
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Alla helgons dag
UID:uuid1211149223748
DTSTART;VALUE=DATE:20171104
DTEND;VALUE=DATE:20171105
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Julafton
UID:uuid1211149223749
DTSTART;VALUE=DATE:20171224
DTEND;VALUE=DATE:20171225
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Juldagen
UID:uuid1211149223750
DTSTART;VALUE=DATE:20171225
DTEND;VALUE=DATE:20171226
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Annandag jul
UID:uuid1211149223751
DTSTART;VALUE=DATE:20171226
DTEND;VALUE=DATE:20171227
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nyårsafton
UID:uuid1211149223752
DTSTART;VALUE=DATE:20171231
DTEND;VALUE=DATE:20180101
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nyårsdagen
UID:uuid1211149223753
UID:enrico-swe-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Nyårsdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trettondagsafton
UID:uuid1211149223754
DTSTART;VALUE=DATE:20180105
DTEND;VALUE=DATE:20180106
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trettondag jul
UID:uuid1211149223755
UID:enrico-swe-20180106@kayaposoft.com
DTSTART;VALUE=DATE:20180106
DTEND;VALUE=DATE:20180107
SUMMARY:Trettondagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Skärtorsdag
UID:uuid1211149223757
DTSTART;VALUE=DATE:20180329
DTEND;VALUE=DATE:20180330
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Långfredag
UID:uuid1211149223758
UID:enrico-swe-20180330@kayaposoft.com
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
SUMMARY:Långfredagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Påskdagen
UID:uuid1211149223759
UID:enrico-swe-20180401@kayaposoft.com
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
SUMMARY:Påskdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Annandag påsk
UID:uuid1211149223760
UID:enrico-swe-20180402@kayaposoft.com
DTSTART;VALUE=DATE:20180402
DTEND;VALUE=DATE:20180403
SUMMARY:Annandag påsk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Valborgsmässoafton
UID:uuid1211149223761
DTSTART;VALUE=DATE:20180430
DTEND;VALUE=DATE:20180501
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Första maj
UID:uuid1211149223762
UID:enrico-swe-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:Första maj
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Kristi himmelfärdsdag
UID:uuid1211149223763
UID:enrico-swe-20180510@kayaposoft.com
DTSTART;VALUE=DATE:20180510
DTEND;VALUE=DATE:20180511
SUMMARY:Kristi himmelfärds dag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pingstafton
UID:uuid1211149223764
DTSTART;VALUE=DATE:20180519
DTEND;VALUE=DATE:20180520
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pingstdagen
UID:uuid1211149223765
UID:enrico-swe-20180520@kayaposoft.com
DTSTART;VALUE=DATE:20180520
DTEND;VALUE=DATE:20180521
SUMMARY:Pingstdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nationaldagen
UID:uuid1211149223766
UID:enrico-swe-20180606@kayaposoft.com
DTSTART;VALUE=DATE:20180606
DTEND;VALUE=DATE:20180607
SUMMARY:Sveriges nationaldag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Midsommarafton
UID:ed74665e-e6b5-4dc8-8788-48eaab5640eb
DTSTART;VALUE=DATE:20180622
DTEND;VALUE=DATE:20180623
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Midsommardagen
UID:uuid1211149223767
UID:enrico-swe-20180623@kayaposoft.com
DTSTART;VALUE=DATE:20180623
DTEND;VALUE=DATE:20180624
SUMMARY:Midsommardagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Övergång till vintertid
UID:uuid1211149223768
DTSTART;VALUE=DATE:20181028
DTEND;VALUE=DATE:20181029
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Alla helgons dag
UID:uuid1211149223769
UID:enrico-swe-20181103@kayaposoft.com
DTSTART;VALUE=DATE:20181103
DTEND;VALUE=DATE:20181104
SUMMARY:Alla helgons dag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Julafton
UID:uuid1211149223770
DTSTART;VALUE=DATE:20181224
DTEND;VALUE=DATE:20181225
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Juldagen
UID:uuid1211149223771
UID:enrico-swe-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Juldagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Annandag jul
UID:uuid1211149223772
UID:enrico-swe-20181226@kayaposoft.com
DTSTART;VALUE=DATE:20181226
DTEND;VALUE=DATE:20181227
SUMMARY:Annandag jul
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nyårsafton
UID:uuid1211149223773
DTSTART;VALUE=DATE:20181231
DTEND;VALUE=DATE:20190101
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nyårsdagen
UID:uuid1211149223774
UID:enrico-swe-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Nyårsdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trettondagsafton
UID:uuid1211149223775
DTSTART;VALUE=DATE:20190105
DTEND;VALUE=DATE:20190106
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trettondag jul
UID:uuid1211149223776
UID:enrico-swe-20190106@kayaposoft.com
DTSTART;VALUE=DATE:20190106
DTEND;VALUE=DATE:20190107
SUMMARY:Trettondagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Skärtorsdag
UID:uuid1211149223778
DTSTART;VALUE=DATE:20190418
DTEND;VALUE=DATE:20190419
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Långfredag
UID:uuid1211149223779
UID:enrico-swe-20190419@kayaposoft.com
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:Långfredagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Påskdagen
UID:uuid1211149223780
UID:enrico-swe-20190421@kayaposoft.com
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
SUMMARY:Påskdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Annandag påsk
UID:uuid1211149223781
UID:enrico-swe-20190422@kayaposoft.com
DTSTART;VALUE=DATE:20190422
DTEND;VALUE=DATE:20190423
SUMMARY:Annandag påsk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Valborgsmässoafton
UID:uuid1211149223782
DTSTART;VALUE=DATE:20190430
DTEND;VALUE=DATE:20190501
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Första maj
UID:uuid1211149223783
UID:enrico-swe-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:Första maj
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Kristi himmelfärdsdag
UID:uuid1211149223784
UID:enrico-swe-20190530@kayaposoft.com
DTSTART;VALUE=DATE:20190530
DTEND;VALUE=DATE:20190531
SUMMARY:Kristi himmelfärds dag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nationaldagen
UID:uuid1211149223785
UID:enrico-swe-20190606@kayaposoft.com
DTSTART;VALUE=DATE:20190606
DTEND;VALUE=DATE:20190607
SUMMARY:Sveriges nationaldag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pingstafton
UID:uuid1211149223786
DTSTART;VALUE=DATE:20190608
DTEND;VALUE=DATE:20190609
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pingstdagen
UID:uuid1211149223787
UID:enrico-swe-20190609@kayaposoft.com
DTSTART;VALUE=DATE:20190609
DTEND;VALUE=DATE:20190610
SUMMARY:Pingstdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Midsommarafton
UID:eeea5d95-9cd0-46ff-84a9-e6c575b3fca1
DTSTART;VALUE=DATE:20190621
DTEND;VALUE=DATE:20190622
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Midsommardagen
UID:uuid1211149223788
UID:enrico-swe-20190622@kayaposoft.com
DTSTART;VALUE=DATE:20190622
DTEND;VALUE=DATE:20190623
SUMMARY:Midsommardagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Övergång till vintertid
UID:uuid1211149223789
DTSTART;VALUE=DATE:20191027
DTEND;VALUE=DATE:20191028
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Alla helgons dag
UID:uuid1211149223790
UID:enrico-swe-20191102@kayaposoft.com
DTSTART;VALUE=DATE:20191102
DTEND;VALUE=DATE:20191103
SUMMARY:Alla helgons dag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Julafton
UID:uuid1211149223791
DTSTART;VALUE=DATE:20191224
DTEND;VALUE=DATE:20191225
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Juldagen
UID:uuid1211149223792
UID:enrico-swe-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Juldagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Annandag jul
UID:uuid1211149223793
UID:enrico-swe-20191226@kayaposoft.com
DTSTART;VALUE=DATE:20191226
DTEND;VALUE=DATE:20191227
SUMMARY:Annandag jul
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Nyårsafton
UID:uuid1211149223794
DTSTART;VALUE=DATE:20191231
DTEND;VALUE=DATE:20200101
UID:enrico-swe-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Nyårsdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200106@kayaposoft.com
DTSTART;VALUE=DATE:20200106
DTEND;VALUE=DATE:20200107
SUMMARY:Trettondagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200410@kayaposoft.com
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
SUMMARY:Långfredagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200412@kayaposoft.com
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
SUMMARY:Påskdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200413@kayaposoft.com
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:Annandag påsk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:Första maj
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200521@kayaposoft.com
DTSTART;VALUE=DATE:20200521
DTEND;VALUE=DATE:20200522
SUMMARY:Kristi himmelfärds dag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200531@kayaposoft.com
DTSTART;VALUE=DATE:20200531
DTEND;VALUE=DATE:20200601
SUMMARY:Pingstdagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200606@kayaposoft.com
DTSTART;VALUE=DATE:20200606
DTEND;VALUE=DATE:20200607
SUMMARY:Sveriges nationaldag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20200620@kayaposoft.com
DTSTART;VALUE=DATE:20200620
DTEND;VALUE=DATE:20200621
SUMMARY:Midsommardagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20201031@kayaposoft.com
DTSTART;VALUE=DATE:20201031
DTEND;VALUE=DATE:20201101
SUMMARY:Alla helgons dag
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Juldagen
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-swe-20201226@kayaposoft.com
DTSTART;VALUE=DATE:20201226
DTEND;VALUE=DATE:20201227
SUMMARY:Annandag jul
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,668 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200329
DTEND;VALUE=DATE:20200330
DTSTAMP:20190328T061054Z
UID:20200329_60o30or4cgo30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:青年節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190329
DTEND;VALUE=DATE:20190330
DTSTAMP:20190328T061054Z
UID:20190329_60o30or4cgo30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:青年節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180329
DTEND;VALUE=DATE:20180330
DTSTAMP:20190328T061054Z
UID:20180329_60o30or4cgo30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:青年節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20201025
DTEND;VALUE=DATE:20201026
DTSTAMP:20190328T061054Z
UID:20201025_60o30dppc8o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:重陽節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191007
DTEND;VALUE=DATE:20191008
DTSTAMP:20190328T061054Z
UID:20191007_60o30dppc8o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:重陽節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181017
DTEND;VALUE=DATE:20181018
DTSTAMP:20190328T061054Z
UID:20181017_60o30dppc8o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:重陽節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200204
DTEND;VALUE=DATE:20200205
DTSTAMP:20190328T061054Z
UID:20200204_60o30dppcoo30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農民節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190204
DTEND;VALUE=DATE:20190205
DTSTAMP:20190328T061054Z
UID:20190204_60o30dppcoo30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農民節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180204
DTEND;VALUE=DATE:20180205
DTSTAMP:20190328T061054Z
UID:20180204_60o30dppcoo30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農民節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200124
DTEND;VALUE=DATE:20200125
DTSTAMP:20190328T061054Z
UID:20200124_60o30dpo70o30e1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆除夕
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190204
DTEND;VALUE=DATE:20190205
DTSTAMP:20190328T061054Z
UID:20190204_60o30dpo70o30e1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆除夕
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180215
DTEND;VALUE=DATE:20180216
DTSTAMP:20190328T061054Z
UID:20180215_60o30dpo70o30e1g60o32chmc4@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆除夕
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200128
DTEND;VALUE=DATE:20200129
DTSTAMP:20190328T061054Z
UID:20200128_60o30dpocco30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初四
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190208
DTEND;VALUE=DATE:20190209
DTSTAMP:20190328T061054Z
UID:20190208_60o30dpocco30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初四
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180219
DTEND;VALUE=DATE:20180220
DTSTAMP:20190328T061054Z
UID:20180219_60o30dpocco30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初四
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200129
DTEND;VALUE=DATE:20200130
DTSTAMP:20190328T061054Z
UID:20200129_60o30ob368o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初五
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190209
DTEND;VALUE=DATE:20190210
DTSTAMP:20190328T061054Z
UID:20190209_60o30ob368o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初五
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180220
DTEND;VALUE=DATE:20180221
DTSTAMP:20190328T061054Z
UID:20180220_60o30ob368o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初五
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200126
DTEND;VALUE=DATE:20200127
DTSTAMP:20190328T061054Z
UID:20200126_60o30dpoc4o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初二
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190206
DTEND;VALUE=DATE:20190207
DTSTAMP:20190328T061054Z
UID:20190206_60o30dpoc4o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初二
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180217
DTEND;VALUE=DATE:20180218
DTSTAMP:20190328T061054Z
UID:20180217_60o30dpoc4o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初二
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200127
DTEND;VALUE=DATE:20200128
DTSTAMP:20190328T061054Z
UID:20200127_60o30dpoc8o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初三
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190207
DTEND;VALUE=DATE:20190208
DTSTAMP:20190328T061054Z
UID:20190207_60o30dpoc8o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初三
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180218
DTEND;VALUE=DATE:20180219
DTSTAMP:20190328T061054Z
UID:20180218_60o30dpoc8o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:農曆初三
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200903
DTEND;VALUE=DATE:20200904
DTSTAMP:20190328T061054Z
UID:20200903_60o30dpp64o32c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:軍人節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190903
DTEND;VALUE=DATE:20190904
DTSTAMP:20190328T061054Z
UID:20190903_60o30dpp64o32c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:軍人節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180903
DTEND;VALUE=DATE:20180904
DTSTAMP:20190328T061054Z
UID:20180903_60o30dpp64o32c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:軍人節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
DTSTAMP:20190328T061054Z
UID:20201225_60o30dppcco30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:行憲紀念日
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
DTSTAMP:20190328T061054Z
UID:20191225_60o30dppcco30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:行憲紀念日
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
DTSTAMP:20190328T061054Z
UID:20181225_60o30dppcco30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:行憲紀念日
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200625
DTEND;VALUE=DATE:20200626
DTSTAMP:20190328T061054Z
UID:20200625_60o30dpp60o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:端午節彈性放假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190607
DTEND;VALUE=DATE:20190608
DTSTAMP:20190328T061054Z
UID:20190607_60o30dpp60o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:端午節彈性放假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180618
DTEND;VALUE=DATE:20180619
DTSTAMP:20190328T061054Z
UID:20180618_60o30dpp60o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:端午節彈性放假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200404
DTEND;VALUE=DATE:20200405
DTSTAMP:20190328T061054Z
UID:20200404_60o30dpocko30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:清明節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190405
DTEND;VALUE=DATE:20190406
DTSTAMP:20190328T061054Z
UID:20190405_60o30dpocko30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:清明節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180405
DTEND;VALUE=DATE:20180406
DTSTAMP:20190328T061054Z
UID:20180405_60o30dpocko30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:清明節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200125
DTEND;VALUE=DATE:20200126
DTSTAMP:20190328T061054Z
UID:20200125_60o30dpo74o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:春節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190205
DTEND;VALUE=DATE:20190206
DTSTAMP:20190328T061054Z
UID:20190205_60o30dpo74o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:春節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180216
DTEND;VALUE=DATE:20180217
DTSTAMP:20190328T061054Z
UID:20180216_60o30dpo74o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:春節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200928
DTEND;VALUE=DATE:20200929
DTSTAMP:20190328T061054Z
UID:20200928_60o30dppc4o30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:教師節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190928
DTEND;VALUE=DATE:20190929
DTSTAMP:20190328T061054Z
UID:20190928_60o30dppc4o30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:教師節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180928
DTEND;VALUE=DATE:20180929
DTSTAMP:20190328T061054Z
UID:20180928_60o30dppc4o30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:教師節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200308
DTEND;VALUE=DATE:20200309
DTSTAMP:20190328T061054Z
UID:20200308_60o30dpp6oo30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:婦女節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190308
DTEND;VALUE=DATE:20190309
DTSTAMP:20190328T061054Z
UID:20190308_60o30dpp6oo30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:婦女節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180308
DTEND;VALUE=DATE:20180309
DTSTAMP:20190328T061054Z
UID:20180308_60o30dpp6oo30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:婦女節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20201009
DTEND;VALUE=DATE:20201010
DTSTAMP:20190328T061054Z
UID:20201009_60o30dpp6co30e1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:國慶日/雙十節彈性放假 補假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20201010
DTEND;VALUE=DATE:20201011
DTSTAMP:20190328T061054Z
UID:20201010_60o30dpp6co30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:國慶日/雙十節彈性放假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191010
DTEND;VALUE=DATE:20191011
DTSTAMP:20190328T061054Z
UID:20191010_60o30dpp6co30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:國慶日/雙十節彈性放假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181010
DTEND;VALUE=DATE:20181011
DTSTAMP:20190328T061054Z
UID:20181010_60o30dpp6co30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:國慶日/雙十節彈性放假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20201025
DTEND;VALUE=DATE:20201026
DTSTAMP:20190328T061054Z
UID:20201025_60o30dpp74o30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:台灣光復節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20191025
DTEND;VALUE=DATE:20191026
DTSTAMP:20190328T061054Z
UID:20191025_60o30dpp74o30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:台灣光復節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20181025
DTEND;VALUE=DATE:20181026
DTSTAMP:20190328T061054Z
UID:20181025_60o30dpp74o30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:台灣光復節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
DTSTAMP:20190328T061054Z
UID:20200501_60o30dpocoo30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:勞動節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
DTSTAMP:20190328T061054Z
UID:20190501_60o30dpocoo30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:勞動節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
DTSTAMP:20190328T061054Z
UID:20180501_60o30dpocoo30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:勞動節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200403
DTEND;VALUE=DATE:20200404
DTSTAMP:20190328T061054Z
UID:20200403_60o30dpp70o34e1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:兒童節 補假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200404
DTEND;VALUE=DATE:20200405
DTSTAMP:20190328T061054Z
UID:20200404_60o30dpp70o34c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:兒童節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190404
DTEND;VALUE=DATE:20190405
DTSTAMP:20190328T061054Z
UID:20190404_60o30dpp70o34c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:兒童節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180404
DTEND;VALUE=DATE:20180405
DTSTAMP:20190328T061054Z
UID:20180404_60o30dpp70o34c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:兒童節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200208
DTEND;VALUE=DATE:20200209
DTSTAMP:20190328T061054Z
UID:20200208_60o30dpp6go30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:元宵節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190219
DTEND;VALUE=DATE:20190220
DTSTAMP:20190328T061054Z
UID:20190219_60o30dpp6go30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:元宵節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180302
DTEND;VALUE=DATE:20180303
DTSTAMP:20190328T061054Z
UID:20180302_60o30dpp6go30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:元宵節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
DTSTAMP:20190328T061054Z
UID:20200101_60o30dpo6oo30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中華民國開國紀念日/元旦
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
DTSTAMP:20190328T061054Z
UID:20190101_60o30dpo6oo30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中華民國開國紀念日/元旦
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
DTSTAMP:20190328T061054Z
UID:20180101_60o30dpo6oo30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中華民國開國紀念日/元旦
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20201001
DTEND;VALUE=DATE:20201002
DTSTAMP:20190328T061054Z
UID:20201001_60o30dpp68o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中秋節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190913
DTEND;VALUE=DATE:20190914
DTSTAMP:20190328T061054Z
UID:20190913_60o30dpp68o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中秋節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180924
DTEND;VALUE=DATE:20180925
DTSTAMP:20190328T061054Z
UID:20180924_60o30dpp68o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中秋節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200902
DTEND;VALUE=DATE:20200903
DTSTAMP:20190328T061054Z
UID:20200902_60o30dr160o30c1g60o32chmcg@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中元節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190815
DTEND;VALUE=DATE:20190816
DTSTAMP:20190328T061054Z
UID:20190815_60o30dr160o30c1g60o32chmcc@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中元節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180825
DTEND;VALUE=DATE:20180826
DTSTAMP:20190328T061054Z
UID:20180825_60o30dr160o30c1g60o32chmc8@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:中元節
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200228
DTEND;VALUE=DATE:20200229
DTSTAMP:20190328T061054Z
UID:20200228_60o30dpocgo30c1g60o30dr56g@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:228連假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190228
DTEND;VALUE=DATE:20190301
DTSTAMP:20190328T061054Z
UID:20190228_60o30dpocgo30c1g60o30dr56c@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:228連假
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20180228
DTEND;VALUE=DATE:20180301
DTSTAMP:20190328T061054Z
UID:20180228_60o30dpocgo30c1g60o30dr568@google.com
CREATED:20190221T131351Z
STATUS:CONFIRMED
SUMMARY:228連假
END:VEVENT
END:VCALENDAR

View file

@ -0,0 +1,316 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:enrico-ukr-20180101@kayaposoft.com
DTSTART;VALUE=DATE:20180101
DTEND;VALUE=DATE:20180102
SUMMARY:Новий Рік
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180108@kayaposoft.com
DTSTART;VALUE=DATE:20180108
DTEND;VALUE=DATE:20180109
SUMMARY:Різдво
DESCRIPTION:Holiday in lieu of 7 Jan 2018
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180308@kayaposoft.com
DTSTART;VALUE=DATE:20180308
DTEND;VALUE=DATE:20180309
SUMMARY:Міжнародний жіночий день
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180309@kayaposoft.com
DTSTART;VALUE=DATE:20180309
DTEND;VALUE=DATE:20180310
SUMMARY:Свято
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180408@kayaposoft.com
DTSTART;VALUE=DATE:20180408
DTEND;VALUE=DATE:20180409
SUMMARY:Пасха
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180409@kayaposoft.com
DTSTART;VALUE=DATE:20180409
DTEND;VALUE=DATE:20180410
SUMMARY:Пасха
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180430@kayaposoft.com
DTSTART;VALUE=DATE:20180430
DTEND;VALUE=DATE:20180501
SUMMARY:Свято
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180501@kayaposoft.com
DTSTART;VALUE=DATE:20180501
DTEND;VALUE=DATE:20180502
SUMMARY:День праці (День міжнародної солідарності трудящих)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180509@kayaposoft.com
DTSTART;VALUE=DATE:20180509
DTEND;VALUE=DATE:20180510
SUMMARY:День перемоги над нацизмом у Другій світовій війні
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180527@kayaposoft.com
DTSTART;VALUE=DATE:20180527
DTEND;VALUE=DATE:20180528
SUMMARY:Трійця
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180528@kayaposoft.com
DTSTART;VALUE=DATE:20180528
DTEND;VALUE=DATE:20180529
SUMMARY:Трійця
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180628@kayaposoft.com
DTSTART;VALUE=DATE:20180628
DTEND;VALUE=DATE:20180629
SUMMARY:День Конституції
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180629@kayaposoft.com
DTSTART;VALUE=DATE:20180629
DTEND;VALUE=DATE:20180630
SUMMARY:Свято
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20180824@kayaposoft.com
DTSTART;VALUE=DATE:20180824
DTEND;VALUE=DATE:20180825
SUMMARY:День Незалежності
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20181015@kayaposoft.com
DTSTART;VALUE=DATE:20181015
DTEND;VALUE=DATE:20181016
SUMMARY:День захисника України
DESCRIPTION:Holiday in lieu of 14 Oct 2018
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20181224@kayaposoft.com
DTSTART;VALUE=DATE:20181224
DTEND;VALUE=DATE:20181225
SUMMARY:Свято
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20181225@kayaposoft.com
DTSTART;VALUE=DATE:20181225
DTEND;VALUE=DATE:20181226
SUMMARY:Різдво
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20181231@kayaposoft.com
DTSTART;VALUE=DATE:20181231
DTEND;VALUE=DATE:20190101
SUMMARY:Свято
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190101@kayaposoft.com
DTSTART;VALUE=DATE:20190101
DTEND;VALUE=DATE:20190102
SUMMARY:Новий Рік
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190107@kayaposoft.com
DTSTART;VALUE=DATE:20190107
DTEND;VALUE=DATE:20190108
SUMMARY:Різдво
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190308@kayaposoft.com
DTSTART;VALUE=DATE:20190308
DTEND;VALUE=DATE:20190309
SUMMARY:Міжнародний жіночий день
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190428@kayaposoft.com
DTSTART;VALUE=DATE:20190428
DTEND;VALUE=DATE:20190429
SUMMARY:Пасха
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190429@kayaposoft.com
DTSTART;VALUE=DATE:20190429
DTEND;VALUE=DATE:20190430
SUMMARY:Пасха
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190501@kayaposoft.com
DTSTART;VALUE=DATE:20190501
DTEND;VALUE=DATE:20190502
SUMMARY:День праці (День міжнародної солідарності трудящих)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190509@kayaposoft.com
DTSTART;VALUE=DATE:20190509
DTEND;VALUE=DATE:20190510
SUMMARY:День перемоги над нацизмом у Другій світовій війні
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190616@kayaposoft.com
DTSTART;VALUE=DATE:20190616
DTEND;VALUE=DATE:20190617
SUMMARY:Трійця
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190617@kayaposoft.com
DTSTART;VALUE=DATE:20190617
DTEND;VALUE=DATE:20190618
SUMMARY:Трійця
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190628@kayaposoft.com
DTSTART;VALUE=DATE:20190628
DTEND;VALUE=DATE:20190629
SUMMARY:День Конституції
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20190826@kayaposoft.com
DTSTART;VALUE=DATE:20190826
DTEND;VALUE=DATE:20190827
SUMMARY:День Незалежності
DESCRIPTION:Holiday in lieu of 24 Aug 2019
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20191014@kayaposoft.com
DTSTART;VALUE=DATE:20191014
DTEND;VALUE=DATE:20191015
SUMMARY:День захисника України
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20191225@kayaposoft.com
DTSTART;VALUE=DATE:20191225
DTEND;VALUE=DATE:20191226
SUMMARY:Різдво
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200101@kayaposoft.com
DTSTART;VALUE=DATE:20200101
DTEND;VALUE=DATE:20200102
SUMMARY:Новий Рік
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200107@kayaposoft.com
DTSTART;VALUE=DATE:20200107
DTEND;VALUE=DATE:20200108
SUMMARY:Різдво
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200309@kayaposoft.com
DTSTART;VALUE=DATE:20200309
DTEND;VALUE=DATE:20200310
SUMMARY:Міжнародний жіночий день
DESCRIPTION:Holiday in lieu of 8 Mar 2020
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200419@kayaposoft.com
DTSTART;VALUE=DATE:20200419
DTEND;VALUE=DATE:20200420
SUMMARY:Пасха
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200420@kayaposoft.com
DTSTART;VALUE=DATE:20200420
DTEND;VALUE=DATE:20200421
SUMMARY:Пасха
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200501@kayaposoft.com
DTSTART;VALUE=DATE:20200501
DTEND;VALUE=DATE:20200502
SUMMARY:День праці (День міжнародної солідарності трудящих)
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200511@kayaposoft.com
DTSTART;VALUE=DATE:20200511
DTEND;VALUE=DATE:20200512
SUMMARY:День перемоги над нацизмом у Другій світовій війні
DESCRIPTION:Holiday in lieu of 9 May 2020
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200607@kayaposoft.com
DTSTART;VALUE=DATE:20200607
DTEND;VALUE=DATE:20200608
SUMMARY:Трійця
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200608@kayaposoft.com
DTSTART;VALUE=DATE:20200608
DTEND;VALUE=DATE:20200609
SUMMARY:Трійця
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200629@kayaposoft.com
DTSTART;VALUE=DATE:20200629
DTEND;VALUE=DATE:20200630
SUMMARY:День Конституції
DESCRIPTION:Holiday in lieu of 28 Jun 2020
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20200824@kayaposoft.com
DTSTART;VALUE=DATE:20200824
DTEND;VALUE=DATE:20200825
SUMMARY:День Незалежності
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20201014@kayaposoft.com
DTSTART;VALUE=DATE:20201014
DTEND;VALUE=DATE:20201015
SUMMARY:День захисника України
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:enrico-ukr-20201225@kayaposoft.com
DTSTART;VALUE=DATE:20201225
DTEND;VALUE=DATE:20201226
SUMMARY:Різдво
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -2,58 +2,33 @@ BEGIN:VCALENDAR
BEGIN:VEVENT
SUMMARY:New Year's Day
UID:4694f46a-aef0-49a0-a8eb-44ab6531e0d9
DTSTART;VALUE=DATE:20170102
DTEND;VALUE=DATE:20170103
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:St. David's Day
UID:a08053d8-530b-4025-8edf-81c88d05fe84
DTSTART;VALUE=DATE:20100301
DTEND;VALUE=DATE:20100302
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:St. George's Day
UID:b58227e2-7f9d-4571-afa5-0ae93192d10e
DTSTART;VALUE=DATE:20100423
DTEND;VALUE=DATE:20100424
DTSTART;VALUE=DATE:20170101
DTEND;VALUE=DATE:20170102
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Early May Bank Holiday
UID:21626542-636f-43d7-8fa9-bad05bb82dca
DTSTART;VALUE=DATE:20100503
DTEND;VALUE=DATE:20100504
DTSTART;VALUE=DATE:20210503
DTEND;VALUE=DATE:20210504
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=5;BYDAY=1MO
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Early May Bank Holiday
UID:21626542-636f-43d7-8fa9-bad05bbsds
DTSTART;VALUE=DATE:20200508
DTEND;VALUE=DATE:20200509
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Summer Bank Holiday
UID:5dac6a63-e519-4ad1-a687-2fd5fccb4656
DTSTART;VALUE=DATE:20100802
DTEND;VALUE=DATE:20100803
DTSTART;VALUE=DATE:20130826
DTEND;VALUE=DATE:20130827
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=8;BYDAY=-1MO
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Summer Bank Holiday
UID:3d37b115-f0fa-4456-98c9-3b18cfffb47d
DTSTART;VALUE=DATE:20170828
DTEND;VALUE=DATE:20170829
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:BST ends
UID:8eb163f3-6d42-494e-9e7c-747619cf965f
DTSTART:20101031T000000Z
DTEND:20101031T020000Z
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christmas Day
@ -71,4 +46,53 @@ DTEND;VALUE=DATE:20101227
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
DTEND;VALUE=DATE:20190423
DTSTART;VALUE=DATE:20190422
SUMMARY:Easter Monday
UID:ca6af7456b0088abad9a69f9f620f5ac-59@gov.uk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:Good Friday
UID:ca6af7456b0088abad9a69f9f620f5ac-58@gov.uk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
SUMMARY:Good Friday
UID:ca6af7456b0088abad9a69f9f620f5ac-2020-04-10-GoodFriday@gov.uk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20200413
DTEND;VALUE=DATE:20200414
SUMMARY:Easter Monday
UID:ca6af7456b0088abad9a69f9f620f5ac-2020-04-13-EasterMonday@gov.uk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210402
DTEND;VALUE=DATE:20210403
SUMMARY:Good Friday
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210405
DTEND;VALUE=DATE:20210406
SUMMARY:Easter Monday
UID:ca6af7456b0088abad9a69f9f620f5ac-2021-04-05-EasterMonday@gov.uk
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Spring Bank Holiday
UID:5dac6a63-e519-4ad1-a687-2fd5fccb4
DTSTART;VALUE=DATE:20130527
DTEND;VALUE=DATE:20130528
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=5;BYDAY=-1MO
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

View file

@ -1,403 +1,83 @@
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
SUMMARY:Ascension Day
UID:7c8351e3-e3fd-4c0b-a60c-f558aa31df55
DTSTART;VALUE=DATE:20170525
DTEND;VALUE=DATE:20170526
DTSTART;VALUE=DATE:20170101
DTEND;VALUE=DATE:20170102
UID:5a4b1ab2e4a3b@calendarlabs.com
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pentecost
UID:452c678d-0b42-4a89-a347-a0b8e12c4fd6
DTSTART;VALUE=DATE:20170604
DTEND;VALUE=DATE:20170605
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trinity Sunday
UID:83608056-f721-4564-88ed-3cc5d12b01fb
DTSTART;VALUE=DATE:20170611
DTEND;VALUE=DATE:20170612
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ash Wednesday
UID:6eff84ea-6763-46d3-9c64-b847376f3e34
DTSTART;VALUE=DATE:20180214
DTEND;VALUE=DATE:20180215
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Good Friday
UID:19fb2499-97ae-457f-8d41-6ec76292c77f
DTSTART;VALUE=DATE:20180330
DTEND;VALUE=DATE:20180331
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Easter Sunday
UID:d869e442-0b4d-40c4-b34c-6780afce8c46
DTSTART;VALUE=DATE:20180401
DTEND;VALUE=DATE:20180402
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ascension Day
UID:db037aff-17bf-430b-b094-52e99879ba4e
DTSTART;VALUE=DATE:20180510
DTEND;VALUE=DATE:20180511
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pentecost
UID:01fec43b-b371-4f56-97cb-ef454132a74a
DTSTART;VALUE=DATE:20180520
DTEND;VALUE=DATE:20180521
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trinity Sunday
UID:cc92b242-3a24-471c-b1be-b8918fb8b6de
DTSTART;VALUE=DATE:20180527
DTEND;VALUE=DATE:20180528
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ash Wednesday
UID:e5d798cf-474f-42c3-83b8-0d1186c2c3ad
DTSTART;VALUE=DATE:20190306
DTEND;VALUE=DATE:20190307
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palm Sunday
UID:334646f6-5fef-43a9-83bc-d2dd88c9ebe6
DTSTART;VALUE=DATE:20190414
DTEND;VALUE=DATE:20190415
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Good Friday
UID:0a125549-300d-4bd9-af20-3fc28935946e
DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Easter Sunday
UID:135738b2-b8d5-4e65-bf7c-736e22c6b8b1
DTSTART;VALUE=DATE:20190421
DTEND;VALUE=DATE:20190422
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ascension Day
UID:dddeea06-c165-474c-96aa-6c1b705c6b0a
DTSTART;VALUE=DATE:20190530
DTEND;VALUE=DATE:20190531
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pentecost
UID:697b8004-261c-4c0b-a15e-06c1af95ab9b
DTSTART;VALUE=DATE:20190609
DTEND;VALUE=DATE:20190610
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trinity Sunday
UID:006195b6-8021-4814-9635-f9f5bffa7a36
DTSTART;VALUE=DATE:20190616
DTEND;VALUE=DATE:20190617
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ash Wednesday
UID:9d17488f-12b8-474b-8790-d22e6786735e
DTSTART;VALUE=DATE:20200226
DTEND;VALUE=DATE:20200227
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Palm Sunday
UID:7f9c6e82-610a-4485-b5fd-dde7f0dba4b8
DTSTART;VALUE=DATE:20200405
DTEND;VALUE=DATE:20200406
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Good Friday
UID:50de218e-013d-4739-b8d4-f30f74a57168
DTSTART;VALUE=DATE:20200410
DTEND;VALUE=DATE:20200411
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Easter Sunday
UID:7606494f-0019-46e6-9d47-ab9498569e5a
DTSTART;VALUE=DATE:20200412
DTEND;VALUE=DATE:20200413
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Ascension Day
UID:09a3f71c-83df-4649-b7d1-4792ae2fb523
DTSTART;VALUE=DATE:20200521
DTEND;VALUE=DATE:20200522
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Pentecost
UID:ac723797-16b2-4fd9-9d5e-2f55cc90dc22
DTSTART;VALUE=DATE:20200531
DTEND;VALUE=DATE:20200601
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:Trinity Sunday
UID:b60896ca-b1eb-4ec1-a9cd-67c7403c6335
DTSTART;VALUE=DATE:20200607
DTEND;VALUE=DATE:20200608
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SUMMARY:New Year's Day
UID:b1f194fc-1dd1-11b2-a973-d219c68b95c4
DTSTART;VALUE=DATE:20000101
DTEND;VALUE=DATE:20000102
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Groundhog's Day
UID:0c771532-1dd2-11b2-8dd9-8638db3aef63
DTSTART;VALUE=DATE:20000202
DTEND;VALUE=DATE:20000203
DTSTART;VALUE=DATE:20170116
DTEND;VALUE=DATE:20170117
UID:5a4b1ab2e4b97@calendarlabs.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:M L King Day
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=1;BYDAY=3MO
END:VEVENT
BEGIN:VEVENT
SUMMARY:Abraham Lincoln's Birthday
UID:4d5b843e-1dd2-11b2-a6c9-8ea942124d1b
DTSTART;VALUE=DATE:20000212
DTEND;VALUE=DATE:20000213
DTSTART;VALUE=DATE:20170220
DTEND;VALUE=DATE:20170221
UID:5a4b1ab2e4c77@calendarlabs.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY:Presidents' Day
RRULE:FREQ=YEARLY;BYMONTH=2;BYDAY=3MO
END:VEVENT
BEGIN:VEVENT
SUMMARY:Valentine's Day
UID:790b86e2-1dd2-11b2-9cb9-c905fa35c6f9
DTSTART;VALUE=DATE:20000214
DTEND;VALUE=DATE:20000215
DTSTART;VALUE=DATE:20170529
DTEND;VALUE=DATE:20170530
UID:5a4b1ab2e4e43@calendarlabs.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:President's Day
UID:9f3df592-1dd1-11b2-8b51-a8c49a575f97
DTSTART;VALUE=DATE:20000221
DTEND;VALUE=DATE:20000222
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:George Washington's Birthday (actual)
UID:aff9f3c8-1dd1-11b2-8593-c63469762eb1
DTSTART;VALUE=DATE:20000222
DTEND;VALUE=DATE:20000223
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:St. Patrick's Day
UID:bd6cfe4c-1dd1-11b2-b3dc-ebaab9302c26
DTSTART;VALUE=DATE:20000317
DTEND;VALUE=DATE:20000318
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:April Fool's Day
UID:c981b858-1dd1-11b2-b69b-94d05f8bda66
DTSTART;VALUE=DATE:20000401
DTEND;VALUE=DATE:20000402
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Tax Day
UID:e46086c2-1dd1-11b2-8a16-a2c99f1c525a
DTSTART;VALUE=DATE:20000415
DTEND;VALUE=DATE:20000416
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Earth Day
UID:f1561106-1dd1-11b2-955f-ba14e5210f45
DTSTART;VALUE=DATE:20000422
DTEND;VALUE=DATE:20000423
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Arbor Day
UID:e20f1b5c-8ac4-4bea-acf4-b4f2bfe95329
DTSTART;VALUE=DATE:20000428
DTEND;VALUE=DATE:20000429
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:National Day of Prayer
UID:a44b8b6e-7ae4-4120-b7ad-14e91691be2a
DTSTART;VALUE=DATE:20000504
DTEND;VALUE=DATE:20000505
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Mother's Day
UID:e0d4c156-1dd1-11b2-b6a4-dac750e0163e
DTSTART;VALUE=DATE:20000514
DTEND;VALUE=DATE:20000515
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Armed Forces Day
UID:c2783248-1dd1-11b2-affa-ee50c39d8083
DTSTART;VALUE=DATE:20000520
DTEND;VALUE=DATE:20000521
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Memorial Day
UID:d9706fa6-1dd1-11b2-a349-e97241bd4740
DTSTART;VALUE=DATE:20000529
DTEND;VALUE=DATE:20000530
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
RRULE:FREQ=YEARLY;BYMONTH=5;BYDAY=-1MO
END:VEVENT
BEGIN:VEVENT
SUMMARY:Flag Day
UID:e8022726-1dd1-11b2-aae6-9f73f16c0f01
DTSTART;VALUE=DATE:20000614
DTEND;VALUE=DATE:20000615
DTSTART;VALUE=DATE:20170704
DTEND;VALUE=DATE:20170705
UID:5a4b1ab2e4f3d@calendarlabs.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Father's Day
UID:cb90487e-1dd1-11b2-9e06-d1a12cc963dc
DTSTART;VALUE=DATE:20000618
DTEND;VALUE=DATE:20000619
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Independence Day
UID:f669a974-1dd1-11b2-9fac-f44d91c657af
DTSTART;VALUE=DATE:20000704
DTEND;VALUE=DATE:20000705
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Parents' Day
UID:46e6845c-1dd2-11b2-bd3d-d8755a1a171f
DTSTART;VALUE=DATE:20000723
DTEND;VALUE=DATE:20000724
DTSTART;VALUE=DATE:20170904
DTEND;VALUE=DATE:20170905
UID:5a4b1ab2e4fd4@calendarlabs.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Labor Day
UID:0726ea42-1dd2-11b2-9fe6-dda3d063fb50
DTSTART;VALUE=DATE:20000904
DTEND;VALUE=DATE:20000905
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=1MO
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20171009
DTEND;VALUE=DATE:20171010
UID:5a4b1ab2e502a@calendarlabs.com
STATUS:CONFIRMED
SUMMARY:Columbus Day
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=2MO
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20171111
DTEND;VALUE=DATE:20171112
UID:5a4b1ab2e515a@calendarlabs.com
STATUS:CONFIRMED
SUMMARY:Veterans Day
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Constitution Day\, Citizenship Day
UID:d3c521e1-ffab-414c-8cfa-99e76758d8c8
DTSTART;VALUE=DATE:20000917
DTEND;VALUE=DATE:20000918
DTSTART;VALUE=DATE:20171123
DTEND;VALUE=DATE:20171124
UID:5a4b1ab2e51ca@calendarlabs.com
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:United Nations Day
UID:8a05b5d3-6b97-4fe1-b26e-b258a073c5e0
DTSTART;VALUE=DATE:20001024
DTEND;VALUE=DATE:20001025
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Halloween
UID:7d4402f4-1dd2-11b2-9790-b6193cfa4349
DTSTART;VALUE=DATE:20001031
DTEND;VALUE=DATE:20001101
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Veteran's Day
UID:2c7ba10c-1dd2-11b2-b0b7-96f89f288199
DTSTART;VALUE=DATE:20001111
DTEND;VALUE=DATE:20001112
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Thanksgiving Day
UID:4299a358-1dd2-11b2-a228-d062222b6f88
DTSTART;VALUE=DATE:20001123
DTEND;VALUE=DATE:20001124
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=4TH
END:VEVENT
BEGIN:VEVENT
SUMMARY:Christmas Day
UID:54f392fa-1dd2-11b2-8ecb-9ae0a7fcebd1
DTSTART;VALUE=DATE:20001225
DTEND;VALUE=DATE:20001226
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:New Year's Eve
UID:a2cbca9c-1dd1-11b2-83e2-abab36f0506d
DTSTART;VALUE=DATE:20001231
DTEND;VALUE=DATE:20010101
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Inauguration Day
UID:088031d1-abea-47ed-978d-39c6319e8bf2
DTSTART;VALUE=DATE:20010120
DTEND;VALUE=DATE:20010121
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=4
END:VEVENT
BEGIN:VEVENT
SUMMARY:Daylight Saving Time begins
UID:e462881a-20b8-4b70-ab3c-cf38016d3398
DTSTART;VALUE=DATE:20070311
DTEND;VALUE=DATE:20070312
STATUS:CONFIRMED
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
BEGIN:VEVENT
SUMMARY:Daylight Saving Time ends
UID:13f83ed2-1dd2-11b2-a0de-ee8645423959
DTSTART;VALUE=DATE:20071104
DTEND;VALUE=DATE:20071105
DTSTART;VALUE=DATE:20171225
DTEND;VALUE=DATE:20171226
UID:5a4b1ab2e5265@calendarlabs.com
STATUS:CONFIRMED
SUMMARY:Christmas
RRULE:FREQ=YEARLY;INTERVAL=1
END:VEVENT
END:VCALENDAR

View file

@ -1,21 +0,0 @@
package com.simplemobiletools.calendar
import android.support.multidex.MultiDexApplication
import com.facebook.stetho.Stetho
import com.simplemobiletools.commons.extensions.checkUseEnglish
import com.squareup.leakcanary.LeakCanary
class App : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
if (LeakCanary.isInAnalyzerProcess(this)) {
return
}
LeakCanary.install(this)
Stetho.initializeWithDefaults(this)
}
checkUseEnglish()
}
}

View file

@ -1,129 +0,0 @@
package com.simplemobiletools.calendar.activities
import android.content.Intent
import android.os.Bundle
import android.support.v4.view.ViewPager
import android.util.SparseIntArray
import android.view.Menu
import android.view.MenuItem
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.adapters.MyDayPagerAdapter
import com.simplemobiletools.calendar.dialogs.FilterEventTypesDialog
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.getNewEventTimestampFromCode
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.helpers.NEW_EVENT_START_TS
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.commons.extensions.isActivityDestroyed
import com.simplemobiletools.commons.extensions.updateTextColors
import kotlinx.android.synthetic.main.activity_day.*
import org.joda.time.DateTime
import java.util.*
class DayActivity : SimpleActivity(), NavigationListener, ViewPager.OnPageChangeListener {
private val PREFILLED_DAYS = 121
private var mDayCode = ""
private var mPagerDays: MutableList<String>? = null
private var mPagerPos = 0
private var eventTypeColors = SparseIntArray()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_day)
val intent = intent ?: return
mDayCode = intent.getStringExtra(DAY_CODE)
if (mDayCode.isEmpty())
return
fillViewPager(mDayCode)
day_fab.setOnClickListener { addNewEvent() }
updateTextColors(day_coordinator)
dbHelper.getEventTypes {
if (!isActivityDestroyed()) {
eventTypeColors.clear()
it.map { eventTypeColors.put(it.id, it.color) }
invalidateOptionsMenu()
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_day, menu)
menu.findItem(R.id.filter).isVisible = eventTypeColors.size() > 1 || config.displayEventTypes.isEmpty()
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.filter -> showFilterDialog()
else -> return super.onOptionsItemSelected(item)
}
return true
}
private fun fillViewPager(targetDay: String) {
getDays(targetDay)
val daysAdapter = MyDayPagerAdapter(supportFragmentManager, mPagerDays!!, this)
mPagerPos = mPagerDays!!.size / 2
view_pager.apply {
adapter = daysAdapter
currentItem = mPagerPos
addOnPageChangeListener(this@DayActivity)
}
}
private fun showFilterDialog() {
FilterEventTypesDialog(this) {
recheckEvents()
}
}
private fun addNewEvent() {
Intent(applicationContext, EventActivity::class.java).apply {
putExtra(NEW_EVENT_START_TS, getNewEventTimestampFromCode(mPagerDays?.get(view_pager.currentItem).toString()))
startActivity(this)
}
}
private fun getDays(code: String) {
mPagerDays = ArrayList(PREFILLED_DAYS)
val today = Formatter.getDateTimeFromCode(code)
for (i in -PREFILLED_DAYS / 2..PREFILLED_DAYS / 2) {
mPagerDays!!.add(Formatter.getDayCodeFromDateTime(today.plusDays(i)))
}
}
fun recheckEvents() {
(view_pager.adapter as MyDayPagerAdapter).checkDayEvents(mPagerPos)
}
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
mPagerPos = position
(view_pager.adapter as MyDayPagerAdapter).destroyMultiselector(position)
}
override fun goLeft() {
view_pager.currentItem = view_pager.currentItem - 1
}
override fun goRight() {
view_pager.currentItem = view_pager.currentItem + 1
}
override fun goToDateTime(dateTime: DateTime) {
fillViewPager(Formatter.getDayCodeFromDateTime(dateTime))
}
}

View file

@ -1,754 +0,0 @@
package com.simplemobiletools.calendar.activities
import android.annotation.SuppressLint
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.dialogs.*
import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.models.CalDAVCalendar
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.models.RadioItem
import kotlinx.android.synthetic.main.activity_event.*
import org.joda.time.DateTime
import java.util.*
class EventActivity : SimpleActivity() {
private var mReminder1Minutes = 0
private var mReminder2Minutes = 0
private var mReminder3Minutes = 0
private var mRepeatInterval = 0
private var mRepeatLimit = 0
private var mRepeatRule = 0
private var mEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
private var mDialogTheme = 0
private var mEventOccurrenceTS = 0
private var mEventCalendarId = STORED_LOCALLY_ONLY
private var wasActivityInitialized = false
lateinit var mEventStartDateTime: DateTime
lateinit var mEventEndDateTime: DateTime
lateinit var mEvent: Event
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_event)
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_cross)
val intent = intent ?: return
mDialogTheme = getDialogTheme()
val eventId = intent.getIntExtra(EVENT_ID, 0)
val event = dbHelper.getEventWithId(eventId)
if (eventId != 0 && event == null) {
finish()
return
}
if (event != null) {
mEvent = event
mEventOccurrenceTS = intent.getIntExtra(EVENT_OCCURRENCE_TS, 0)
setupEditEvent()
} else {
mEvent = Event()
mReminder1Minutes = config.defaultReminderMinutes
mReminder2Minutes = -1
mReminder3Minutes = -1
val startTS = intent.getIntExtra(NEW_EVENT_START_TS, 0)
if (startTS == 0) {
return
}
setupNewEvent(Formatter.getDateTimeFromTS(startTS))
}
checkReminderTexts()
updateRepetitionText()
updateStartTexts()
updateEndTexts()
updateEventType()
updateCalDAVCalendar()
updateLocation()
event_start_date.setOnClickListener { setupStartDate() }
event_start_time.setOnClickListener { setupStartTime() }
event_end_date.setOnClickListener { setupEndDate() }
event_end_time.setOnClickListener { setupEndTime() }
event_all_day.setOnCheckedChangeListener { compoundButton, isChecked -> toggleAllDay(isChecked) }
event_repetition.setOnClickListener { showRepeatIntervalDialog() }
event_repetition_rule_holder.setOnClickListener { showRepetitionRuleDialog() }
event_repetition_limit_holder.setOnClickListener { showRepetitionTypePicker() }
event_reminder_1.setOnClickListener { showReminder1Dialog() }
event_reminder_2.setOnClickListener { showReminder2Dialog() }
event_reminder_3.setOnClickListener { showReminder3Dialog() }
event_type_holder.setOnClickListener { showEventTypeDialog() }
if (mEvent.flags and FLAG_ALL_DAY != 0)
event_all_day.toggle()
updateTextColors(event_scrollview)
updateIconColors()
wasActivityInitialized = true
}
private fun setupEditEvent() {
val realStart = if (mEventOccurrenceTS == 0) mEvent.startTS else mEventOccurrenceTS
val duration = mEvent.endTS - mEvent.startTS
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
supportActionBar?.title = resources.getString(R.string.edit_event)
mEventStartDateTime = Formatter.getDateTimeFromTS(realStart)
mEventEndDateTime = Formatter.getDateTimeFromTS(realStart + duration)
event_title.setText(mEvent.title)
event_location.setText(mEvent.location)
event_description.setText(mEvent.description)
event_description.movementMethod = LinkMovementMethod.getInstance()
mReminder1Minutes = mEvent.reminder1Minutes
mReminder2Minutes = mEvent.reminder2Minutes
mReminder3Minutes = mEvent.reminder3Minutes
mRepeatInterval = mEvent.repeatInterval
mRepeatLimit = mEvent.repeatLimit
mRepeatRule = mEvent.repeatRule
mEventTypeId = mEvent.eventType
mEventCalendarId = mEvent.getCalDAVCalendarId()
checkRepeatTexts(mRepeatInterval)
}
private fun setupNewEvent(dateTime: DateTime) {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
supportActionBar?.title = resources.getString(R.string.new_event)
mEventStartDateTime = dateTime
val addHours = if (intent.getBooleanExtra(NEW_EVENT_SET_HOUR_DURATION, false)) 1 else 0
mEventEndDateTime = mEventStartDateTime.plusHours(addHours)
val isLastCaldavCalendarOK = config.caldavSync && config.getSyncedCalendarIdsAsList().contains(config.lastUsedCaldavCalendar.toString())
mEventCalendarId = if (isLastCaldavCalendarOK) config.lastUsedCaldavCalendar else STORED_LOCALLY_ONLY
}
private fun showReminder1Dialog() {
showEventReminderDialog(mReminder1Minutes) {
mReminder1Minutes = it
checkReminderTexts()
}
}
private fun showReminder2Dialog() {
showEventReminderDialog(mReminder2Minutes) {
mReminder2Minutes = it
checkReminderTexts()
}
}
private fun showReminder3Dialog() {
showEventReminderDialog(mReminder3Minutes) {
mReminder3Minutes = it
checkReminderTexts()
}
}
private fun showRepeatIntervalDialog() {
showEventRepeatIntervalDialog(mRepeatInterval) {
setRepeatInterval(it)
}
}
private fun setRepeatInterval(interval: Int) {
mRepeatInterval = interval
updateRepetitionText()
checkRepeatTexts(interval)
if (mRepeatInterval.isXWeeklyRepetition()) {
setRepeatRule(Math.pow(2.0, (mEventStartDateTime.dayOfWeek - 1).toDouble()).toInt())
} else if (mRepeatInterval.isXMonthlyRepetition()) {
setRepeatRule(REPEAT_MONTH_SAME_DAY)
}
}
private fun checkRepeatTexts(limit: Int) {
event_repetition_limit_holder.beGoneIf(limit == 0)
checkRepetitionLimitText()
event_repetition_rule_holder.beVisibleIf(mRepeatInterval.isXWeeklyRepetition() || mRepeatInterval.isXMonthlyRepetition())
checkRepetitionRuleText()
}
private fun showRepetitionTypePicker() {
hideKeyboard()
RepeatLimitTypePickerDialog(this, mRepeatLimit, mEventStartDateTime.seconds()) {
setRepeatLimit(it)
}
}
private fun setRepeatLimit(limit: Int) {
mRepeatLimit = limit
checkRepetitionLimitText()
}
private fun checkRepetitionLimitText() {
event_repetition_limit.text = when {
mRepeatLimit == 0 -> {
event_repetition_limit_label.text = getString(R.string.repeat)
resources.getString(R.string.forever)
}
mRepeatLimit > 0 -> {
event_repetition_limit_label.text = getString(R.string.repeat_till)
val repeatLimitDateTime = Formatter.getDateTimeFromTS(mRepeatLimit)
Formatter.getFullDate(applicationContext, repeatLimitDateTime)
}
else -> {
event_repetition_limit_label.text = getString(R.string.repeat)
"${-mRepeatLimit} ${getString(R.string.times)}"
}
}
}
private fun showRepetitionRuleDialog() {
hideKeyboard()
if (mRepeatInterval.isXWeeklyRepetition()) {
RepeatRuleWeeklyDialog(this, mRepeatRule) {
setRepeatRule(it)
}
} else if (mRepeatInterval.isXMonthlyRepetition()) {
val items = arrayListOf(RadioItem(REPEAT_MONTH_SAME_DAY, getString(R.string.repeat_on_the_same_day)))
// split Every Last Sunday and Every Fourth Sunday of the month, if the month has 4 sundays
if (isLastWeekDayOfMonth()) {
val order = (mEventStartDateTime.dayOfMonth - 1) / 7 + 1
if (order == 4) {
items.add(RadioItem(REPEAT_MONTH_ORDER_WEEKDAY, getRepeatXthDayString(true, REPEAT_MONTH_ORDER_WEEKDAY)))
items.add(RadioItem(REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST, getRepeatXthDayString(true, REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST)))
} else if (order == 5) {
items.add(RadioItem(REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST, getRepeatXthDayString(true, REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST)))
}
} else {
items.add(RadioItem(REPEAT_MONTH_ORDER_WEEKDAY, getRepeatXthDayString(true, REPEAT_MONTH_ORDER_WEEKDAY)))
}
if (isLastDayOfTheMonth()) {
items.add(RadioItem(REPEAT_MONTH_LAST_DAY, getString(R.string.repeat_on_the_last_day)))
}
RadioGroupDialog(this, items, mRepeatRule) {
setRepeatRule(it as Int)
}
}
}
private fun isLastDayOfTheMonth() = mEventStartDateTime.dayOfMonth == mEventStartDateTime.dayOfMonth().withMaximumValue().dayOfMonth
private fun isLastWeekDayOfMonth() = mEventStartDateTime.monthOfYear != mEventStartDateTime.plusDays(7).monthOfYear
private fun getRepeatXthDayString(includeBase: Boolean, repeatRule: Int): String {
val dayOfWeek = mEventStartDateTime.dayOfWeek
val base = getBaseString(dayOfWeek)
val order = getOrderString(repeatRule)
val dayString = getDayString(dayOfWeek)
return if (includeBase) {
"$base $order $dayString"
} else {
val everyString = getString(if (isMaleGender(mEventStartDateTime.dayOfWeek)) R.string.every_m else R.string.every_f)
"$everyString $order $dayString"
}
}
private fun getBaseString(day: Int): String {
return getString(if (isMaleGender(day)) {
R.string.repeat_every_m
} else {
R.string.repeat_every_f
})
}
private fun isMaleGender(day: Int) = day == 1 || day == 2 || day == 4 || day == 5
private fun getOrderString(repeatRule: Int): String {
val dayOfMonth = mEventStartDateTime.dayOfMonth
var order = (dayOfMonth - 1) / 7 + 1
if (order == 4 && isLastWeekDayOfMonth() && repeatRule == REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST) {
order = -1
}
val isMale = isMaleGender(mEventStartDateTime.dayOfWeek)
return getString(when (order) {
1 -> if (isMale) R.string.first_m else R.string.first_f
2 -> if (isMale) R.string.second_m else R.string.second_f
3 -> if (isMale) R.string.third_m else R.string.third_f
4 -> if (isMale) R.string.fourth_m else R.string.fourth_f
else -> if (isMale) R.string.last_m else R.string.last_f
})
}
private fun getDayString(day: Int): String {
return getString(when (day) {
1 -> R.string.monday_alt
2 -> R.string.tuesday_alt
3 -> R.string.wednesday_alt
4 -> R.string.thursday_alt
5 -> R.string.friday_alt
6 -> R.string.saturday_alt
else -> R.string.sunday_alt
})
}
private fun setRepeatRule(rule: Int) {
mRepeatRule = rule
checkRepetitionRuleText()
if (rule == 0) {
setRepeatInterval(0)
}
}
private fun checkRepetitionRuleText() {
if (mRepeatInterval.isXWeeklyRepetition()) {
event_repetition_rule.text = if (mRepeatRule == EVERY_DAY) getString(R.string.every_day) else getSelectedDaysString()
} else if (mRepeatInterval.isXMonthlyRepetition()) {
val repeatString = if (mRepeatRule == REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST || mRepeatRule == REPEAT_MONTH_ORDER_WEEKDAY)
R.string.repeat else R.string.repeat_on
event_repetition_rule_label.text = getString(repeatString)
event_repetition_rule.text = getMonthlyRepetitionRuleText()
}
}
private fun getSelectedDaysString(): String {
var days = ""
if (mRepeatRule and MONDAY != 0)
days += "${getString(R.string.monday).substringTo(3)}, "
if (mRepeatRule and TUESDAY != 0)
days += "${getString(R.string.tuesday).substringTo(3)}, "
if (mRepeatRule and WEDNESDAY != 0)
days += "${getString(R.string.wednesday).substringTo(3)}, "
if (mRepeatRule and THURSDAY != 0)
days += "${getString(R.string.thursday).substringTo(3)}, "
if (mRepeatRule and FRIDAY != 0)
days += "${getString(R.string.friday).substringTo(3)}, "
if (mRepeatRule and SATURDAY != 0)
days += "${getString(R.string.saturday).substringTo(3)}, "
if (mRepeatRule and SUNDAY != 0)
days += "${getString(R.string.sunday).substringTo(3)}, "
return days.trim().trimEnd(',')
}
private fun getMonthlyRepetitionRuleText() = when (mRepeatRule) {
REPEAT_MONTH_SAME_DAY -> getString(R.string.the_same_day)
REPEAT_MONTH_LAST_DAY -> getString(R.string.the_last_day)
else -> getRepeatXthDayString(false, mRepeatRule)
}
private fun showEventTypeDialog() {
hideKeyboard()
SelectEventTypeDialog(this, mEventTypeId) {
mEventTypeId = it
updateEventType()
}
}
private fun checkReminderTexts() {
updateReminder1Text()
updateReminder2Text()
updateReminder3Text()
}
private fun updateReminder1Text() {
event_reminder_1.text = getFormattedMinutes(mReminder1Minutes)
if (mReminder1Minutes == REMINDER_OFF) {
mReminder2Minutes = REMINDER_OFF
mReminder3Minutes = REMINDER_OFF
}
}
private fun updateReminder2Text() {
event_reminder_2.apply {
beGoneIf(mReminder1Minutes == REMINDER_OFF)
if (mReminder2Minutes == REMINDER_OFF) {
text = resources.getString(R.string.add_another_reminder)
alpha = 0.4f
mReminder3Minutes = REMINDER_OFF
} else {
text = getFormattedMinutes(mReminder2Minutes)
alpha = 1f
}
}
}
private fun updateReminder3Text() {
event_reminder_3.apply {
beGoneIf(mReminder2Minutes == REMINDER_OFF || mReminder1Minutes == REMINDER_OFF)
if (mReminder3Minutes == REMINDER_OFF) {
text = resources.getString(R.string.add_another_reminder)
alpha = 0.4f
} else {
text = getFormattedMinutes(mReminder3Minutes)
alpha = 1f
}
}
}
private fun updateRepetitionText() {
event_repetition.text = getRepetitionText(mRepeatInterval)
}
private fun updateEventType() {
val eventType = dbHelper.getEventType(mEventTypeId)
if (eventType != null) {
event_type.text = eventType.title
event_type_color.setBackgroundWithStroke(eventType.color, config.backgroundColor)
}
}
private fun updateCalDAVCalendar() {
if (config.caldavSync) {
event_caldav_calendar_image.beVisible()
event_caldav_calendar_holder.beVisible()
event_caldav_calendar_divider.beVisible()
val calendars = CalDAVHandler(applicationContext).getCalDAVCalendars().filter {
it.canWrite() && config.getSyncedCalendarIdsAsList().contains(it.id.toString())
}
updateCurrentCalendarInfo(if (mEventCalendarId == STORED_LOCALLY_ONLY) null else getCalendarWithId(calendars, getCalendarId()))
event_caldav_calendar_holder.setOnClickListener {
hideKeyboard()
SelectEventCalendarDialog(this, calendars, mEventCalendarId) {
if (mEventCalendarId != STORED_LOCALLY_ONLY && it == STORED_LOCALLY_ONLY) {
mEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
updateEventType()
}
mEventCalendarId = it
config.lastUsedCaldavCalendar = it
updateCurrentCalendarInfo(getCalendarWithId(calendars, it))
}
}
} else {
updateCurrentCalendarInfo(null)
}
}
private fun getCalendarId() = if (mEvent.source == SOURCE_SIMPLE_CALENDAR) config.lastUsedCaldavCalendar else mEvent.getCalDAVCalendarId()
private fun getCalendarWithId(calendars: List<CalDAVCalendar>, calendarId: Int): CalDAVCalendar? =
calendars.firstOrNull { it.id == calendarId }
private fun updateCurrentCalendarInfo(currentCalendar: CalDAVCalendar?) {
event_type_image.beVisibleIf(currentCalendar == null)
event_type_holder.beVisibleIf(currentCalendar == null)
event_caldav_calendar_divider.beVisibleIf(currentCalendar == null)
event_caldav_calendar_email.beGoneIf(currentCalendar == null)
if (currentCalendar == null) {
event_caldav_calendar_name.apply {
text = getString(R.string.store_locally_only)
setPadding(paddingLeft, paddingTop, paddingRight, resources.getDimension(R.dimen.medium_margin).toInt())
}
} else {
event_caldav_calendar_email.text = currentCalendar.accountName
event_caldav_calendar_name.apply {
text = currentCalendar.displayName
setPadding(paddingLeft, paddingTop, paddingRight, resources.getDimension(R.dimen.tiny_margin).toInt())
}
}
}
private fun updateLocation() {
event_location.setText(mEvent.location)
}
private fun toggleAllDay(isChecked: Boolean) {
hideKeyboard()
event_start_time.beGoneIf(isChecked)
event_end_time.beGoneIf(isChecked)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_event, menu)
if (wasActivityInitialized) {
menu.findItem(R.id.delete).isVisible = mEvent.id != 0
menu.findItem(R.id.share).isVisible = mEvent.id != 0
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save -> saveEvent()
R.id.delete -> deleteEvent()
R.id.share -> shareEvent()
else -> return super.onOptionsItemSelected(item)
}
return true
}
private fun shareEvent() {
shareEvents(arrayListOf(mEvent.id))
}
private fun deleteEvent() {
DeleteEventDialog(this, arrayListOf(mEvent.id)) {
if (it) {
dbHelper.deleteEvents(arrayOf(mEvent.id.toString()), true)
} else {
dbHelper.addEventRepeatException(mEvent.id, mEventOccurrenceTS)
}
finish()
}
}
private fun saveEvent() {
val newTitle = event_title.value
if (newTitle.isEmpty()) {
toast(R.string.title_empty)
event_title.requestFocus()
return
}
val newStartTS = mEventStartDateTime.withSecondOfMinute(0).withMillisOfSecond(0).seconds()
val newEndTS = mEventEndDateTime.withSecondOfMinute(0).withMillisOfSecond(0).seconds()
if (newStartTS > newEndTS) {
toast(R.string.end_before_start)
return
}
val wasRepeatable = mEvent.repeatInterval > 0
val oldSource = mEvent.source
val newImportId = if (mEvent.id != 0) mEvent.importId else UUID.randomUUID().toString().replace("-", "") + System.currentTimeMillis().toString()
val newEventType = if (!config.caldavSync || config.lastUsedCaldavCalendar == 0 || mEventCalendarId == STORED_LOCALLY_ONLY) {
mEventTypeId
} else {
dbHelper.getEventTypeWithCalDAVCalendarId(config.lastUsedCaldavCalendar)?.id ?: DBHelper.REGULAR_EVENT_TYPE_ID
}
val newSource = if (!config.caldavSync || config.lastUsedCaldavCalendar == 0 || mEventCalendarId == STORED_LOCALLY_ONLY) {
SOURCE_SIMPLE_CALENDAR
} else {
"$CALDAV-${config.lastUsedCaldavCalendar}"
}
val reminders = sortedSetOf(mReminder1Minutes, mReminder2Minutes, mReminder3Minutes).filter { it != REMINDER_OFF }
mEvent.apply {
startTS = newStartTS
endTS = newEndTS
title = newTitle
description = event_description.value
reminder1Minutes = reminders.elementAtOrElse(0) { REMINDER_OFF }
reminder2Minutes = reminders.elementAtOrElse(1) { REMINDER_OFF }
reminder3Minutes = reminders.elementAtOrElse(2) { REMINDER_OFF }
repeatInterval = mRepeatInterval
importId = newImportId
flags = if (event_all_day.isChecked) (mEvent.flags or FLAG_ALL_DAY) else (mEvent.flags.removeFlag(FLAG_ALL_DAY))
repeatLimit = if (repeatInterval == 0) 0 else mRepeatLimit
repeatRule = mRepeatRule
eventType = newEventType
offset = getCurrentOffset()
isDstIncluded = TimeZone.getDefault().inDaylightTime(Date())
lastUpdated = System.currentTimeMillis()
source = newSource
location = event_location.value
}
// recreate the event if it was moved in a different CalDAV calendar
if (mEvent.id != 0 && oldSource != newSource) {
dbHelper.deleteEvents(arrayOf(mEvent.id.toString()), true)
mEvent.id = 0
}
storeEvent(wasRepeatable)
}
private fun storeEvent(wasRepeatable: Boolean) {
if (mEvent.id == 0) {
dbHelper.insert(mEvent, true) {
if (DateTime.now().isAfter(mEventStartDateTime.millis)) {
if (mEvent.getReminders().isNotEmpty()) {
notifyEvent(mEvent)
}
} else {
toast(R.string.event_added)
}
finish()
}
} else {
if (mRepeatInterval > 0 && wasRepeatable) {
EditRepeatingEventDialog(this) {
if (it) {
dbHelper.update(mEvent, true) {
eventUpdated()
}
} else {
dbHelper.addEventRepeatException(mEvent.id, mEventOccurrenceTS)
mEvent.parentId = mEvent.id
mEvent.id = 0
dbHelper.insert(mEvent, true) {
toast(R.string.event_updated)
finish()
}
}
}
} else {
dbHelper.update(mEvent, true) {
eventUpdated()
}
}
}
}
private fun eventUpdated() {
toast(R.string.event_updated)
finish()
}
private fun updateStartTexts() {
updateStartDateText()
updateStartTimeText()
}
private fun updateStartDateText() {
event_start_date.text = Formatter.getDate(applicationContext, mEventStartDateTime)
checkStartEndValidity()
}
private fun updateStartTimeText() {
event_start_time.text = Formatter.getTime(this, mEventStartDateTime)
checkStartEndValidity()
}
private fun updateEndTexts() {
updateEndDateText()
updateEndTimeText()
}
private fun updateEndDateText() {
event_end_date.text = Formatter.getDate(applicationContext, mEventEndDateTime)
checkStartEndValidity()
}
private fun updateEndTimeText() {
event_end_time.text = Formatter.getTime(this, mEventEndDateTime)
checkStartEndValidity()
}
private fun checkStartEndValidity() {
val textColor = if (mEventStartDateTime.isAfter(mEventEndDateTime)) resources.getColor(R.color.red_text) else config.textColor
event_end_date.setTextColor(textColor)
event_end_time.setTextColor(textColor)
}
@SuppressLint("NewApi")
private fun setupStartDate() {
hideKeyboard()
config.backgroundColor.getContrastColor()
val datepicker = DatePickerDialog(this, mDialogTheme, startDateSetListener, mEventStartDateTime.year, mEventStartDateTime.monthOfYear - 1,
mEventStartDateTime.dayOfMonth)
if (isLollipopPlus()) {
datepicker.datePicker.firstDayOfWeek = if (config.isSundayFirst) Calendar.SUNDAY else Calendar.MONDAY
}
datepicker.show()
}
private fun setupStartTime() {
hideKeyboard()
TimePickerDialog(this, mDialogTheme, startTimeSetListener, mEventStartDateTime.hourOfDay, mEventStartDateTime.minuteOfHour, config.use24hourFormat).show()
}
@SuppressLint("NewApi")
private fun setupEndDate() {
hideKeyboard()
val datepicker = DatePickerDialog(this, mDialogTheme, endDateSetListener, mEventEndDateTime.year, mEventEndDateTime.monthOfYear - 1,
mEventEndDateTime.dayOfMonth)
if (isLollipopPlus()) {
datepicker.datePicker.firstDayOfWeek = if (config.isSundayFirst) Calendar.SUNDAY else Calendar.MONDAY
}
datepicker.show()
}
private fun setupEndTime() {
hideKeyboard()
TimePickerDialog(this, mDialogTheme, endTimeSetListener, mEventEndDateTime.hourOfDay, mEventEndDateTime.minuteOfHour, config.use24hourFormat).show()
}
private val startDateSetListener = DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth ->
dateSet(year, monthOfYear, dayOfMonth, true)
}
private val startTimeSetListener = TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute ->
timeSet(hourOfDay, minute, true)
}
private val endDateSetListener = DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth -> dateSet(year, monthOfYear, dayOfMonth, false) }
private val endTimeSetListener = TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute -> timeSet(hourOfDay, minute, false) }
private fun dateSet(year: Int, month: Int, day: Int, isStart: Boolean) {
if (isStart) {
val diff = mEventEndDateTime.seconds() - mEventStartDateTime.seconds()
mEventStartDateTime = mEventStartDateTime.withDate(year, month + 1, day)
updateStartDateText()
checkRepeatRule()
mEventEndDateTime = mEventStartDateTime.plusSeconds(diff)
updateEndTexts()
} else {
mEventEndDateTime = mEventEndDateTime.withDate(year, month + 1, day)
updateEndDateText()
}
}
private fun timeSet(hours: Int, minutes: Int, isStart: Boolean) {
if (isStart) {
val diff = mEventEndDateTime.seconds() - mEventStartDateTime.seconds()
mEventStartDateTime = mEventStartDateTime.withHourOfDay(hours).withMinuteOfHour(minutes)
updateStartTimeText()
mEventEndDateTime = mEventStartDateTime.plusSeconds(diff)
updateEndTexts()
} else {
mEventEndDateTime = mEventEndDateTime.withHourOfDay(hours).withMinuteOfHour(minutes)
updateEndTimeText()
}
}
private fun checkRepeatRule() {
if (mRepeatInterval.isXWeeklyRepetition()) {
val day = mRepeatRule
if (day == MONDAY || day == TUESDAY || day == WEDNESDAY || day == THURSDAY || day == FRIDAY || day == SATURDAY || day == SUNDAY) {
setRepeatRule(Math.pow(2.0, (mEventStartDateTime.dayOfWeek - 1).toDouble()).toInt())
}
} else if (mRepeatInterval.isXMonthlyRepetition()) {
if (mRepeatRule == REPEAT_MONTH_LAST_DAY && !isLastDayOfTheMonth())
mRepeatRule = REPEAT_MONTH_SAME_DAY
checkRepetitionRuleText()
}
}
private fun updateIconColors() {
val textColor = config.textColor
event_time_image.applyColorFilter(textColor)
event_repetition_image.applyColorFilter(textColor)
event_reminder_image.applyColorFilter(textColor)
event_type_image.applyColorFilter(textColor)
event_caldav_calendar_image.applyColorFilter(textColor)
}
}

View file

@ -1,832 +0,0 @@
package com.simplemobiletools.calendar.activities
import android.content.ContentResolver
import android.content.Intent
import android.content.pm.ActivityInfo
import android.database.ContentObserver
import android.database.Cursor
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.provider.CalendarContract
import android.provider.ContactsContract
import android.support.v4.view.ViewPager
import android.util.SparseIntArray
import android.view.Menu
import android.view.MenuItem
import android.widget.TextView
import android.widget.Toast
import com.simplemobiletools.calendar.BuildConfig
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.adapters.MyMonthPagerAdapter
import com.simplemobiletools.calendar.adapters.MyWeekPagerAdapter
import com.simplemobiletools.calendar.adapters.MyYearPagerAdapter
import com.simplemobiletools.calendar.dialogs.ExportEventsDialog
import com.simplemobiletools.calendar.dialogs.FilterEventTypesDialog
import com.simplemobiletools.calendar.dialogs.ImportEventsDialog
import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.fragments.EventListFragment
import com.simplemobiletools.calendar.fragments.WeekFragment
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.calendar.views.MyScrollView
import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.models.Release
import kotlinx.android.synthetic.main.activity_main.*
import org.joda.time.DateTime
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
class MainActivity : SimpleActivity(), NavigationListener {
private val CALDAV_SYNC_DELAY = 2000L
private val PREFILLED_MONTHS = 97
private val PREFILLED_YEARS = 31
private val PREFILLED_WEEKS = 61
private var mIsMonthSelected = false
private var mStoredUseEnglish = false
private var mStoredTextColor = 0
private var mStoredBackgroundColor = 0
private var mStoredPrimaryColor = 0
private var mStoredDayCode = ""
private var mStoredIsSundayFirst = false
private var mStoredUse24HourFormat = false
private var mShouldFilterBeVisible = false
private var mCalDAVSyncHandler = Handler()
private var mDefaultWeeklyPage = 0
private var mDefaultMonthlyPage = 0
private var mDefaultYearlyPage = 0
companion object {
var mWeekScrollY = 0
var eventTypeColors = SparseIntArray()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
appLaunched()
calendar_fab.setOnClickListener { launchNewEventIntent() }
checkWhatsNewDialog()
if (resources.getBoolean(R.bool.portrait_only))
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
if (intent?.action == Intent.ACTION_VIEW && intent.data != null) {
val uri = intent.data
if (uri.authority == "com.android.calendar") {
// clicking date on a third party widget: content://com.android.calendar/time/1507309245683
if (intent?.extras?.getBoolean("DETAIL_VIEW", false) == true) {
val timestamp = uri.pathSegments.last()
if (timestamp.areDigitsOnly()) {
openDayAt(timestamp.toLong())
return
}
}
} else {
tryImportEventsFromFile(uri)
}
}
storeStateVariables()
updateViewPager()
if (!hasPermission(PERMISSION_WRITE_CALENDAR) || !hasPermission(PERMISSION_READ_CALENDAR)) {
config.caldavSync = false
}
recheckCalDAVCalendars {}
if (config.googleSync) {
val ids = dbHelper.getGoogleSyncEvents().map { it.id.toString() }.toTypedArray()
dbHelper.deleteEvents(ids, false)
config.googleSync = false
}
checkOpenIntents()
}
override fun onResume() {
super.onResume()
if (mStoredUseEnglish != config.useEnglish) {
restartActivity()
return
}
if (mStoredTextColor != config.textColor || mStoredBackgroundColor != config.backgroundColor || mStoredPrimaryColor != config.primaryColor
|| mStoredDayCode != Formatter.getTodayCode()) {
updateViewPager()
}
dbHelper.getEventTypes {
eventTypeColors.clear()
it.map { eventTypeColors.put(it.id, it.color) }
mShouldFilterBeVisible = eventTypeColors.size() > 1 || config.displayEventTypes.isEmpty()
invalidateOptionsMenu()
}
storeStateVariables()
if (config.storedView == WEEKLY_VIEW) {
if (mStoredIsSundayFirst != config.isSundayFirst || mStoredUse24HourFormat != config.use24hourFormat) {
fillWeeklyViewPager()
}
}
updateWidgets()
updateTextColors(calendar_coordinator)
}
override fun onPause() {
super.onPause()
storeStateVariables()
}
override fun onStop() {
super.onStop()
mCalDAVSyncHandler.removeCallbacksAndMessages(null)
contentResolver.unregisterContentObserver(calDAVSyncObserver)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
menu.apply {
findItem(R.id.filter).isVisible = mShouldFilterBeVisible
findItem(R.id.go_to_today).isVisible = shouldGoToTodayBeVisible()
findItem(R.id.refresh_caldav_calendars).isVisible = config.caldavSync
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.change_view -> showViewDialog()
R.id.go_to_today -> goToToday()
R.id.filter -> showFilterDialog()
R.id.refresh_caldav_calendars -> refreshCalDAVCalendars()
R.id.add_holidays -> addHolidays()
R.id.add_birthdays -> tryAddBirthdays()
R.id.add_anniversaries -> tryAddAnniversaries()
R.id.import_events -> tryImportEvents()
R.id.export_events -> tryExportEvents()
R.id.settings -> launchSettings()
R.id.about -> launchAbout()
else -> return super.onOptionsItemSelected(item)
}
return true
}
override fun onBackPressed() {
if (mIsMonthSelected && config.storedView == YEARLY_VIEW) {
updateView(YEARLY_VIEW)
} else {
super.onBackPressed()
}
}
private fun storeStateVariables() {
config.apply {
mStoredUseEnglish = useEnglish
mStoredIsSundayFirst = isSundayFirst
mStoredTextColor = textColor
mStoredPrimaryColor = primaryColor
mStoredBackgroundColor = backgroundColor
mStoredUse24HourFormat = use24hourFormat
}
mStoredDayCode = Formatter.getTodayCode()
}
private fun checkOpenIntents() {
val dayCodeToOpen = intent.getStringExtra(DAY_CODE) ?: ""
if (dayCodeToOpen.isNotEmpty()) {
openDayCode(dayCodeToOpen)
}
val eventIdToOpen = intent.getIntExtra(EVENT_ID, 0)
val eventOccurrenceToOpen = intent.getIntExtra(EVENT_OCCURRENCE_TS, 0)
if (eventIdToOpen != 0 && eventOccurrenceToOpen != 0) {
Intent(this, EventActivity::class.java).apply {
putExtra(EVENT_ID, eventIdToOpen)
putExtra(EVENT_OCCURRENCE_TS, eventOccurrenceToOpen)
startActivity(this)
}
}
}
private fun showViewDialog() {
val res = resources
val items = arrayListOf(
RadioItem(WEEKLY_VIEW, res.getString(R.string.weekly_view)),
RadioItem(MONTHLY_VIEW, res.getString(R.string.monthly_view)),
RadioItem(YEARLY_VIEW, res.getString(R.string.yearly_view)),
RadioItem(EVENTS_LIST_VIEW, res.getString(R.string.simple_event_list)))
RadioGroupDialog(this, items, config.storedView) {
updateView(it as Int)
invalidateOptionsMenu()
}
}
private fun goToToday() {
if (config.storedView == WEEKLY_VIEW) {
week_view_view_pager.currentItem = mDefaultWeeklyPage
} else if (config.storedView == MONTHLY_VIEW) {
main_view_pager.currentItem = mDefaultMonthlyPage
} else if (config.storedView == YEARLY_VIEW) {
if (mIsMonthSelected) {
openMonthlyToday()
} else {
main_view_pager.currentItem = mDefaultYearlyPage
}
}
}
private fun shouldGoToTodayBeVisible() = when {
config.storedView == WEEKLY_VIEW -> week_view_view_pager.currentItem != mDefaultWeeklyPage
config.storedView == MONTHLY_VIEW -> main_view_pager.currentItem != mDefaultMonthlyPage
config.storedView == YEARLY_VIEW -> main_view_pager.currentItem != mDefaultYearlyPage
else -> false
}
private fun showFilterDialog() {
FilterEventTypesDialog(this) {
refreshViewPager()
}
}
private fun refreshCalDAVCalendars() {
toast(R.string.refreshing)
val uri = CalendarContract.Calendars.CONTENT_URI
contentResolver.registerContentObserver(uri, false, calDAVSyncObserver)
Bundle().apply {
putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true)
putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true)
ContentResolver.requestSync(null, uri.authority, this)
}
scheduleCalDAVSync(true)
}
private val calDAVSyncObserver = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
if (!selfChange) {
mCalDAVSyncHandler.removeCallbacksAndMessages(null)
mCalDAVSyncHandler.postDelayed({
recheckCalDAVCalendars {
refreshViewPager()
toast(R.string.refreshing_complete)
}
}, CALDAV_SYNC_DELAY)
}
}
}
private fun addHolidays() {
val items = getHolidayRadioItems()
RadioGroupDialog(this, items) {
toast(R.string.importing)
Thread {
val holidays = getString(R.string.holidays)
var eventTypeId = dbHelper.getEventTypeIdWithTitle(holidays)
if (eventTypeId == -1) {
val eventType = EventType(0, holidays, resources.getColor(R.color.default_holidays_color))
eventTypeId = dbHelper.insertEventType(eventType)
}
val result = IcsImporter(this).importEvents(it as String, eventTypeId)
handleParseResult(result)
if (result != IcsImporter.ImportResult.IMPORT_FAIL) {
runOnUiThread {
updateViewPager()
}
}
}.start()
}
}
private fun tryAddBirthdays() {
handlePermission(PERMISSION_READ_CONTACTS) {
if (it) {
Thread {
addContactEvents(true) {
if (it > 0) {
toast(R.string.birthdays_added)
updateViewPager()
} else {
toast(R.string.no_birthdays)
}
}
}.start()
} else {
toast(R.string.no_contacts_permission)
}
}
}
private fun tryAddAnniversaries() {
handlePermission(PERMISSION_READ_CONTACTS) {
if (it) {
Thread {
addContactEvents(false) {
if (it > 0) {
toast(R.string.anniversaries_added)
updateViewPager()
} else {
toast(R.string.no_anniversaries)
}
}
}.start()
} else {
toast(R.string.no_contacts_permission)
}
}
}
private fun handleParseResult(result: IcsImporter.ImportResult) {
toast(when (result) {
IcsImporter.ImportResult.IMPORT_OK -> R.string.holidays_imported_successfully
IcsImporter.ImportResult.IMPORT_PARTIAL -> R.string.importing_some_holidays_failed
else -> R.string.importing_holidays_failed
}, Toast.LENGTH_LONG)
}
private fun addContactEvents(birthdays: Boolean, callback: (Int) -> Unit) {
var eventsAdded = 0
val uri = ContactsContract.Data.CONTENT_URI
val projection = arrayOf(ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.CONTACT_LAST_UPDATED_TIMESTAMP,
ContactsContract.CommonDataKinds.Event.START_DATE)
val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.CommonDataKinds.Event.TYPE} = ?"
val type = if (birthdays) ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY else ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY
val selectionArgs = arrayOf(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, type.toString())
var cursor: Cursor? = null
try {
cursor = contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor?.moveToFirst() == true) {
val dateFormats = getDateFormats()
val existingEvents = if (birthdays) dbHelper.getBirthdays() else dbHelper.getAnniversaries()
val importIDs = existingEvents.map { it.importId }
val eventTypeId = if (birthdays) getBirthdaysEventTypeId() else getAnniversariesEventTypeId()
do {
val contactId = cursor.getIntValue(ContactsContract.CommonDataKinds.Event.CONTACT_ID).toString()
val name = cursor.getStringValue(ContactsContract.Contacts.DISPLAY_NAME)
val startDate = cursor.getStringValue(ContactsContract.CommonDataKinds.Event.START_DATE)
for (format in dateFormats) {
try {
val formatter = SimpleDateFormat(format, Locale.getDefault())
val date = formatter.parse(startDate)
if (date.year < 70)
date.year = 70
val timestamp = (date.time / 1000).toInt()
val source = if (birthdays) SOURCE_CONTACT_BIRTHDAY else SOURCE_CONTACT_ANNIVERSARY
val lastUpdated = cursor.getLongValue(ContactsContract.CommonDataKinds.Event.CONTACT_LAST_UPDATED_TIMESTAMP)
val event = Event(0, timestamp, timestamp, name, importId = contactId, flags = FLAG_ALL_DAY, repeatInterval = YEAR,
eventType = eventTypeId, source = source, lastUpdated = lastUpdated)
if (!importIDs.contains(contactId)) {
dbHelper.insert(event, false) {
eventsAdded++
}
}
break
} catch (e: Exception) {
}
}
} while (cursor.moveToNext())
}
} catch (e: Exception) {
showErrorToast(e)
} finally {
cursor?.close()
}
runOnUiThread {
callback(eventsAdded)
}
}
private fun getBirthdaysEventTypeId(): Int {
val birthdays = getString(R.string.birthdays)
var eventTypeId = dbHelper.getEventTypeIdWithTitle(birthdays)
if (eventTypeId == -1) {
val eventType = EventType(0, birthdays, resources.getColor(R.color.default_birthdays_color))
eventTypeId = dbHelper.insertEventType(eventType)
}
return eventTypeId
}
private fun getAnniversariesEventTypeId(): Int {
val anniversaries = getString(R.string.anniversaries)
var eventTypeId = dbHelper.getEventTypeIdWithTitle(anniversaries)
if (eventTypeId == -1) {
val eventType = EventType(0, anniversaries, resources.getColor(R.color.default_anniversaries_color))
eventTypeId = dbHelper.insertEventType(eventType)
}
return eventTypeId
}
private fun updateView(view: Int) {
calendar_fab.beGoneIf(view == YEARLY_VIEW)
mIsMonthSelected = view == MONTHLY_VIEW
config.storedView = view
updateViewPager()
}
private fun updateViewPager() {
resetTitle()
when {
config.storedView == YEARLY_VIEW -> fillYearlyViewPager()
config.storedView == EVENTS_LIST_VIEW -> fillEventsList()
config.storedView == WEEKLY_VIEW -> fillWeeklyViewPager()
else -> openMonthlyToday()
}
mWeekScrollY = 0
}
private fun openMonthlyToday() {
val targetDay = DateTime().toString(Formatter.DAYCODE_PATTERN)
fillMonthlyViewPager(targetDay)
}
private fun refreshViewPager() {
when {
config.storedView == YEARLY_VIEW && !mIsMonthSelected -> (main_view_pager.adapter as? MyYearPagerAdapter)?.refreshEvents(main_view_pager.currentItem)
config.storedView == EVENTS_LIST_VIEW -> fillEventsList()
config.storedView == WEEKLY_VIEW -> (week_view_view_pager.adapter as? MyWeekPagerAdapter)?.refreshEvents(week_view_view_pager.currentItem)
else -> (main_view_pager.adapter as? MyMonthPagerAdapter)?.refreshEvents(main_view_pager.currentItem)
}
}
private fun tryImportEvents() {
handlePermission(PERMISSION_READ_STORAGE) {
if (it) {
importEvents()
}
}
}
private fun importEvents() {
FilePickerDialog(this) {
importEventsDialog(it)
}
}
private fun tryImportEventsFromFile(uri: Uri) {
when {
uri.scheme == "file" -> importEventsDialog(uri.path)
uri.scheme == "content" -> {
val tempFile = getTempFile()
if (tempFile == null) {
toast(R.string.unknown_error_occurred)
return
}
val inputStream = contentResolver.openInputStream(uri)
val out = FileOutputStream(tempFile)
inputStream.copyTo(out)
importEventsDialog(tempFile.absolutePath)
}
else -> toast(R.string.invalid_file_format)
}
}
private fun importEventsDialog(path: String) {
ImportEventsDialog(this, path) {
if (it) {
runOnUiThread {
updateViewPager()
}
}
}
}
private fun tryExportEvents() {
handlePermission(PERMISSION_WRITE_STORAGE) {
if (it) {
exportEvents()
}
}
}
private fun exportEvents() {
FilePickerDialog(this, pickFile = false, showFAB = true) {
val path = it
ExportEventsDialog(this, path) { exportPastEvents, file, eventTypes ->
Thread {
val events = dbHelper.getEventsToExport(exportPastEvents).filter { eventTypes.contains(it.eventType.toString()) }
if (events.isEmpty()) {
toast(R.string.no_events_for_exporting)
} else {
toast(R.string.exporting)
IcsExporter().exportEvents(this, file, events as ArrayList<Event>) {
toast(when (it) {
IcsExporter.ExportResult.EXPORT_OK -> R.string.events_exported_successfully
IcsExporter.ExportResult.EXPORT_PARTIAL -> R.string.exporting_some_events_failed
else -> R.string.exporting_events_failed
})
}
}
}.start()
}
}
}
private fun launchSettings() {
startActivity(Intent(applicationContext, SettingsActivity::class.java))
}
private fun launchAbout() {
startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_JODA or LICENSE_STETHO or LICENSE_MULTISELECT or LICENSE_GSON or
LICENSE_LEAK_CANARY, BuildConfig.VERSION_NAME)
}
private fun resetTitle() {
supportActionBar?.title = getString(R.string.app_launcher_name)
supportActionBar?.subtitle = ""
}
private fun fillMonthlyViewPager(targetDay: String) {
main_weekly_scrollview.beGone()
calendar_fab.beVisible()
val codes = getMonths(targetDay)
val monthlyAdapter = MyMonthPagerAdapter(supportFragmentManager, codes, this)
mDefaultMonthlyPage = codes.size / 2
main_view_pager.apply {
adapter = monthlyAdapter
beVisible()
addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
invalidateOptionsMenu()
if (config.storedView == YEARLY_VIEW) {
val dateTime = Formatter.getDateTimeFromCode(codes[position])
supportActionBar?.title = "${getString(R.string.app_launcher_name)} - ${Formatter.getYear(dateTime)}"
}
}
})
currentItem = mDefaultMonthlyPage
}
calendar_event_list_holder.beGone()
}
private fun getMonths(code: String): List<String> {
val months = ArrayList<String>(PREFILLED_MONTHS)
val today = Formatter.getDateTimeFromCode(code)
for (i in -PREFILLED_MONTHS / 2..PREFILLED_MONTHS / 2) {
months.add(Formatter.getDayCodeFromDateTime(today.plusMonths(i)))
}
return months
}
private fun fillWeeklyViewPager() {
var thisweek = DateTime().withDayOfWeek(1).withTimeAtStartOfDay().minusDays(if (config.isSundayFirst) 1 else 0)
if (DateTime().minusDays(7).seconds() > thisweek.seconds()) {
thisweek = thisweek.plusDays(7)
}
val weekTSs = getWeekTimestamps(thisweek.seconds())
val weeklyAdapter = MyWeekPagerAdapter(supportFragmentManager, weekTSs, object : WeekFragment.WeekScrollListener {
override fun scrollTo(y: Int) {
week_view_hours_scrollview.scrollY = y
mWeekScrollY = y
}
})
main_view_pager.beGone()
calendar_event_list_holder.beGone()
main_weekly_scrollview.beVisible()
week_view_hours_holder.removeAllViews()
val hourDateTime = DateTime().withDate(2000, 1, 1).withTime(0, 0, 0, 0)
for (i in 1..23) {
val formattedHours = Formatter.getHours(applicationContext, hourDateTime.withHourOfDay(i))
(layoutInflater.inflate(R.layout.weekly_view_hour_textview, null, false) as TextView).apply {
text = formattedHours
setTextColor(mStoredTextColor)
week_view_hours_holder.addView(this)
}
}
mDefaultWeeklyPage = weekTSs.size / 2
week_view_view_pager.apply {
adapter = weeklyAdapter
addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
invalidateOptionsMenu()
setupWeeklyActionbarTitle(weekTSs[position])
}
})
currentItem = mDefaultWeeklyPage
}
week_view_hours_scrollview.setOnScrollviewListener(object : MyScrollView.ScrollViewListener {
override fun onScrollChanged(scrollView: MyScrollView, x: Int, y: Int, oldx: Int, oldy: Int) {
mWeekScrollY = y
weeklyAdapter.updateScrollY(week_view_view_pager.currentItem, y)
}
})
week_view_hours_scrollview.setOnTouchListener { view, motionEvent -> true }
}
fun updateHoursTopMargin(margin: Int) {
week_view_hours_divider.layoutParams.height = margin
week_view_hours_scrollview.requestLayout()
}
private fun getWeekTimestamps(targetWeekTS: Int): List<Int> {
val weekTSs = ArrayList<Int>(PREFILLED_WEEKS)
for (i in -PREFILLED_WEEKS / 2..PREFILLED_WEEKS / 2) {
weekTSs.add(Formatter.getDateTimeFromTS(targetWeekTS).plusWeeks(i).seconds())
}
return weekTSs
}
private fun setupWeeklyActionbarTitle(timestamp: Int) {
val startDateTime = Formatter.getDateTimeFromTS(timestamp)
val endDateTime = Formatter.getDateTimeFromTS(timestamp + WEEK_SECONDS)
val startMonthName = Formatter.getMonthName(applicationContext, startDateTime.monthOfYear)
if (startDateTime.monthOfYear == endDateTime.monthOfYear) {
var newTitle = startMonthName
if (startDateTime.year != DateTime().year)
newTitle += " - ${startDateTime.year}"
supportActionBar?.title = newTitle
} else {
val endMonthName = Formatter.getMonthName(applicationContext, endDateTime.monthOfYear)
supportActionBar?.title = "$startMonthName - $endMonthName"
}
supportActionBar?.subtitle = "${getString(R.string.week)} ${startDateTime.plusDays(3).weekOfWeekyear}"
}
private fun fillYearlyViewPager() {
main_weekly_scrollview.beGone()
calendar_fab.beGone()
val targetYear = DateTime().toString(Formatter.YEAR_PATTERN).toInt()
val years = getYears(targetYear)
val yearlyAdapter = MyYearPagerAdapter(supportFragmentManager, years, this)
mDefaultYearlyPage = years.size / 2
main_view_pager.apply {
adapter = yearlyAdapter
addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
invalidateOptionsMenu()
if (position < years.size) {
supportActionBar?.title = "${getString(R.string.app_launcher_name)} - ${years[position]}"
}
}
})
currentItem = mDefaultYearlyPage
beVisible()
}
supportActionBar?.title = "${getString(R.string.app_launcher_name)} - ${years[years.size / 2]}"
calendar_event_list_holder.beGone()
}
private fun getYears(targetYear: Int): List<Int> {
val years = ArrayList<Int>(PREFILLED_YEARS)
years += targetYear - PREFILLED_YEARS / 2..targetYear + PREFILLED_YEARS / 2
return years
}
private fun fillEventsList() {
main_view_pager.adapter = null
main_view_pager.beGone()
main_weekly_scrollview.beGone()
calendar_event_list_holder.beVisible()
supportFragmentManager.beginTransaction().replace(R.id.calendar_event_list_holder, EventListFragment(), "").commit()
}
override fun goLeft() {
main_view_pager.currentItem = main_view_pager.currentItem - 1
}
override fun goRight() {
main_view_pager.currentItem = main_view_pager.currentItem + 1
}
override fun goToDateTime(dateTime: DateTime) {
fillMonthlyViewPager(Formatter.getDayCodeFromDateTime(dateTime))
mIsMonthSelected = true
}
private fun openDayAt(timestamp: Long) {
val dayCode = Formatter.getDayCodeFromTS((timestamp / 1000).toInt())
openDayCode(dayCode)
}
private fun openDayCode(dayCode: String) {
Intent(this, DayActivity::class.java).apply {
putExtra(DAY_CODE, dayCode)
startActivity(this)
}
}
private fun getHolidayRadioItems(): ArrayList<RadioItem> {
val items = ArrayList<RadioItem>()
LinkedHashMap<String, String>().apply {
put("Algeria", "algeria.ics")
put("Argentina", "argentina.ics")
put("België", "belgium.ics")
put("Bolivia", "bolivia.ics")
put("Brasil", "brazil.ics")
put("Canada", "canada.ics")
put("Česká republika", "czech.ics")
put("Deutschland", "germany.ics")
put("Eesti", "estonia.ics")
put("España", "spain.ics")
put("Éire", "ireland.ics")
put("France", "france.ics")
put("Hanguk", "southkorea.ics")
put("Hellas", "greece.ics")
put("India", "india.ics")
put("Ísland", "iceland.ics")
put("Italia", "italy.ics")
put("Magyarország", "hungary.ics")
put("Nederland", "netherlands.ics")
put("日本", "japan.ics")
put("Norge", "norway.ics")
put("Österreich", "austria.ics")
put("Pākistān", "pakistan.ics")
put("Polska", "poland.ics")
put("Portugal", "portugal.ics")
put("Россия", "russia.ics")
put("Schweiz", "switzerland.ics")
put("Slovenija", "slovenia.ics")
put("Slovensko", "slovakia.ics")
put("Suomi", "finland.ics")
put("Sverige", "sweden.ics")
put("United Kingdom", "unitedkingdom.ics")
put("United States", "unitedstates.ics")
var i = 0
for ((country, file) in this) {
items.add(RadioItem(i++, country, file))
}
}
return items
}
private fun checkWhatsNewDialog() {
arrayListOf<Release>().apply {
add(Release(39, R.string.release_39))
add(Release(40, R.string.release_40))
add(Release(42, R.string.release_42))
add(Release(44, R.string.release_44))
add(Release(46, R.string.release_46))
add(Release(48, R.string.release_48))
add(Release(49, R.string.release_49))
add(Release(51, R.string.release_51))
add(Release(52, R.string.release_52))
add(Release(54, R.string.release_54))
add(Release(57, R.string.release_57))
add(Release(59, R.string.release_59))
add(Release(60, R.string.release_60))
add(Release(62, R.string.release_62))
add(Release(67, R.string.release_67))
add(Release(69, R.string.release_69))
add(Release(71, R.string.release_71))
add(Release(73, R.string.release_73))
add(Release(76, R.string.release_76))
add(Release(77, R.string.release_77))
add(Release(80, R.string.release_80))
add(Release(84, R.string.release_84))
add(Release(86, R.string.release_86))
add(Release(88, R.string.release_88))
add(Release(98, R.string.release_98))
checkWhatsNew(this, BuildConfig.VERSION_CODE)
}
}
}

View file

@ -1,367 +0,0 @@
package com.simplemobiletools.calendar.activities
import android.content.Intent
import android.content.res.Resources
import android.media.RingtoneManager
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.text.TextUtils
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.dialogs.CustomEventReminderDialog
import com.simplemobiletools.calendar.dialogs.SelectCalendarsDialog
import com.simplemobiletools.calendar.dialogs.SnoozePickerDialog
import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.helpers.CalDAVHandler
import com.simplemobiletools.calendar.helpers.FONT_SIZE_LARGE
import com.simplemobiletools.calendar.helpers.FONT_SIZE_MEDIUM
import com.simplemobiletools.calendar.helpers.FONT_SIZE_SMALL
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CALENDAR
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CALENDAR
import com.simplemobiletools.commons.models.RadioItem
import kotlinx.android.synthetic.main.activity_settings.*
import java.util.*
class SettingsActivity : SimpleActivity() {
private val GET_RINGTONE_URI = 1
lateinit var res: Resources
private var mStoredPrimaryColor = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
res = resources
mStoredPrimaryColor = config.primaryColor
setupCaldavSync()
}
override fun onResume() {
super.onResume()
setupCustomizeColors()
setupUseEnglish()
setupManageEventTypes()
setupHourFormat()
setupSundayFirst()
setupReplaceDescription()
setupWeekNumbers()
setupWeeklyStart()
setupWeeklyEnd()
setupVibrate()
setupReminderSound()
setupSnoozeDelay()
setupEventReminder()
setupDisplayPastEvents()
setupFontSize()
updateTextColors(settings_holder)
checkPrimaryColor()
}
override fun onPause() {
super.onPause()
mStoredPrimaryColor = config.primaryColor
}
private fun checkPrimaryColor() {
if (config.primaryColor != mStoredPrimaryColor) {
dbHelper.getEventTypes {
if (it.filter { it.caldavCalendarId == 0 }.size == 1) {
val eventType = it.first { it.caldavCalendarId == 0 }
eventType.color = config.primaryColor
dbHelper.updateEventType(eventType)
}
}
}
}
private fun setupCustomizeColors() {
settings_customize_colors_holder.setOnClickListener {
startCustomizationActivity()
}
}
private fun setupUseEnglish() {
settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
settings_use_english.isChecked = config.useEnglish
settings_use_english_holder.setOnClickListener {
settings_use_english.toggle()
config.useEnglish = settings_use_english.isChecked
useEnglishToggled()
}
}
private fun setupManageEventTypes() {
settings_manage_event_types_holder.setOnClickListener {
startActivity(Intent(this, ManageEventTypesActivity::class.java))
}
}
private fun setupHourFormat() {
settings_hour_format.isChecked = config.use24hourFormat
settings_hour_format_holder.setOnClickListener {
settings_hour_format.toggle()
config.use24hourFormat = settings_hour_format.isChecked
}
}
private fun setupCaldavSync() {
settings_caldav_sync.isChecked = config.caldavSync
settings_caldav_sync_holder.setOnClickListener {
if (config.caldavSync) {
toggleCaldavSync(false)
} else {
handlePermission(PERMISSION_WRITE_CALENDAR) {
if (it) {
handlePermission(PERMISSION_READ_CALENDAR) {
if (it) {
toggleCaldavSync(true)
}
}
}
}
}
}
settings_manage_synced_calendars_holder.beVisibleIf(config.caldavSync)
settings_manage_synced_calendars_holder.setOnClickListener {
showCalendarPicker()
}
}
private fun toggleCaldavSync(enable: Boolean) {
if (enable) {
showCalendarPicker()
} else {
settings_caldav_sync.isChecked = false
config.caldavSync = false
settings_manage_synced_calendars_holder.beGone()
config.getSyncedCalendarIdsAsList().forEach {
CalDAVHandler(applicationContext).deleteCalDAVCalendarEvents(it.toLong())
}
dbHelper.deleteEventTypesWithCalendarId(config.caldavSyncedCalendarIDs)
}
}
private fun showCalendarPicker() {
val oldCalendarIds = config.getSyncedCalendarIdsAsList()
SelectCalendarsDialog(this) {
val newCalendarIds = config.getSyncedCalendarIdsAsList()
settings_manage_synced_calendars_holder.beVisibleIf(newCalendarIds.isNotEmpty())
settings_caldav_sync.isChecked = newCalendarIds.isNotEmpty()
config.caldavSync = newCalendarIds.isNotEmpty()
toast(R.string.syncing)
Thread {
if (newCalendarIds.isNotEmpty()) {
val existingEventTypeNames = dbHelper.fetchEventTypes().map { it.getDisplayTitle().toLowerCase() } as ArrayList<String>
getSyncedCalDAVCalendars().forEach {
val calendarTitle = it.getFullTitle()
if (!existingEventTypeNames.contains(calendarTitle.toLowerCase())) {
val eventType = EventType(0, it.displayName, it.color, it.id, it.displayName, it.accountName)
existingEventTypeNames.add(calendarTitle.toLowerCase())
dbHelper.insertEventType(eventType)
}
}
CalDAVHandler(applicationContext).refreshCalendars(this) {}
}
val removedCalendarIds = oldCalendarIds.filter { !newCalendarIds.contains(it) }
removedCalendarIds.forEach {
CalDAVHandler(applicationContext).deleteCalDAVCalendarEvents(it.toLong())
dbHelper.getEventTypeWithCalDAVCalendarId(it.toInt())?.apply {
dbHelper.deleteEventTypes(arrayListOf(this), true) {}
}
}
dbHelper.deleteEventTypesWithCalendarId(TextUtils.join(",", removedCalendarIds))
toast(R.string.synchronization_completed)
}.start()
}
}
private fun setupSundayFirst() {
settings_sunday_first.isChecked = config.isSundayFirst
settings_sunday_first_holder.setOnClickListener {
settings_sunday_first.toggle()
config.isSundayFirst = settings_sunday_first.isChecked
}
}
private fun setupReplaceDescription() {
settings_replace_description.isChecked = config.replaceDescription
settings_replace_description_holder.setOnClickListener {
settings_replace_description.toggle()
config.replaceDescription = settings_replace_description.isChecked
}
}
private fun setupWeeklyStart() {
settings_start_weekly_at.text = getHoursString(config.startWeeklyAt)
settings_start_weekly_at_holder.setOnClickListener {
val items = ArrayList<RadioItem>()
(0..24).mapTo(items) { RadioItem(it, getHoursString(it)) }
RadioGroupDialog(this@SettingsActivity, items, config.startWeeklyAt) {
if (it as Int >= config.endWeeklyAt) {
toast(R.string.day_end_before_start)
} else {
config.startWeeklyAt = it
settings_start_weekly_at.text = getHoursString(it)
}
}
}
}
private fun setupWeeklyEnd() {
settings_end_weekly_at.text = getHoursString(config.endWeeklyAt)
settings_end_weekly_at_holder.setOnClickListener {
val items = ArrayList<RadioItem>()
(0..24).mapTo(items) { RadioItem(it, getHoursString(it)) }
RadioGroupDialog(this@SettingsActivity, items, config.endWeeklyAt) {
if (it as Int <= config.startWeeklyAt) {
toast(R.string.day_end_before_start)
} else {
config.endWeeklyAt = it
settings_end_weekly_at.text = getHoursString(it)
}
}
}
}
private fun setupWeekNumbers() {
settings_week_numbers.isChecked = config.displayWeekNumbers
settings_week_numbers_holder.setOnClickListener {
settings_week_numbers.toggle()
config.displayWeekNumbers = settings_week_numbers.isChecked
}
}
private fun setupReminderSound() {
val noRingtone = res.getString(R.string.no_ringtone_selected)
if (config.reminderSound.isEmpty()) {
settings_reminder_sound.text = noRingtone
} else {
settings_reminder_sound.text = RingtoneManager.getRingtone(this, Uri.parse(config.reminderSound))?.getTitle(this) ?: noRingtone
}
settings_reminder_sound_holder.setOnClickListener {
Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, res.getString(R.string.reminder_sound))
putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(config.reminderSound))
if (resolveActivity(packageManager) != null)
startActivityForResult(this, GET_RINGTONE_URI)
else {
toast(R.string.no_ringtone_picker)
}
}
}
}
private fun setupVibrate() {
settings_vibrate.isChecked = config.vibrateOnReminder
settings_vibrate_holder.setOnClickListener {
settings_vibrate.toggle()
config.vibrateOnReminder = settings_vibrate.isChecked
}
}
private fun setupSnoozeDelay() {
updateSnoozeText()
settings_snooze_delay_holder.setOnClickListener {
SnoozePickerDialog(this, config.snoozeDelay) {
config.snoozeDelay = it
updateSnoozeText()
}
}
}
private fun updateSnoozeText() {
settings_snooze_delay.text = res.getQuantityString(R.plurals.by_minutes, config.snoozeDelay, config.snoozeDelay)
}
private fun setupEventReminder() {
var reminderMinutes = config.defaultReminderMinutes
settings_default_reminder.text = getFormattedMinutes(reminderMinutes)
settings_default_reminder_holder.setOnClickListener {
showEventReminderDialog(reminderMinutes) {
config.defaultReminderMinutes = it
reminderMinutes = it
settings_default_reminder.text = getFormattedMinutes(it)
}
}
}
private fun getHoursString(hours: Int): String {
return if (hours < 10) {
"0$hours:00"
} else {
"$hours:00"
}
}
private fun setupDisplayPastEvents() {
var displayPastEvents = config.displayPastEvents
updatePastEventsText(displayPastEvents)
settings_display_past_events_holder.setOnClickListener {
CustomEventReminderDialog(this, displayPastEvents) {
displayPastEvents = it
config.displayPastEvents = it
updatePastEventsText(it)
}
}
}
private fun updatePastEventsText(displayPastEvents: Int) {
settings_display_past_events.text = getDisplayPastEventsText(displayPastEvents)
}
private fun getDisplayPastEventsText(displayPastEvents: Int): String {
return if (displayPastEvents == 0)
getString(R.string.never)
else
getFormattedMinutes(displayPastEvents, false)
}
private fun setupFontSize() {
settings_font_size.text = getFontSizeText()
settings_font_size_holder.setOnClickListener {
val items = arrayListOf(
RadioItem(FONT_SIZE_SMALL, res.getString(R.string.small)),
RadioItem(FONT_SIZE_MEDIUM, res.getString(R.string.medium)),
RadioItem(FONT_SIZE_LARGE, res.getString(R.string.large)))
RadioGroupDialog(this@SettingsActivity, items, config.fontSize) {
config.fontSize = it as Int
settings_font_size.text = getFontSizeText()
updateWidgets()
updateListWidget()
}
}
}
private fun getFontSizeText() = getString(when (config.fontSize) {
FONT_SIZE_SMALL -> R.string.small
FONT_SIZE_MEDIUM -> R.string.medium
else -> R.string.large
})
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == RESULT_OK) {
if (requestCode == GET_RINGTONE_URI) {
val uri = data?.getParcelableExtra<Parcelable>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
if (uri == null) {
config.reminderSound = ""
} else {
settings_reminder_sound.text = RingtoneManager.getRingtone(this, uri as Uri)?.getTitle(this)
config.reminderSound = uri.toString()
}
}
}
}
}

View file

@ -1,90 +0,0 @@
package com.simplemobiletools.calendar.activities
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.dialogs.CustomEventReminderDialog
import com.simplemobiletools.calendar.dialogs.CustomEventRepeatIntervalDialog
import com.simplemobiletools.calendar.extensions.getFormattedMinutes
import com.simplemobiletools.calendar.extensions.getRepetitionText
import com.simplemobiletools.calendar.helpers.DAY
import com.simplemobiletools.calendar.helpers.MONTH
import com.simplemobiletools.calendar.helpers.WEEK
import com.simplemobiletools.calendar.helpers.YEAR
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.models.RadioItem
import java.util.TreeSet
import kotlin.collections.ArrayList
open class SimpleActivity : BaseSimpleActivity() {
protected fun showEventReminderDialog(curMinutes: Int, callback: (minutes: Int) -> Unit) {
hideKeyboard()
val minutes = TreeSet<Int>()
minutes.apply {
add(-1)
add(0)
add(10)
add(30)
add(curMinutes)
}
val items = ArrayList<RadioItem>(minutes.size + 1)
minutes.mapIndexedTo(items, { index, value ->
RadioItem(index, getFormattedMinutes(value), value)
})
var selectedIndex = 0
minutes.forEachIndexed { index, value ->
if (value == curMinutes)
selectedIndex = index
}
items.add(RadioItem(-2, getString(R.string.custom)))
RadioGroupDialog(this, items, selectedIndex) {
if (it == -2) {
CustomEventReminderDialog(this) {
callback(it)
}
} else {
callback(it as Int)
}
}
}
protected fun showEventRepeatIntervalDialog(curSeconds: Int, callback: (minutes: Int) -> Unit) {
hideKeyboard()
val seconds = TreeSet<Int>()
seconds.apply {
add(0)
add(DAY)
add(WEEK)
add(MONTH)
add(YEAR)
add(curSeconds)
}
val items = ArrayList<RadioItem>(seconds.size + 1)
seconds.mapIndexedTo(items, { index, value ->
RadioItem(index, getRepetitionText(value), value)
})
var selectedIndex = 0
seconds.forEachIndexed { index, value ->
if (value == curSeconds)
selectedIndex = index
}
items.add(RadioItem(-1, getString(R.string.custom)))
RadioGroupDialog(this, items, selectedIndex) {
if (it == -1) {
CustomEventRepeatIntervalDialog(this) {
callback(it)
}
} else {
callback(it as Int)
}
}
}
}

View file

@ -1,25 +0,0 @@
package com.simplemobiletools.calendar.activities
import android.content.Intent
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.helpers.EVENT_ID
import com.simplemobiletools.calendar.helpers.EVENT_OCCURRENCE_TS
import com.simplemobiletools.commons.activities.BaseSplashActivity
class SplashActivity : BaseSplashActivity() {
override fun initActivity() {
when {
intent.extras?.containsKey(DAY_CODE) == true -> Intent(this, MainActivity::class.java).apply {
putExtra(DAY_CODE, intent.getStringExtra(DAY_CODE))
startActivity(this)
}
intent.extras?.containsKey(EVENT_ID) == true -> Intent(this, MainActivity::class.java).apply {
putExtra(EVENT_ID, intent.getIntExtra(EVENT_ID, 0))
putExtra(EVENT_OCCURRENCE_TS, intent.getIntExtra(EVENT_OCCURRENCE_TS, 0))
startActivity(this)
}
else -> startActivity(Intent(this, MainActivity::class.java))
}
finish()
}
}

View file

@ -1,123 +0,0 @@
package com.simplemobiletools.calendar.adapters
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.dialogs.DeleteEventDialog
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.shareEvents
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.DeleteEventsListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.beInvisible
import com.simplemobiletools.commons.extensions.beInvisibleIf
import com.simplemobiletools.commons.views.MyRecyclerView
import kotlinx.android.synthetic.main.event_item_day_view.view.*
class DayEventsAdapter(activity: SimpleActivity, val events: ArrayList<Event>, val listener: DeleteEventsListener?, recyclerView: MyRecyclerView,
itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
private var allDayString = resources.getString(R.string.all_day)
private var replaceDescriptionWithLocation = activity.config.replaceDescription
override fun getActionMenuId() = R.menu.cab_day
override fun prepareActionMode(menu: Menu) {}
override fun prepareItemSelection(view: View) {}
override fun markItemSelection(select: Boolean, view: View?) {
view?.event_item_frame?.isSelected = select
}
override fun actionItemPressed(id: Int) {
when (id) {
R.id.cab_share -> shareEvents()
R.id.cab_delete -> askConfirmDelete()
}
}
override fun getSelectableItemCount() = events.size
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int) = createViewHolder(R.layout.event_item_day_view, parent)
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val event = events[position]
val view = holder.bindView(event) { itemView, layoutPosition ->
setupView(itemView, event)
}
bindViewHolder(holder, position, view)
}
override fun getItemCount() = events.size
private fun setupView(view: View, event: Event) {
view.apply {
event_section_title.text = event.title
event_item_description.text = if (replaceDescriptionWithLocation) event.location else event.description
event_item_start.text = if (event.getIsAllDay()) allDayString else Formatter.getTimeFromTS(context, event.startTS)
event_item_end.beInvisibleIf(event.startTS == event.endTS)
event_item_color.applyColorFilter(event.color)
if (event.startTS != event.endTS) {
val startCode = Formatter.getDayCodeFromTS(event.startTS)
val endCode = Formatter.getDayCodeFromTS(event.endTS)
event_item_end.apply {
text = Formatter.getTimeFromTS(context, event.endTS)
if (startCode != endCode) {
if (event.getIsAllDay()) {
text = Formatter.getDateFromCode(context, endCode, true)
} else {
append(" (${Formatter.getDateFromCode(context, endCode, true)})")
}
} else if (event.getIsAllDay()) {
beInvisible()
}
}
}
event_item_start.setTextColor(textColor)
event_item_end.setTextColor(textColor)
event_section_title.setTextColor(textColor)
event_item_description.setTextColor(textColor)
}
}
private fun shareEvents() {
val eventIds = ArrayList<Int>(selectedPositions.size)
selectedPositions.forEach {
eventIds.add(events[it].id)
}
activity.shareEvents(eventIds.distinct())
}
private fun askConfirmDelete() {
val eventIds = ArrayList<Int>(selectedPositions.size)
val timestamps = ArrayList<Int>(selectedPositions.size)
selectedPositions.forEach {
eventIds.add(events[it].id)
timestamps.add(events[it].startTS)
}
DeleteEventDialog(activity, eventIds) {
val eventsToDelete = ArrayList<Event>(selectedPositions.size)
selectedPositions.sortedDescending().forEach {
val event = events[it]
eventsToDelete.add(event)
}
events.removeAll(eventsToDelete)
if (it) {
listener?.deleteItems(eventIds)
} else {
listener?.addEventRepeatException(eventIds, timestamps)
}
removeSelectedItems()
}
}
}

View file

@ -1,166 +0,0 @@
package com.simplemobiletools.calendar.adapters
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.dialogs.DeleteEventDialog
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.shareEvents
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.DeleteEventsListener
import com.simplemobiletools.calendar.models.ListEvent
import com.simplemobiletools.calendar.models.ListItem
import com.simplemobiletools.calendar.models.ListSection
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.beInvisible
import com.simplemobiletools.commons.extensions.beInvisibleIf
import com.simplemobiletools.commons.views.MyRecyclerView
import kotlinx.android.synthetic.main.event_list_item.view.*
import java.util.*
class EventListAdapter(activity: SimpleActivity, val listItems: ArrayList<ListItem>, val allowLongClick: Boolean, val listener: DeleteEventsListener?,
recyclerView: MyRecyclerView, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
private val ITEM_EVENT = 0
private val ITEM_HEADER = 1
private val topDivider = resources.getDrawable(R.drawable.divider_width)
private val allDayString = resources.getString(R.string.all_day)
private val replaceDescriptionWithLocation = activity.config.replaceDescription
private val redTextColor = resources.getColor(R.color.red_text)
private val now = (System.currentTimeMillis() / 1000).toInt()
private val todayDate = Formatter.getDayTitle(activity, Formatter.getDayCodeFromTS(now))
override fun getActionMenuId() = R.menu.cab_event_list
override fun prepareActionMode(menu: Menu) {}
override fun prepareItemSelection(view: View) {}
override fun markItemSelection(select: Boolean, view: View?) {
view?.event_item_frame?.isSelected = select
}
override fun actionItemPressed(id: Int) {
when (id) {
R.id.cab_share -> shareEvents()
R.id.cab_delete -> askConfirmDelete()
}
}
override fun getSelectableItemCount() = listItems.filter { it is ListEvent }.size
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyRecyclerViewAdapter.ViewHolder {
val layoutId = if (viewType == ITEM_EVENT) R.layout.event_list_item else R.layout.event_list_section
return createViewHolder(layoutId, parent)
}
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val listItem = listItems[position]
val view = holder.bindView(listItem, allowLongClick) { itemView, layoutPosition ->
if (listItem is ListSection) {
setupListSection(itemView, listItem, position)
} else if (listItem is ListEvent) {
setupListEvent(itemView, listItem)
}
}
bindViewHolder(holder, position, view)
}
override fun getItemCount() = listItems.size
override fun getItemViewType(position: Int) = if (listItems[position] is ListEvent) ITEM_EVENT else ITEM_HEADER
private fun setupListEvent(view: View, listEvent: ListEvent) {
view.apply {
event_section_title.text = listEvent.title
event_item_description.text = if (replaceDescriptionWithLocation) listEvent.location else listEvent.description
event_item_start.text = if (listEvent.isAllDay) allDayString else Formatter.getTimeFromTS(context, listEvent.startTS)
event_item_end.beInvisibleIf(listEvent.startTS == listEvent.endTS)
event_item_color.applyColorFilter(listEvent.color)
if (listEvent.startTS != listEvent.endTS) {
val startCode = Formatter.getDayCodeFromTS(listEvent.startTS)
val endCode = Formatter.getDayCodeFromTS(listEvent.endTS)
event_item_end.apply {
text = Formatter.getTimeFromTS(context, listEvent.endTS)
if (startCode != endCode) {
if (listEvent.isAllDay) {
text = Formatter.getDateFromCode(context, endCode, true)
} else {
append(" (${Formatter.getDateFromCode(context, endCode, true)})")
}
} else if (listEvent.isAllDay) {
beInvisible()
}
}
}
var startTextColor = textColor
var endTextColor = textColor
if (listEvent.startTS <= now && listEvent.endTS <= now) {
if (listEvent.isAllDay) {
if (Formatter.getDayCodeFromTS(listEvent.startTS) == Formatter.getDayCodeFromTS(now))
startTextColor = primaryColor
} else {
startTextColor = redTextColor
}
endTextColor = redTextColor
} else if (listEvent.startTS <= now && listEvent.endTS >= now) {
startTextColor = primaryColor
}
event_item_start.setTextColor(startTextColor)
event_item_end.setTextColor(endTextColor)
event_section_title.setTextColor(startTextColor)
event_item_description.setTextColor(startTextColor)
}
}
private fun setupListSection(view: View, listSection: ListSection, position: Int) {
view.event_section_title.apply {
text = listSection.title
setCompoundDrawablesWithIntrinsicBounds(null, if (position == 0) null else topDivider, null, null)
setTextColor(if (listSection.title == todayDate) primaryColor else textColor)
}
}
private fun shareEvents() {
val eventIds = ArrayList<Int>(selectedPositions.size)
selectedPositions.forEach {
eventIds.add((listItems[it] as ListEvent).id)
}
activity.shareEvents(eventIds.distinct())
finishActMode()
}
private fun askConfirmDelete() {
val eventIds = ArrayList<Int>(selectedPositions.size)
val timestamps = ArrayList<Int>(selectedPositions.size)
selectedPositions.forEach {
eventIds.add((listItems[it] as ListEvent).id)
timestamps.add((listItems[it] as ListEvent).startTS)
}
DeleteEventDialog(activity, eventIds) {
val listItemsToDelete = ArrayList<ListItem>(selectedPositions.size)
selectedPositions.sortedDescending().forEach {
val listItem = listItems[it]
listItemsToDelete.add(listItem)
}
listItems.removeAll(listItemsToDelete)
if (it) {
listener?.deleteItems(eventIds)
} else {
listener?.addEventRepeatException(eventIds, timestamps)
}
finishActMode()
}
}
}

View file

@ -1,140 +0,0 @@
package com.simplemobiletools.calendar.adapters
import android.content.Context
import android.content.Intent
import android.view.View
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.R.id.event_item_holder
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.EVENT_ID
import com.simplemobiletools.calendar.helpers.EVENT_OCCURRENCE_TS
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.models.ListEvent
import com.simplemobiletools.calendar.models.ListItem
import com.simplemobiletools.calendar.models.ListSection
import com.simplemobiletools.commons.extensions.getColoredBitmap
import com.simplemobiletools.commons.extensions.setText
import com.simplemobiletools.commons.extensions.setTextSize
import org.joda.time.DateTime
import java.util.*
class EventListWidgetAdapter(val context: Context) : RemoteViewsService.RemoteViewsFactory {
private val ITEM_EVENT = 0
private val ITEM_HEADER = 1
private val allDayString = context.resources.getString(R.string.all_day)
private var events = ArrayList<ListItem>()
private val textColor = context.config.widgetTextColor
private val replaceDescription = context.config.replaceDescription
private var mediumFontSize = context.config.getFontSize()
private var todayDate = ""
override fun getViewAt(position: Int): RemoteViews? {
val type = getItemViewType(position)
val remoteView: RemoteViews
if (type == ITEM_EVENT) {
val item = events[position] as ListEvent
remoteView = RemoteViews(context.packageName, R.layout.event_list_item_widget).apply {
setText(R.id.event_section_title, item.title)
setText(R.id.event_item_description, if (replaceDescription) item.location else item.description)
setText(R.id.event_item_start, if (item.isAllDay) allDayString else Formatter.getTimeFromTS(context, item.startTS))
setImageViewBitmap(R.id.event_item_color, context.resources.getColoredBitmap(R.drawable.monthly_event_dot, item.color))
if (item.startTS == item.endTS) {
setViewVisibility(R.id.event_item_end, View.INVISIBLE)
} else {
setViewVisibility(R.id.event_item_end, View.VISIBLE)
var endString = Formatter.getTimeFromTS(context, item.endTS)
val startCode = Formatter.getDayCodeFromTS(item.startTS)
val endCode = Formatter.getDayCodeFromTS(item.endTS)
if (startCode != endCode) {
if (item.isAllDay) {
endString = Formatter.getDateFromCode(context, endCode, true)
} else {
endString += " (${Formatter.getDateFromCode(context, endCode, true)})"
}
} else if (item.isAllDay) {
setViewVisibility(R.id.event_item_end, View.INVISIBLE)
}
setText(R.id.event_item_end, endString)
}
setTextColor(R.id.event_section_title, textColor)
setTextColor(R.id.event_item_description, textColor)
setTextColor(R.id.event_item_start, textColor)
setTextColor(R.id.event_item_end, textColor)
setTextSize(R.id.event_section_title, mediumFontSize)
setTextSize(R.id.event_item_description, mediumFontSize)
setTextSize(R.id.event_item_start, mediumFontSize)
setTextSize(R.id.event_item_end, mediumFontSize)
Intent().apply {
putExtra(EVENT_ID, item.id)
putExtra(EVENT_OCCURRENCE_TS, item.startTS)
setOnClickFillInIntent(event_item_holder, this)
}
}
} else {
val item = events[position] as ListSection
remoteView = RemoteViews(context.packageName, R.layout.event_list_section_widget).apply {
setTextColor(R.id.event_section_title, textColor)
setTextSize(R.id.event_section_title, mediumFontSize)
setText(R.id.event_section_title, item.title)
}
}
return remoteView
}
private fun getItemViewType(position: Int) = if (events[position] is ListEvent) ITEM_EVENT else ITEM_HEADER
override fun getLoadingView() = null
override fun getViewTypeCount() = 2
override fun onCreate() {
val now = (System.currentTimeMillis() / 1000).toInt()
val todayCode = Formatter.getDayCodeFromTS(now)
todayDate = Formatter.getDayTitle(context, todayCode)
}
override fun getItemId(position: Int) = position.toLong()
override fun onDataSetChanged() {
mediumFontSize = context.config.getFontSize()
val fromTS = DateTime().seconds() - context.config.displayPastEvents * 60
val toTS = DateTime().plusYears(1).seconds()
context.dbHelper.getEventsInBackground(fromTS, toTS) {
val listItems = ArrayList<ListItem>(it.size)
val replaceDescription = context.config.replaceDescription
val sorted = it.sortedWith(compareBy({ it.startTS }, { it.endTS }, { it.title }, { if (replaceDescription) it.location else it.description }))
val sublist = sorted.subList(0, Math.min(sorted.size, 100))
var prevCode = ""
sublist.forEach {
val code = Formatter.getDayCodeFromTS(it.startTS)
if (code != prevCode) {
val day = Formatter.getDayTitle(context, code)
if (day != todayDate)
listItems.add(ListSection(day))
prevCode = code
}
listItems.add(ListEvent(it.id, it.startTS, it.endTS, it.title, it.description, it.getIsAllDay(), it.color, it.location))
}
this@EventListWidgetAdapter.events = listItems
}
}
override fun hasStableIds() = true
override fun getCount() = events.size
override fun onDestroy() {}
}

View file

@ -1,86 +0,0 @@
package com.simplemobiletools.calendar.adapters
import android.support.v7.widget.RecyclerView
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.extensions.setBackgroundWithStroke
import com.simplemobiletools.commons.interfaces.MyAdapterListener
import kotlinx.android.synthetic.main.filter_event_type_view.view.*
import java.util.*
class FilterEventTypeAdapter(val activity: SimpleActivity, val eventTypes: List<EventType>, val displayEventTypes: Set<String>) :
RecyclerView.Adapter<FilterEventTypeAdapter.ViewHolder>() {
private val itemViews = SparseArray<View>()
private val selectedPositions = HashSet<Int>()
init {
eventTypes.forEachIndexed { index, eventType ->
if (displayEventTypes.contains(eventType.id.toString())) {
selectedPositions.add(index)
}
}
}
private fun toggleItemSelection(select: Boolean, pos: Int) {
if (select) {
if (itemViews[pos] != null) {
selectedPositions.add(pos)
}
} else {
selectedPositions.remove(pos)
}
itemViews[pos]?.filter_event_type_checkbox?.isChecked = select
}
private val adapterListener = object : MyAdapterListener {
override fun toggleItemSelectionAdapter(select: Boolean, position: Int) {
toggleItemSelection(select, position)
}
override fun getSelectedPositions() = selectedPositions
override fun itemLongClicked(position: Int) {}
}
fun getSelectedItemsSet(): HashSet<String> {
val selectedItemsSet = HashSet<String>(selectedPositions.size)
selectedPositions.forEach { selectedItemsSet.add(eventTypes[it].id.toString()) }
return selectedItemsSet
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = activity.layoutInflater.inflate(R.layout.filter_event_type_view, parent, false)
return ViewHolder(view, adapterListener, activity)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val eventType = eventTypes[position]
itemViews.put(position, holder.bindView(eventType))
toggleItemSelection(selectedPositions.contains(position), position)
}
override fun getItemCount() = eventTypes.size
class ViewHolder(view: View, val adapterListener: MyAdapterListener, val activity: SimpleActivity) : RecyclerView.ViewHolder(view) {
fun bindView(eventType: EventType): View {
itemView.apply {
filter_event_type_checkbox.setColors(activity.config.textColor, activity.config.primaryColor, activity.config.backgroundColor)
filter_event_type_checkbox.text = eventType.getDisplayTitle()
filter_event_type_color.setBackgroundWithStroke(eventType.color, activity.config.backgroundColor)
filter_event_type_holder.setOnClickListener { viewClicked(!filter_event_type_checkbox.isChecked) }
}
return itemView
}
private fun viewClicked(select: Boolean) {
adapterListener.toggleItemSelectionAdapter(select, adapterPosition)
}
}
}

View file

@ -1,107 +0,0 @@
package com.simplemobiletools.calendar.adapters
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.helpers.DBHelper
import com.simplemobiletools.calendar.interfaces.DeleteEventTypesListener
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.setBackgroundWithStroke
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.views.MyRecyclerView
import kotlinx.android.synthetic.main.item_event_type.view.*
import java.util.*
class ManageEventTypesAdapter(activity: SimpleActivity, val eventTypes: ArrayList<EventType>, val listener: DeleteEventTypesListener?, recyclerView: MyRecyclerView,
itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
override fun getActionMenuId() = R.menu.cab_event_type
override fun prepareActionMode(menu: Menu) {}
override fun prepareItemSelection(view: View) {}
override fun markItemSelection(select: Boolean, view: View?) {
view?.event_item_frame?.isSelected = select
}
override fun actionItemPressed(id: Int) {
when (id) {
R.id.cab_delete -> askConfirmDelete()
}
}
override fun getSelectableItemCount() = eventTypes.size
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int) = createViewHolder(R.layout.item_event_type, parent)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val eventType = eventTypes[position]
val view = holder.bindView(eventType) { itemView, layoutPosition ->
setupView(itemView, eventType)
}
bindViewHolder(holder, position, view)
}
override fun getItemCount() = eventTypes.size
private fun setupView(view: View, eventType: EventType) {
view.apply {
event_type_title.text = eventType.getDisplayTitle()
event_type_color.setBackgroundWithStroke(eventType.color, activity.config.backgroundColor)
event_type_title.setTextColor(textColor)
}
}
private fun askConfirmDelete() {
val eventTypes = ArrayList<EventType>(selectedPositions.size)
selectedPositions.forEach { eventTypes.add(this.eventTypes[it]) }
if (activity.dbHelper.doEventTypesContainEvent(eventTypes)) {
val MOVE_EVENTS = 0
val DELETE_EVENTS = 1
val res = activity.resources
val items = ArrayList<RadioItem>().apply {
add(RadioItem(MOVE_EVENTS, res.getString(R.string.move_events_into_default)))
add(RadioItem(DELETE_EVENTS, res.getString(R.string.remove_affected_events)))
}
RadioGroupDialog(activity, items) {
deleteEventTypes(it == DELETE_EVENTS)
}
} else {
ConfirmationDialog(activity) {
deleteEventTypes(true)
}
}
}
private fun deleteEventTypes(deleteEvents: Boolean) {
val eventTypesToDelete = ArrayList<EventType>(selectedPositions.size)
for (pos in selectedPositions) {
if (eventTypes[pos].id == DBHelper.REGULAR_EVENT_TYPE_ID) {
activity.toast(R.string.cannot_delete_default_type)
selectedPositions.remove(pos)
toggleItemSelection(false, pos)
break
}
}
selectedPositions.sortedDescending().forEach {
val eventType = eventTypes[it]
eventTypesToDelete.add(eventType)
}
eventTypes.removeAll(eventTypesToDelete)
listener?.deleteEventTypes(eventTypesToDelete, deleteEvents)
removeSelectedItems()
}
}

View file

@ -1,39 +0,0 @@
package com.simplemobiletools.calendar.adapters
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentStatePagerAdapter
import android.util.SparseArray
import com.simplemobiletools.calendar.fragments.WeekFragment
import com.simplemobiletools.calendar.helpers.WEEK_START_TIMESTAMP
class MyWeekPagerAdapter(fm: FragmentManager, val mWeekTimestamps: List<Int>, val mListener: WeekFragment.WeekScrollListener) : FragmentStatePagerAdapter(fm) {
private val mFragments = SparseArray<WeekFragment>()
override fun getCount() = mWeekTimestamps.size
override fun getItem(position: Int): Fragment {
val bundle = Bundle()
val weekTimestamp = mWeekTimestamps[position]
bundle.putInt(WEEK_START_TIMESTAMP, weekTimestamp)
val fragment = WeekFragment()
fragment.arguments = bundle
fragment.mListener = mListener
mFragments.put(position, fragment)
return fragment
}
fun updateScrollY(pos: Int, y: Int) {
mFragments[pos - 1]?.updateScrollY(y)
mFragments[pos + 1]?.updateScrollY(y)
}
fun refreshEvents(pos: Int) {
for (i in -1..1) {
mFragments[pos + i]?.updateEvents()
}
}
}

View file

@ -1,57 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.app.Activity
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import android.view.WindowManager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.value
import kotlinx.android.synthetic.main.dialog_custom_event_reminder.view.*
class CustomEventReminderDialog(val activity: Activity, val selectedMinutes: Int = 0, val callback: (minutes: Int) -> Unit) {
var dialog: AlertDialog
var view = (activity.layoutInflater.inflate(R.layout.dialog_custom_event_reminder, null) as ViewGroup).apply {
when {
selectedMinutes == 0 -> dialog_radio_view.check(R.id.dialog_radio_minutes)
selectedMinutes % 1440 == 0 -> {
dialog_radio_view.check(R.id.dialog_radio_days)
dialog_custom_reminder_value.setText((selectedMinutes / 1440).toString())
}
selectedMinutes % 60 == 0 -> {
dialog_radio_view.check(R.id.dialog_radio_hours)
dialog_custom_reminder_value.setText((selectedMinutes / 60).toString())
}
else -> {
dialog_radio_view.check(R.id.dialog_radio_minutes)
dialog_custom_reminder_value.setText(selectedMinutes.toString())
}
}
}
init {
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, { dialogInterface, i -> confirmReminder() })
.setNegativeButton(R.string.cancel, null)
.create().apply {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
activity.setupDialogStuff(view, this)
}
}
private fun confirmReminder() {
val value = view.dialog_custom_reminder_value.value
val multiplier = getMultiplier(view.dialog_radio_view.checkedRadioButtonId)
val minutes = Integer.valueOf(if (value.isEmpty()) "0" else value)
callback(minutes * multiplier)
activity.hideKeyboard()
dialog.dismiss()
}
private fun getMultiplier(id: Int) = when (id) {
R.id.dialog_radio_hours -> 60
R.id.dialog_radio_days -> 1440
else -> 1
}
}

View file

@ -1,41 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.app.Activity
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.dialog_delete_event.view.*
class DeleteEventDialog(val activity: Activity, eventIds: List<Int>, val callback: (allOccurrences: Boolean) -> Unit) {
val dialog: AlertDialog?
init {
val events = activity.dbHelper.getEventsWithIds(eventIds)
val hasRepeatableEvent = events.any { it.repeatInterval > 0 }
val view = activity.layoutInflater.inflate(R.layout.dialog_delete_event, null).apply {
delete_event_repeat_description.beVisibleIf(hasRepeatableEvent)
delete_event_radio_view.beVisibleIf(hasRepeatableEvent)
if (eventIds.size > 1) {
delete_event_repeat_description.text = resources.getString(R.string.selection_contains_repetition)
}
}
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.yes, { dialog, which -> dialogConfirmed(view as ViewGroup, hasRepeatableEvent) })
.setNegativeButton(R.string.no, null)
.create().apply {
activity.setupDialogStuff(view, this)
}
}
private fun dialogConfirmed(view: ViewGroup, hasRepeatableEvent: Boolean) {
val deleteAllOccurrences = !hasRepeatableEvent || view.delete_event_radio_view.checkedRadioButtonId == R.id.delete_event_all
dialog?.dismiss()
callback(deleteAllOccurrences)
}
}

View file

@ -1,63 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import android.widget.LinearLayout
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.adapters.FilterEventTypeAdapter
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.commons.extensions.*
import kotlinx.android.synthetic.main.dialog_export_events.view.*
import java.io.File
class ExportEventsDialog(val activity: SimpleActivity, val path: String, val callback: (exportPastEvents: Boolean, file: File, eventTypes: HashSet<String>) -> Unit) {
init {
val view = (activity.layoutInflater.inflate(R.layout.dialog_export_events, null) as ViewGroup).apply {
export_events_folder.text = activity.humanizePath(path)
export_events_filename.setText("events_${System.currentTimeMillis() / 1000}")
activity.dbHelper.getEventTypes {
val eventTypes = HashSet<String>()
it.mapTo(eventTypes, { it.id.toString() })
activity.runOnUiThread {
export_events_types_list.adapter = FilterEventTypeAdapter(activity, it, eventTypes)
if (it.size > 1) {
export_events_pick_types.beVisible()
val margin = activity.resources.getDimension(R.dimen.normal_margin).toInt()
(export_events_checkbox.layoutParams as LinearLayout.LayoutParams).leftMargin = margin
}
}
}
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this, R.string.export_events) {
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val filename = view.export_events_filename.value
when {
filename.isEmpty() -> activity.toast(R.string.empty_name)
filename.isAValidFilename() -> {
val file = File(path, "$filename.ics")
if (file.exists()) {
activity.toast(R.string.name_taken)
return@setOnClickListener
}
val eventTypes = (view.export_events_types_list.adapter as FilterEventTypeAdapter).getSelectedItemsSet()
callback(view.export_events_checkbox.isChecked, file, eventTypes)
dismiss()
}
else -> activity.toast(R.string.invalid_name)
}
}
}
}
}
}

View file

@ -1,37 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.support.v7.app.AlertDialog
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.adapters.FilterEventTypeAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.dialog_filter_event_types.view.*
class FilterEventTypesDialog(val activity: SimpleActivity, val callback: () -> Unit) {
var dialog: AlertDialog
val view = activity.layoutInflater.inflate(R.layout.dialog_filter_event_types, null)
init {
val eventTypes = activity.dbHelper.fetchEventTypes()
val displayEventTypes = activity.config.displayEventTypes
view.filter_event_types_list.adapter = FilterEventTypeAdapter(activity, eventTypes, displayEventTypes)
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, { dialogInterface, i -> confirmEventTypes() })
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this, R.string.filter_events_by_type)
}
}
private fun confirmEventTypes() {
val selectedItems = (view.filter_event_types_list.adapter as FilterEventTypeAdapter).getSelectedItemsSet()
if (activity.config.displayEventTypes != selectedItems) {
activity.config.displayEventTypes = selectedItems
callback()
}
dialog.dismiss()
}
}

View file

@ -1,62 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.helpers.DBHelper
import com.simplemobiletools.calendar.helpers.IcsImporter
import com.simplemobiletools.calendar.helpers.IcsImporter.ImportResult.*
import com.simplemobiletools.commons.extensions.setBackgroundWithStroke
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.toast
import kotlinx.android.synthetic.main.dialog_import_events.view.*
class ImportEventsDialog(val activity: SimpleActivity, val path: String, val callback: (refreshView: Boolean) -> Unit) {
var currEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
init {
val view = (activity.layoutInflater.inflate(R.layout.dialog_import_events, null) as ViewGroup).apply {
updateEventType(this)
import_event_type_holder.setOnClickListener {
SelectEventTypeDialog(activity, currEventTypeId) {
currEventTypeId = it
updateEventType(this)
}
}
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this, R.string.import_events) {
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
activity.toast(R.string.importing)
Thread {
val result = IcsImporter(activity).importEvents(path, currEventTypeId)
handleParseResult(result)
dismiss()
}.start()
}
}
}
}
private fun updateEventType(view: ViewGroup) {
val eventType = activity.dbHelper.getEventType(currEventTypeId)
view.import_event_type_title.text = eventType!!.getDisplayTitle()
view.import_event_type_color.setBackgroundWithStroke(eventType.color, activity.config.backgroundColor)
}
private fun handleParseResult(result: IcsImporter.ImportResult) {
activity.toast(when (result) {
IMPORT_OK -> R.string.events_imported_successfully
IMPORT_PARTIAL -> R.string.importing_some_events_failed
else -> R.string.importing_events_failed
})
callback(result != IMPORT_FAIL)
}
}

View file

@ -1,61 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.app.Activity
import android.graphics.Color
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.RadioGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.CalDAVHandler
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.extensions.setBackgroundWithStroke
import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.dialog_select_radio_group.view.*
import kotlinx.android.synthetic.main.radio_button_with_color.view.*
class SelectEventTypeColorDialog(val activity: Activity, val eventType: EventType, val callback: (color: Int) -> Unit) {
private val dialog: AlertDialog?
private val radioGroup: RadioGroup
private var wasInit = false
private val colors = CalDAVHandler(activity).getAvailableCalDAVCalendarColors(eventType)
init {
val view = activity.layoutInflater.inflate(R.layout.dialog_select_radio_group, null) as ViewGroup
radioGroup = view.dialog_radio_group
colors.forEachIndexed { index, value ->
addRadioButton(index, value)
}
wasInit = true
dialog = AlertDialog.Builder(activity)
.create().apply {
activity.setupDialogStuff(view, this)
}
}
private fun addRadioButton(colorKey: Int, color: Int) {
val view = activity.layoutInflater.inflate(R.layout.radio_button_with_color, null)
(view.dialog_radio_button as RadioButton).apply {
text = String.format("#%06X", 0xFFFFFF and color)
isChecked = color == eventType.color
id = colorKey
}
if (color != Color.TRANSPARENT)
view.dialog_radio_color.setBackgroundWithStroke(color, activity.config.backgroundColor)
view.setOnClickListener { viewClicked(colorKey) }
radioGroup.addView(view, RadioGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
}
private fun viewClicked(colorKey: Int) {
if (!wasInit)
return
callback(colors[colorKey])
dialog?.dismiss()
}
}

View file

@ -1,81 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.app.Activity
import android.graphics.Color
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.RadioGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.setBackgroundWithStroke
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.updateTextColors
import kotlinx.android.synthetic.main.dialog_select_radio_group.view.*
import kotlinx.android.synthetic.main.radio_button_with_color.view.*
import java.util.*
class SelectEventTypeDialog(val activity: Activity, val currEventType: Int, val callback: (checkedId: Int) -> Unit) {
private val NEW_TYPE_ID = -2
private val dialog: AlertDialog?
private val radioGroup: RadioGroup
private var wasInit = false
private var eventTypes = ArrayList<EventType>()
init {
val view = activity.layoutInflater.inflate(R.layout.dialog_select_radio_group, null) as ViewGroup
radioGroup = view.dialog_radio_group
activity.dbHelper.getEventTypes {
eventTypes = it
activity.runOnUiThread {
eventTypes.filter { it.caldavCalendarId == 0 }.forEach {
addRadioButton(it.getDisplayTitle(), it.id, it.color)
}
addRadioButton(activity.getString(R.string.add_new_type), NEW_TYPE_ID, Color.TRANSPARENT)
wasInit = true
activity.updateTextColors(view.dialog_radio_holder)
}
}
dialog = AlertDialog.Builder(activity)
.create().apply {
activity.setupDialogStuff(view, this)
}
}
private fun addRadioButton(title: String, typeId: Int, color: Int) {
val view = activity.layoutInflater.inflate(R.layout.radio_button_with_color, null)
(view.dialog_radio_button as RadioButton).apply {
text = title
isChecked = typeId == currEventType
id = typeId
}
if (color != Color.TRANSPARENT)
view.dialog_radio_color.setBackgroundWithStroke(color, activity.config.backgroundColor)
view.setOnClickListener { viewClicked(typeId) }
radioGroup.addView(view, RadioGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
}
private fun viewClicked(typeId: Int) {
if (!wasInit)
return
if (typeId == NEW_TYPE_ID) {
UpdateEventTypeDialog(activity) {
callback(it)
activity.hideKeyboard()
dialog?.dismiss()
}
} else {
callback(typeId)
dialog?.dismiss()
}
}
}

View file

@ -1,34 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import android.view.WindowManager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.value
import kotlinx.android.synthetic.main.dialog_snooze_picker.view.*
class SnoozePickerDialog(val activity: SimpleActivity, val minutes: Int, val callback: (newMinutes: Int) -> Unit) {
init {
val view = (activity.layoutInflater.inflate(R.layout.dialog_snooze_picker, null) as ViewGroup).apply {
snooze_picker_label.text = snooze_picker_label.text.toString().capitalize()
snooze_picker.setText(minutes.toString())
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this) {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val value = view.snooze_picker.value
val minutes = Integer.valueOf(if (value.isEmpty() || value == "0") "1" else value)
callback(minutes)
dismiss()
}
}
}
}
}

View file

@ -1,88 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import android.app.Activity
import android.support.v7.app.AlertDialog
import android.view.WindowManager
import android.widget.ImageView
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.extensions.setBackgroundWithStroke
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.value
import kotlinx.android.synthetic.main.dialog_event_type.view.*
class UpdateEventTypeDialog(val activity: Activity, var eventType: EventType? = null, val callback: (eventTypeId: Int) -> Unit) {
var isNewEvent = eventType == null
init {
if (eventType == null)
eventType = EventType(0, "", activity.config.primaryColor)
val view = activity.layoutInflater.inflate(R.layout.dialog_event_type, null).apply {
setupColor(type_color)
type_title.setText(eventType!!.title)
type_color.setOnClickListener {
if (eventType?.caldavCalendarId == 0) {
ColorPickerDialog(activity, eventType!!.color) {
eventType!!.color = it
setupColor(type_color)
}
} else {
SelectEventTypeColorDialog(activity, eventType!!) {
eventType!!.color = it
setupColor(type_color)
}
}
}
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
activity.setupDialogStuff(view, this, if (isNewEvent) R.string.add_new_type else R.string.edit_type) {
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val title = view.type_title.value
val eventIdWithTitle = activity.dbHelper.getEventTypeIdWithTitle(title)
var isEventTypeTitleTaken = isNewEvent && eventIdWithTitle != -1
if (!isEventTypeTitleTaken)
isEventTypeTitleTaken = !isNewEvent && eventType!!.id != eventIdWithTitle && eventIdWithTitle != -1
if (title.isEmpty()) {
activity.toast(R.string.title_empty)
return@setOnClickListener
} else if (isEventTypeTitleTaken) {
activity.toast(R.string.type_already_exists)
return@setOnClickListener
}
eventType!!.title = title
if (eventType!!.caldavCalendarId != 0)
eventType!!.caldavDisplayName = title
val eventTypeId = if (isNewEvent) {
activity.dbHelper.insertEventType(eventType!!)
} else {
activity.dbHelper.updateEventType(eventType!!)
}
if (eventTypeId != -1) {
dismiss()
callback(eventTypeId)
} else {
activity.toast(R.string.editing_calendar_failed)
}
}
}
}
}
private fun setupColor(view: ImageView) {
view.setBackgroundWithStroke(eventType!!.color, activity.config.backgroundColor)
}
}

View file

@ -1,38 +0,0 @@
package com.simplemobiletools.calendar.extensions
import com.simplemobiletools.calendar.BuildConfig
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.helpers.IcsExporter
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.getFilePublicUri
import com.simplemobiletools.commons.extensions.shareUri
import com.simplemobiletools.commons.extensions.toast
import java.io.File
fun BaseSimpleActivity.shareEvents(ids: List<Int>) {
val file = getTempFile()
if (file == null) {
toast(R.string.unknown_error_occurred)
return
}
val events = dbHelper.getEventsWithIds(ids)
IcsExporter().exportEvents(this, file, events) {
if (it == IcsExporter.ExportResult.EXPORT_OK) {
val uri = getFilePublicUri(file, BuildConfig.APPLICATION_ID)
shareUri(uri, BuildConfig.APPLICATION_ID)
}
}
}
fun BaseSimpleActivity.getTempFile(): File? {
val folder = File(cacheDir, "events")
if (!folder.exists()) {
if (!folder.mkdir()) {
toast(R.string.unknown_error_occurred)
return null
}
}
return File(folder, "events.ics")
}

View file

@ -1,8 +0,0 @@
package com.simplemobiletools.calendar.extensions
import java.io.BufferedWriter
fun BufferedWriter.writeLn(line: String) {
write(line)
newLine()
}

View file

@ -1,325 +0,0 @@
package com.simplemobiletools.calendar.extensions
import android.annotation.SuppressLint
import android.app.*
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.net.Uri
import android.support.v4.app.NotificationCompat
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.models.DayMonthly
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.receivers.CalDAVSyncReceiver
import com.simplemobiletools.calendar.receivers.NotificationReceiver
import com.simplemobiletools.calendar.services.SnoozeService
import com.simplemobiletools.commons.extensions.*
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import java.text.SimpleDateFormat
import java.util.*
val Context.config: Config get() = Config.newInstance(applicationContext)
val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext)
fun Context.updateWidgets() {
val widgetsCnt = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(ComponentName(applicationContext, MyWidgetMonthlyProvider::class.java))
if (widgetsCnt.isNotEmpty()) {
val ids = intArrayOf(R.xml.widget_monthly_info)
Intent(applicationContext, MyWidgetMonthlyProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
sendBroadcast(this)
}
}
updateListWidget()
}
fun Context.updateListWidget() {
val widgetsCnt = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(ComponentName(applicationContext, MyWidgetListProvider::class.java))
if (widgetsCnt.isNotEmpty()) {
val ids = intArrayOf(R.xml.widget_list_info)
Intent(applicationContext, MyWidgetListProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
sendBroadcast(this)
}
}
}
fun Context.scheduleAllEvents() {
val events = dbHelper.getEventsAtReboot()
events.forEach {
scheduleNextEventReminder(it, dbHelper)
}
}
fun Context.scheduleNextEventReminder(event: Event, dbHelper: DBHelper) {
if (event.getReminders().isEmpty())
return
val now = (System.currentTimeMillis() / 1000).toInt()
val reminderSeconds = event.getReminders().reversed().map { it * 60 }
dbHelper.getEvents(now, now + YEAR, event.id) {
if (it.isNotEmpty()) {
for (curEvent in it) {
for (curReminder in reminderSeconds) {
if (curEvent.getEventStartTS() - curReminder > now) {
scheduleEventIn((curEvent.getEventStartTS() - curReminder) * 1000L, curEvent)
return@getEvents
}
}
}
}
}
}
fun Context.scheduleEventIn(notifTS: Long, event: Event) {
if (notifTS < System.currentTimeMillis())
return
val pendingIntent = getNotificationIntent(applicationContext, event)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
when {
isMarshmallowPlus() -> alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, notifTS, pendingIntent)
isKitkatPlus() -> alarmManager.setExact(AlarmManager.RTC_WAKEUP, notifTS, pendingIntent)
else -> alarmManager.set(AlarmManager.RTC_WAKEUP, notifTS, pendingIntent)
}
}
fun Context.cancelNotification(id: Int) {
val intent = Intent(applicationContext, NotificationReceiver::class.java)
PendingIntent.getBroadcast(applicationContext, id, intent, PendingIntent.FLAG_UPDATE_CURRENT).cancel()
}
private fun getNotificationIntent(context: Context, event: Event): PendingIntent {
val intent = Intent(context, NotificationReceiver::class.java)
intent.putExtra(EVENT_ID, event.id)
intent.putExtra(EVENT_OCCURRENCE_TS, event.startTS)
return PendingIntent.getBroadcast(context, event.id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
fun Context.getFormattedMinutes(minutes: Int, showBefore: Boolean = true) = when (minutes) {
-1 -> getString(R.string.no_reminder)
0 -> getString(R.string.at_start)
else -> {
if (minutes % 525600 == 0)
resources.getQuantityString(R.plurals.years, minutes / 525600, minutes / 525600)
when {
minutes % 43200 == 0 -> resources.getQuantityString(R.plurals.months, minutes / 43200, minutes / 43200)
minutes % 10080 == 0 -> resources.getQuantityString(R.plurals.weeks, minutes / 10080, minutes / 10080)
minutes % 1440 == 0 -> resources.getQuantityString(R.plurals.days, minutes / 1440, minutes / 1440)
minutes % 60 == 0 -> {
val base = if (showBefore) R.plurals.hours_before else R.plurals.by_hours
resources.getQuantityString(base, minutes / 60, minutes / 60)
}
else -> {
val base = if (showBefore) R.plurals.minutes_before else R.plurals.by_minutes
resources.getQuantityString(base, minutes, minutes)
}
}
}
}
fun Context.getRepetitionText(seconds: Int) = when (seconds) {
0 -> getString(R.string.no_repetition)
DAY -> getString(R.string.daily)
WEEK -> getString(R.string.weekly)
MONTH -> getString(R.string.monthly)
YEAR -> getString(R.string.yearly)
else -> {
when {
seconds % YEAR == 0 -> resources.getQuantityString(R.plurals.years, seconds / YEAR, seconds / YEAR)
seconds % MONTH == 0 -> resources.getQuantityString(R.plurals.months, seconds / MONTH, seconds / MONTH)
seconds % WEEK == 0 -> resources.getQuantityString(R.plurals.weeks, seconds / WEEK, seconds / WEEK)
else -> resources.getQuantityString(R.plurals.days, seconds / DAY, seconds / DAY)
}
}
}
fun Context.getFilteredEvents(events: List<Event>): List<Event> {
val displayEventTypes = config.displayEventTypes
return events.filter { displayEventTypes.contains(it.eventType.toString()) }
}
fun Context.notifyRunningEvents() {
dbHelper.getRunningEvents().forEach { notifyEvent(it) }
}
fun Context.notifyEvent(event: Event) {
val pendingIntent = getPendingIntent(applicationContext, event)
val startTime = Formatter.getTimeFromTS(applicationContext, event.startTS)
val endTime = Formatter.getTimeFromTS(applicationContext, event.endTS)
val timeRange = if (event.getIsAllDay()) getString(R.string.all_day) else getFormattedEventTime(startTime, endTime)
val descriptionOrLocation = if (config.replaceDescription) event.location else event.description
val notification = getNotification(applicationContext, pendingIntent, event, "$timeRange $descriptionOrLocation")
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(event.id, notification)
}
@SuppressLint("NewApi")
private fun getNotification(context: Context, pendingIntent: PendingIntent, event: Event, content: String): Notification {
val channelId = "reminder_channel"
if (context.isOreoPlus()) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val name = context.resources.getString(R.string.event_reminders)
val importance = NotificationManager.IMPORTANCE_HIGH
NotificationChannel(channelId, name, importance).apply {
enableLights(true)
lightColor = event.color
enableVibration(false)
notificationManager.createNotificationChannel(this)
}
}
val soundUri = Uri.parse(context.config.reminderSound)
val builder = NotificationCompat.Builder(context)
.setContentTitle(event.title)
.setContentText(content)
.setSmallIcon(R.drawable.ic_calendar)
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_LIGHTS)
.setAutoCancel(true)
.setSound(soundUri)
.setChannelId(channelId)
.addAction(R.drawable.ic_snooze, context.getString(R.string.snooze), getSnoozePendingIntent(context, event))
if (context.isLollipopPlus())
builder.setVisibility(Notification.VISIBILITY_PUBLIC)
if (context.config.vibrateOnReminder)
builder.setVibrate(longArrayOf(0, 300, 300, 300))
return builder.build()
}
private fun getFormattedEventTime(startTime: String, endTime: String) = if (startTime == endTime) startTime else "$startTime - $endTime"
private fun getPendingIntent(context: Context, event: Event): PendingIntent {
val intent = Intent(context, EventActivity::class.java)
intent.putExtra(EVENT_ID, event.id)
intent.putExtra(EVENT_OCCURRENCE_TS, event.startTS)
return PendingIntent.getActivity(context, event.id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun getSnoozePendingIntent(context: Context, event: Event): PendingIntent {
val intent = Intent(context, SnoozeService::class.java).setAction("snooze")
intent.putExtra(EVENT_ID, event.id)
intent.putExtra(EVENT_OCCURRENCE_TS, event.startTS)
return PendingIntent.getService(context, event.id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
fun Context.launchNewEventIntent() {
val code = Formatter.getDayCodeFromDateTime(DateTime(DateTimeZone.getDefault()))
Intent(applicationContext, EventActivity::class.java).apply {
putExtra(NEW_EVENT_START_TS, getNewEventTimestampFromCode(code))
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(this)
}
}
fun Context.getNewEventTimestampFromCode(dayCode: String): Int {
val currHour = DateTime(System.currentTimeMillis(), DateTimeZone.getDefault()).hourOfDay
val dateTime = Formatter.getLocalDateTimeFromCode(dayCode).withHourOfDay(currHour)
val newDateTime = dateTime.plusHours(1).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0)
// make sure the date doesn't change
return newDateTime.withDate(dateTime.year, dateTime.monthOfYear, dateTime.dayOfMonth).seconds()
}
fun Context.getCurrentOffset() = SimpleDateFormat("Z", Locale.getDefault()).format(Date())
fun Context.getSyncedCalDAVCalendars() = CalDAVHandler(applicationContext).getCalDAVCalendars(null, config.caldavSyncedCalendarIDs)
fun Context.recheckCalDAVCalendars(callback: () -> Unit) {
if (config.caldavSync) {
Thread {
CalDAVHandler(applicationContext).refreshCalendars(null, callback)
updateWidgets()
}.start()
}
}
fun Context.scheduleCalDAVSync(activate: Boolean) {
val syncIntent = Intent(applicationContext, CalDAVSyncReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(applicationContext, 0, syncIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager
if (activate) {
val syncCheckInterval = 4 * AlarmManager.INTERVAL_HOUR
alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + syncCheckInterval, syncCheckInterval, pendingIntent)
} else {
alarm.cancel(pendingIntent)
}
}
fun Context.addDayNumber(rawTextColor: Int, day: DayMonthly, linearLayout: LinearLayout, dayLabelHeight: Int, callback: (Int) -> Unit) {
var textColor = rawTextColor
if (!day.isThisMonth)
textColor = textColor.adjustAlpha(LOW_ALPHA)
(View.inflate(applicationContext, R.layout.day_monthly_number_view, null) as TextView).apply {
setTextColor(textColor)
text = day.value.toString()
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
linearLayout.addView(this)
if (day.isToday) {
val primaryColor = config.primaryColor
setTextColor(config.primaryColor.getContrastColor())
if (dayLabelHeight == 0) {
onGlobalLayout {
val height = this@apply.height
if (height > 0) {
callback(height)
addTodaysBackground(this, resources, height, primaryColor)
}
}
} else {
addTodaysBackground(this, resources, dayLabelHeight, primaryColor)
}
}
}
}
private fun addTodaysBackground(textView: TextView, res: Resources, dayLabelHeight: Int, mPrimaryColor: Int) =
textView.addResizedBackgroundDrawable(res, dayLabelHeight, mPrimaryColor, R.drawable.monthly_today_circle)
fun Context.addDayEvents(day: DayMonthly, linearLayout: LinearLayout, res: Resources, dividerMargin: Int) {
val eventLayoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
day.dayEvents.sortedWith(compareBy({ it.startTS }, { it.endTS }, { it.title })).forEach {
val backgroundDrawable = res.getDrawable(R.drawable.day_monthly_event_background)
backgroundDrawable.applyColorFilter(it.color)
eventLayoutParams.setMargins(dividerMargin, 0, dividerMargin, dividerMargin)
var textColor = it.color.getContrastColor()
if (!day.isThisMonth) {
backgroundDrawable.alpha = 64
textColor = textColor.adjustAlpha(0.25f)
}
(View.inflate(applicationContext, R.layout.day_monthly_event_view, null) as TextView).apply {
setTextColor(textColor)
text = it.title.replace(" ", "\u00A0") // allow word break by char
background = backgroundDrawable
layoutParams = eventLayoutParams
linearLayout.addView(this)
}
}
}

View file

@ -1,5 +0,0 @@
package com.simplemobiletools.calendar.extensions
import org.joda.time.DateTime
fun DateTime.seconds() = (millis / 1000).toInt()

View file

@ -1,16 +0,0 @@
package com.simplemobiletools.calendar.extensions
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.helpers.MONTH
import com.simplemobiletools.calendar.helpers.WEEK
import com.simplemobiletools.calendar.models.Event
fun Int.isTsOnProperDay(event: Event): Boolean {
val dateTime = Formatter.getDateTimeFromTS(this)
val power = Math.pow(2.0, (dateTime.dayOfWeek - 1).toDouble()).toInt()
return event.repeatRule and power != 0
}
fun Int.isXWeeklyRepetition() = this != 0 && this % WEEK == 0
fun Int.isXMonthlyRepetition() = this != 0 && this % MONTH == 0

View file

@ -1,8 +0,0 @@
package com.simplemobiletools.calendar.extensions
fun String.substringTo(cnt: Int): String {
return if (isEmpty()) {
""
} else
substring(0, Math.min(length, cnt))
}

View file

@ -1,170 +0,0 @@
package com.simplemobiletools.calendar.fragments
import android.content.Intent
import android.content.res.Resources
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.DatePicker
import android.widget.RelativeLayout
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.DayActivity
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.adapters.DayEventsAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.getFilteredEvents
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.helpers.EVENT_ID
import com.simplemobiletools.calendar.helpers.EVENT_OCCURRENCE_TS
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.DeleteEventsListener
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.getDialogTheme
import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.fragment_day.view.*
import kotlinx.android.synthetic.main.top_navigation.view.*
import org.joda.time.DateTime
import java.util.*
class DayFragment : Fragment(), DeleteEventsListener {
var mListener: NavigationListener? = null
private var mTextColor = 0
private var mDayCode = ""
private var lastHash = 0
lateinit var mRes: Resources
lateinit var mHolder: RelativeLayout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_day, container, false)
mRes = resources
mHolder = view.day_holder
mDayCode = arguments!!.getString(DAY_CODE)
val day = Formatter.getDayTitle(context!!, mDayCode)
mHolder.top_value.apply {
text = day
setOnClickListener { pickDay() }
setTextColor(context.config.textColor)
}
setupButtons()
return view
}
override fun onResume() {
super.onResume()
checkEvents()
}
private fun setupButtons() {
mTextColor = context!!.config.textColor
mHolder.apply {
top_left_arrow.applyColorFilter(mTextColor)
top_right_arrow.applyColorFilter(mTextColor)
top_left_arrow.background = null
top_right_arrow.background = null
top_left_arrow.setOnClickListener {
mListener?.goLeft()
}
top_right_arrow.setOnClickListener {
mListener?.goRight()
}
}
}
fun getDayEventsAdapter() = mHolder.day_events?.adapter as? DayEventsAdapter
private fun pickDay() {
activity!!.setTheme(context!!.getDialogTheme())
val view = layoutInflater.inflate(R.layout.date_picker, null)
val datePicker = view.findViewById<DatePicker>(R.id.date_picker)
val dateTime = Formatter.getDateTimeFromCode(mDayCode)
datePicker.init(dateTime.year, dateTime.monthOfYear - 1, dateTime.dayOfMonth, null)
AlertDialog.Builder(context!!)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok) { dialog, which -> positivePressed(dateTime, datePicker) }
.create().apply {
activity?.setupDialogStuff(view, this)
}
}
private fun positivePressed(dateTime: DateTime, datePicker: DatePicker) {
val month = datePicker.month + 1
val year = datePicker.year
val day = datePicker.dayOfMonth
val newDateTime = dateTime.withDate(year, month, day)
mListener?.goToDateTime(newDateTime)
}
fun checkEvents() {
val startTS = Formatter.getDayStartTS(mDayCode)
val endTS = Formatter.getDayEndTS(mDayCode)
context!!.dbHelper.getEvents(startTS, endTS) {
receivedEvents(it)
}
}
private fun receivedEvents(events: List<Event>) {
val filtered = context?.getFilteredEvents(events) ?: ArrayList()
val newHash = filtered.hashCode()
if (newHash == lastHash || !isAdded) {
return
}
lastHash = newHash
val replaceDescription = context!!.config.replaceDescription
val sorted = ArrayList<Event>(filtered.sortedWith(compareBy({ it.startTS }, { it.endTS }, { it.title }, {
if (replaceDescription) it.location else it.description
})))
activity?.runOnUiThread {
updateEvents(sorted)
}
}
private fun updateEvents(events: ArrayList<Event>) {
if (activity == null)
return
DayEventsAdapter(activity as SimpleActivity, events, this, mHolder.day_events) {
editEvent(it as Event)
}.apply {
setupDragListener(true)
addVerticalDividers(true)
mHolder.day_events.adapter = this
}
}
private fun editEvent(event: Event) {
Intent(context, EventActivity::class.java).apply {
putExtra(EVENT_ID, event.id)
putExtra(EVENT_OCCURRENCE_TS, event.startTS)
startActivity(this)
}
}
override fun deleteItems(ids: ArrayList<Int>) {
val eventIDs = Array(ids.size, { i -> (ids[i].toString()) })
context!!.dbHelper.deleteEvents(eventIDs, true)
}
override fun addEventRepeatException(parentIds: ArrayList<Int>, timestamps: ArrayList<Int>) {
parentIds.forEachIndexed { index, value ->
context!!.dbHelper.addEventRepeatException(parentIds[index], timestamps[index])
}
(activity as DayActivity).recheckEvents()
}
}

View file

@ -1,130 +0,0 @@
package com.simplemobiletools.calendar.fragments
import android.content.Intent
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.adapters.EventListAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.getFilteredEvents
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.EVENT_ID
import com.simplemobiletools.calendar.helpers.EVENT_OCCURRENCE_TS
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.DeleteEventsListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.ListEvent
import com.simplemobiletools.calendar.models.ListItem
import com.simplemobiletools.calendar.models.ListSection
import com.simplemobiletools.commons.extensions.beGoneIf
import com.simplemobiletools.commons.extensions.beVisibleIf
import kotlinx.android.synthetic.main.fragment_event_list.view.*
import org.joda.time.DateTime
import java.util.*
class EventListFragment : Fragment(), DeleteEventsListener {
private var mEvents: List<Event> = ArrayList()
private var prevEventsHash = 0
private var lastHash = 0
lateinit var mView: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mView = inflater.inflate(R.layout.fragment_event_list, container, false)
val placeholderText = String.format(getString(R.string.two_string_placeholder), "${getString(R.string.no_upcoming_events)}\n", getString(R.string.add_some_events))
mView.calendar_empty_list_placeholder.text = placeholderText
return mView
}
override fun onResume() {
super.onResume()
checkEvents()
}
private fun checkEvents() {
val fromTS = DateTime().seconds() - context!!.config.displayPastEvents * 60
val toTS = DateTime().plusYears(1).seconds()
context!!.dbHelper.getEvents(fromTS, toTS) {
receivedEvents(it)
}
}
private fun receivedEvents(events: MutableList<Event>) {
if (context == null || activity == null)
return
val newHash = events.hashCode()
if (newHash == lastHash) {
return
}
lastHash = newHash
val filtered = context!!.getFilteredEvents(events)
val hash = filtered.hashCode()
if (prevEventsHash == hash)
return
prevEventsHash = hash
mEvents = filtered
val listItems = ArrayList<ListItem>(mEvents.size)
val replaceDescription = context!!.config.replaceDescription
val sorted = mEvents.sortedWith(compareBy({ it.startTS }, { it.endTS }, { it.title }, { if (replaceDescription) it.location else it.description }))
val sublist = sorted.subList(0, Math.min(sorted.size, 100))
var prevCode = ""
sublist.forEach {
val code = Formatter.getDayCodeFromTS(it.startTS)
if (code != prevCode) {
val day = Formatter.getDayTitle(context!!, code)
listItems.add(ListSection(day))
prevCode = code
}
listItems.add(ListEvent(it.id, it.startTS, it.endTS, it.title, it.description, it.getIsAllDay(), it.color, it.location))
}
val eventsAdapter = EventListAdapter(activity as SimpleActivity, listItems, true, this, mView.calendar_events_list) {
if (it is ListEvent) {
editEvent(it)
}
}
activity?.runOnUiThread {
mView.calendar_events_list.apply {
this@apply.adapter = eventsAdapter
}
checkPlaceholderVisibility()
}
}
private fun checkPlaceholderVisibility() {
mView.calendar_empty_list_placeholder.beVisibleIf(mEvents.isEmpty())
mView.calendar_events_list.beGoneIf(mEvents.isEmpty())
if (activity != null)
mView.calendar_empty_list_placeholder.setTextColor(activity!!.config.textColor)
}
private fun editEvent(event: ListEvent) {
Intent(context, EventActivity::class.java).apply {
putExtra(EVENT_ID, event.id)
putExtra(EVENT_OCCURRENCE_TS, event.startTS)
startActivity(this)
}
}
override fun deleteItems(ids: ArrayList<Int>) {
val eventIDs = Array(ids.size, { i -> (ids[i].toString()) })
context!!.dbHelper.deleteEvents(eventIDs, true)
checkEvents()
}
override fun addEventRepeatException(parentIds: ArrayList<Int>, timestamps: ArrayList<Int>) {
parentIds.forEachIndexed { index, value ->
context!!.dbHelper.addEventRepeatException(value, timestamps[index])
}
checkEvents()
}
}

View file

@ -1,201 +0,0 @@
package com.simplemobiletools.calendar.fragments
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.DatePicker
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.DayActivity
import com.simplemobiletools.calendar.extensions.addDayEvents
import com.simplemobiletools.calendar.extensions.addDayNumber
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.models.DayMonthly
import com.simplemobiletools.commons.extensions.*
import kotlinx.android.synthetic.main.first_row.*
import kotlinx.android.synthetic.main.fragment_month.view.*
import kotlinx.android.synthetic.main.top_navigation.view.*
import org.joda.time.DateTime
class MonthFragment : Fragment(), MonthlyCalendar {
private var mTextColor = 0
private var mPrimaryColor = 0
private var mSundayFirst = false
private var mDayCode = ""
private var mPackageName = ""
private var dayLabelHeight = 0
private var lastHash = 0L
var listener: NavigationListener? = null
lateinit var mRes: Resources
lateinit var mHolder: RelativeLayout
lateinit var mConfig: Config
lateinit var mCalendar: MonthlyCalendarImpl
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_month, container, false)
mRes = resources
mPackageName = activity!!.packageName
mHolder = view.calendar_holder
mDayCode = arguments!!.getString(DAY_CODE)
mConfig = context!!.config
mSundayFirst = mConfig.isSundayFirst
setupButtons()
setupLabels()
mCalendar = MonthlyCalendarImpl(this, context!!)
return view
}
override fun onResume() {
super.onResume()
if (mConfig.isSundayFirst != mSundayFirst) {
mSundayFirst = mConfig.isSundayFirst
setupLabels()
}
mCalendar.apply {
mTargetDate = Formatter.getDateTimeFromCode(mDayCode)
getDays(false) // prefill the screen asap, even if without events
}
updateCalendar()
}
fun updateCalendar() {
mCalendar.updateMonthlyCalendar(Formatter.getDateTimeFromCode(mDayCode))
}
override fun updateMonthlyCalendar(context: Context, month: String, days: List<DayMonthly>, checkedEvents: Boolean) {
val newHash = month.hashCode() + days.hashCode().toLong()
if ((lastHash != 0L && !checkedEvents) || lastHash == newHash) {
return
}
lastHash = newHash
activity?.runOnUiThread {
mHolder.top_value.apply {
text = month
setTextColor(mConfig.textColor)
}
updateDays(days)
}
}
private fun setupButtons() {
val baseColor = mConfig.textColor
mTextColor = baseColor
mPrimaryColor = mConfig.primaryColor
mHolder.top_left_arrow.apply {
applyColorFilter(mTextColor)
background = null
setOnClickListener {
listener?.goLeft()
}
}
mHolder.top_right_arrow.apply {
applyColorFilter(mTextColor)
background = null
setOnClickListener {
listener?.goRight()
}
}
mHolder.top_value.setOnClickListener { showMonthDialog() }
}
private fun showMonthDialog() {
activity!!.setTheme(context!!.getDialogTheme())
val view = layoutInflater.inflate(R.layout.date_picker, null)
val datePicker = view.findViewById<DatePicker>(R.id.date_picker)
datePicker.findViewById<View>(Resources.getSystem().getIdentifier("day", "id", "android")).beGone()
val dateTime = DateTime(mCalendar.mTargetDate.toString())
datePicker.init(dateTime.year, dateTime.monthOfYear - 1, 1, null)
AlertDialog.Builder(context!!)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok) { dialog, which -> positivePressed(dateTime, datePicker) }
.create().apply {
activity?.setupDialogStuff(view, this)
}
}
private fun positivePressed(dateTime: DateTime, datePicker: DatePicker) {
val month = datePicker.month + 1
val year = datePicker.year
val newDateTime = dateTime.withDate(year, month, 1)
listener?.goToDateTime(newDateTime)
}
private fun setupLabels() {
val letters = letterIDs
for (i in 0..6) {
var index = i
if (!mSundayFirst)
index = (index + 1) % letters.size
mHolder.findViewById<TextView>(mRes.getIdentifier("label_$i", "id", mPackageName)).apply {
setTextColor(mTextColor)
text = getString(letters[index])
}
}
}
private fun updateDays(days: List<DayMonthly>) {
val displayWeekNumbers = mConfig.displayWeekNumbers
val len = days.size
if (week_num == null)
return
week_num.setTextColor(mTextColor)
week_num.beVisibleIf(displayWeekNumbers)
for (i in 0..5) {
mHolder.findViewById<TextView>(mRes.getIdentifier("week_num_$i", "id", mPackageName)).apply {
text = "${days[i * 7 + 3].weekOfYear}:" // fourth day of the week matters
setTextColor(mTextColor)
beVisibleIf(displayWeekNumbers)
}
}
val dividerMargin = mRes.displayMetrics.density.toInt()
for (i in 0 until len) {
mHolder.findViewById<LinearLayout>(mRes.getIdentifier("day_$i", "id", mPackageName)).apply {
val day = days[i]
setOnClickListener { openDay(day.code) }
removeAllViews()
context.addDayNumber(mTextColor, day, this, dayLabelHeight) { dayLabelHeight = it }
context.addDayEvents(day, this, mRes, dividerMargin)
}
}
}
private fun openDay(code: String) {
if (code.isNotEmpty()) {
Intent(context, DayActivity::class.java).apply {
putExtra(DAY_CODE, code)
startActivity(this)
}
}
}
}

View file

@ -1,440 +0,0 @@
package com.simplemobiletools.calendar.fragments
import android.content.Intent
import android.content.res.Resources
import android.graphics.Rect
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.*
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.activities.MainActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.getFilteredEvents
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.WeeklyCalendar
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.views.MyScrollView
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.beGone
import com.simplemobiletools.commons.extensions.getContrastColor
import kotlinx.android.synthetic.main.fragment_week.*
import kotlinx.android.synthetic.main.fragment_week.view.*
import org.joda.time.DateTime
import org.joda.time.Days
import java.util.*
class WeekFragment : Fragment(), WeeklyCalendar {
private val CLICK_DURATION_THRESHOLD = 150
private val PLUS_FADEOUT_DELAY = 5000L
var mListener: WeekScrollListener? = null
private var mWeekTimestamp = 0
private var mRowHeight = 0
private var minScrollY = -1
private var maxScrollY = -1
private var mWasDestroyed = false
private var primaryColor = 0
private var lastHash = 0
private var isFragmentVisible = false
private var wasFragmentInit = false
private var wasExtraHeightAdded = false
private var clickStartTime = 0L
private var selectedGrid: View? = null
private var todayColumnIndex = -1
private var events = ArrayList<Event>()
private var allDayHolders = ArrayList<RelativeLayout>()
private var allDayRows = ArrayList<HashSet<Int>>()
lateinit var inflater: LayoutInflater
lateinit var mView: View
lateinit var mCalendar: WeeklyCalendarImpl
lateinit var mRes: Resources
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
this.inflater = inflater
mRowHeight = (context!!.resources.getDimension(R.dimen.weekly_view_row_height)).toInt()
minScrollY = mRowHeight * context!!.config.startWeeklyAt
mWeekTimestamp = arguments!!.getInt(WEEK_START_TIMESTAMP)
primaryColor = context!!.config.primaryColor
mRes = resources
allDayRows.add(HashSet())
mView = inflater.inflate(R.layout.fragment_week, container, false).apply {
week_events_scrollview.setOnScrollviewListener(object : MyScrollView.ScrollViewListener {
override fun onScrollChanged(scrollView: MyScrollView, x: Int, y: Int, oldx: Int, oldy: Int) {
checkScrollLimits(y)
}
})
week_events_scrollview.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
week_events_scrollview.viewTreeObserver.removeOnGlobalLayoutListener(this)
updateScrollY(Math.max(MainActivity.mWeekScrollY, minScrollY))
}
})
}
(0..6).map { inflater.inflate(R.layout.stroke_vertical_divider, mView.week_vertical_grid_holder) }
(0..23).map { inflater.inflate(R.layout.stroke_horizontal_divider, mView.week_horizontal_grid_holder) }
mCalendar = WeeklyCalendarImpl(this, context!!)
wasFragmentInit = true
return mView
}
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
isFragmentVisible = menuVisible
if (isFragmentVisible && wasFragmentInit) {
(activity as MainActivity).updateHoursTopMargin(mView.week_top_holder.height)
checkScrollLimits(mView.week_events_scrollview.scrollY)
}
}
override fun onPause() {
super.onPause()
wasExtraHeightAdded = true
}
override fun onResume() {
super.onResume()
setupDayLabels()
mCalendar.updateWeeklyCalendar(mWeekTimestamp)
mView.week_events_scrollview.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (context == null)
return
mView.week_events_scrollview.viewTreeObserver.removeOnGlobalLayoutListener(this)
minScrollY = mRowHeight * context!!.config.startWeeklyAt
maxScrollY = mRowHeight * context!!.config.endWeeklyAt
val bounds = Rect()
week_events_holder.getGlobalVisibleRect(bounds)
maxScrollY -= bounds.bottom - bounds.top
if (minScrollY > maxScrollY)
maxScrollY = -1
checkScrollLimits(mView.week_events_scrollview.scrollY)
}
})
}
private fun setupDayLabels() {
var curDay = Formatter.getDateTimeFromTS(mWeekTimestamp)
val textColor = context!!.config.textColor
val todayCode = Formatter.getDayCodeFromDateTime(DateTime())
for (i in 0..6) {
val dayCode = Formatter.getDayCodeFromDateTime(curDay)
val dayLetter = getDayLetter(curDay.dayOfWeek)
mView.findViewById<TextView>(mRes.getIdentifier("week_day_label_$i", "id", context!!.packageName)).apply {
text = "$dayLetter\n${curDay.dayOfMonth}"
setTextColor(if (todayCode == dayCode) primaryColor else textColor)
if (todayCode == dayCode)
todayColumnIndex = i
}
curDay = curDay.plusDays(1)
}
}
private fun getDayLetter(pos: Int): String {
return mRes.getString(when (pos) {
1 -> R.string.monday_letter
2 -> R.string.tuesday_letter
3 -> R.string.wednesday_letter
4 -> R.string.thursday_letter
5 -> R.string.friday_letter
6 -> R.string.saturday_letter
else -> R.string.sunday_letter
})
}
private fun checkScrollLimits(y: Int) {
if (minScrollY != -1 && y < minScrollY) {
mView.week_events_scrollview.scrollY = minScrollY
} else if (maxScrollY != -1 && y > maxScrollY) {
mView.week_events_scrollview.scrollY = maxScrollY
} else {
if (isFragmentVisible)
mListener?.scrollTo(y)
}
}
private fun initGrid() {
(0..6).map { getColumnWithId(it) }
.forEachIndexed { index, layout ->
layout.removeAllViews()
layout.setOnTouchListener { view, motionEvent ->
checkGridClick(motionEvent, index, layout)
true
}
}
}
private fun checkGridClick(event: MotionEvent, index: Int, view: ViewGroup) {
when (event.action) {
MotionEvent.ACTION_DOWN -> clickStartTime = System.currentTimeMillis()
MotionEvent.ACTION_UP -> {
if (System.currentTimeMillis() - clickStartTime < CLICK_DURATION_THRESHOLD) {
selectedGrid?.animation?.cancel()
selectedGrid?.beGone()
val rowHeight = resources.getDimension(R.dimen.weekly_view_row_height)
val hour = (event.y / rowHeight).toInt()
selectedGrid = (inflater.inflate(R.layout.week_grid_item, null, false) as View).apply {
view.addView(this)
background = ColorDrawable(primaryColor)
layoutParams.width = view.width
layoutParams.height = rowHeight.toInt()
y = hour * rowHeight
setOnClickListener {
val timestamp = mWeekTimestamp + index * DAY_SECONDS + hour * 60 * 60
Intent(context, EventActivity::class.java).apply {
putExtra(NEW_EVENT_START_TS, timestamp)
putExtra(NEW_EVENT_SET_HOUR_DURATION, true)
startActivity(this)
}
}
animate().alpha(0f).setStartDelay(PLUS_FADEOUT_DELAY).withEndAction {
beGone()
}
}
}
}
else -> {
}
}
}
override fun updateWeeklyCalendar(events: ArrayList<Event>) {
val newHash = events.hashCode()
if (newHash == lastHash) {
return
}
lastHash = newHash
this.events = events
updateEvents()
}
fun updateEvents() {
if (mWasDestroyed)
return
activity!!.runOnUiThread {
if (context != null && isAdded)
addEvents()
}
}
private fun addEvents() {
val filtered = context!!.getFilteredEvents(events)
initGrid()
allDayHolders.clear()
allDayRows.clear()
allDayRows.add(HashSet())
week_all_day_holder?.removeAllViews()
addNewLine()
val fullHeight = mRes.getDimension(R.dimen.weekly_view_events_height)
val minuteHeight = fullHeight / (24 * 60)
val minimalHeight = mRes.getDimension(R.dimen.weekly_view_minimal_event_height).toInt()
var hadAllDayEvent = false
val replaceDescription = context!!.config.replaceDescription
val sorted = filtered.sortedWith(compareBy({ it.startTS }, { it.endTS }, { it.title }, { if (replaceDescription) it.location else it.description }))
for (event in sorted) {
if (event.getIsAllDay() || Formatter.getDayCodeFromTS(event.startTS) != Formatter.getDayCodeFromTS(event.endTS)) {
hadAllDayEvent = true
addAllDayEvent(event)
} else {
val startDateTime = Formatter.getDateTimeFromTS(event.startTS)
val endDateTime = Formatter.getDateTimeFromTS(event.endTS)
val dayOfWeek = startDateTime.plusDays(if (context!!.config.isSundayFirst) 1 else 0).dayOfWeek - 1
val layout = getColumnWithId(dayOfWeek)
val startMinutes = startDateTime.minuteOfDay
val duration = endDateTime.minuteOfDay - startMinutes
(inflater.inflate(R.layout.week_event_marker, null, false) as TextView).apply {
val backgroundColor = MainActivity.eventTypeColors.get(event.eventType, primaryColor)
background = ColorDrawable(backgroundColor)
setTextColor(backgroundColor.getContrastColor())
text = event.title
layout.addView(this)
y = startMinutes * minuteHeight
(layoutParams as RelativeLayout.LayoutParams).apply {
width = layout.width - 1
minHeight = if (event.startTS == event.endTS) minimalHeight else (duration * minuteHeight).toInt() - 1
}
setOnClickListener {
Intent(context, EventActivity::class.java).apply {
putExtra(EVENT_ID, event.id)
putExtra(EVENT_OCCURRENCE_TS, event.startTS)
startActivity(this)
}
}
}
}
}
if (!hadAllDayEvent) {
checkTopHolderHeight()
}
addCurrentTimeIndicator(minuteHeight)
}
private fun addNewLine() {
val allDaysLine = inflater.inflate(R.layout.all_day_events_holder_line, null, false) as RelativeLayout
week_all_day_holder.addView(allDaysLine)
allDayHolders.add(allDaysLine)
}
private fun addCurrentTimeIndicator(minuteHeight: Float) {
if (todayColumnIndex != -1) {
val minutes = DateTime().minuteOfDay
val todayColumn = getColumnWithId(todayColumnIndex)
(inflater.inflate(R.layout.week_now_marker, null, false) as ImageView).apply {
applyColorFilter(primaryColor)
mView.week_events_holder.addView(this, 0)
val extraWidth = (todayColumn.width * 0.3).toInt()
val markerHeight = resources.getDimension(R.dimen.weekly_view_now_height).toInt()
(layoutParams as RelativeLayout.LayoutParams).apply {
width = todayColumn.width + extraWidth
height = markerHeight
}
x = todayColumn.x - extraWidth / 2
y = minutes * minuteHeight - markerHeight / 2
}
}
}
private fun checkTopHolderHeight() {
mView.week_top_holder.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
mView.week_top_holder.viewTreeObserver.removeOnGlobalLayoutListener(this)
if (isFragmentVisible && activity != null) {
(activity as MainActivity).updateHoursTopMargin(mView.week_top_holder.height)
}
}
})
}
private fun addAllDayEvent(event: Event) {
(inflater.inflate(R.layout.week_all_day_event_marker, null, false) as TextView).apply {
if (activity == null)
return
val backgroundColor = MainActivity.eventTypeColors.get(event.eventType, primaryColor)
background = ColorDrawable(backgroundColor)
setTextColor(backgroundColor.getContrastColor())
text = event.title
val startDateTime = Formatter.getDateTimeFromTS(event.startTS)
val endDateTime = Formatter.getDateTimeFromTS(event.endTS)
val minTS = Math.max(startDateTime.seconds(), mWeekTimestamp)
val maxTS = Math.min(endDateTime.seconds(), mWeekTimestamp + WEEK_SECONDS)
val startDateTimeInWeek = Formatter.getDateTimeFromTS(minTS)
val firstDayIndex = (startDateTimeInWeek.dayOfWeek - if (context.config.isSundayFirst) 0 else 1) % 7
val daysCnt = Days.daysBetween(Formatter.getDateTimeFromTS(minTS).toLocalDate(), Formatter.getDateTimeFromTS(maxTS).toLocalDate()).days
var doesEventFit: Boolean
val cnt = allDayRows.size - 1
var wasEventHandled = false
var drawAtLine = 0
for (index in 0..cnt) {
doesEventFit = true
drawAtLine = index
val row = allDayRows[index]
for (i in firstDayIndex..firstDayIndex + daysCnt) {
if (row.contains(i)) {
doesEventFit = false
}
}
for (dayIndex in firstDayIndex..firstDayIndex + daysCnt) {
if (doesEventFit) {
row.add(dayIndex)
wasEventHandled = true
} else if (index == cnt) {
if (allDayRows.size == index + 1) {
allDayRows.add(HashSet<Int>())
addNewLine()
drawAtLine++
wasEventHandled = true
}
allDayRows.last().add(dayIndex)
}
}
if (wasEventHandled) {
break
}
}
allDayHolders[drawAtLine].addView(this)
(layoutParams as RelativeLayout.LayoutParams).apply {
topMargin = mRes.getDimension(R.dimen.tiny_margin).toInt()
leftMargin = getColumnWithId(firstDayIndex).x.toInt()
bottomMargin = 1
width = getColumnWithId(Math.min(firstDayIndex + daysCnt, 6)).right - leftMargin - 1
}
calculateExtraHeight()
setOnClickListener {
Intent(context, EventActivity::class.java).apply {
putExtra(EVENT_ID, event.id)
putExtra(EVENT_OCCURRENCE_TS, event.startTS)
startActivity(this)
}
}
}
}
private fun calculateExtraHeight() {
mView.week_top_holder.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (activity == null)
return
mView.week_top_holder.viewTreeObserver.removeOnGlobalLayoutListener(this)
if (isFragmentVisible) {
(activity as MainActivity).updateHoursTopMargin(mView.week_top_holder.height)
}
if (!wasExtraHeightAdded) {
maxScrollY += mView.week_all_day_holder.height
wasExtraHeightAdded = true
}
}
})
}
override fun onDestroyView() {
super.onDestroyView()
mWasDestroyed = true
}
private fun getColumnWithId(id: Int) = mView.findViewById<ViewGroup>(mRes.getIdentifier("week_column_$id", "id", context!!.packageName))
fun updateScrollY(y: Int) {
if (wasFragmentInit)
mView.week_events_scrollview.scrollY = y
}
interface WeekScrollListener {
fun scrollTo(y: Int)
}
}

View file

@ -1,406 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.ContentUris
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.provider.CalendarContract
import android.provider.CalendarContract.Reminders
import android.util.SparseIntArray
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.scheduleCalDAVSync
import com.simplemobiletools.calendar.models.CalDAVCalendar
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CALENDAR
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CALENDAR
import java.util.*
import kotlin.collections.ArrayList
class CalDAVHandler(val context: Context) {
fun refreshCalendars(activity: SimpleActivity? = null, callback: () -> Unit) {
val dbHelper = context.dbHelper
for (calendar in getCalDAVCalendars(activity, context.config.caldavSyncedCalendarIDs)) {
val localEventType = dbHelper.getEventTypeWithCalDAVCalendarId(calendar.id) ?: continue
localEventType.apply {
title = calendar.displayName
caldavDisplayName = calendar.displayName
caldavEmail = calendar.accountName
color = calendar.color
dbHelper.updateLocalEventType(this)
}
CalDAVHandler(context).fetchCalDAVCalendarEvents(calendar.id, localEventType.id, activity)
}
context.scheduleCalDAVSync(true)
callback()
}
fun getCalDAVCalendars(activity: SimpleActivity? = null, ids: String = ""): List<CalDAVCalendar> {
val calendars = ArrayList<CalDAVCalendar>()
if (!context.hasPermission(PERMISSION_WRITE_CALENDAR) || !context.hasPermission(PERMISSION_READ_CALENDAR)) {
return calendars
}
val uri = CalendarContract.Calendars.CONTENT_URI
val projection = arrayOf(
CalendarContract.Calendars._ID,
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,
CalendarContract.Calendars.ACCOUNT_NAME,
CalendarContract.Calendars.OWNER_ACCOUNT,
CalendarContract.Calendars.CALENDAR_COLOR,
CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL)
val selection = if (ids.trim().isNotEmpty()) "${CalendarContract.Calendars._ID} IN ($ids)" else null
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, projection, selection, null, null)
if (cursor != null && cursor.moveToFirst()) {
do {
val id = cursor.getIntValue(CalendarContract.Calendars._ID)
val displayName = cursor.getStringValue(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME)
val accountName = cursor.getStringValue(CalendarContract.Calendars.ACCOUNT_NAME)
val ownerName = cursor.getStringValue(CalendarContract.Calendars.OWNER_ACCOUNT)
val color = cursor.getIntValue(CalendarContract.Calendars.CALENDAR_COLOR)
val accessLevel = cursor.getIntValue(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL)
val calendar = CalDAVCalendar(id, displayName, accountName, ownerName, color, accessLevel)
calendars.add(calendar)
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity?.showErrorToast(e)
} finally {
cursor?.close()
}
return calendars
}
fun updateCalDAVCalendar(eventType: EventType): Boolean {
val uri = CalendarContract.Calendars.CONTENT_URI
val values = fillCalendarContentValues(eventType)
val newUri = ContentUris.withAppendedId(uri, eventType.caldavCalendarId.toLong())
return try {
context.contentResolver.update(newUri, values, null, null) == 1
} catch (e: IllegalArgumentException) {
false
}
}
private fun fillCalendarContentValues(eventType: EventType): ContentValues {
val colorKey = getEventTypeColorKey(eventType)
return ContentValues().apply {
put(CalendarContract.Calendars.CALENDAR_COLOR_KEY, colorKey)
put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, eventType.title)
}
}
private fun getEventTypeColorKey(eventType: EventType): Int {
val uri = CalendarContract.Colors.CONTENT_URI
val projection = arrayOf(CalendarContract.Colors.COLOR_KEY)
val selection = "${CalendarContract.Colors.COLOR_TYPE} = ? AND ${CalendarContract.Colors.COLOR} = ? AND ${CalendarContract.Colors.ACCOUNT_NAME} = ?"
val selectionArgs = arrayOf(CalendarContract.Colors.TYPE_CALENDAR.toString(), eventType.color.toString(), eventType.caldavEmail)
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor?.moveToFirst() == true) {
return cursor.getStringValue(CalendarContract.Colors.COLOR_KEY).toInt()
}
} finally {
cursor?.close()
}
return -1
}
// it doesnt work properly, needs better SyncAdapter handling
private fun insertNewColor(eventType: EventType): Int {
val maxId = getMaxColorId(eventType) + 1
val values = ContentValues().apply {
put(CalendarContract.Colors.COLOR_KEY, maxId)
put(CalendarContract.Colors.COLOR, eventType.color)
put(CalendarContract.Colors.ACCOUNT_NAME, eventType.caldavEmail)
put(CalendarContract.Colors.ACCOUNT_TYPE, "com.google")
put(CalendarContract.Colors.COLOR_TYPE, CalendarContract.Colors.TYPE_CALENDAR)
}
val uri = CalendarContract.Colors.CONTENT_URI.buildUpon()
.appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, eventType.caldavEmail)
.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, "com.google")
.build()
return if (context.contentResolver.insert(uri, values) != null) {
maxId
} else {
0
}
}
private fun getMaxColorId(eventType: EventType): Int {
val uri = CalendarContract.Colors.CONTENT_URI
val projection = arrayOf(CalendarContract.Colors.COLOR_KEY, CalendarContract.Colors.COLOR)
val selection = "${CalendarContract.Colors.COLOR_TYPE} = ? AND ${CalendarContract.Colors.ACCOUNT_NAME} = ?"
val selectionArgs = arrayOf(CalendarContract.Colors.TYPE_CALENDAR.toString(), eventType.caldavEmail)
var maxId = 1
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
do {
maxId = Math.max(maxId, cursor.getIntValue(CalendarContract.Colors.COLOR_KEY))
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
return maxId
}
fun getAvailableCalDAVCalendarColors(eventType: EventType): ArrayList<Int> {
val colors = SparseIntArray()
val uri = CalendarContract.Colors.CONTENT_URI
val projection = arrayOf(CalendarContract.Colors.COLOR, CalendarContract.Colors.COLOR_KEY)
val selection = "${CalendarContract.Colors.COLOR_TYPE} = ? AND ${CalendarContract.Colors.ACCOUNT_NAME} = ?"
val selectionArgs = arrayOf(CalendarContract.Colors.TYPE_CALENDAR.toString(), eventType.caldavEmail)
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
do {
val colorKey = cursor.getIntValue(CalendarContract.Colors.COLOR_KEY)
val color = cursor.getIntValue(CalendarContract.Colors.COLOR)
colors.put(colorKey, color)
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
val sortedColors = ArrayList<Int>(colors.size())
(0 until colors.size()).mapTo(sortedColors) { colors[it] }
return sortedColors
}
private fun fetchCalDAVCalendarEvents(calendarId: Int, eventTypeId: Int, activity: SimpleActivity?) {
val importIdsMap = HashMap<String, Event>()
val fetchedEventIds = ArrayList<String>()
val existingEvents = context.dbHelper.getEventsFromCalDAVCalendar(calendarId)
existingEvents.forEach {
importIdsMap.put(it.importId, it)
}
val uri = CalendarContract.Events.CONTENT_URI
val projection = arrayOf(
CalendarContract.Events._ID,
CalendarContract.Events.TITLE,
CalendarContract.Events.DESCRIPTION,
CalendarContract.Events.DTSTART,
CalendarContract.Events.DTEND,
CalendarContract.Events.DURATION,
CalendarContract.Events.ALL_DAY,
CalendarContract.Events.RRULE,
CalendarContract.Events.EVENT_LOCATION)
val selection = "${CalendarContract.Events.CALENDAR_ID} = $calendarId"
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, projection, selection, null, null)
if (cursor != null && cursor.moveToFirst()) {
do {
val id = cursor.getLongValue(CalendarContract.Events._ID)
val title = cursor.getStringValue(CalendarContract.Events.TITLE) ?: continue
val description = cursor.getStringValue(CalendarContract.Events.DESCRIPTION) ?: ""
val startTS = (cursor.getLongValue(CalendarContract.Events.DTSTART) / 1000).toInt()
var endTS = (cursor.getLongValue(CalendarContract.Events.DTEND) / 1000).toInt()
val allDay = cursor.getIntValue(CalendarContract.Events.ALL_DAY)
val rrule = cursor.getStringValue(CalendarContract.Events.RRULE) ?: ""
val location = cursor.getStringValue(CalendarContract.Events.EVENT_LOCATION) ?: ""
val reminders = getCalDAVEventReminders(id)
if (endTS == 0) {
val duration = cursor.getStringValue(CalendarContract.Events.DURATION) ?: ""
endTS = startTS + Parser().parseDurationSeconds(duration)
}
val importId = getCalDAVEventImportId(calendarId, id)
val repeatRule = Parser().parseRepeatInterval(rrule, startTS)
val event = Event(0, startTS, endTS, title, description, reminders.getOrElse(0, { -1 }),
reminders.getOrElse(1, { -1 }), reminders.getOrElse(2, { -1 }), repeatRule.repeatInterval,
importId, allDay, repeatRule.repeatLimit, repeatRule.repeatRule, eventTypeId, source = "$CALDAV-$calendarId",
location = location)
if (event.getIsAllDay() && endTS > startTS) {
event.endTS -= DAY
}
fetchedEventIds.add(importId)
if (importIdsMap.containsKey(event.importId)) {
val existingEvent = importIdsMap[importId]
val originalEventId = existingEvent!!.id
existingEvent.id = 0
if (existingEvent.hashCode() != event.hashCode()) {
event.id = originalEventId
context.dbHelper.update(event, false) {
}
}
} else {
context.dbHelper.insert(event, false) {
importIdsMap.put(event.importId, event)
}
}
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity?.showErrorToast(e)
} finally {
cursor?.close()
}
val eventIdsToDelete = ArrayList<String>()
importIdsMap.keys.filter { !fetchedEventIds.contains(it) }.forEach {
val caldavEventId = it
existingEvents.forEach {
if (it.importId == caldavEventId) {
eventIdsToDelete.add(it.id.toString())
}
}
}
eventIdsToDelete.forEach {
context.dbHelper.deleteEvents(eventIdsToDelete.toTypedArray(), false)
}
}
fun insertCalDAVEvent(event: Event) {
val uri = CalendarContract.Events.CONTENT_URI
val values = fillEventContentValues(event)
val newUri = context.contentResolver.insert(uri, values)
val calendarId = event.getCalDAVCalendarId()
val eventRemoteID = java.lang.Long.parseLong(newUri.lastPathSegment)
event.importId = getCalDAVEventImportId(calendarId, eventRemoteID)
setupCalDAVEventReminders(event)
setupCalDAVEventImportId(event)
}
fun updateCalDAVEvent(event: Event) {
val uri = CalendarContract.Events.CONTENT_URI
val values = fillEventContentValues(event)
val eventRemoteID = event.getCalDAVEventId()
event.importId = getCalDAVEventImportId(event.getCalDAVCalendarId(), eventRemoteID)
val newUri = ContentUris.withAppendedId(uri, eventRemoteID)
context.contentResolver.update(newUri, values, null, null)
setupCalDAVEventReminders(event)
setupCalDAVEventImportId(event)
}
private fun setupCalDAVEventReminders(event: Event) {
clearEventReminders(event)
event.getReminders().forEach {
ContentValues().apply {
put(Reminders.MINUTES, it)
put(Reminders.EVENT_ID, event.getCalDAVEventId())
put(Reminders.METHOD, Reminders.METHOD_ALERT)
context.contentResolver.insert(Reminders.CONTENT_URI, this)
}
}
}
private fun setupCalDAVEventImportId(event: Event) {
context.dbHelper.updateEventImportIdAndSource(event.id, event.importId, "$CALDAV-${event.getCalDAVCalendarId()}")
}
private fun fillEventContentValues(event: Event): ContentValues {
return ContentValues().apply {
put(CalendarContract.Events.CALENDAR_ID, event.getCalDAVCalendarId())
put(CalendarContract.Events.TITLE, event.title)
put(CalendarContract.Events.DESCRIPTION, event.description)
put(CalendarContract.Events.DTSTART, event.startTS * 1000L)
put(CalendarContract.Events.ALL_DAY, if (event.getIsAllDay()) 1 else 0)
put(CalendarContract.Events.RRULE, Parser().getRepeatCode(event))
put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().toString())
put(CalendarContract.Events.EVENT_LOCATION, event.location)
if (event.getIsAllDay() && event.endTS > event.startTS)
event.endTS += DAY
if (event.repeatInterval > 0) {
put(CalendarContract.Events.DURATION, getDurationCode(event))
putNull(CalendarContract.Events.DTEND)
} else {
put(CalendarContract.Events.DTEND, event.endTS * 1000L)
putNull(CalendarContract.Events.DURATION)
}
}
}
private fun clearEventReminders(event: Event) {
val selection = "${Reminders.EVENT_ID} = ?"
val selectionArgs = arrayOf(event.getCalDAVEventId().toString())
context.contentResolver.delete(Reminders.CONTENT_URI, selection, selectionArgs)
}
private fun getDurationCode(event: Event): String {
return if (event.getIsAllDay()) {
val dur = Math.max(1, (event.endTS - event.startTS) / DAY)
"P${dur}D"
} else {
Parser().getDurationCode((event.endTS - event.startTS) / 60)
}
}
fun deleteCalDAVCalendarEvents(calendarId: Long) {
val events = context.dbHelper.getCalDAVCalendarEvents(calendarId)
val eventIds = events.map { it.id.toString() }.toTypedArray()
context.dbHelper.deleteEvents(eventIds, false)
}
fun deleteCalDAVEvent(event: Event) {
val uri = CalendarContract.Events.CONTENT_URI
val contentUri = ContentUris.withAppendedId(uri, event.getCalDAVEventId())
try {
context.contentResolver.delete(contentUri, null, null)
} catch (ignored: Exception) {
}
}
private fun getCalDAVEventReminders(eventId: Long): List<Int> {
val reminders = ArrayList<Int>()
val uri = CalendarContract.Reminders.CONTENT_URI
val projection = arrayOf(
CalendarContract.Reminders.MINUTES,
CalendarContract.Reminders.METHOD)
val selection = "${CalendarContract.Reminders.EVENT_ID} = $eventId"
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, projection, selection, null, null)
if (cursor != null && cursor.moveToFirst()) {
do {
val minutes = cursor.getIntValue(CalendarContract.Reminders.MINUTES)
val method = cursor.getIntValue(CalendarContract.Reminders.METHOD)
if (method == CalendarContract.Reminders.METHOD_ALERT) {
reminders.add(minutes)
}
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
return reminders
}
private fun getCalDAVEventImportId(calendarId: Int, eventId: Long) = "$CALDAV-$calendarId-$eventId"
}

View file

@ -1,132 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.Context
import android.media.RingtoneManager
import android.text.format.DateFormat
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.scheduleCalDAVSync
import com.simplemobiletools.commons.helpers.BaseConfig
import java.util.*
class Config(context: Context) : BaseConfig(context) {
companion object {
fun newInstance(context: Context) = Config(context)
}
var isSundayFirst: Boolean
get() {
val isSundayFirst = Calendar.getInstance(Locale.getDefault()).firstDayOfWeek == Calendar.SUNDAY
return prefs.getBoolean(SUNDAY_FIRST, isSundayFirst)
}
set(sundayFirst) = prefs.edit().putBoolean(SUNDAY_FIRST, sundayFirst).apply()
var use24hourFormat: Boolean
get() {
val use24hourFormat = DateFormat.is24HourFormat(context)
return prefs.getBoolean(USE_24_HOUR_FORMAT, use24hourFormat)
}
set(use24hourFormat) = prefs.edit().putBoolean(USE_24_HOUR_FORMAT, use24hourFormat).apply()
var displayWeekNumbers: Boolean
get() = prefs.getBoolean(WEEK_NUMBERS, false)
set(displayWeekNumbers) = prefs.edit().putBoolean(WEEK_NUMBERS, displayWeekNumbers).apply()
var startWeeklyAt: Int
get() = prefs.getInt(START_WEEKLY_AT, 7)
set(startWeeklyAt) = prefs.edit().putInt(START_WEEKLY_AT, startWeeklyAt).apply()
var endWeeklyAt: Int
get() = prefs.getInt(END_WEEKLY_AT, 23)
set(endWeeklyAt) = prefs.edit().putInt(END_WEEKLY_AT, endWeeklyAt).apply()
var vibrateOnReminder: Boolean
get() = prefs.getBoolean(VIBRATE, false)
set(vibrate) = prefs.edit().putBoolean(VIBRATE, vibrate).apply()
var reminderSound: String
get() = prefs.getString(REMINDER_SOUND, getDefaultNotificationSound())
set(path) = prefs.edit().putString(REMINDER_SOUND, path).apply()
var storedView: Int
get() = prefs.getInt(VIEW, MONTHLY_VIEW)
set(view) = prefs.edit().putInt(VIEW, view).apply()
var defaultReminderMinutes: Int
get() = prefs.getInt(REMINDER_MINUTES, 10)
set(mins) = prefs.edit().putInt(REMINDER_MINUTES, mins).apply()
var snoozeDelay: Int
get() = prefs.getInt(SNOOZE_DELAY, 10)
set(snoozeDelay) = prefs.edit().putInt(SNOOZE_DELAY, snoozeDelay).apply()
var displayPastEvents: Int
get() = prefs.getInt(DISPLAY_PAST_EVENTS, 0)
set(displayPastEvents) = prefs.edit().putInt(DISPLAY_PAST_EVENTS, displayPastEvents).apply()
var displayEventTypes: Set<String>
get() = prefs.getStringSet(DISPLAY_EVENT_TYPES, HashSet<String>())
set(displayEventTypes) = prefs.edit().remove(DISPLAY_EVENT_TYPES).putStringSet(DISPLAY_EVENT_TYPES, displayEventTypes).apply()
var fontSize: Int
get() = prefs.getInt(FONT_SIZE, FONT_SIZE_MEDIUM)
set(size) = prefs.edit().putInt(FONT_SIZE, size).apply()
var googleSync: Boolean
get() = prefs.getBoolean(GOOGLE_SYNC, false)
set(googleSync) = prefs.edit().putBoolean(GOOGLE_SYNC, googleSync).apply()
var caldavSync: Boolean
get() = prefs.getBoolean(CALDAV_SYNC, false)
set(caldavSync) {
context.scheduleCalDAVSync(caldavSync)
prefs.edit().putBoolean(CALDAV_SYNC, caldavSync).apply()
}
var caldavSyncedCalendarIDs: String
get() = prefs.getString(CALDAV_SYNCED_CALENDAR_IDS, "")
set(calendarIDs) = prefs.edit().putString(CALDAV_SYNCED_CALENDAR_IDS, calendarIDs).apply()
var lastUsedCaldavCalendar: Int
get() = prefs.getInt(LAST_USED_CALDAV_CALENDAR, getSyncedCalendarIdsAsList().first().toInt())
set(calendarId) = prefs.edit().putInt(LAST_USED_CALDAV_CALENDAR, calendarId).apply()
var replaceDescription: Boolean
get() = prefs.getBoolean(REPLACE_DESCRIPTION, false)
set(replaceDescription) = prefs.edit().putBoolean(REPLACE_DESCRIPTION, replaceDescription).apply()
fun getSyncedCalendarIdsAsList() = caldavSyncedCalendarIDs.split(",").filter { it.trim().isNotEmpty() } as ArrayList<String>
fun addDisplayEventType(type: String) {
addDisplayEventTypes(HashSet<String>(Arrays.asList(type)))
}
private fun addDisplayEventTypes(types: Set<String>) {
val currDisplayEventTypes = HashSet<String>(displayEventTypes)
currDisplayEventTypes.addAll(types)
displayEventTypes = currDisplayEventTypes
}
fun removeDisplayEventTypes(types: Set<String>) {
val currDisplayEventTypes = HashSet<String>(displayEventTypes)
currDisplayEventTypes.removeAll(types)
displayEventTypes = currDisplayEventTypes
}
private fun getDefaultNotificationSound(): String {
return try {
RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_NOTIFICATION)?.toString() ?: ""
} catch (e: Exception) {
""
}
}
fun getFontSize() = when (fontSize) {
FONT_SIZE_SMALL -> getSmallFontSize()
FONT_SIZE_MEDIUM -> getMediumFontSize()
else -> getLargeFontSize()
}
private fun getSmallFontSize() = getMediumFontSize() - 3f
private fun getMediumFontSize() = context.resources.getDimension(R.dimen.day_text_size) / context.resources.displayMetrics.density
private fun getLargeFontSize() = getMediumFontSize() + 3f
}

View file

@ -1,138 +0,0 @@
package com.simplemobiletools.calendar.helpers
import com.simplemobiletools.calendar.R
val LOW_ALPHA = .3f
val MEDIUM_ALPHA = .6f
val STORED_LOCALLY_ONLY = 0
val DAY_CODE = "day_code"
val YEAR_LABEL = "year"
val EVENT_ID = "event_id"
val EVENT_OCCURRENCE_TS = "event_occurrence_ts"
val NEW_EVENT_START_TS = "new_event_start_ts"
val WEEK_START_TIMESTAMP = "week_start_timestamp"
val NEW_EVENT_SET_HOUR_DURATION = "new_event_set_hour_duration"
val CALDAV = "Caldav"
val MONTHLY_VIEW = 1
val YEARLY_VIEW = 2
val EVENTS_LIST_VIEW = 3
val WEEKLY_VIEW = 4
val REMINDER_OFF = -1
val DAY = 86400
val WEEK = 604800
val MONTH = 2592001 // exact value not taken into account, Joda is used for adding months and years
val YEAR = 31536000
val DAY_MINUTES = 24 * 60
val DAY_SECONDS = 24 * 60 * 60
val WEEK_SECONDS = 7 * DAY_SECONDS
// Shared Preferences
val USE_24_HOUR_FORMAT = "use_24_hour_format"
val SUNDAY_FIRST = "sunday_first"
val WEEK_NUMBERS = "week_numbers"
val START_WEEKLY_AT = "start_weekly_at"
val END_WEEKLY_AT = "end_weekly_at"
val VIBRATE = "vibrate"
val REMINDER_SOUND = "reminder_sound"
val VIEW = "view"
val REMINDER_MINUTES = "reminder_minutes"
val DISPLAY_EVENT_TYPES = "display_event_types"
val FONT_SIZE = "font_size"
val CALDAV_SYNC = "caldav_sync"
val CALDAV_SYNCED_CALENDAR_IDS = "caldav_synced_calendar_ids"
val LAST_USED_CALDAV_CALENDAR = "last_used_caldav_calendar"
val SNOOZE_DELAY = "snooze_delay"
val DISPLAY_PAST_EVENTS = "display_past_events"
val REPLACE_DESCRIPTION = "replace_description"
val GOOGLE_SYNC = "google_sync" // deprecated
val letterIDs = intArrayOf(R.string.sunday_letter, R.string.monday_letter, R.string.tuesday_letter, R.string.wednesday_letter,
R.string.thursday_letter, R.string.friday_letter, R.string.saturday_letter)
// repeat_rule for weekly repetition
val MONDAY = 1
val TUESDAY = 2
val WEDNESDAY = 4
val THURSDAY = 8
val FRIDAY = 16
val SATURDAY = 32
val SUNDAY = 64
val EVERY_DAY = 127
// repeat_rule for monthly repetition
val REPEAT_MONTH_SAME_DAY = 1 // ie 25th every month
val REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST = 2 // ie every xth sunday. 4th if a month has 4 sundays, 5th if 5
val REPEAT_MONTH_LAST_DAY = 3 // ie every last day of the month
val REPEAT_MONTH_ORDER_WEEKDAY = 4 // ie every 4th sunday, even if a month has 4 sundays only (will stay 4th even at months with 5)
// special event flags
val FLAG_ALL_DAY = 1
// constants related to ICS file exporting / importing
val BEGIN_CALENDAR = "BEGIN:VCALENDAR"
val END_CALENDAR = "END:VCALENDAR"
val CALENDAR_PRODID = "PRODID:-//Simple Mobile Tools//NONSGML Event Calendar//EN"
val CALENDAR_VERSION = "VERSION:2.0"
val BEGIN_EVENT = "BEGIN:VEVENT"
val END_EVENT = "END:VEVENT"
val BEGIN_ALARM = "BEGIN:VALARM"
val END_ALARM = "END:VALARM"
val DTSTART = "DTSTART"
val DTEND = "DTEND"
val LAST_MODIFIED = "LAST-MODIFIED"
val DURATION = "DURATION:"
val SUMMARY = "SUMMARY"
val DESCRIPTION = "DESCRIPTION:"
val UID = "UID:"
val ACTION = "ACTION:"
val TRIGGER = "TRIGGER:"
val RRULE = "RRULE:"
val CATEGORIES = "CATEGORIES:"
val STATUS = "STATUS:"
val EXDATE = "EXDATE"
val BYDAY = "BYDAY"
val BYMONTHDAY = "BYMONTHDAY"
val LOCATION = "LOCATION:"
// this tag isn't a standard ICS tag, but there's no official way of adding a category color in an ics file
val CATEGORY_COLOR = "CATEGORY_COLOR:"
val DISPLAY = "DISPLAY"
val FREQ = "FREQ"
val UNTIL = "UNTIL"
val COUNT = "COUNT"
val INTERVAL = "INTERVAL"
val CONFIRMED = "CONFIRMED"
val VALUE = "VALUE"
val DATE = "DATE"
val DAILY = "DAILY"
val WEEKLY = "WEEKLY"
val MONTHLY = "MONTHLY"
val YEARLY = "YEARLY"
val MO = "MO"
val TU = "TU"
val WE = "WE"
val TH = "TH"
val FR = "FR"
val SA = "SA"
val SU = "SU"
// font sizes
val FONT_SIZE_SMALL = 0
val FONT_SIZE_MEDIUM = 1
val FONT_SIZE_LARGE = 2
val SOURCE_SIMPLE_CALENDAR = "simple-calendar"
val SOURCE_IMPORTED_ICS = "imported-ics"
val SOURCE_CONTACT_BIRTHDAY = "contact-birthday"
val SOURCE_CONTACT_ANNIVERSARY = "contact-anniversary"
// deprecated
val SOURCE_GOOGLE_CALENDAR = 1

View file

@ -1,960 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteOpenHelper
import android.database.sqlite.SQLiteQueryBuilder
import android.text.TextUtils
import android.util.SparseIntArray
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.extensions.getIntValue
import com.simplemobiletools.commons.extensions.getLongValue
import com.simplemobiletools.commons.extensions.getStringValue
import org.joda.time.DateTime
import java.util.*
import kotlin.collections.ArrayList
class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
private val MAIN_TABLE_NAME = "events"
private val COL_ID = "id"
private val COL_START_TS = "start_ts"
private val COL_END_TS = "end_ts"
private val COL_TITLE = "title"
private val COL_DESCRIPTION = "description"
private val COL_REMINDER_MINUTES = "reminder_minutes"
private val COL_REMINDER_MINUTES_2 = "reminder_minutes_2"
private val COL_REMINDER_MINUTES_3 = "reminder_minutes_3"
private val COL_IMPORT_ID = "import_id"
private val COL_FLAGS = "flags"
private val COL_EVENT_TYPE = "event_type"
private val COL_OFFSET = "offset"
private val COL_IS_DST_INCLUDED = "is_dst_included"
private val COL_LAST_UPDATED = "last_updated"
private val COL_EVENT_SOURCE = "event_source"
private val COL_LOCATION = "location"
private val COL_SOURCE = "source" // deprecated
private val META_TABLE_NAME = "events_meta"
private val COL_EVENT_ID = "event_id"
private val COL_REPEAT_START = "repeat_start"
private val COL_REPEAT_INTERVAL = "repeat_interval"
private val COL_REPEAT_RULE = "repeat_rule"
private val COL_REPEAT_LIMIT = "repeat_limit"
private val TYPES_TABLE_NAME = "event_types"
private val COL_TYPE_ID = "event_type_id"
private val COL_TYPE_TITLE = "event_type_title"
private val COL_TYPE_COLOR = "event_type_color"
private val COL_TYPE_CALDAV_CALENDAR_ID = "event_caldav_calendar_id"
private val COL_TYPE_CALDAV_DISPLAY_NAME = "event_caldav_display_name"
private val COL_TYPE_CALDAV_EMAIL = "event_caldav_email"
private val EXCEPTIONS_TABLE_NAME = "event_repeat_exceptions"
private val COL_EXCEPTION_ID = "event_exception_id"
private val COL_OCCURRENCE_TIMESTAMP = "event_occurrence_timestamp"
private val COL_OCCURRENCE_DAYCODE = "event_occurrence_daycode"
private val COL_PARENT_EVENT_ID = "event_parent_id"
private val COL_CHILD_EVENT_ID = "event_child_id"
private val mDb: SQLiteDatabase = writableDatabase
companion object {
private val DB_VERSION = 19
val DB_NAME = "events.db"
val REGULAR_EVENT_TYPE_ID = 1
var dbInstance: DBHelper? = null
fun newInstance(context: Context): DBHelper {
if (dbInstance == null)
dbInstance = DBHelper(context)
return dbInstance!!
}
}
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $MAIN_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_START_TS INTEGER, $COL_END_TS INTEGER, " +
"$COL_TITLE TEXT, $COL_DESCRIPTION TEXT, $COL_REMINDER_MINUTES INTEGER, $COL_REMINDER_MINUTES_2 INTEGER, $COL_REMINDER_MINUTES_3 INTEGER, " +
"$COL_IMPORT_ID TEXT, $COL_FLAGS INTEGER, $COL_EVENT_TYPE INTEGER NOT NULL DEFAULT $REGULAR_EVENT_TYPE_ID, " +
"$COL_PARENT_EVENT_ID INTEGER, $COL_OFFSET TEXT, $COL_IS_DST_INCLUDED INTEGER, $COL_LAST_UPDATED INTEGER, $COL_EVENT_SOURCE TEXT, " +
"$COL_LOCATION TEXT)")
createMetaTable(db)
createTypesTable(db)
createExceptionsTable(db)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
if (oldVersion == 1) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_REMINDER_MINUTES INTEGER DEFAULT -1")
}
if (oldVersion < 3) {
createMetaTable(db)
}
if (oldVersion < 4) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_IMPORT_ID TEXT DEFAULT ''")
}
if (oldVersion < 5) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_FLAGS INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE $META_TABLE_NAME ADD COLUMN $COL_REPEAT_LIMIT INTEGER NOT NULL DEFAULT 0")
}
if (oldVersion < 6) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_REMINDER_MINUTES_2 INTEGER NOT NULL DEFAULT -1")
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_REMINDER_MINUTES_3 INTEGER NOT NULL DEFAULT -1")
}
if (oldVersion < 7) {
createTypesTable(db)
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_EVENT_TYPE INTEGER NOT NULL DEFAULT $REGULAR_EVENT_TYPE_ID")
}
if (oldVersion < 8) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_PARENT_EVENT_ID INTEGER NOT NULL DEFAULT 0")
createExceptionsTable(db)
}
if (oldVersion < 9) {
try {
db.execSQL("ALTER TABLE $EXCEPTIONS_TABLE_NAME ADD COLUMN $COL_OCCURRENCE_DAYCODE INTEGER NOT NULL DEFAULT 0")
} catch (ignored: SQLiteException) {
}
convertExceptionTimestampToDaycode(db)
}
if (oldVersion < 11) {
db.execSQL("ALTER TABLE $META_TABLE_NAME ADD COLUMN $COL_REPEAT_RULE INTEGER NOT NULL DEFAULT 0")
setupRepeatRules(db)
}
if (oldVersion < 12) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_OFFSET TEXT DEFAULT ''")
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_IS_DST_INCLUDED INTEGER NOT NULL DEFAULT 0")
}
if (oldVersion < 13) {
try {
createExceptionsTable(db)
} catch (e: Exception) {
try {
db.execSQL("ALTER TABLE $EXCEPTIONS_TABLE_NAME ADD COLUMN $COL_CHILD_EVENT_ID INTEGER NOT NULL DEFAULT 0")
} catch (e: Exception) {
}
}
}
if (oldVersion < 14) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_LAST_UPDATED INTEGER NOT NULL DEFAULT 0")
}
if (oldVersion < 15) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_EVENT_SOURCE TEXT DEFAULT ''")
}
if (oldVersion < 16) {
db.execSQL("ALTER TABLE $TYPES_TABLE_NAME ADD COLUMN $COL_TYPE_CALDAV_CALENDAR_ID INTEGER NOT NULL DEFAULT 0")
}
if (oldVersion < 17) {
db.execSQL("ALTER TABLE $TYPES_TABLE_NAME ADD COLUMN $COL_TYPE_CALDAV_DISPLAY_NAME TEXT DEFAULT ''")
db.execSQL("ALTER TABLE $TYPES_TABLE_NAME ADD COLUMN $COL_TYPE_CALDAV_EMAIL TEXT DEFAULT ''")
}
if (oldVersion < 18) {
updateOldMonthlyEvents(db)
}
if (oldVersion < 19) {
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_LOCATION TEXT DEFAULT ''")
}
}
private fun createMetaTable(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $META_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_EVENT_ID INTEGER UNIQUE, $COL_REPEAT_START INTEGER, " +
"$COL_REPEAT_INTERVAL INTEGER, $COL_REPEAT_LIMIT INTEGER, $COL_REPEAT_RULE INTEGER)")
}
private fun createTypesTable(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $TYPES_TABLE_NAME ($COL_TYPE_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_TYPE_TITLE TEXT, $COL_TYPE_COLOR INTEGER, " +
"$COL_TYPE_CALDAV_CALENDAR_ID INTEGER, $COL_TYPE_CALDAV_DISPLAY_NAME TEXT, $COL_TYPE_CALDAV_EMAIL TEXT)")
addRegularEventType(db)
}
private fun createExceptionsTable(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $EXCEPTIONS_TABLE_NAME ($COL_EXCEPTION_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_PARENT_EVENT_ID INTEGER, " +
"$COL_OCCURRENCE_TIMESTAMP INTEGER, $COL_OCCURRENCE_DAYCODE INTEGER, $COL_CHILD_EVENT_ID INTEGER)")
}
private fun addRegularEventType(db: SQLiteDatabase) {
val regularEvent = context.resources.getString(R.string.regular_event)
val eventType = EventType(REGULAR_EVENT_TYPE_ID, regularEvent, context.config.primaryColor)
addEventType(eventType, db)
}
fun insert(event: Event, addToCalDAV: Boolean, callback: (id: Int) -> Unit) {
if (event.startTS > event.endTS || event.title.trim().isEmpty()) {
callback(0)
return
}
val eventValues = fillEventValues(event)
val id = mDb.insert(MAIN_TABLE_NAME, null, eventValues)
event.id = id.toInt()
if (event.repeatInterval != 0 && event.parentId == 0) {
val metaValues = fillMetaValues(event)
mDb.insert(META_TABLE_NAME, null, metaValues)
}
context.updateWidgets()
context.scheduleNextEventReminder(event, this)
if (addToCalDAV && event.source != SOURCE_SIMPLE_CALENDAR && context.config.caldavSync) {
CalDAVHandler(context).insertCalDAVEvent(event)
}
callback(event.id)
}
fun update(event: Event, updateAtCalDAV: Boolean, callback: () -> Unit) {
val selectionArgs = arrayOf(event.id.toString())
val values = fillEventValues(event)
val selection = "$COL_ID = ?"
mDb.update(MAIN_TABLE_NAME, values, selection, selectionArgs)
if (event.repeatInterval == 0) {
val metaSelection = "$COL_EVENT_ID = ?"
mDb.delete(META_TABLE_NAME, metaSelection, selectionArgs)
} else {
val metaValues = fillMetaValues(event)
mDb.insertWithOnConflict(META_TABLE_NAME, null, metaValues, SQLiteDatabase.CONFLICT_REPLACE)
}
context.updateWidgets()
context.scheduleNextEventReminder(event, this)
if (updateAtCalDAV && event.source != SOURCE_SIMPLE_CALENDAR && context.config.caldavSync) {
CalDAVHandler(context).updateCalDAVEvent(event)
}
callback()
}
private fun fillEventValues(event: Event): ContentValues {
return ContentValues().apply {
put(COL_START_TS, event.startTS)
put(COL_END_TS, event.endTS)
put(COL_TITLE, event.title)
put(COL_DESCRIPTION, event.description)
put(COL_REMINDER_MINUTES, event.reminder1Minutes)
put(COL_REMINDER_MINUTES_2, event.reminder2Minutes)
put(COL_REMINDER_MINUTES_3, event.reminder3Minutes)
put(COL_IMPORT_ID, event.importId)
put(COL_FLAGS, event.flags)
put(COL_EVENT_TYPE, event.eventType)
put(COL_PARENT_EVENT_ID, event.parentId)
put(COL_OFFSET, event.offset)
put(COL_IS_DST_INCLUDED, if (event.isDstIncluded) 1 else 0)
put(COL_LAST_UPDATED, event.lastUpdated)
put(COL_EVENT_SOURCE, event.source)
put(COL_LOCATION, event.location)
}
}
private fun fillMetaValues(event: Event): ContentValues {
return ContentValues().apply {
put(COL_EVENT_ID, event.id)
put(COL_REPEAT_START, event.startTS)
put(COL_REPEAT_INTERVAL, event.repeatInterval)
put(COL_REPEAT_LIMIT, event.repeatLimit)
put(COL_REPEAT_RULE, event.repeatRule)
}
}
private fun addEventType(eventType: EventType, db: SQLiteDatabase) {
insertEventType(eventType, db)
}
fun insertEventType(eventType: EventType, db: SQLiteDatabase = mDb): Int {
val values = fillEventTypeValues(eventType)
val insertedId = db.insert(TYPES_TABLE_NAME, null, values).toInt()
context.config.addDisplayEventType(insertedId.toString())
return insertedId
}
fun updateEventType(eventType: EventType): Int {
return if (eventType.caldavCalendarId != 0) {
if (CalDAVHandler(context).updateCalDAVCalendar(eventType)) {
updateLocalEventType(eventType)
} else {
-1
}
} else {
updateLocalEventType(eventType)
}
}
fun updateLocalEventType(eventType: EventType): Int {
val selectionArgs = arrayOf(eventType.id.toString())
val values = fillEventTypeValues(eventType)
val selection = "$COL_TYPE_ID = ?"
return mDb.update(TYPES_TABLE_NAME, values, selection, selectionArgs)
}
private fun fillEventTypeValues(eventType: EventType): ContentValues {
return ContentValues().apply {
put(COL_TYPE_TITLE, eventType.title)
put(COL_TYPE_COLOR, eventType.color)
put(COL_TYPE_CALDAV_CALENDAR_ID, eventType.caldavCalendarId)
put(COL_TYPE_CALDAV_DISPLAY_NAME, eventType.caldavDisplayName)
put(COL_TYPE_CALDAV_EMAIL, eventType.caldavEmail)
}
}
private fun fillExceptionValues(parentEventId: Int, occurrenceTS: Int, callback: (values: ContentValues) -> Unit) {
val childEvent = getEventWithId(parentEventId)
if (childEvent == null) {
callback(ContentValues())
return
}
childEvent.apply {
id = 0
parentId = parentEventId
startTS = 0
endTS = 0
}
insert(childEvent, false) {
callback(ContentValues().apply {
put(COL_PARENT_EVENT_ID, parentEventId)
put(COL_OCCURRENCE_DAYCODE, Formatter.getDayCodeFromTS(occurrenceTS))
put(COL_CHILD_EVENT_ID, it)
})
}
}
fun getEventTypeIdWithTitle(title: String): Int {
val cols = arrayOf(COL_TYPE_ID)
val selection = "$COL_TYPE_TITLE = ? COLLATE NOCASE"
val selectionArgs = arrayOf(title)
var cursor: Cursor? = null
try {
cursor = mDb.query(TYPES_TABLE_NAME, cols, selection, selectionArgs, null, null, null)
if (cursor?.moveToFirst() == true) {
return cursor.getIntValue(COL_TYPE_ID)
}
} finally {
cursor?.close()
}
return -1
}
fun getEventTypeWithCalDAVCalendarId(calendarId: Int): EventType? {
val cols = arrayOf(COL_TYPE_ID)
val selection = "$COL_TYPE_CALDAV_CALENDAR_ID = ?"
val selectionArgs = arrayOf(calendarId.toString())
var cursor: Cursor? = null
try {
cursor = mDb.query(TYPES_TABLE_NAME, cols, selection, selectionArgs, null, null, null)
if (cursor?.moveToFirst() == true) {
return getEventType(cursor.getIntValue(COL_TYPE_ID))
}
} finally {
cursor?.close()
}
return null
}
fun getEventType(id: Int): EventType? {
val cols = arrayOf(COL_TYPE_TITLE, COL_TYPE_COLOR, COL_TYPE_CALDAV_CALENDAR_ID, COL_TYPE_CALDAV_DISPLAY_NAME, COL_TYPE_CALDAV_EMAIL)
val selection = "$COL_TYPE_ID = ?"
val selectionArgs = arrayOf(id.toString())
var cursor: Cursor? = null
try {
cursor = mDb.query(TYPES_TABLE_NAME, cols, selection, selectionArgs, null, null, null)
if (cursor?.moveToFirst() == true) {
val title = cursor.getStringValue(COL_TYPE_TITLE)
val color = cursor.getIntValue(COL_TYPE_COLOR)
val calendarId = cursor.getIntValue(COL_TYPE_CALDAV_CALENDAR_ID)
val displayName = cursor.getStringValue(COL_TYPE_CALDAV_DISPLAY_NAME)
val email = cursor.getStringValue(COL_TYPE_CALDAV_EMAIL)
return EventType(id, title, color, calendarId, displayName, email)
}
} finally {
cursor?.close()
}
return null
}
fun getBirthdays(): List<Event> {
val selection = "$MAIN_TABLE_NAME.$COL_EVENT_SOURCE = ?"
val selectionArgs = arrayOf(SOURCE_CONTACT_BIRTHDAY)
val cursor = getEventsCursor(selection, selectionArgs)
return fillEvents(cursor)
}
fun getAnniversaries(): List<Event> {
val selection = "$MAIN_TABLE_NAME.$COL_EVENT_SOURCE = ?"
val selectionArgs = arrayOf(SOURCE_CONTACT_ANNIVERSARY)
val cursor = getEventsCursor(selection, selectionArgs)
return fillEvents(cursor)
}
fun deleteEvents(ids: Array<String>, deleteFromCalDAV: Boolean) {
val args = TextUtils.join(", ", ids)
val selection = "$MAIN_TABLE_NAME.$COL_ID IN ($args)"
val cursor = getEventsCursor(selection)
val events = fillEvents(cursor).filter { it.importId.isNotEmpty() }
mDb.delete(MAIN_TABLE_NAME, selection, null)
val metaSelection = "$COL_EVENT_ID IN ($args)"
mDb.delete(META_TABLE_NAME, metaSelection, null)
val exceptionSelection = "$COL_PARENT_EVENT_ID IN ($args)"
mDb.delete(EXCEPTIONS_TABLE_NAME, exceptionSelection, null)
context.updateWidgets()
ids.forEach {
context.cancelNotification(it.toInt())
}
if (deleteFromCalDAV && context.config.caldavSync) {
events.forEach {
CalDAVHandler(context).deleteCalDAVEvent(it)
}
}
deleteChildEvents(args, deleteFromCalDAV)
}
private fun deleteChildEvents(ids: String, deleteFromCalDAV: Boolean) {
val projection = arrayOf(COL_ID)
val selection = "$COL_PARENT_EVENT_ID IN ($ids)"
val childIds = ArrayList<String>()
var cursor: Cursor? = null
try {
cursor = mDb.query(MAIN_TABLE_NAME, projection, selection, null, null, null, null)
if (cursor?.moveToFirst() == true) {
do {
childIds.add(cursor.getStringValue(COL_ID))
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
if (childIds.isNotEmpty())
deleteEvents(childIds.toTypedArray(), deleteFromCalDAV)
}
fun getCalDAVCalendarEvents(calendarId: Long): List<Event> {
val selection = "$MAIN_TABLE_NAME.$COL_EVENT_SOURCE = (?)"
val selectionArgs = arrayOf("$CALDAV-$calendarId")
val cursor = getEventsCursor(selection, selectionArgs)
return fillEvents(cursor).filter { it.importId.isNotEmpty() }
}
private fun updateOldMonthlyEvents(db: SQLiteDatabase) {
val OLD_MONTH = 2592000
val projection = arrayOf(COL_ID, COL_REPEAT_INTERVAL)
val selection = "$COL_REPEAT_INTERVAL != 0 AND $COL_REPEAT_INTERVAL % $OLD_MONTH == 0"
var cursor: Cursor? = null
try {
cursor = db.query(META_TABLE_NAME, projection, selection, null, null, null, null)
if (cursor?.moveToFirst() == true) {
do {
val id = cursor.getIntValue(COL_ID)
val repeatInterval = cursor.getIntValue(COL_REPEAT_INTERVAL)
val multiplies = repeatInterval / OLD_MONTH
val values = ContentValues().apply {
put(COL_REPEAT_INTERVAL, multiplies * MONTH)
}
val updateSelection = "$COL_ID = $id"
db.update(META_TABLE_NAME, values, updateSelection, null)
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
}
fun addEventRepeatException(parentEventId: Int, occurrenceTS: Int) {
fillExceptionValues(parentEventId, occurrenceTS) {
mDb.insert(EXCEPTIONS_TABLE_NAME, null, it)
}
}
fun deleteEventTypes(eventTypes: ArrayList<EventType>, deleteEvents: Boolean, callback: (deletedCnt: Int) -> Unit) {
var deleteIds = eventTypes.filter { it.caldavCalendarId == 0 }.map { it.id }
deleteIds = deleteIds.filter { it != DBHelper.REGULAR_EVENT_TYPE_ID } as ArrayList<Int>
val deletedSet = HashSet<String>()
deleteIds.map { deletedSet.add(it.toString()) }
context.config.removeDisplayEventTypes(deletedSet)
if (deleteIds.isEmpty())
return
for (eventTypeId in deleteIds) {
if (deleteEvents) {
deleteEventsWithType(eventTypeId)
} else {
resetEventsWithType(eventTypeId)
}
}
val args = TextUtils.join(", ", deleteIds)
val selection = "$COL_TYPE_ID IN ($args)"
callback(mDb.delete(TYPES_TABLE_NAME, selection, null))
}
fun deleteEventTypesWithCalendarId(calendarIds: String) {
val selection = "$COL_TYPE_CALDAV_CALENDAR_ID IN ($calendarIds)"
mDb.delete(TYPES_TABLE_NAME, selection, null)
}
private fun deleteEventsWithType(eventTypeId: Int) {
val selection = "$MAIN_TABLE_NAME.$COL_EVENT_TYPE = ?"
val selectionArgs = arrayOf(eventTypeId.toString())
val cursor = getEventsCursor(selection, selectionArgs)
val events = fillEvents(cursor)
val eventIDs = Array(events.size, { i -> (events[i].id.toString()) })
deleteEvents(eventIDs, true)
}
private fun resetEventsWithType(eventTypeId: Int) {
val values = ContentValues()
values.put(COL_EVENT_TYPE, REGULAR_EVENT_TYPE_ID)
val selection = "$COL_EVENT_TYPE = ?"
val selectionArgs = arrayOf(eventTypeId.toString())
mDb.update(MAIN_TABLE_NAME, values, selection, selectionArgs)
}
fun updateEventImportIdAndSource(eventId: Int, importId: String, source: String) {
val values = ContentValues()
values.put(COL_IMPORT_ID, importId)
values.put(COL_EVENT_SOURCE, source)
val selection = "$MAIN_TABLE_NAME.$COL_ID = ?"
val selectionArgs = arrayOf(eventId.toString())
mDb.update(MAIN_TABLE_NAME, values, selection, selectionArgs)
}
fun getEventsWithImportIds() = getEvents("").filter { it.importId.trim().isNotEmpty() } as ArrayList<Event>
fun getEventWithId(id: Int): Event? {
val selection = "$MAIN_TABLE_NAME.$COL_ID = ?"
val selectionArgs = arrayOf(id.toString())
val cursor = getEventsCursor(selection, selectionArgs)
val events = fillEvents(cursor)
return if (events.isNotEmpty()) {
events[0]
} else {
null
}
}
fun getEvents(fromTS: Int, toTS: Int, eventId: Int = -1, callback: (events: MutableList<Event>) -> Unit) {
Thread {
getEventsInBackground(fromTS, toTS, eventId, callback)
}.start()
}
fun getEventsInBackground(fromTS: Int, toTS: Int, eventId: Int = -1, callback: (events: MutableList<Event>) -> Unit) {
val events = ArrayList<Event>()
var selection = "$COL_START_TS <= ? AND $COL_END_TS >= ? AND $COL_REPEAT_INTERVAL IS NULL AND $COL_START_TS != 0"
if (eventId != -1)
selection += " AND $MAIN_TABLE_NAME.$COL_ID = $eventId"
val selectionArgs = arrayOf(toTS.toString(), fromTS.toString())
val cursor = getEventsCursor(selection, selectionArgs)
events.addAll(fillEvents(cursor))
events.addAll(getRepeatableEventsFor(fromTS, toTS, eventId))
events.addAll(getAllDayEvents(fromTS, toTS, eventId))
val filtered = events.distinct().filterNot { it.ignoreEventOccurrences.contains(Formatter.getDayCodeFromTS(it.startTS).toInt()) } as MutableList<Event>
callback(filtered)
}
private fun getRepeatableEventsFor(fromTS: Int, toTS: Int, eventId: Int = -1): List<Event> {
val newEvents = ArrayList<Event>()
// get repeatable events
var selection = "$COL_REPEAT_INTERVAL != 0 AND $COL_START_TS <= $toTS AND $COL_START_TS != 0"
if (eventId != -1)
selection += " AND $MAIN_TABLE_NAME.$COL_ID = $eventId"
val events = getEvents(selection)
val startTimes = SparseIntArray(events.size)
events.forEach {
startTimes.put(it.id, it.startTS)
if (it.repeatLimit >= 0) {
newEvents.addAll(getEventsRepeatingTillDateOrForever(fromTS, toTS, startTimes, it))
} else {
newEvents.addAll(getEventsRepeatingXTimes(fromTS, toTS, startTimes, it))
}
}
return newEvents
}
private fun getEventsRepeatingTillDateOrForever(fromTS: Int, toTS: Int, startTimes: SparseIntArray, event: Event): ArrayList<Event> {
val original = event.copy()
val events = ArrayList<Event>()
while (event.startTS <= toTS && (event.repeatLimit == 0 || event.repeatLimit >= event.startTS)) {
if (event.endTS >= fromTS) {
if (event.repeatInterval.isXWeeklyRepetition()) {
if (event.startTS.isTsOnProperDay(event)) {
if (isOnProperWeek(event, startTimes)) {
events.add(event.copy())
}
}
} else {
events.add(event.copy())
}
}
if (event.getIsAllDay()) {
if (event.repeatInterval.isXWeeklyRepetition()) {
if (event.endTS >= toTS && event.startTS.isTsOnProperDay(event)) {
if (isOnProperWeek(event, startTimes)) {
events.add(event.copy())
}
}
} else {
val dayCode = Formatter.getDayCodeFromTS(fromTS)
val endDayCode = Formatter.getDayCodeFromTS(event.endTS)
if (dayCode == endDayCode) {
events.add(event.copy())
}
}
}
event.addIntervalTime(original)
}
return events
}
private fun getEventsRepeatingXTimes(fromTS: Int, toTS: Int, startTimes: SparseIntArray, event: Event): ArrayList<Event> {
val original = event.copy()
val events = ArrayList<Event>()
while (event.repeatLimit < 0 && event.startTS <= toTS) {
if (event.repeatInterval.isXWeeklyRepetition()) {
if (event.startTS.isTsOnProperDay(event)) {
if (isOnProperWeek(event, startTimes)) {
if (event.endTS >= fromTS) {
events.add(event.copy())
}
event.repeatLimit++
}
}
} else {
if (event.endTS >= fromTS) {
events.add(event.copy())
} else if (event.getIsAllDay()) {
val dayCode = Formatter.getDayCodeFromTS(fromTS)
val endDayCode = Formatter.getDayCodeFromTS(event.endTS)
if (dayCode == endDayCode) {
events.add(event.copy())
}
}
event.repeatLimit++
}
event.addIntervalTime(original)
}
return events
}
private fun getAllDayEvents(fromTS: Int, toTS: Int, eventId: Int = -1): List<Event> {
val events = ArrayList<Event>()
var selection = "($COL_FLAGS & $FLAG_ALL_DAY) != 0"
if (eventId != -1)
selection += " AND $MAIN_TABLE_NAME.$COL_ID = $eventId"
val dayCode = Formatter.getDayCodeFromTS(fromTS)
val cursor = getEventsCursor(selection)
events.addAll(fillEvents(cursor).filter { dayCode == Formatter.getDayCodeFromTS(it.startTS) })
return events
}
// check if its the proper week, for events repeating by x weeks
private fun isOnProperWeek(event: Event, startTimes: SparseIntArray): Boolean {
val initialWeekOfYear = Formatter.getDateTimeFromTS(startTimes[event.id]).weekOfWeekyear
val currentWeekOfYear = Formatter.getDateTimeFromTS(event.startTS).weekOfWeekyear
return (currentWeekOfYear - initialWeekOfYear) % (event.repeatInterval / WEEK) == 0
}
fun getRunningEvents(): List<Event> {
val events = ArrayList<Event>()
val ts = (System.currentTimeMillis() / 1000).toInt()
val selection = "$COL_START_TS <= ? AND $COL_END_TS >= ? AND $COL_REPEAT_INTERVAL IS 0 AND $COL_START_TS != 0"
val selectionArgs = arrayOf(ts.toString(), ts.toString())
val cursor = getEventsCursor(selection, selectionArgs)
events.addAll(fillEvents(cursor))
events.addAll(getRepeatableEventsFor(ts, ts))
return events
}
private fun getEvents(selection: String): List<Event> {
val events = ArrayList<Event>()
var cursor: Cursor? = null
try {
cursor = getEventsCursor(selection)
if (cursor != null) {
val currEvents = fillEvents(cursor)
events.addAll(currEvents)
}
} finally {
cursor?.close()
}
return events
}
fun getEventsWithIds(ids: List<Int>): ArrayList<Event> {
val args = TextUtils.join(", ", ids)
val selection = "$MAIN_TABLE_NAME.$COL_ID IN ($args)"
return getEvents(selection) as ArrayList<Event>
}
// get deprecated Google Sync events
fun getGoogleSyncEvents(): ArrayList<Event> {
val selection = "$MAIN_TABLE_NAME.$COL_SOURCE = $SOURCE_GOOGLE_CALENDAR"
return getEvents(selection) as ArrayList<Event>
}
fun getEventsAtReboot(): List<Event> {
val selection = "$COL_REMINDER_MINUTES != -1 AND ($COL_START_TS > ? OR $COL_REPEAT_INTERVAL != 0) AND $COL_START_TS != 0"
val selectionArgs = arrayOf(DateTime.now().seconds().toString())
val cursor = getEventsCursor(selection, selectionArgs)
return fillEvents(cursor)
}
fun getEventsToExport(includePast: Boolean): ArrayList<Event> {
val currTime = (System.currentTimeMillis() / 1000).toString()
var events = ArrayList<Event>()
// non repeating events
var cursor = if (includePast) {
getEventsCursor()
} else {
val selection = "$COL_END_TS > ?"
val selectionArgs = arrayOf(currTime)
getEventsCursor(selection, selectionArgs)
}
events.addAll(fillEvents(cursor))
// repeating events
if (!includePast) {
val selection = "$COL_REPEAT_INTERVAL != 0 AND ($COL_REPEAT_LIMIT == 0 OR $COL_REPEAT_LIMIT > ?)"
val selectionArgs = arrayOf(currTime)
cursor = getEventsCursor(selection, selectionArgs)
events.addAll(fillEvents(cursor))
}
events = events.distinctBy { it.id } as ArrayList<Event>
return events
}
fun getEventsFromCalDAVCalendar(calendarId: Int): List<Event> {
val selection = "$MAIN_TABLE_NAME.$COL_EVENT_SOURCE = ?"
val selectionArgs = arrayOf("$CALDAV-$calendarId")
val cursor = getEventsCursor(selection, selectionArgs)
return fillEvents(cursor)
}
private fun getEventsCursor(selection: String = "", selectionArgs: Array<String>? = null): Cursor? {
val builder = SQLiteQueryBuilder()
builder.tables = "$MAIN_TABLE_NAME LEFT OUTER JOIN $META_TABLE_NAME ON $COL_EVENT_ID = $MAIN_TABLE_NAME.$COL_ID"
val projection = allColumns
return builder.query(mDb, projection, selection, selectionArgs, "$MAIN_TABLE_NAME.$COL_ID", null, COL_START_TS)
}
private val allColumns: Array<String>
get() = arrayOf("$MAIN_TABLE_NAME.$COL_ID", COL_START_TS, COL_END_TS, COL_TITLE, COL_DESCRIPTION, COL_REMINDER_MINUTES, COL_REMINDER_MINUTES_2,
COL_REMINDER_MINUTES_3, COL_REPEAT_INTERVAL, COL_REPEAT_RULE, COL_IMPORT_ID, COL_FLAGS, COL_REPEAT_LIMIT, COL_EVENT_TYPE, COL_OFFSET,
COL_IS_DST_INCLUDED, COL_LAST_UPDATED, COL_EVENT_SOURCE, COL_LOCATION)
private fun fillEvents(cursor: Cursor?): List<Event> {
val eventTypeColors = SparseIntArray()
fetchEventTypes().forEach {
eventTypeColors.put(it.id, it.color)
}
val events = ArrayList<Event>()
cursor?.use {
if (cursor.moveToFirst()) {
do {
val id = cursor.getIntValue(COL_ID)
val startTS = cursor.getIntValue(COL_START_TS)
val endTS = cursor.getIntValue(COL_END_TS)
val reminder1Minutes = cursor.getIntValue(COL_REMINDER_MINUTES)
val reminder2Minutes = cursor.getIntValue(COL_REMINDER_MINUTES_2)
val reminder3Minutes = cursor.getIntValue(COL_REMINDER_MINUTES_3)
val repeatInterval = cursor.getIntValue(COL_REPEAT_INTERVAL)
var repeatRule = cursor.getIntValue(COL_REPEAT_RULE)
val title = cursor.getStringValue(COL_TITLE)
val description = cursor.getStringValue(COL_DESCRIPTION)
val importId = cursor.getStringValue(COL_IMPORT_ID) ?: ""
val flags = cursor.getIntValue(COL_FLAGS)
val repeatLimit = cursor.getIntValue(COL_REPEAT_LIMIT)
val eventType = cursor.getIntValue(COL_EVENT_TYPE)
val offset = cursor.getStringValue(COL_OFFSET)
val isDstIncluded = cursor.getIntValue(COL_IS_DST_INCLUDED) == 1
val lastUpdated = cursor.getLongValue(COL_LAST_UPDATED)
val source = cursor.getStringValue(COL_EVENT_SOURCE)
val location = cursor.getStringValue(COL_LOCATION)
val color = eventTypeColors[eventType]
val ignoreEventOccurrences = if (repeatInterval != 0) {
getIgnoredOccurrences(id)
} else {
ArrayList()
}
if (repeatInterval > 0 && repeatInterval % MONTH == 0 && repeatRule == 0) {
repeatRule = REPEAT_MONTH_SAME_DAY
}
val event = Event(id, startTS, endTS, title, description, reminder1Minutes, reminder2Minutes, reminder3Minutes,
repeatInterval, importId, flags, repeatLimit, repeatRule, eventType, ignoreEventOccurrences, offset, isDstIncluded,
0, lastUpdated, source, color, location)
events.add(event)
} while (cursor.moveToNext())
}
}
return events
}
fun getEventTypes(callback: (types: ArrayList<EventType>) -> Unit) {
Thread {
callback(fetchEventTypes())
}.start()
}
fun fetchEventTypes(): ArrayList<EventType> {
val eventTypes = ArrayList<EventType>(4)
val cols = arrayOf(COL_TYPE_ID, COL_TYPE_TITLE, COL_TYPE_COLOR, COL_TYPE_CALDAV_CALENDAR_ID, COL_TYPE_CALDAV_DISPLAY_NAME, COL_TYPE_CALDAV_EMAIL)
var cursor: Cursor? = null
try {
cursor = mDb.query(TYPES_TABLE_NAME, cols, null, null, null, null, "$COL_TYPE_TITLE ASC")
if (cursor?.moveToFirst() == true) {
do {
val id = cursor.getIntValue(COL_TYPE_ID)
val title = cursor.getStringValue(COL_TYPE_TITLE)
val color = cursor.getIntValue(COL_TYPE_COLOR)
val calendarId = cursor.getIntValue(COL_TYPE_CALDAV_CALENDAR_ID)
val displayName = cursor.getStringValue(COL_TYPE_CALDAV_DISPLAY_NAME)
val email = cursor.getStringValue(COL_TYPE_CALDAV_EMAIL)
val eventType = EventType(id, title, color, calendarId, displayName, email)
eventTypes.add(eventType)
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
return eventTypes
}
fun doEventTypesContainEvent(types: ArrayList<EventType>): Boolean {
val args = TextUtils.join(", ", types.map { it.id })
val columns = arrayOf(COL_ID)
val selection = "$COL_EVENT_TYPE IN ($args)"
var cursor: Cursor? = null
try {
cursor = mDb.query(MAIN_TABLE_NAME, columns, selection, null, null, null, null)
return cursor?.moveToFirst() == true
} finally {
cursor?.close()
}
}
private fun getIgnoredOccurrences(eventId: Int): ArrayList<Int> {
val projection = arrayOf(COL_OCCURRENCE_DAYCODE)
val selection = "$COL_PARENT_EVENT_ID = ?"
val selectionArgs = arrayOf(eventId.toString())
val daycodes = ArrayList<Int>()
var cursor: Cursor? = null
try {
cursor = mDb.query(EXCEPTIONS_TABLE_NAME, projection, selection, selectionArgs, null, null, COL_OCCURRENCE_DAYCODE)
if (cursor?.moveToFirst() == true) {
do {
daycodes.add(cursor.getIntValue(COL_OCCURRENCE_DAYCODE))
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
return daycodes
}
private fun convertExceptionTimestampToDaycode(db: SQLiteDatabase) {
val projection = arrayOf(COL_EXCEPTION_ID, COL_OCCURRENCE_TIMESTAMP)
var cursor: Cursor? = null
try {
cursor = db.query(EXCEPTIONS_TABLE_NAME, projection, null, null, null, null, null)
if (cursor?.moveToFirst() == true) {
do {
val id = cursor.getIntValue(COL_EXCEPTION_ID)
val ts = cursor.getIntValue(COL_OCCURRENCE_TIMESTAMP)
val values = ContentValues()
values.put(COL_OCCURRENCE_DAYCODE, Formatter.getDayCodeFromTS(ts))
val selection = "$COL_EXCEPTION_ID = ?"
val selectionArgs = arrayOf(id.toString())
db.update(EXCEPTIONS_TABLE_NAME, values, selection, selectionArgs)
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
}
private fun setupRepeatRules(db: SQLiteDatabase) {
val projection = arrayOf(COL_EVENT_ID, COL_REPEAT_INTERVAL, COL_REPEAT_START)
val selection = "$COL_REPEAT_INTERVAL != 0"
var cursor: Cursor? = null
try {
cursor = db.query(META_TABLE_NAME, projection, selection, null, null, null, null)
if (cursor?.moveToFirst() == true) {
do {
val interval = cursor.getIntValue(COL_REPEAT_INTERVAL)
if (interval != MONTH && interval % WEEK != 0)
continue
val eventId = cursor.getIntValue(COL_EVENT_ID)
val start = cursor.getIntValue(COL_REPEAT_START)
var rule = Math.pow(2.0, (Formatter.getDateTimeFromTS(start).dayOfWeek - 1).toDouble()).toInt()
if (interval == MONTH) {
rule = REPEAT_MONTH_SAME_DAY
}
val values = ContentValues()
values.put(COL_REPEAT_RULE, rule)
val curSelection = "$COL_EVENT_ID = ?"
val curSelectionArgs = arrayOf(eventId.toString())
db.update(META_TABLE_NAME, values, curSelection, curSelectionArgs)
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
}
}

View file

@ -1,226 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.Context
import android.widget.Toast
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.helpers.IcsImporter.ImportResult.*
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.extensions.areDigitsOnly
import com.simplemobiletools.commons.extensions.showErrorToast
import java.io.File
class IcsImporter(val activity: SimpleActivity) {
enum class ImportResult {
IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL
}
private var curStart = -1
private var curEnd = -1
private var curTitle = ""
private var curDescription = ""
private var curImportId = ""
private var curFlags = 0
private var curReminderMinutes = ArrayList<Int>()
private var curRepeatExceptions = ArrayList<Int>()
private var curRepeatInterval = 0
private var curRepeatLimit = 0
private var curRepeatRule = 0
private var curEventType = DBHelper.REGULAR_EVENT_TYPE_ID
private var curLastModified = 0L
private var curLocation = ""
private var curCategoryColor = -2
private var isNotificationDescription = false
private var isProperReminderAction = false
private var curReminderTriggerMinutes = -1
private var eventsImported = 0
private var eventsFailed = 0
fun importEvents(path: String, defaultEventType: Int): ImportResult {
try {
val existingEvents = activity.dbHelper.getEventsWithImportIds()
var prevLine = ""
val inputStream = if (path.contains("/")) {
File(path).inputStream()
} else {
activity.assets.open(path)
}
inputStream.bufferedReader().use {
while (true) {
var line = it.readLine() ?: break
if (line.trim().isEmpty())
continue
if (line.substring(0, 1) == " ") {
line = prevLine + line.trim()
eventsFailed--
}
if (line == BEGIN_EVENT) {
resetValues()
curEventType = defaultEventType
} else if (line.startsWith(DTSTART)) {
curStart = getTimestamp(line.substring(DTSTART.length))
} else if (line.startsWith(DTEND)) {
curEnd = getTimestamp(line.substring(DTEND.length))
} else if (line.startsWith(DURATION)) {
val duration = line.substring(DURATION.length)
curEnd = curStart + Parser().parseDurationSeconds(duration)
} else if (line.startsWith(SUMMARY) && !isNotificationDescription) {
curTitle = line.substring(SUMMARY.length)
curTitle = getTitle(curTitle).replace("\\n", "\n")
} else if (line.startsWith(DESCRIPTION) && !isNotificationDescription) {
curDescription = line.substring(DESCRIPTION.length).replace("\\n", "\n")
} else if (line.startsWith(UID)) {
curImportId = line.substring(UID.length).trim()
} else if (line.startsWith(RRULE)) {
val repeatRule = Parser().parseRepeatInterval(line.substring(RRULE.length), curStart)
curRepeatRule = repeatRule.repeatRule
curRepeatInterval = repeatRule.repeatInterval
curRepeatLimit = repeatRule.repeatLimit
} else if (line.startsWith(ACTION)) {
isNotificationDescription = true
isProperReminderAction = line.substring(ACTION.length) == DISPLAY
} else if (line.startsWith(TRIGGER)) {
curReminderTriggerMinutes = Parser().parseDurationSeconds(line.substring(TRIGGER.length)) / 60
} else if (line.startsWith(CATEGORY_COLOR)) {
val color = line.substring(CATEGORY_COLOR.length)
if (color.trimStart('-').areDigitsOnly()) {
curCategoryColor = Integer.parseInt(color)
}
} else if (line.startsWith(CATEGORIES)) {
val categories = line.substring(CATEGORIES.length)
tryAddCategories(categories, activity)
} else if (line.startsWith(LAST_MODIFIED)) {
curLastModified = getTimestamp(line.substring(LAST_MODIFIED.length)) * 1000L
} else if (line.startsWith(EXDATE)) {
var value = line.substring(EXDATE.length)
if (value.endsWith('}'))
value = value.substring(0, value.length - 1)
curRepeatExceptions.add(getTimestamp(value))
} else if (line.startsWith(LOCATION)) {
curLocation = line.substring(LOCATION.length)
} else if (line == END_ALARM) {
if (isProperReminderAction && curReminderTriggerMinutes != -1) {
curReminderMinutes.add(curReminderTriggerMinutes)
}
} else if (line == END_EVENT) {
if (curStart != -1 && curEnd == -1)
curEnd = curStart
if (curTitle.isEmpty() || curStart == -1)
continue
val eventToUpdate = existingEvents.firstOrNull { curImportId.isNotEmpty() && curImportId == it.importId }
if (eventToUpdate != null && eventToUpdate.lastUpdated >= curLastModified) {
continue
}
val event = Event(0, curStart, curEnd, curTitle, curDescription, curReminderMinutes.getOrElse(0, { -1 }),
curReminderMinutes.getOrElse(1, { -1 }), curReminderMinutes.getOrElse(2, { -1 }), curRepeatInterval,
curImportId, curFlags, curRepeatLimit, curRepeatRule, curEventType, lastUpdated = curLastModified,
source = SOURCE_IMPORTED_ICS, location = curLocation)
if (event.getIsAllDay() && curEnd > curStart) {
event.endTS -= DAY
}
if (eventToUpdate == null) {
activity.dbHelper.insert(event, false) {
for (exceptionTS in curRepeatExceptions) {
activity.dbHelper.addEventRepeatException(it, exceptionTS)
}
existingEvents.add(event)
}
} else {
event.id = eventToUpdate.id
activity.dbHelper.update(event, true) {}
}
eventsImported++
resetValues()
}
prevLine = line
}
}
} catch (e: Exception) {
activity.showErrorToast(e, Toast.LENGTH_LONG)
eventsFailed++
}
return when {
eventsImported == 0 -> IMPORT_FAIL
eventsFailed > 0 -> IMPORT_PARTIAL
else -> IMPORT_OK
}
}
private fun getTimestamp(fullString: String): Int {
return try {
if (fullString.startsWith(';')) {
val value = fullString.substring(fullString.lastIndexOf(':') + 1)
if (!value.contains("T"))
curFlags = curFlags or FLAG_ALL_DAY
Parser().parseDateTimeValue(value)
} else {
Parser().parseDateTimeValue(fullString.substring(1))
}
} catch (e: Exception) {
activity.showErrorToast(e, Toast.LENGTH_LONG)
eventsFailed++
-1
}
}
private fun tryAddCategories(categories: String, context: Context) {
val eventTypeTitle = if (categories.contains(",")) {
categories.split(",")[0]
} else {
categories
}
val eventId = context.dbHelper.getEventTypeIdWithTitle(eventTypeTitle)
curEventType = if (eventId == -1) {
val newTypeColor = if (curCategoryColor == -2) context.resources.getColor(R.color.color_primary) else curCategoryColor
val eventType = EventType(0, eventTypeTitle, newTypeColor)
context.dbHelper.insertEventType(eventType)
} else {
eventId
}
}
private fun getTitle(title: String): String {
return if (title.startsWith(";") && title.contains(":")) {
title.substring(title.lastIndexOf(':') + 1)
} else {
title.substring(1, Math.min(title.length, 80))
}
}
private fun resetValues() {
curStart = -1
curEnd = -1
curTitle = ""
curDescription = ""
curImportId = ""
curFlags = 0
curReminderMinutes = ArrayList()
curRepeatExceptions = ArrayList()
curRepeatInterval = 0
curRepeatLimit = 0
curRepeatRule = 0
curEventType = DBHelper.REGULAR_EVENT_TYPE_ID
curLastModified = 0L
curCategoryColor = -2
curLocation = ""
isNotificationDescription = false
isProperReminderAction = false
curReminderTriggerMinutes = -1
}
}

View file

@ -1,141 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.Context
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.getFilteredEvents
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.models.DayMonthly
import com.simplemobiletools.calendar.models.Event
import org.joda.time.DateTime
import java.util.*
import kotlin.collections.ArrayList
class MonthlyCalendarImpl(val mCallback: MonthlyCalendar, val mContext: Context) {
private val DAYS_CNT = 42
private val YEAR_PATTERN = "YYYY"
private val mToday: String = DateTime().toString(Formatter.DAYCODE_PATTERN)
private var mEvents = ArrayList<Event>()
private var mFilterEventTypes = true
lateinit var mTargetDate: DateTime
fun updateMonthlyCalendar(targetDate: DateTime, filterEventTypes: Boolean = true) {
mFilterEventTypes = filterEventTypes
mTargetDate = targetDate
val startTS = mTargetDate.minusMonths(1).seconds()
val endTS = mTargetDate.plusMonths(1).seconds()
mContext.dbHelper.getEvents(startTS, endTS) {
gotEvents(it as ArrayList<Event>)
}
}
fun getMonth(targetDate: DateTime) {
updateMonthlyCalendar(targetDate)
}
fun getDays(markDaysWithEvents: Boolean) {
val days = ArrayList<DayMonthly>(DAYS_CNT)
val currMonthDays = mTargetDate.dayOfMonth().maximumValue
var firstDayIndex = mTargetDate.withDayOfMonth(1).dayOfWeek
if (!mContext.config.isSundayFirst)
firstDayIndex -= 1
val prevMonthDays = mTargetDate.minusMonths(1).dayOfMonth().maximumValue
var isThisMonth = false
var isToday: Boolean
var value = prevMonthDays - firstDayIndex + 1
var curDay: DateTime = mTargetDate
for (i in 0 until DAYS_CNT) {
when {
i < firstDayIndex -> {
isThisMonth = false
curDay = mTargetDate.withDayOfMonth(1).minusMonths(1)
}
i == firstDayIndex -> {
value = 1
isThisMonth = true
curDay = mTargetDate
}
value == currMonthDays + 1 -> {
value = 1
isThisMonth = false
curDay = mTargetDate.withDayOfMonth(1).plusMonths(1)
}
}
isToday = isThisMonth && isToday(mTargetDate, value)
val newDay = curDay.withDayOfMonth(value)
val dayCode = Formatter.getDayCodeFromDateTime(newDay)
val day = DayMonthly(value, isThisMonth, isToday, dayCode, newDay.weekOfWeekyear, ArrayList())
days.add(day)
value++
}
if (markDaysWithEvents) {
markDaysWithEvents(days)
} else {
mCallback.updateMonthlyCalendar(mContext, monthName, days, false)
}
}
// it works more often than not, dont touch
private fun markDaysWithEvents(days: ArrayList<DayMonthly>) {
mContext.dbHelper.getEventTypes {
val dayEvents = HashMap<String, ArrayList<Event>>()
mEvents.forEach {
val startDateTime = Formatter.getDateTimeFromTS(it.startTS)
val endDateTime = Formatter.getDateTimeFromTS(it.endTS)
val endCode = Formatter.getDayCodeFromDateTime(endDateTime)
var currDay = startDateTime
var dayCode = Formatter.getDayCodeFromDateTime(currDay)
var currDayEvents = (dayEvents[dayCode] ?: ArrayList()).apply { add(it) }
dayEvents.put(dayCode, currDayEvents)
while (Formatter.getDayCodeFromDateTime(currDay) != endCode) {
currDay = currDay.plusDays(1)
dayCode = Formatter.getDayCodeFromDateTime(currDay)
currDayEvents = (dayEvents[dayCode] ?: ArrayList()).apply { add(it) }
dayEvents.put(dayCode, currDayEvents)
}
}
days.filter { dayEvents.keys.contains(it.code) }.forEach {
it.dayEvents = dayEvents[it.code]!!
}
mCallback.updateMonthlyCalendar(mContext, monthName, days, true)
}
}
private fun isToday(targetDate: DateTime, curDayInMonth: Int): Boolean {
return if (curDayInMonth > targetDate.dayOfMonth().maximumValue)
false
else
targetDate.withDayOfMonth(curDayInMonth).toString(Formatter.DAYCODE_PATTERN) == mToday
}
private val monthName: String
get() {
var month = Formatter.getMonthName(mContext, mTargetDate.monthOfYear)
val targetYear = mTargetDate.toString(YEAR_PATTERN)
if (targetYear != DateTime().toString(YEAR_PATTERN)) {
month += " $targetYear"
}
return month
}
private fun gotEvents(events: ArrayList<Event>) {
mEvents = if (mFilterEventTypes) {
mContext.getFilteredEvents(events) as ArrayList<Event>
} else {
events
}
getDays(true)
}
}

View file

@ -1,20 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.Context
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.interfaces.WeeklyCalendar
import com.simplemobiletools.calendar.models.Event
import java.util.*
class WeeklyCalendarImpl(val mCallback: WeeklyCalendar, val mContext: Context) {
var mEvents = ArrayList<Event>()
fun updateWeeklyCalendar(weekStartTS: Int) {
val startTS = weekStartTS
val endTS = startTS + WEEK_SECONDS
mContext.dbHelper.getEvents(startTS, endTS) {
mEvents = it as ArrayList<Event>
mCallback.updateWeeklyCalendar(it)
}
}
}

View file

@ -1,8 +0,0 @@
package com.simplemobiletools.calendar.interfaces
import com.simplemobiletools.calendar.models.EventType
import java.util.*
interface DeleteEventTypesListener {
fun deleteEventTypes(eventTypes: ArrayList<EventType>, deleteEvents: Boolean)
}

View file

@ -1,9 +0,0 @@
package com.simplemobiletools.calendar.interfaces
import java.util.*
interface DeleteEventsListener {
fun deleteItems(ids: ArrayList<Int>)
fun addEventRepeatException(parentIds: ArrayList<Int>, timestamps: ArrayList<Int>)
}

View file

@ -1,8 +0,0 @@
package com.simplemobiletools.calendar.interfaces
import android.content.Context
import com.simplemobiletools.calendar.models.DayMonthly
interface MonthlyCalendar {
fun updateMonthlyCalendar(context: Context, month: String, days: List<DayMonthly>, checkedEvents: Boolean)
}

View file

@ -1,7 +0,0 @@
package com.simplemobiletools.calendar.interfaces
import com.simplemobiletools.calendar.models.Event
interface WeeklyCalendar {
fun updateWeeklyCalendar(events: ArrayList<Event>)
}

View file

@ -1,7 +0,0 @@
package com.simplemobiletools.calendar.models
data class CalDAVCalendar(val id: Int, val displayName: String, val accountName: String, val ownerName: String, val color: Int, val accessLevel: Int) {
fun canWrite() = accessLevel >= 500
fun getFullTitle() = "$displayName ($accountName)"
}

View file

@ -1,114 +0,0 @@
package com.simplemobiletools.calendar.models
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import org.joda.time.DateTime
import java.io.Serializable
import java.util.*
data class Event(var id: Int = 0, var startTS: Int = 0, var endTS: Int = 0, var title: String = "", var description: String = "",
var reminder1Minutes: Int = -1, var reminder2Minutes: Int = -1, var reminder3Minutes: Int = -1, var repeatInterval: Int = 0,
var importId: String = "", var flags: Int = 0, var repeatLimit: Int = 0, var repeatRule: Int = 0,
var eventType: Int = DBHelper.REGULAR_EVENT_TYPE_ID, var ignoreEventOccurrences: ArrayList<Int> = ArrayList(),
var offset: String = "", var isDstIncluded: Boolean = false, var parentId: Int = 0, var lastUpdated: Long = 0L,
var source: String = SOURCE_SIMPLE_CALENDAR, var color: Int = 0, var location: String = "") : Serializable {
companion object {
private val serialVersionUID = -32456795132345616L
}
fun addIntervalTime(original: Event) {
val currStart = Formatter.getDateTimeFromTS(startTS)
val newStart: DateTime
newStart = when (repeatInterval) {
DAY -> currStart.plusDays(1)
else -> {
when {
repeatInterval % YEAR == 0 -> currStart.plusYears(repeatInterval / YEAR)
repeatInterval % MONTH == 0 -> when (repeatRule) {
REPEAT_MONTH_SAME_DAY -> addMonthsWithSameDay(currStart, original)
REPEAT_MONTH_ORDER_WEEKDAY_USE_LAST -> addXthDayInterval(currStart, original, true)
REPEAT_MONTH_ORDER_WEEKDAY -> addXthDayInterval(currStart, original, false)
else -> currStart.plusMonths(repeatInterval / MONTH).dayOfMonth().withMaximumValue()
}
repeatInterval % WEEK == 0 -> {
// step through weekly repetition by days too, as events can trigger multiple times a week
currStart.plusDays(1)
}
else -> currStart.plusSeconds(repeatInterval)
}
}
}
val newStartTS = newStart.seconds()
val newEndTS = newStartTS + (endTS - startTS)
startTS = newStartTS
endTS = newEndTS
}
// if an event should happen on 31st with Same Day monthly repetition, dont show it at all at months with 30 or less days
private fun addMonthsWithSameDay(currStart: DateTime, original: Event): DateTime {
var newDateTime = currStart.plusMonths(repeatInterval / MONTH)
if (newDateTime.dayOfMonth == currStart.dayOfMonth) {
return newDateTime
}
while (newDateTime.dayOfMonth().maximumValue < Formatter.getDateTimeFromTS(original.startTS).dayOfMonth().maximumValue) {
newDateTime = newDateTime.plusMonths(repeatInterval / MONTH)
newDateTime = newDateTime.withDayOfMonth(newDateTime.dayOfMonth().maximumValue)
}
return newDateTime
}
// handle monthly repetitions like Third Monday
private fun addXthDayInterval(currStart: DateTime, original: Event, forceLastWeekday: Boolean): DateTime {
val day = currStart.dayOfWeek
var order = (currStart.dayOfMonth - 1) / 7
val properMonth = currStart.withDayOfMonth(7).plusMonths(repeatInterval / MONTH).withDayOfWeek(day)
var firstProperDay = properMonth.dayOfMonth % 7
if (firstProperDay == 0)
firstProperDay = properMonth.dayOfMonth
// check if it should be for example Fourth Monday, or Last Monday
if (forceLastWeekday && (order == 3 || order == 4)) {
val originalDateTime = Formatter.getDateTimeFromTS(original.startTS)
val isLastWeekday = originalDateTime.monthOfYear != originalDateTime.plusDays(7).monthOfYear
if (isLastWeekday)
order = -1
}
val daysCnt = properMonth.dayOfMonth().maximumValue
var wantedDay = firstProperDay + order * 7
if (wantedDay > daysCnt)
wantedDay -= 7
if (order == -1) {
wantedDay = firstProperDay + ((daysCnt - firstProperDay) / 7) * 7
}
return properMonth.withDayOfMonth(wantedDay)
}
fun getIsAllDay() = flags and FLAG_ALL_DAY != 0
fun getReminders() = setOf(reminder1Minutes, reminder2Minutes, reminder3Minutes).filter { it != REMINDER_OFF }
// properly return the start time of all-day events as midnight
fun getEventStartTS(): Int {
return if (getIsAllDay()) {
Formatter.getDateTimeFromTS(startTS).withTime(0, 0, 0, 0).seconds()
} else {
startTS
}
}
fun getCalDAVEventId(): Long {
return try {
(importId.split("-").lastOrNull() ?: "0").toString().toLong()
} catch (e: NumberFormatException) {
0L
}
}
fun getCalDAVCalendarId() = if (source.startsWith(CALDAV)) (source.split("-").lastOrNull() ?: "0").toString().toInt() else 0
}

View file

@ -1,5 +0,0 @@
package com.simplemobiletools.calendar.models
data class EventType(var id: Int = 0, var title: String, var color: Int, var caldavCalendarId: Int = 0, var caldavDisplayName: String = "", var caldavEmail: String = "") {
fun getDisplayTitle() = if (caldavCalendarId == 0) title else "$caldavDisplayName ($caldavEmail)"
}

View file

@ -1,4 +0,0 @@
package com.simplemobiletools.calendar.models
class ListEvent(var id: Int = 0, var startTS: Int = 0, var endTS: Int = 0, var title: String = "", var description: String = "",
var isAllDay: Boolean, var color: Int, var location: String = "") : ListItem()

View file

@ -1,3 +0,0 @@
package com.simplemobiletools.calendar.models
open class ListItem

View file

@ -1,5 +0,0 @@
package com.simplemobiletools.calendar.models
class ListSection(val title: String, val isToday: Boolean = false) : ListItem() {
override fun toString() = "ListSection {title=$title, isToday=$isToday}"
}

View file

@ -1,3 +0,0 @@
package com.simplemobiletools.calendar.models
data class RepeatRule(val repeatInterval: Int, val repeatRule: Int, val repeatLimit: Int)

View file

@ -0,0 +1,11 @@
package com.simplemobiletools.calendar.pro
import androidx.multidex.MultiDexApplication
import com.simplemobiletools.commons.extensions.checkUseEnglish
class App : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
checkUseEnglish()
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,17 @@
package com.simplemobiletools.calendar.activities
package com.simplemobiletools.calendar.pro.activities
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.adapters.ManageEventTypesAdapter
import com.simplemobiletools.calendar.dialogs.UpdateEventTypeDialog
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.interfaces.DeleteEventTypesListener
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.adapters.ManageEventTypesAdapter
import com.simplemobiletools.calendar.pro.dialogs.EditEventTypeDialog
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.interfaces.DeleteEventTypesListener
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.updateTextColors
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import kotlinx.android.synthetic.main.activity_manage_event_types.*
import java.util.*
@ -24,25 +25,23 @@ class ManageEventTypesActivity : SimpleActivity(), DeleteEventTypesListener {
}
private fun showEventTypeDialog(eventType: EventType? = null) {
UpdateEventTypeDialog(this, eventType?.copy()) {
EditEventTypeDialog(this, eventType?.copy()) {
getEventTypes()
}
}
private fun getEventTypes() {
dbHelper.getEventTypes {
runOnUiThread {
eventsHelper.getEventTypes(this, false) {
val adapter = ManageEventTypesAdapter(this, it, this, manage_event_types_list) {
showEventTypeDialog(it as EventType)
}
adapter.setupDragListener(true)
manage_event_types_list.adapter = adapter
}
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_event_types, menu)
updateMenuItemColors(menu)
return true
}
@ -54,15 +53,17 @@ class ManageEventTypesActivity : SimpleActivity(), DeleteEventTypesListener {
return true
}
override fun deleteEventTypes(eventTypes: ArrayList<EventType>, deleteEvents: Boolean) {
override fun deleteEventTypes(eventTypes: ArrayList<EventType>, deleteEvents: Boolean): Boolean {
if (eventTypes.any { it.caldavCalendarId != 0 }) {
toast(R.string.unsync_caldav_calendar)
if (eventTypes.size == 1) {
return false
}
}
dbHelper.deleteEventTypes(eventTypes, deleteEvents) {
if (it == 0) {
toast(R.string.unknown_error_occurred)
}
}
ensureBackgroundThread {
eventsHelper.deleteEventTypes(eventTypes, deleteEvents)
}
return true
}
}

Some files were not shown because too many files have changed in this diff Show more