Merge pull request #17 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2018-12-05 08:40:43 +03:00 committed by GitHub
commit 5a59b833e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
166 changed files with 2360 additions and 2599 deletions

7
.gitignore vendored
View File

@ -1,10 +1,11 @@
*.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,28 @@
Changelog
==========
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)*
----------------------------

View File

@ -13,15 +13,15 @@ The Storage permission is needed only for exporting or importing events from .ic
The Contacts permission is used only at importing contact birthdays and anniversaries.
This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
<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/packages/com.simplemobiletools.calendar'><img src='http://simplemobiletools.github.io/assets/public/f-droid.png' alt='Get it on F-Droid' height='45' /></a>
<a href='https://play.google.com/store/apps/details?id=com.simplemobiletools.calendar.pro'><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/packages/com.simplemobiletools.calendar.pro'><img src='http://simplemobiletools.github.io/assets/public/f-droid.png' alt='Get it on F-Droid' height='45' /></a>
<div style="display:flex;">
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app.png" width="30%">
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app_4.png" width="30%">
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app_5.png" width="30%">
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app_6.png" width="30%">
</div>
License

View File

@ -1,23 +1,33 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.simplemobiletools.calendar"
applicationId "com.simplemobiletools.calendar.pro"
minSdkVersion 21
targetSdkVersion 28
versionCode 133
versionName "5.1.1"
versionCode 136
versionName "6.0.1"
multiDexEnabled true
setProperty("archivesBaseName", "calendar")
}
signingConfigs {
release
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
@ -42,27 +52,11 @@ android {
}
dependencies {
implementation 'com.simplemobiletools:commons:5.2.6'
implementation 'joda-time:joda-time:2.9.9'
implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'com.simplemobiletools:commons:5.5.5'
implementation 'joda-time:joda-time:2.10.1'
implementation 'androidx.multidex:multidex:2.0.0'
}
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.0.0'
implementation 'androidx.room:room-runtime:2.0.0'
annotationProcessor 'androidx.room:room-compiler:2.0.0'
}

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

View File

@ -2,7 +2,7 @@
<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"/>

View File

@ -1,30 +0,0 @@
package com.simplemobiletools.calendar.activities
import com.simplemobiletools.calendar.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
open class SimpleActivity : BaseSimpleActivity() {
override fun getAppIconIDs() = arrayListOf(
R.mipmap.ic_launcher_red,
R.mipmap.ic_launcher_pink,
R.mipmap.ic_launcher_purple,
R.mipmap.ic_launcher_deep_purple,
R.mipmap.ic_launcher_indigo,
R.mipmap.ic_launcher_blue,
R.mipmap.ic_launcher_light_blue,
R.mipmap.ic_launcher_cyan,
R.mipmap.ic_launcher_teal,
R.mipmap.ic_launcher_green,
R.mipmap.ic_launcher_light_green,
R.mipmap.ic_launcher_lime,
R.mipmap.ic_launcher_yellow,
R.mipmap.ic_launcher_amber,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher_deep_orange,
R.mipmap.ic_launcher_brown,
R.mipmap.ic_launcher_blue_grey,
R.mipmap.ic_launcher_grey_black
)
override fun getAppLauncherName() = getString(R.string.app_launcher_name)
}

View File

@ -1,32 +0,0 @@
package com.simplemobiletools.calendar.activities
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.rescheduleReminder
import com.simplemobiletools.calendar.helpers.EVENT_ID
import com.simplemobiletools.commons.extensions.showPickSecondsDialogHelper
class SnoozeReminderActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
showPickSecondsDialogHelper(config.snoozeTime, true, cancelCallback = { dialogCancelled() }) {
val eventId = intent.getIntExtra(EVENT_ID, 0)
val event = dbHelper.getEventWithId(eventId)
config.snoozeTime = it / 60
rescheduleReminder(event, it / 60)
finishActivity()
}
}
private fun dialogCancelled() {
finishActivity()
}
private fun finishActivity() {
finish()
overridePendingTransition(0, 0)
}
}

View File

@ -1,37 +0,0 @@
package com.simplemobiletools.calendar.dialogs
import androidx.appcompat.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.getEventTypesSync()
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,5 +0,0 @@
package com.simplemobiletools.calendar.extensions
import org.joda.time.DateTime
fun DateTime.seconds() = (millis / 1000).toInt()

View File

@ -1,19 +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.helpers.YEAR
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
fun Int.isXYearlyRepetition() = this != 0 && this % YEAR == 0

View File

@ -1,99 +0,0 @@
package com.simplemobiletools.calendar.helpers
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.helpers.IcsExporter.ExportResult.*
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.getFileOutputStream
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.writeLn
import com.simplemobiletools.commons.models.FileDirItem
import java.io.BufferedWriter
import java.io.File
class IcsExporter {
enum class ExportResult {
EXPORT_FAIL, EXPORT_OK, EXPORT_PARTIAL
}
private var eventsExported = 0
private var eventsFailed = 0
fun exportEvents(activity: BaseSimpleActivity, file: File, events: ArrayList<Event>, showExportingToast: Boolean, callback: (result: ExportResult) -> Unit) {
val fileDirItem = FileDirItem(file.absolutePath, file.name)
activity.getFileOutputStream(fileDirItem, true) {
if (it == null) {
callback(EXPORT_FAIL)
return@getFileOutputStream
}
if (showExportingToast) {
activity.toast(R.string.exporting)
}
it.bufferedWriter().use { out ->
out.writeLn(BEGIN_CALENDAR)
out.writeLn(CALENDAR_PRODID)
out.writeLn(CALENDAR_VERSION)
for (event in events) {
out.writeLn(BEGIN_EVENT)
event.title.replace("\n", "\\n").let { if (it.isNotEmpty()) out.writeLn("$SUMMARY:$it") }
event.description.replace("\n", "\\n").let { if (it.isNotEmpty()) out.writeLn("$DESCRIPTION$it") }
event.importId.let { if (it.isNotEmpty()) out.writeLn("$UID$it") }
event.eventType.let { out.writeLn("$CATEGORY_COLOR${activity.dbHelper.getEventType(it)?.color}") }
event.eventType.let { out.writeLn("$CATEGORIES${activity.dbHelper.getEventType(it)?.title}") }
event.lastUpdated.let { out.writeLn("$LAST_MODIFIED:${Formatter.getExportedTime(it)}") }
event.location.let { if (it.isNotEmpty()) out.writeLn("$LOCATION$it") }
if (event.getIsAllDay()) {
out.writeLn("$DTSTART;$VALUE=$DATE:${Formatter.getDayCodeFromTS(event.startTS)}")
out.writeLn("$DTEND;$VALUE=$DATE:${Formatter.getDayCodeFromTS(event.endTS + DAY)}")
} else {
event.startTS.let { out.writeLn("$DTSTART:${Formatter.getExportedTime(it * 1000L)}") }
event.endTS.let { out.writeLn("$DTEND:${Formatter.getExportedTime(it * 1000L)}") }
}
out.writeLn("$STATUS$CONFIRMED")
Parser().getRepeatCode(event).let { if (it.isNotEmpty()) out.writeLn("$RRULE$it") }
fillReminders(event, out)
fillIgnoredOccurrences(event, out)
eventsExported++
out.writeLn(END_EVENT)
}
out.writeLn(END_CALENDAR)
}
callback(when {
eventsExported == 0 -> EXPORT_FAIL
eventsFailed > 0 -> EXPORT_PARTIAL
else -> EXPORT_OK
})
}
}
private fun fillReminders(event: Event, out: BufferedWriter) {
checkReminder(event.reminder1Minutes, out)
checkReminder(event.reminder2Minutes, out)
checkReminder(event.reminder3Minutes, out)
}
private fun checkReminder(minutes: Int, out: BufferedWriter) {
if (minutes != -1) {
out.apply {
writeLn(BEGIN_ALARM)
writeLn("$ACTION$DISPLAY")
writeLn("$TRIGGER-${Parser().getDurationCode(minutes)}")
writeLn(END_ALARM)
}
}
}
private fun fillIgnoredOccurrences(event: Event, out: BufferedWriter) {
event.ignoreEventOccurrences.forEach {
out.writeLn("$EXDATE:$it}")
}
}
}

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 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)"
fun isSyncedEventType() = caldavCalendarId != 0
}

View File

@ -1,4 +0,0 @@
package com.simplemobiletools.calendar.models
data 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 = "", var isPastEvent: Boolean = false, var isRepeatable: Boolean = false) : ListItem()

View File

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

View File

@ -1,4 +0,0 @@
package com.simplemobiletools.calendar.models
data class MonthViewEvent(val id: Int, val title: String, val startTS: Int, val color: Int, val startDayIndex: Int, val daysCnt: Int, val originalStartDayIndex: Int,
val isAllDay: Boolean, val isPastEvent: Boolean)

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

@ -1,16 +1,11 @@
package com.simplemobiletools.calendar
package com.simplemobiletools.calendar.pro
import androidx.multidex.MultiDexApplication
import com.facebook.stetho.Stetho
import com.simplemobiletools.commons.extensions.checkUseEnglish
class App : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Stetho.initializeWithDefaults(this)
}
checkUseEnglish()
}
}

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.activities
package com.simplemobiletools.calendar.pro.activities
import android.app.DatePickerDialog
import android.app.TimePickerDialog
@ -10,13 +10,14 @@ import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import androidx.core.app.NotificationManagerCompat
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.dialogs.*
import com.simplemobiletools.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.models.CalDAVCalendar
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
@ -44,17 +45,17 @@ class EventActivity : SimpleActivity() {
private var mReminder2Minutes = 0
private var mReminder3Minutes = 0
private var mRepeatInterval = 0
private var mRepeatLimit = 0
private var mRepeatLimit = 0L
private var mRepeatRule = 0
private var mEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
private var mEventTypeId = REGULAR_EVENT_TYPE_ID
private var mDialogTheme = 0
private var mEventOccurrenceTS = 0
private var mEventOccurrenceTS = 0L
private var mEventCalendarId = STORED_LOCALLY_ONLY
private var wasActivityInitialized = false
lateinit var mEventStartDateTime: DateTime
lateinit var mEventEndDateTime: DateTime
lateinit var mEvent: Event
private lateinit var mEventStartDateTime: DateTime
private lateinit var mEventEndDateTime: DateTime
private lateinit var mEvent: Event
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -64,35 +65,42 @@ class EventActivity : SimpleActivity() {
val intent = intent ?: return
mDialogTheme = getDialogTheme()
val eventId = intent.getIntExtra(EVENT_ID, 0)
val event = dbHelper.getEventWithId(eventId)
val eventId = intent.getLongExtra(EVENT_ID, 0L)
Thread {
val event = eventsDB.getEventWithId(eventId)
if (eventId != 0L && event == null) {
finish()
return@Thread
}
if (eventId != 0 && event == null) {
finish()
return
}
val localEventType = eventTypesDB.getEventTypeWithId(config.lastUsedLocalEventTypeId)
runOnUiThread {
gotEvent(savedInstanceState, localEventType, event)
}
}.start()
}
val localEventType = dbHelper.getEventType(config.lastUsedLocalEventTypeId)
private fun gotEvent(savedInstanceState: Bundle?, localEventType: EventType?, event: Event?) {
if (localEventType == null || localEventType.caldavCalendarId != 0) {
config.lastUsedLocalEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
config.lastUsedLocalEventTypeId = REGULAR_EVENT_TYPE_ID
}
mEventTypeId = config.lastUsedLocalEventTypeId
if (event != null) {
mEvent = event
mEventOccurrenceTS = intent.getIntExtra(EVENT_OCCURRENCE_TS, 0)
mEventOccurrenceTS = intent.getLongExtra(EVENT_OCCURRENCE_TS, 0L)
if (savedInstanceState == null) {
setupEditEvent()
}
if (intent.getBooleanExtra(IS_DUPLICATE_INTENT, false)) {
mEvent.id = 0
mEvent.id = null
} else {
cancelNotification(mEvent.id!!)
}
cancelNotification(mEvent.id)
} else {
mEvent = Event()
mEvent = Event(null)
config.apply {
mReminder1Minutes = if (usePreviousEventReminders) lastEventReminderMinutes1 else defaultReminder1
mReminder2Minutes = if (usePreviousEventReminders) lastEventReminderMinutes2 else defaultReminder2
@ -150,16 +158,16 @@ class EventActivity : SimpleActivity() {
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
menu.findItem(R.id.duplicate).isVisible = mEvent.id != 0
menu.findItem(R.id.delete).isVisible = mEvent.id != null
menu.findItem(R.id.share).isVisible = mEvent.id != null
menu.findItem(R.id.duplicate).isVisible = mEvent.id != null
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save -> saveEvent()
R.id.save -> saveCurrentEvent()
R.id.delete -> deleteEvent()
R.id.duplicate -> duplicateEvent()
R.id.share -> shareEvent()
@ -170,36 +178,47 @@ class EventActivity : SimpleActivity() {
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(START_TS, mEventStartDateTime.seconds())
outState.putInt(END_TS, mEventEndDateTime.seconds())
if (!wasActivityInitialized) {
return
}
outState.putInt(REMINDER_1_MINUTES, mReminder1Minutes)
outState.putInt(REMINDER_2_MINUTES, mReminder2Minutes)
outState.putInt(REMINDER_3_MINUTES, mReminder3Minutes)
outState.apply {
putLong(START_TS, mEventStartDateTime.seconds())
putLong(END_TS, mEventEndDateTime.seconds())
outState.putInt(REPEAT_INTERVAL, mRepeatInterval)
outState.putInt(REPEAT_LIMIT, mRepeatLimit)
outState.putInt(REPEAT_RULE, mRepeatRule)
putInt(REMINDER_1_MINUTES, mReminder1Minutes)
putInt(REMINDER_2_MINUTES, mReminder2Minutes)
putInt(REMINDER_3_MINUTES, mReminder3Minutes)
outState.putInt(EVENT_TYPE_ID, mEventTypeId)
outState.putInt(EVENT_CALENDAR_ID, mEventCalendarId)
putInt(REPEAT_INTERVAL, mRepeatInterval)
putInt(REPEAT_RULE, mRepeatRule)
putLong(REPEAT_LIMIT, mRepeatLimit)
putLong(EVENT_TYPE_ID, mEventTypeId)
putInt(EVENT_CALENDAR_ID, mEventCalendarId)
}
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
if (!savedInstanceState.containsKey(START_TS)) {
finish()
return
}
savedInstanceState.apply {
mEventStartDateTime = Formatter.getDateTimeFromTS(getInt(START_TS))
mEventEndDateTime = Formatter.getDateTimeFromTS(getInt(END_TS))
mEventStartDateTime = Formatter.getDateTimeFromTS(getLong(START_TS))
mEventEndDateTime = Formatter.getDateTimeFromTS(getLong(END_TS))
mReminder1Minutes = getInt(REMINDER_1_MINUTES)
mReminder2Minutes = getInt(REMINDER_2_MINUTES)
mReminder3Minutes = getInt(REMINDER_3_MINUTES)
mRepeatInterval = getInt(REPEAT_INTERVAL)
mRepeatLimit = getInt(REPEAT_LIMIT)
mRepeatRule = getInt(REPEAT_RULE)
mRepeatLimit = getLong(REPEAT_LIMIT)
mEventTypeId = getInt(EVENT_TYPE_ID)
mEventTypeId = getLong(EVENT_TYPE_ID)
mEventCalendarId = getInt(EVENT_CALENDAR_ID)
}
@ -218,7 +237,7 @@ class EventActivity : SimpleActivity() {
}
private fun setupEditEvent() {
val realStart = if (mEventOccurrenceTS == 0) mEvent.startTS else mEventOccurrenceTS
val realStart = if (mEventOccurrenceTS == 0L) mEvent.startTS else mEventOccurrenceTS
val duration = mEvent.endTS - mEvent.startTS
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
updateActionBarTitle(getString(R.string.edit_event))
@ -227,9 +246,6 @@ class EventActivity : SimpleActivity() {
event_title.setText(mEvent.title)
event_location.setText(mEvent.location)
event_description.setText(mEvent.description)
if (event_description.value.isNotEmpty()) {
event_description.movementMethod = LinkMovementMethod.getInstance()
}
mReminder1Minutes = mEvent.reminder1Minutes
mReminder2Minutes = mEvent.reminder2Minutes
@ -243,17 +259,17 @@ class EventActivity : SimpleActivity() {
}
private fun setupNewEvent() {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
event_title.requestFocus()
updateActionBarTitle(getString(R.string.new_event))
val isLastCaldavCalendarOK = config.caldavSync && config.getSyncedCalendarIdsAsList().contains(config.lastUsedCaldavCalendarId.toString())
val isLastCaldavCalendarOK = config.caldavSync && config.getSyncedCalendarIdsAsList().contains(config.lastUsedCaldavCalendarId)
mEventCalendarId = if (isLastCaldavCalendarOK) config.lastUsedCaldavCalendarId else STORED_LOCALLY_ONLY
if (intent.action == Intent.ACTION_EDIT || intent.action == Intent.ACTION_INSERT) {
val startTS = (intent.getLongExtra("beginTime", System.currentTimeMillis()) / 1000).toInt()
val startTS = intent.getLongExtra("beginTime", System.currentTimeMillis()) / 1000L
mEventStartDateTime = Formatter.getDateTimeFromTS(startTS)
val endTS = (intent.getLongExtra("endTime", System.currentTimeMillis()) / 1000).toInt()
val endTS = intent.getLongExtra("endTime", System.currentTimeMillis()) / 1000L
mEventEndDateTime = Formatter.getDateTimeFromTS(endTS)
event_title.setText(intent.getStringExtra("title"))
@ -263,7 +279,7 @@ class EventActivity : SimpleActivity() {
event_description.movementMethod = LinkMovementMethod.getInstance()
}
} else {
val startTS = intent.getIntExtra(NEW_EVENT_START_TS, 0)
val startTS = intent.getLongExtra(NEW_EVENT_START_TS, 0L)
val dateTime = Formatter.getDateTimeFromTS(startTS)
mEventStartDateTime = dateTime
@ -336,14 +352,14 @@ class EventActivity : SimpleActivity() {
}
}
private fun setRepeatLimit(limit: Int) {
private fun setRepeatLimit(limit: Long) {
mRepeatLimit = limit
checkRepetitionLimitText()
}
private fun checkRepetitionLimitText() {
event_repetition_limit.text = when {
mRepeatLimit == 0 -> {
mRepeatLimit == 0L -> {
event_repetition_limit_label.text = getString(R.string.repeat)
resources.getString(R.string.forever)
}
@ -526,7 +542,7 @@ class EventActivity : SimpleActivity() {
private fun showEventTypeDialog() {
hideKeyboard()
SelectEventTypeDialog(this, mEventTypeId, false) {
mEventTypeId = it.id
mEventTypeId = it.id!!
updateEventType()
}
}
@ -539,19 +555,14 @@ class EventActivity : SimpleActivity() {
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)
beGoneIf(event_reminder_2.isGone() && 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
@ -561,7 +572,7 @@ class EventActivity : SimpleActivity() {
private fun updateReminder3Text() {
event_reminder_3.apply {
beGoneIf(mReminder2Minutes == REMINDER_OFF || mReminder1Minutes == REMINDER_OFF)
beGoneIf(event_reminder_3.isGone() && (mReminder2Minutes == REMINDER_OFF || mReminder1Minutes == REMINDER_OFF))
if (mReminder3Minutes == REMINDER_OFF) {
text = resources.getString(R.string.add_another_reminder)
alpha = 0.4f
@ -577,11 +588,15 @@ class EventActivity : SimpleActivity() {
}
private fun updateEventType() {
val eventType = dbHelper.getEventType(mEventTypeId)
if (eventType != null) {
event_type.text = eventType.title
event_type_color.setFillWithStroke(eventType.color, config.backgroundColor)
}
Thread {
val eventType = eventTypesDB.getEventTypeWithId(mEventTypeId)
if (eventType != null) {
runOnUiThread {
event_type.text = eventType.title
event_type_color.setFillWithStroke(eventType.color, config.backgroundColor)
}
}
}.start()
}
private fun updateCalDAVCalendar() {
@ -590,8 +605,8 @@ class EventActivity : SimpleActivity() {
event_caldav_calendar_holder.beVisible()
event_caldav_calendar_divider.beVisible()
val calendars = CalDAVHandler(applicationContext).getCalDAVCalendars(this).filter {
it.canWrite() && config.getSyncedCalendarIdsAsList().contains(it.id.toString())
val calendars = calDAVHelper.getCalDAVCalendars("", true).filter {
config.getSyncedCalendarIdsAsList().contains(it.id)
}
updateCurrentCalendarInfo(if (mEventCalendarId == STORED_LOCALLY_ONLY) null else getCalendarWithId(calendars, getCalendarId()))
@ -638,17 +653,22 @@ class EventActivity : SimpleActivity() {
} else {
event_caldav_calendar_email.text = currentCalendar.accountName
val calendarColor = dbHelper.getEventTypeWithCalDAVCalendarId(currentCalendar.id)?.color ?: currentCalendar.color
event_caldav_calendar_color.setFillWithStroke(calendarColor, config.backgroundColor)
Thread {
val calendarColor = eventsHelper.getEventTypeWithCalDAVCalendarId(currentCalendar.id)?.color
?: currentCalendar.color
event_caldav_calendar_name.apply {
text = currentCalendar.displayName
setPadding(paddingLeft, paddingTop, paddingRight, resources.getDimension(R.dimen.tiny_margin).toInt())
}
runOnUiThread {
event_caldav_calendar_color.setFillWithStroke(calendarColor, config.backgroundColor)
event_caldav_calendar_name.apply {
text = currentCalendar.displayName
setPadding(paddingLeft, paddingTop, paddingRight, resources.getDimension(R.dimen.tiny_margin).toInt())
}
event_caldav_calendar_holder.apply {
setPadding(paddingLeft, 0, paddingRight, 0)
}
event_caldav_calendar_holder.apply {
setPadding(paddingLeft, 0, paddingRight, 0)
}
}
}.start()
}
}
@ -659,17 +679,21 @@ class EventActivity : SimpleActivity() {
}
private fun shareEvent() {
shareEvents(arrayListOf(mEvent.id))
shareEvents(arrayListOf(mEvent.id!!))
}
private fun deleteEvent() {
DeleteEventDialog(this, arrayListOf(mEvent.id), mEvent.repeatInterval > 0) {
when (it) {
DELETE_SELECTED_OCCURRENCE -> dbHelper.addEventRepeatException(mEvent.id, mEventOccurrenceTS, true)
DELETE_FUTURE_OCCURRENCES -> dbHelper.addEventRepeatLimit(mEvent.id, mEventOccurrenceTS)
DELETE_ALL_OCCURRENCES -> dbHelper.deleteEvents(arrayOf(mEvent.id.toString()), true)
}
finish()
DeleteEventDialog(this, arrayListOf(mEvent.id!!), mEvent.repeatInterval > 0) {
Thread {
when (it) {
DELETE_SELECTED_OCCURRENCE -> eventsHelper.addEventRepetitionException(mEvent.id!!, mEventOccurrenceTS, true)
DELETE_FUTURE_OCCURRENCES -> eventsHelper.addEventRepeatLimit(mEvent.id!!, mEventOccurrenceTS)
DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mEvent.id!!, true)
}
runOnUiThread {
finish()
}
}.start()
}
}
@ -683,11 +707,19 @@ class EventActivity : SimpleActivity() {
finish()
}
private fun saveCurrentEvent() {
Thread {
saveEvent()
}.start()
}
private fun saveEvent() {
val newTitle = event_title.value
if (newTitle.isEmpty()) {
toast(R.string.title_empty)
event_title.requestFocus()
runOnUiThread {
event_title.requestFocus()
}
return
}
@ -701,12 +733,21 @@ class EventActivity : SimpleActivity() {
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 newImportId = if (mEvent.id != null) mEvent.importId else UUID.randomUUID().toString().replace("-", "") + System.currentTimeMillis().toString()
val newEventType = if (!config.caldavSync || config.lastUsedCaldavCalendarId == 0 || mEventCalendarId == STORED_LOCALLY_ONLY) {
mEventTypeId
} else {
dbHelper.getEventTypeWithCalDAVCalendarId(mEventCalendarId)?.id ?: config.lastUsedLocalEventTypeId
calDAVHelper.getCalDAVCalendars("", true).firstOrNull { it.id == mEventCalendarId }?.apply {
if (!canWrite()) {
runOnUiThread {
toast(R.string.insufficient_permissions)
}
return
}
}
eventsHelper.getEventTypeWithCalDAVCalendarId(mEventCalendarId)?.id ?: config.lastUsedLocalEventTypeId
}
val newSource = if (!config.caldavSync || mEventCalendarId == STORED_LOCALLY_ONLY) {
@ -739,29 +780,27 @@ class EventActivity : SimpleActivity() {
reminder3Minutes = reminder3
repeatInterval = mRepeatInterval
importId = newImportId
flags = if (event_all_day.isChecked) (mEvent.flags.addBit(FLAG_ALL_DAY)) else (mEvent.flags.removeBit(FLAG_ALL_DAY))
flags = mEvent.flags.addBitIf(event_all_day.isChecked, 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
if (mEvent.id != null && oldSource != newSource) {
eventsHelper.deleteEvent(mEvent.id!!, true)
mEvent.id = null
}
storeEvent(wasRepeatable)
}
private fun storeEvent(wasRepeatable: Boolean) {
if (mEvent.id == 0) {
dbHelper.insert(mEvent, true, this) {
if (mEvent.id == null || mEvent.id == null) {
eventsHelper.insertEvent(mEvent, true, true) {
if (DateTime.now().isAfter(mEventStartDateTime.millis)) {
if (mEvent.repeatInterval == 0 && mEvent.getReminders().isNotEmpty()) {
notifyEvent(mEvent)
@ -772,34 +811,44 @@ class EventActivity : SimpleActivity() {
}
} else {
if (mRepeatInterval > 0 && wasRepeatable) {
EditRepeatingEventDialog(this) {
if (it) {
dbHelper.update(mEvent, true, this) {
finish()
}
} else {
dbHelper.addEventRepeatException(mEvent.id, mEventOccurrenceTS, true)
mEvent.apply {
parentId = id
id = 0
repeatRule = 0
repeatInterval = 0
repeatLimit = 0
}
dbHelper.insert(mEvent, true, this) {
finish()
}
}
runOnUiThread {
showEditRepeatingEventDialog()
}
} else {
dbHelper.update(mEvent, true, this) {
eventsHelper.updateEvent(mEvent, true, true) {
finish()
}
}
}
}
private fun showEditRepeatingEventDialog() {
EditRepeatingEventDialog(this) {
if (it) {
Thread {
eventsHelper.updateEvent(mEvent, true, true) {
finish()
}
}.start()
} else {
Thread {
eventsHelper.addEventRepetitionException(mEvent.id!!, mEventOccurrenceTS, true)
mEvent.apply {
parentId = id!!.toLong()
id = null
repeatRule = 0
repeatInterval = 0
repeatLimit = 0
}
eventsHelper.insertEvent(mEvent, true, true) {
finish()
}
}.start()
}
}
}
private fun updateStartTexts() {
updateStartDateText()
updateStartTimeText()
@ -912,7 +961,7 @@ class EventActivity : SimpleActivity() {
updateStartDateText()
checkRepeatRule()
mEventEndDateTime = mEventStartDateTime.plusSeconds(diff)
mEventEndDateTime = mEventStartDateTime.plusSeconds(diff.toInt())
updateEndTexts()
} else {
mEventEndDateTime = mEventEndDateTime.withDate(year, month + 1, day)
@ -927,7 +976,7 @@ class EventActivity : SimpleActivity() {
mEventStartDateTime = mEventStartDateTime.withHourOfDay(hours).withMinuteOfHour(minutes)
updateStartTimeText()
mEventEndDateTime = mEventStartDateTime.plusSeconds(diff)
mEventEndDateTime = mEventStartDateTime.plusSeconds(diff.toInt())
updateEndTexts()
} else {
mEventEndDateTime = mEventEndDateTime.withHourOfDay(hours).withMinuteOfHour(minutes)

View File

@ -1,35 +1,33 @@
package com.simplemobiletools.calendar.activities
package com.simplemobiletools.calendar.pro.activities
import android.app.SearchManager
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.database.ContentObserver
import android.database.Cursor
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.provider.ContactsContract
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.widget.SearchView
import androidx.core.view.MenuItemCompat
import com.simplemobiletools.calendar.BuildConfig
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.R.id.*
import com.simplemobiletools.calendar.adapters.EventListAdapter
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.*
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.calendar.models.ListEvent
import com.simplemobiletools.calendar.pro.BuildConfig
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.adapters.EventListAdapter
import com.simplemobiletools.calendar.pro.databases.EventsDatabase
import com.simplemobiletools.calendar.pro.dialogs.ExportEventsDialog
import com.simplemobiletools.calendar.pro.dialogs.FilterEventTypesDialog
import com.simplemobiletools.calendar.pro.dialogs.ImportEventsDialog
import com.simplemobiletools.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.fragments.*
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.calendar.pro.models.ListEvent
import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
@ -46,13 +44,10 @@ import java.util.*
import kotlin.collections.ArrayList
class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
private val CALDAV_SYNC_DELAY = 1000L
private var showCalDAVRefreshToast = false
private var mShouldFilterBeVisible = false
private var mIsSearchOpen = false
private var mLatestSearchQuery = ""
private var mCalDAVSyncHandler = Handler()
private var mSearchMenuItem: MenuItem? = null
private var shouldGoToTodayBeVisible = false
private var goToTodayButton: MenuItem? = null
@ -94,11 +89,9 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
refreshCalDAVCalendars(false)
}
if (!checkViewIntents()) {
return
}
checkIsViewIntent()
if (!checkOpenIntents()) {
if (!checkIsOpenIntent()) {
updateViewPager()
}
@ -112,8 +105,12 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
updateViewPager()
}
dbHelper.getEventTypes {
mShouldFilterBeVisible = it.size > 1 || config.displayEventTypes.isEmpty()
eventsHelper.getEventTypes(this) {
val newShouldFilterBeVisible = it.size > 1 || config.displayEventTypes.isEmpty()
if (newShouldFilterBeVisible != mShouldFilterBeVisible) {
mShouldFilterBeVisible = newShouldFilterBeVisible
invalidateOptionsMenu()
}
}
if (config.storedView == WEEKLY_VIEW) {
@ -141,11 +138,16 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
override fun onStop() {
super.onStop()
mCalDAVSyncHandler.removeCallbacksAndMessages(null)
contentResolver.unregisterContentObserver(calDAVSyncObserver)
closeSearch()
}
override fun onDestroy() {
super.onDestroy()
if (!isChangingConfigurations) {
EventsDatabase.destroyInstance()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
menu.apply {
@ -198,8 +200,8 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
checkOpenIntents()
checkViewIntents()
checkIsOpenIntent()
checkIsViewIntent()
}
private fun storeStateVariables() {
@ -254,7 +256,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
mSearchMenuItem?.collapseActionView()
}
private fun checkOpenIntents(): Boolean {
private fun checkIsOpenIntent(): Boolean {
val dayCodeToOpen = intent.getStringExtra(DAY_CODE) ?: ""
val viewToOpen = intent.getIntExtra(VIEW_TO_OPEN, DAILY_VIEW)
intent.removeExtra(VIEW_TO_OPEN)
@ -268,11 +270,11 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
return true
}
val eventIdToOpen = intent.getIntExtra(EVENT_ID, 0)
val eventOccurrenceToOpen = intent.getIntExtra(EVENT_OCCURRENCE_TS, 0)
val eventIdToOpen = intent.getLongExtra(EVENT_ID, 0L)
val eventOccurrenceToOpen = intent.getLongExtra(EVENT_OCCURRENCE_TS, 0L)
intent.removeExtra(EVENT_ID)
intent.removeExtra(EVENT_OCCURRENCE_TS)
if (eventIdToOpen != 0 && eventOccurrenceToOpen != 0) {
if (eventIdToOpen != 0L && eventOccurrenceToOpen != 0L) {
Intent(this, EventActivity::class.java).apply {
putExtra(EVENT_ID, eventIdToOpen)
putExtra(EVENT_OCCURRENCE_TS, eventOccurrenceToOpen)
@ -283,35 +285,36 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
return false
}
private fun checkViewIntents(): Boolean {
private fun checkIsViewIntent() {
if (intent?.action == Intent.ACTION_VIEW && intent.data != null) {
val uri = intent.data
if (uri.authority == "com.android.calendar") {
if (uri.path.startsWith("/events")) {
// intents like content://com.android.calendar/events/1756
val eventId = uri.lastPathSegment
val id = dbHelper.getEventIdWithLastImportId(eventId)
if (id != 0) {
Intent(this, EventActivity::class.java).apply {
putExtra(EVENT_ID, id)
startActivity(this)
Thread {
// intents like content://com.android.calendar/events/1756
val eventId = uri.lastPathSegment
val id = eventsDB.getEventIdWithLastImportId("%-$eventId")
if (id != null) {
Intent(this, EventActivity::class.java).apply {
putExtra(EVENT_ID, id)
startActivity(this)
}
} else {
toast(R.string.unknown_error_occurred)
}
} else {
toast(R.string.unknown_error_occurred)
}
}.start()
} else if (intent?.extras?.getBoolean("DETAIL_VIEW", false) == true) {
// clicking date on a third party widget: content://com.android.calendar/time/1507309245683
val timestamp = uri.pathSegments.last()
if (timestamp.areDigitsOnly()) {
openDayAt(timestamp.toLong())
return false
return
}
}
} else {
tryImportEventsFromFile(uri)
}
}
return true
}
private fun showViewDialog() {
@ -361,27 +364,20 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
toast(R.string.refreshing)
}
syncCalDAVCalendars(this, calDAVSyncObserver)
scheduleCalDAVSync(true)
syncCalDAVCalendars {
calDAVHelper.refreshCalendars(true) {
calDAVChanged()
}
}
}
private val calDAVSyncObserver = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
if (!selfChange) {
mCalDAVSyncHandler.removeCallbacksAndMessages(null)
mCalDAVSyncHandler.postDelayed({
recheckCalDAVCalendars {
refreshViewPager()
if (showCalDAVRefreshToast) {
toast(R.string.refreshing_complete)
}
runOnUiThread {
swipe_refresh_layout.isRefreshing = false
}
}
}, CALDAV_SYNC_DELAY)
}
private fun calDAVChanged() {
refreshViewPager()
if (showCalDAVRefreshToast) {
toast(R.string.refreshing_complete)
}
runOnUiThread {
swipe_refresh_layout.isRefreshing = false
}
}
@ -391,10 +387,10 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
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)
var eventTypeId = eventsHelper.getEventTypeIdWithTitle(holidays)
if (eventTypeId == -1L) {
val eventType = EventType(null, holidays, resources.getColor(R.color.default_holidays_color))
eventTypeId = eventsHelper.insertOrUpdateEventTypeSync(eventType)
}
val result = IcsImporter(this).importEvents(it as String, eventTypeId, 0, false)
@ -470,7 +466,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
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 existingEvents = if (birthdays) eventsDB.getBirthdays() else eventsDB.getAnniversaries()
val importIDs = existingEvents.map { it.importId }
val eventTypeId = if (birthdays) getBirthdaysEventTypeId() else getAnniversariesEventTypeId()
@ -487,14 +483,14 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
date.year = 70
}
val timestamp = (date.time / 1000).toInt()
val timestamp = date.time / 1000L
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,
val event = Event(null, 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) {
eventsHelper.insertEvent(event, false, false) {
eventsAdded++
}
}
@ -515,22 +511,22 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
}
}
private fun getBirthdaysEventTypeId(): Int {
private fun getBirthdaysEventTypeId(): Long {
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)
var eventTypeId = eventsHelper.getEventTypeIdWithTitle(birthdays)
if (eventTypeId == -1L) {
val eventType = EventType(null, birthdays, resources.getColor(R.color.default_birthdays_color))
eventTypeId = eventsHelper.insertOrUpdateEventTypeSync(eventType)
}
return eventTypeId
}
private fun getAnniversariesEventTypeId(): Int {
private fun getAnniversariesEventTypeId(): Long {
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)
var eventTypeId = eventsHelper.getEventTypeIdWithTitle(anniversaries)
if (eventTypeId == -1L) {
val eventType = EventType(null, anniversaries, resources.getColor(R.color.default_anniversaries_color))
eventTypeId = eventsHelper.insertOrUpdateEventTypeSync(eventType)
}
return eventTypeId
}
@ -688,11 +684,11 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
FilePickerDialog(this, pickFile = false, showFAB = true) {
ExportEventsDialog(this, it) { exportPastEvents, file, eventTypes ->
Thread {
val events = dbHelper.getEventsToExport(exportPastEvents).filter { eventTypes.contains(it.eventType.toString()) }
val events = eventsHelper.getEventsToExport(exportPastEvents, eventTypes)
if (events.isEmpty()) {
toast(R.string.no_entries_for_exporting)
} else {
IcsExporter().exportEvents(this, file, events as ArrayList<Event>, true) {
IcsExporter().exportEvents(this, file, events, true) {
toast(when (it) {
IcsExporter.ExportResult.EXPORT_OK -> R.string.exporting_successful
IcsExporter.ExportResult.EXPORT_PARTIAL -> R.string.exporting_some_entries_failed
@ -710,7 +706,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
}
private fun launchAbout() {
val licenses = LICENSE_JODA or LICENSE_STETHO
val licenses = LICENSE_JODA
val faqItems = arrayListOf(
FAQItem(R.string.faq_1_title_commons, R.string.faq_1_text_commons),
@ -727,23 +723,21 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
mLatestSearchQuery = text
search_placeholder_2.beGoneIf(text.length >= 2)
if (text.length >= 2) {
dbHelper.getEventsWithSearchQuery(text) { searchedText, events ->
eventsHelper.getEventsWithSearchQuery(text, this) { searchedText, events ->
if (searchedText == mLatestSearchQuery) {
runOnUiThread {
search_results_list.beVisibleIf(events.isNotEmpty())
search_placeholder.beVisibleIf(events.isEmpty())
val listItems = getEventListItems(events)
val eventsAdapter = EventListAdapter(this, listItems, true, this, search_results_list) {
if (it is ListEvent) {
Intent(applicationContext, EventActivity::class.java).apply {
putExtra(EVENT_ID, it.id)
startActivity(this)
}
search_results_list.beVisibleIf(events.isNotEmpty())
search_placeholder.beVisibleIf(events.isEmpty())
val listItems = getEventListItems(events)
val eventsAdapter = EventListAdapter(this, listItems, true, this, search_results_list) {
if (it is ListEvent) {
Intent(applicationContext, EventActivity::class.java).apply {
putExtra(EVENT_ID, it.id)
startActivity(this)
}
}
search_results_list.adapter = eventsAdapter
}
search_results_list.adapter = eventsAdapter
}
}
} else {
@ -766,7 +760,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
}
private fun openDayAt(timestamp: Long) {
val dayCode = Formatter.getDayCodeFromTS((timestamp / 1000).toInt())
val dayCode = Formatter.getDayCodeFromTS(timestamp / 1000L)
calendar_fab.beVisible()
config.storedView = DAILY_VIEW
updateViewPager(dayCode)

View File

@ -1,14 +1,14 @@
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.EditEventTypeDialog
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 kotlinx.android.synthetic.main.activity_manage_event_types.*
@ -30,13 +30,11 @@ class ManageEventTypesActivity : SimpleActivity(), DeleteEventTypesListener {
}
private fun getEventTypes() {
dbHelper.getEventTypes {
runOnUiThread {
val adapter = ManageEventTypesAdapter(this, it, this, manage_event_types_list) {
showEventTypeDialog(it as EventType)
}
manage_event_types_list.adapter = adapter
eventsHelper.getEventTypes(this) {
val adapter = ManageEventTypesAdapter(this, it, this, manage_event_types_list) {
showEventTypeDialog(it as EventType)
}
manage_event_types_list.adapter = adapter
}
}
@ -62,11 +60,7 @@ class ManageEventTypesActivity : SimpleActivity(), DeleteEventTypesListener {
}
Thread {
dbHelper.deleteEventTypes(eventTypes, deleteEvents) {
if (it == 0) {
toast(R.string.unknown_error_occurred)
}
}
eventsHelper.deleteEventTypes(eventTypes, deleteEvents)
}.start()
return true
}

View File

@ -1,18 +1,14 @@
package com.simplemobiletools.calendar.activities
package com.simplemobiletools.calendar.pro.activities
import android.content.Intent
import android.content.res.Resources
import android.media.AudioManager
import android.os.Bundle
import android.text.TextUtils
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.dialogs.SelectCalendarsDialog
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.getSyncedCalDAVCalendars
import com.simplemobiletools.calendar.extensions.updateWidgets
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.dialogs.SelectCalendarsDialog
import com.simplemobiletools.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.CustomIntervalPickerDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
@ -43,13 +39,11 @@ class SettingsActivity : SimpleActivity() {
override fun onResume() {
super.onResume()
setupPurchaseThankYou()
setupCustomizeColors()
setupUseEnglish()
setupManageEventTypes()
setupHourFormat()
setupSundayFirst()
setupAvoidWhatsNew()
setupDeleteAllEvents()
setupReplaceDescription()
setupWeekNumbers()
@ -94,13 +88,14 @@ class SettingsActivity : SimpleActivity() {
private fun checkPrimaryColor() {
if (config.primaryColor != mStoredPrimaryColor) {
dbHelper.getEventTypes {
if (it.filter { it.caldavCalendarId == 0 }.size == 1) {
val eventType = it.first { it.caldavCalendarId == 0 }
Thread {
val eventTypes = eventsHelper.getEventTypesSync()
if (eventTypes.filter { it.caldavCalendarId == 0 }.size == 1) {
val eventType = eventTypes.first { it.caldavCalendarId == 0 }
eventType.color = config.primaryColor
dbHelper.updateEventType(eventType)
eventsHelper.insertOrUpdateEventTypeSync(eventType)
}
}
}.start()
}
}
@ -111,13 +106,6 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupPurchaseThankYou() {
settings_purchase_thank_you_holder.beVisibleIf(config.appRunCount > 10 && !isThankYouInstalled())
settings_purchase_thank_you_holder.setOnClickListener {
launchPurchaseThankYouIntent()
}
}
private fun setupCustomizeColors() {
settings_customize_colors_holder.setOnClickListener {
startCustomizationActivity()
@ -191,10 +179,13 @@ class SettingsActivity : SimpleActivity() {
config.caldavSync = false
settings_manage_synced_calendars_holder.beGone()
settings_caldav_pull_to_refresh_holder.beGone()
config.getSyncedCalendarIdsAsList().forEach {
CalDAVHandler(applicationContext).deleteCalDAVCalendarEvents(it.toLong())
}
dbHelper.deleteEventTypesWithCalendarId(config.caldavSyncedCalendarIDs)
Thread {
config.getSyncedCalendarIdsAsList().forEach {
calDAVHelper.deleteCalDAVCalendarEvents(it.toLong())
}
eventTypesDB.deleteEventTypesWithCalendarId(config.getSyncedCalendarIdsAsList())
}.start()
}
}
@ -217,29 +208,34 @@ class SettingsActivity : SimpleActivity() {
Thread {
if (newCalendarIds.isNotEmpty()) {
val existingEventTypeNames = dbHelper.getEventTypesSync().map { it.getDisplayTitle().toLowerCase() } as ArrayList<String>
val existingEventTypeNames = eventsHelper.getEventTypesSync().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)
val eventType = EventType(null, it.displayName, it.color, it.id, it.displayName, it.accountName)
existingEventTypeNames.add(calendarTitle.toLowerCase())
dbHelper.insertEventType(eventType)
eventsHelper.insertOrUpdateEventType(this, eventType)
}
}
syncCalDAVCalendars {
calDAVHelper.refreshCalendars(true) {
if (settings_caldav_sync.isChecked) {
toast(R.string.synchronization_completed)
}
}
}
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) {}
calDAVHelper.deleteCalDAVCalendarEvents(it.toLong())
eventsHelper.getEventTypeWithCalDAVCalendarId(it)?.apply {
eventsHelper.deleteEventTypes(arrayListOf(this), true)
}
}
dbHelper.deleteEventTypesWithCalendarId(TextUtils.join(",", removedCalendarIds))
if (settings_caldav_sync.isChecked) {
toast(R.string.synchronization_completed)
}
eventTypesDB.deleteEventTypesWithCalendarId(removedCalendarIds)
}.start()
}
}
@ -252,20 +248,10 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupAvoidWhatsNew() {
settings_avoid_whats_new.isChecked = config.avoidWhatsNew
settings_avoid_whats_new_holder.setOnClickListener {
settings_avoid_whats_new.toggle()
config.avoidWhatsNew = settings_avoid_whats_new.isChecked
}
}
private fun setupDeleteAllEvents() {
settings_delete_all_events_holder.setOnClickListener {
ConfirmationDialog(this, messageId = R.string.delete_all_events_confirmation) {
Thread {
dbHelper.deleteAllEvents()
}.start()
eventsHelper.deleteAllEvents()
}
}
}

View File

@ -0,0 +1,71 @@
package com.simplemobiletools.calendar.pro.activities
import android.content.Context
import android.database.ContentObserver
import android.os.Handler
import android.provider.CalendarContract
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.refreshCalDAVCalendars
import com.simplemobiletools.commons.activities.BaseSimpleActivity
open class SimpleActivity : BaseSimpleActivity() {
val CALDAV_REFRESH_DELAY = 3000L
val calDAVRefreshHandler = Handler()
var calDAVRefreshCallback: (() -> Unit)? = null
override fun getAppIconIDs() = arrayListOf(
R.mipmap.ic_launcher_red,
R.mipmap.ic_launcher_pink,
R.mipmap.ic_launcher_purple,
R.mipmap.ic_launcher_deep_purple,
R.mipmap.ic_launcher_indigo,
R.mipmap.ic_launcher_blue,
R.mipmap.ic_launcher_light_blue,
R.mipmap.ic_launcher_cyan,
R.mipmap.ic_launcher_teal,
R.mipmap.ic_launcher_green,
R.mipmap.ic_launcher_light_green,
R.mipmap.ic_launcher_lime,
R.mipmap.ic_launcher_yellow,
R.mipmap.ic_launcher_amber,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher_deep_orange,
R.mipmap.ic_launcher_brown,
R.mipmap.ic_launcher_blue_grey,
R.mipmap.ic_launcher_grey_black
)
override fun getAppLauncherName() = getString(R.string.app_launcher_name)
fun Context.syncCalDAVCalendars(callback: () -> Unit) {
calDAVRefreshCallback = callback
Thread {
val uri = CalendarContract.Calendars.CONTENT_URI
contentResolver.unregisterContentObserver(calDAVSyncObserver)
contentResolver.registerContentObserver(uri, false, calDAVSyncObserver)
refreshCalDAVCalendars(config.caldavSyncedCalendarIDs, true)
}.start()
}
// caldav refresh content observer triggers multiple times in a row at updating, so call the callback only a few seconds after the (hopefully) last one
private val calDAVSyncObserver = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
if (!selfChange) {
calDAVRefreshHandler.removeCallbacksAndMessages(null)
calDAVRefreshHandler.postDelayed({
Thread {
unregisterObserver()
calDAVRefreshCallback?.invoke()
calDAVRefreshCallback = null
}.start()
}, CALDAV_REFRESH_DELAY)
}
}
}
private fun unregisterObserver() {
contentResolver.unregisterContentObserver(calDAVSyncObserver)
}
}

View File

@ -0,0 +1,36 @@
package com.simplemobiletools.calendar.pro.activities
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsDB
import com.simplemobiletools.calendar.pro.extensions.rescheduleReminder
import com.simplemobiletools.calendar.pro.helpers.EVENT_ID
import com.simplemobiletools.commons.extensions.showPickSecondsDialogHelper
class SnoozeReminderActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
showPickSecondsDialogHelper(config.snoozeTime, true, cancelCallback = { dialogCancelled() }) {
Thread {
val eventId = intent.getLongExtra(EVENT_ID, 0L)
val event = eventsDB.getEventWithId(eventId)
config.snoozeTime = it / 60
rescheduleReminder(event, it / 60)
runOnUiThread {
finishActivity()
}
}.start()
}
}
private fun dialogCancelled() {
finishActivity()
}
private fun finishActivity() {
finish()
overridePendingTransition(0, 0)
}
}

View File

@ -1,7 +1,7 @@
package com.simplemobiletools.calendar.activities
package com.simplemobiletools.calendar.pro.activities
import android.content.Intent
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.commons.activities.BaseSplashActivity
class SplashActivity : BaseSplashActivity() {
@ -13,8 +13,8 @@ class SplashActivity : BaseSplashActivity() {
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))
putExtra(EVENT_ID, intent.getLongExtra(EVENT_ID, 0L))
putExtra(EVENT_OCCURRENCE_TS, intent.getLongExtra(EVENT_OCCURRENCE_TS, 0L))
startActivity(this)
}
else -> startActivity(Intent(this, MainActivity::class.java))

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.activities
package com.simplemobiletools.calendar.pro.activities
import android.app.Activity
import android.appwidget.AppWidgetManager
@ -6,15 +6,15 @@ import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.widget.SeekBar
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.adapters.EventListAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.helpers.MyWidgetListProvider
import com.simplemobiletools.calendar.models.ListEvent
import com.simplemobiletools.calendar.models.ListItem
import com.simplemobiletools.calendar.models.ListSection
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.adapters.EventListAdapter
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.helpers.MyWidgetListProvider
import com.simplemobiletools.calendar.pro.models.ListEvent
import com.simplemobiletools.calendar.pro.models.ListItem
import com.simplemobiletools.calendar.pro.models.ListSection
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.extensions.adjustAlpha
import com.simplemobiletools.commons.extensions.setFillWithStroke
@ -147,9 +147,9 @@ class WidgetListConfigureActivity : SimpleActivity() {
listItems.add(ListSection(day, code, false, false))
var time = dateTime.withHourOfDay(7)
listItems.add(ListEvent(1, time.seconds(), time.plusMinutes(30).seconds(), getString(R.string.sample_title_1), getString(R.string.sample_description_1), false, config.primaryColor))
listItems.add(ListEvent(1, time.seconds(), time.plusMinutes(30).seconds(), getString(R.string.sample_title_1), getString(R.string.sample_description_1), false, config.primaryColor, "", false, false))
time = dateTime.withHourOfDay(8)
listItems.add(ListEvent(2, time.seconds(), time.plusHours(1).seconds(), getString(R.string.sample_title_2), getString(R.string.sample_description_2), false, config.primaryColor))
listItems.add(ListEvent(2, time.seconds(), time.plusHours(1).seconds(), getString(R.string.sample_title_2), getString(R.string.sample_description_2), false, config.primaryColor, "", false, false))
dateTime = dateTime.plusDays(1)
code = Formatter.getDayCodeFromTS(dateTime.seconds())
@ -157,11 +157,11 @@ class WidgetListConfigureActivity : SimpleActivity() {
listItems.add(ListSection(day, code, false, false))
time = dateTime.withHourOfDay(8)
listItems.add(ListEvent(3, time.seconds(), time.plusHours(1).seconds(), getString(R.string.sample_title_3), "", false, config.primaryColor))
listItems.add(ListEvent(3, time.seconds(), time.plusHours(1).seconds(), getString(R.string.sample_title_3), "", false, config.primaryColor, "", false, false))
time = dateTime.withHourOfDay(13)
listItems.add(ListEvent(4, time.seconds(), time.plusHours(1).seconds(), getString(R.string.sample_title_4), getString(R.string.sample_description_4), false, config.primaryColor))
listItems.add(ListEvent(4, time.seconds(), time.plusHours(1).seconds(), getString(R.string.sample_title_4), getString(R.string.sample_description_4), false, config.primaryColor, "", false, false))
time = dateTime.withHourOfDay(18)
listItems.add(ListEvent(5, time.seconds(), time.plusMinutes(10).seconds(), getString(R.string.sample_title_5), "", false, config.primaryColor))
listItems.add(ListEvent(5, time.seconds(), time.plusMinutes(10).seconds(), getString(R.string.sample_title_5), "", false, config.primaryColor, "", false, false))
return listItems
}

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.activities
package com.simplemobiletools.calendar.pro.activities
import android.app.Activity
import android.appwidget.AppWidgetManager
@ -10,15 +10,15 @@ import android.os.Bundle
import android.widget.LinearLayout
import android.widget.SeekBar
import android.widget.TextView
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.addDayEvents
import com.simplemobiletools.calendar.extensions.addDayNumber
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.LOW_ALPHA
import com.simplemobiletools.calendar.helpers.MonthlyCalendarImpl
import com.simplemobiletools.calendar.helpers.MyWidgetMonthlyProvider
import com.simplemobiletools.calendar.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.models.DayMonthly
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.addDayEvents
import com.simplemobiletools.calendar.pro.extensions.addDayNumber
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.helpers.LOW_ALPHA
import com.simplemobiletools.calendar.pro.helpers.MonthlyCalendarImpl
import com.simplemobiletools.calendar.pro.helpers.MyWidgetMonthlyProvider
import com.simplemobiletools.calendar.pro.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.pro.models.DayMonthly
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.extensions.adjustAlpha
import com.simplemobiletools.commons.extensions.applyColorFilter

View File

@ -1,20 +1,20 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.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.dbHelper
import com.simplemobiletools.calendar.extensions.handleEventDeleting
import com.simplemobiletools.calendar.extensions.shareEvents
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.helpers.ITEM_EVENT
import com.simplemobiletools.calendar.helpers.ITEM_EVENT_SIMPLE
import com.simplemobiletools.calendar.helpers.LOW_ALPHA
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.dialogs.DeleteEventDialog
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.extensions.handleEventDeleting
import com.simplemobiletools.calendar.pro.extensions.shareEvents
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.helpers.ITEM_EVENT
import com.simplemobiletools.calendar.pro.helpers.ITEM_EVENT_SIMPLE
import com.simplemobiletools.calendar.pro.helpers.LOW_ALPHA
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.extensions.adjustAlpha
import com.simplemobiletools.commons.extensions.applyColorFilter
@ -49,9 +49,9 @@ class DayEventsAdapter(activity: SimpleActivity, val events: ArrayList<Event>, r
override fun getIsItemSelectable(position: Int) = true
override fun getItemSelectionKey(position: Int) = events.getOrNull(position)?.id
override fun getItemSelectionKey(position: Int) = events.getOrNull(position)?.id?.toInt()
override fun getItemKeyPosition(key: Int) = events.indexOfFirst { it.id == key }
override fun getItemKeyPosition(key: Int) = events.indexOfFirst { it.id?.toInt() == key }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyRecyclerViewAdapter.ViewHolder {
val layoutId = when (viewType) {
@ -93,7 +93,7 @@ class DayEventsAdapter(activity: SimpleActivity, val events: ArrayList<Event>, r
private fun setupView(view: View, event: Event) {
view.apply {
event_item_frame.isSelected = selectedKeys.contains(event.id)
event_item_frame.isSelected = selectedKeys.contains(event.id?.toInt())
event_item_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)
@ -130,11 +130,11 @@ class DayEventsAdapter(activity: SimpleActivity, val events: ArrayList<Event>, r
}
}
private fun shareEvents() = activity.shareEvents(selectedKeys.distinct())
private fun shareEvents() = activity.shareEvents(selectedKeys.distinct().map { it.toLong() })
private fun askConfirmDelete() {
val eventIds = selectedKeys.toMutableList()
val eventsToDelete = events.filter { selectedKeys.contains(it.id) }
val eventIds = selectedKeys.map { it.toLong() }.toMutableList()
val eventsToDelete = events.filter { selectedKeys.contains(it.id?.toInt()) }
val timestamps = eventsToDelete.map { it.startTS }
val positions = getSelectedItemPositions()
@ -142,12 +142,16 @@ class DayEventsAdapter(activity: SimpleActivity, val events: ArrayList<Event>, r
DeleteEventDialog(activity, eventIds, hasRepeatableEvent) { it ->
events.removeAll(eventsToDelete)
val nonRepeatingEventIDs = eventsToDelete.asSequence().filter { it.repeatInterval == 0 }.map { it.id.toString() }.toList().toTypedArray()
activity.dbHelper.deleteEvents(nonRepeatingEventIDs, true)
Thread {
val nonRepeatingEventIDs = eventsToDelete.asSequence().filter { it.repeatInterval == 0 }.mapNotNull { it.id }.toMutableList()
activity.eventsHelper.deleteEvents(nonRepeatingEventIDs, true)
val repeatingEventIDs = eventsToDelete.asSequence().filter { it.repeatInterval != 0 }.map { it.id }.toList()
activity.handleEventDeleting(repeatingEventIDs, timestamps, it)
removeSelectedItems(positions)
val repeatingEventIDs = eventsToDelete.asSequence().filter { it.repeatInterval != 0 }.mapNotNull { it.id }.toList()
activity.handleEventDeleting(repeatingEventIDs, timestamps, it)
activity.runOnUiThread {
removeSelectedItems(positions)
}
}.start()
}
}
}

View File

@ -1,20 +1,20 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.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.dbHelper
import com.simplemobiletools.calendar.extensions.handleEventDeleting
import com.simplemobiletools.calendar.extensions.shareEvents
import com.simplemobiletools.calendar.helpers.*
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.dialogs.DeleteEventDialog
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.extensions.handleEventDeleting
import com.simplemobiletools.calendar.pro.extensions.shareEvents
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.models.ListEvent
import com.simplemobiletools.calendar.pro.models.ListItem
import com.simplemobiletools.calendar.pro.models.ListSection
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.extensions.adjustAlpha
import com.simplemobiletools.commons.extensions.applyColorFilter
@ -70,9 +70,9 @@ class EventListAdapter(activity: SimpleActivity, var listItems: ArrayList<ListIt
override fun getIsItemSelectable(position: Int) = listItems[position] is ListEvent
override fun getItemSelectionKey(position: Int) = (listItems.getOrNull(position) as? ListEvent)?.id
override fun getItemSelectionKey(position: Int) = (listItems.getOrNull(position) as? ListEvent)?.hashCode()
override fun getItemKeyPosition(key: Int) = listItems.indexOfFirst { (it as? ListEvent)?.id == key }
override fun getItemKeyPosition(key: Int) = listItems.indexOfFirst { (it as? ListEvent)?.hashCode() == key }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyRecyclerViewAdapter.ViewHolder {
val layoutId = when (viewType) {
@ -85,7 +85,7 @@ class EventListAdapter(activity: SimpleActivity, var listItems: ArrayList<ListIt
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val listItem = listItems[position]
holder.bindView(listItem, true, allowLongClick) { itemView, layoutPosition ->
holder.bindView(listItem, true, allowLongClick && listItem is ListEvent) { itemView, layoutPosition ->
if (listItem is ListSection) {
setupListSection(itemView, listItem, position)
} else if (listItem is ListEvent) {
@ -136,7 +136,7 @@ class EventListAdapter(activity: SimpleActivity, var listItems: ArrayList<ListIt
private fun setupListEvent(view: View, listEvent: ListEvent) {
view.apply {
event_item_frame.isSelected = selectedKeys.contains(listEvent.id)
event_item_frame.isSelected = selectedKeys.contains(listEvent.hashCode())
event_item_title.text = listEvent.title
event_item_description?.text = if (replaceDescription) listEvent.location else listEvent.description
event_item_start.text = if (listEvent.isAllDay) allDayString else Formatter.getTimeFromTS(context, listEvent.startTS)
@ -195,24 +195,30 @@ class EventListAdapter(activity: SimpleActivity, var listItems: ArrayList<ListIt
}
}
private fun shareEvents() = activity.shareEvents(selectedKeys.distinct())
private fun shareEvents() = activity.shareEvents(getSelectedEventIds())
private fun getSelectedEventIds() = listItems.filter { it is ListEvent && selectedKeys.contains(it.hashCode()) }.map { (it as ListEvent).id }.toMutableList() as ArrayList<Long>
private fun askConfirmDelete() {
val eventIds = selectedKeys.toMutableList()
val eventsToDelete = listItems.filter { selectedKeys.contains((it as? ListEvent)?.id) } as List<ListEvent>
val eventIds = getSelectedEventIds()
val eventsToDelete = listItems.filter { selectedKeys.contains((it as? ListEvent)?.hashCode()) } as List<ListEvent>
val timestamps = eventsToDelete.mapNotNull { (it as? ListEvent)?.startTS }
val hasRepeatableEvent = eventsToDelete.any { it.isRepeatable }
DeleteEventDialog(activity, eventIds, hasRepeatableEvent) {
listItems.removeAll(eventsToDelete)
val nonRepeatingEventIDs = eventsToDelete.filter { !it.isRepeatable }.map { it.id.toString() }.toTypedArray()
activity.dbHelper.deleteEvents(nonRepeatingEventIDs, true)
Thread {
val nonRepeatingEventIDs = eventsToDelete.filter { !it.isRepeatable }.mapNotNull { it.id }.toMutableList()
activity.eventsHelper.deleteEvents(nonRepeatingEventIDs, true)
val repeatingEventIDs = eventsToDelete.filter { it.isRepeatable }.map { it.id }
activity.handleEventDeleting(repeatingEventIDs, timestamps, it)
listener?.refreshItems()
finishActMode()
val repeatingEventIDs = eventsToDelete.filter { it.isRepeatable }.map { it.id }
activity.handleEventDeleting(repeatingEventIDs, timestamps, it)
activity.runOnUiThread {
listener?.refreshItems()
finishActMode()
}
}.start()
}
}
}

View File

@ -1,21 +1,21 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.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.R.id.event_section_title
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.*
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.R.id.event_item_holder
import com.simplemobiletools.calendar.pro.R.id.event_section_title
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.models.ListEvent
import com.simplemobiletools.calendar.pro.models.ListItem
import com.simplemobiletools.calendar.pro.models.ListSection
import com.simplemobiletools.commons.extensions.adjustAlpha
import com.simplemobiletools.commons.extensions.setBackgroundColor
import com.simplemobiletools.commons.extensions.setText
@ -156,7 +156,7 @@ class EventListWidgetAdapter(val context: Context) : RemoteViewsService.RemoteVi
mediumFontSize = context.config.getFontSize()
val fromTS = DateTime().seconds() - context.config.displayPastEvents * 60
val toTS = DateTime().plusYears(1).seconds()
context.dbHelper.getEventsInBackground(fromTS, toTS, applyTypeFilter = true) {
context.eventsHelper.getEventsSync(fromTS, toTS, applyTypeFilter = true) {
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 }))
@ -174,7 +174,7 @@ class EventListWidgetAdapter(val context: Context) : RemoteViewsService.RemoteVi
prevCode = code
}
val listEvent = ListEvent(it.id, it.startTS, it.endTS, it.title, it.description, it.getIsAllDay(), it.color, it.location, it.isPastEvent, it.repeatInterval > 0)
val listEvent = ListEvent(it.id!!, it.startTS, it.endTS, it.title, it.description, it.getIsAllDay(), it.color, it.location, it.isPastEvent, it.repeatInterval > 0)
listItems.add(listEvent)
}

View File

@ -1,12 +1,12 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.adapters
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
import com.simplemobiletools.commons.extensions.setFillWithStroke
import kotlinx.android.synthetic.main.filter_event_type_view.view.*
@ -14,19 +14,19 @@ import java.util.*
class FilterEventTypeAdapter(val activity: SimpleActivity, val eventTypes: List<EventType>, val displayEventTypes: Set<String>) :
RecyclerView.Adapter<FilterEventTypeAdapter.ViewHolder>() {
private val selectedKeys = HashSet<Int>()
private val selectedKeys = HashSet<Long>()
init {
eventTypes.forEachIndexed { index, eventType ->
if (displayEventTypes.contains(eventType.id.toString())) {
selectedKeys.add(eventType.id)
selectedKeys.add(eventType.id!!)
}
}
}
private fun toggleItemSelection(select: Boolean, eventType: EventType, pos: Int) {
if (select) {
selectedKeys.add(eventType.id)
selectedKeys.add(eventType.id!!)
} else {
selectedKeys.remove(eventType.id)
}
@ -34,7 +34,7 @@ class FilterEventTypeAdapter(val activity: SimpleActivity, val eventTypes: List<
notifyItemChanged(pos)
}
fun getSelectedItemsSet() = selectedKeys.asSequence().map { it.toString() }.toHashSet()
fun getSelectedItemsList() = selectedKeys.asSequence().map { it }.toMutableList() as ArrayList<Long>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = activity.layoutInflater.inflate(R.layout.filter_event_type_view, parent, false)

View File

@ -1,15 +1,15 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.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.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.helpers.REGULAR_EVENT_TYPE_ID
import com.simplemobiletools.calendar.pro.interfaces.DeleteEventTypesListener
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
@ -41,9 +41,9 @@ class ManageEventTypesAdapter(activity: SimpleActivity, val eventTypes: ArrayLis
override fun getIsItemSelectable(position: Int) = true
override fun getItemSelectionKey(position: Int) = eventTypes.getOrNull(position)?.id
override fun getItemSelectionKey(position: Int) = eventTypes.getOrNull(position)?.id?.toInt()
override fun getItemKeyPosition(key: Int) = eventTypes.indexOfFirst { it.id == key }
override fun getItemKeyPosition(key: Int) = eventTypes.indexOfFirst { it.id?.toInt() == key }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_event_type, parent)
@ -57,13 +57,13 @@ class ManageEventTypesAdapter(activity: SimpleActivity, val eventTypes: ArrayLis
override fun getItemCount() = eventTypes.size
private fun getItemWithKey(key: Int): EventType? = eventTypes.firstOrNull { it.id == key }
private fun getItemWithKey(key: Int): EventType? = eventTypes.firstOrNull { it.id?.toInt() == key }
private fun getSelectedItems() = eventTypes.filter { selectedKeys.contains(it.id) } as ArrayList<EventType>
private fun getSelectedItems() = eventTypes.filter { selectedKeys.contains(it.id?.toInt()) } as ArrayList<EventType>
private fun setupView(view: View, eventType: EventType) {
view.apply {
event_item_frame.isSelected = selectedKeys.contains(eventType.id)
event_item_frame.isSelected = selectedKeys.contains(eventType.id?.toInt())
event_type_title.text = eventType.getDisplayTitle()
event_type_color.setFillWithStroke(eventType.color, activity.config.backgroundColor)
event_type_title.setTextColor(textColor)
@ -71,22 +71,26 @@ class ManageEventTypesAdapter(activity: SimpleActivity, val eventTypes: ArrayLis
}
private fun askConfirmDelete() {
val eventTypes = eventTypes.filter { selectedKeys.contains(it.id) } as ArrayList<EventType>
val eventTypes = eventTypes.filter { selectedKeys.contains(it.id?.toInt()) }.map { it.id } as ArrayList<Long>
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)
activity.eventsHelper.doEventTypesContainEvents(eventTypes) {
activity.runOnUiThread {
if (it) {
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)
}
}
}
}
}
@ -96,10 +100,10 @@ class ManageEventTypesAdapter(activity: SimpleActivity, val eventTypes: ArrayLis
for (key in selectedKeys) {
val type = getItemWithKey(key) ?: continue
if (type.id == DBHelper.REGULAR_EVENT_TYPE_ID) {
if (type.id == REGULAR_EVENT_TYPE_ID) {
activity.toast(R.string.cannot_delete_default_type)
eventTypesToDelete.remove(type)
toggleItemSelection(false, getItemKeyPosition(type.id))
toggleItemSelection(false, getItemKeyPosition(type.id!!.toInt()))
break
}
}

View File

@ -1,13 +1,13 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.adapters
import android.os.Bundle
import android.util.SparseArray
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import com.simplemobiletools.calendar.fragments.DayFragment
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.pro.fragments.DayFragment
import com.simplemobiletools.calendar.pro.helpers.DAY_CODE
import com.simplemobiletools.calendar.pro.interfaces.NavigationListener
class MyDayPagerAdapter(fm: FragmentManager, private val mCodes: List<String>, private val mListener: NavigationListener) :
FragmentStatePagerAdapter(fm) {

View File

@ -1,13 +1,13 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.adapters
import android.os.Bundle
import android.util.SparseArray
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import com.simplemobiletools.calendar.fragments.MonthFragment
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.pro.fragments.MonthFragment
import com.simplemobiletools.calendar.pro.helpers.DAY_CODE
import com.simplemobiletools.calendar.pro.interfaces.NavigationListener
class MyMonthPagerAdapter(fm: FragmentManager, private val mCodes: List<String>, private val mListener: NavigationListener) : FragmentStatePagerAdapter(fm) {
private val mFragments = SparseArray<MonthFragment>()

View File

@ -1,15 +1,15 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.adapters
import android.os.Bundle
import android.util.SparseArray
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import com.simplemobiletools.calendar.fragments.WeekFragment
import com.simplemobiletools.calendar.helpers.WEEK_START_TIMESTAMP
import com.simplemobiletools.calendar.interfaces.WeekFragmentListener
import com.simplemobiletools.calendar.pro.fragments.WeekFragment
import com.simplemobiletools.calendar.pro.helpers.WEEK_START_TIMESTAMP
import com.simplemobiletools.calendar.pro.interfaces.WeekFragmentListener
class MyWeekPagerAdapter(fm: FragmentManager, val mWeekTimestamps: List<Int>, val mListener: WeekFragmentListener) : FragmentStatePagerAdapter(fm) {
class MyWeekPagerAdapter(fm: FragmentManager, val mWeekTimestamps: List<Long>, val mListener: WeekFragmentListener) : FragmentStatePagerAdapter(fm) {
private val mFragments = SparseArray<WeekFragment>()
override fun getCount() = mWeekTimestamps.size
@ -17,7 +17,7 @@ class MyWeekPagerAdapter(fm: FragmentManager, val mWeekTimestamps: List<Int>, va
override fun getItem(position: Int): Fragment {
val bundle = Bundle()
val weekTimestamp = mWeekTimestamps[position]
bundle.putInt(WEEK_START_TIMESTAMP, weekTimestamp)
bundle.putLong(WEEK_START_TIMESTAMP, weekTimestamp)
val fragment = WeekFragment()
fragment.arguments = bundle

View File

@ -1,12 +1,12 @@
package com.simplemobiletools.calendar.adapters
package com.simplemobiletools.calendar.pro.adapters
import android.os.Bundle
import android.util.SparseArray
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import com.simplemobiletools.calendar.fragments.YearFragment
import com.simplemobiletools.calendar.helpers.YEAR_LABEL
import com.simplemobiletools.calendar.pro.fragments.YearFragment
import com.simplemobiletools.calendar.pro.helpers.YEAR_LABEL
class MyYearPagerAdapter(fm: FragmentManager, val mYears: List<Int>) : FragmentStatePagerAdapter(fm) {
private val mFragments = SparseArray<YearFragment>()

View File

@ -0,0 +1,62 @@
package com.simplemobiletools.calendar.pro.databases
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.sqlite.db.SupportSQLiteDatabase
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.helpers.Converters
import com.simplemobiletools.calendar.pro.helpers.REGULAR_EVENT_TYPE_ID
import com.simplemobiletools.calendar.pro.interfaces.EventTypesDao
import com.simplemobiletools.calendar.pro.interfaces.EventsDao
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType
import java.util.concurrent.Executors
@Database(entities = [Event::class, EventType::class], version = 1)
@TypeConverters(Converters::class)
abstract class EventsDatabase : RoomDatabase() {
abstract fun EventsDao(): EventsDao
abstract fun EventTypesDao(): EventTypesDao
companion object {
private var db: EventsDatabase? = null
fun getInstance(context: Context): EventsDatabase {
if (db == null) {
synchronized(EventsDatabase::class) {
if (db == null) {
db = Room.databaseBuilder(context.applicationContext, EventsDatabase::class.java, "events.db")
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
insertRegularEventType(context)
}
})
.build()
db!!.openHelper.setWriteAheadLoggingEnabled(true)
}
}
}
return db!!
}
fun destroyInstance() {
db = null
}
private fun insertRegularEventType(context: Context) {
Executors.newSingleThreadScheduledExecutor().execute {
val regularEvent = context.resources.getString(R.string.regular_event)
val eventType = EventType(REGULAR_EVENT_TYPE_ID, regularEvent, context.config.primaryColor)
db!!.EventTypesDao().insertOrUpdate(eventType)
context.config.addDisplayEventType(REGULAR_EVENT_TYPE_ID.toString())
}
}
}
}

View File

@ -1,13 +1,13 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.calendar.R
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.helpers.DAY
import com.simplemobiletools.calendar.pro.helpers.MONTH
import com.simplemobiletools.calendar.pro.helpers.WEEK
import com.simplemobiletools.calendar.pro.helpers.YEAR
import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.showKeyboard

View File

@ -1,17 +1,17 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.helpers.DELETE_ALL_OCCURRENCES
import com.simplemobiletools.calendar.helpers.DELETE_FUTURE_OCCURRENCES
import com.simplemobiletools.calendar.helpers.DELETE_SELECTED_OCCURRENCE
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.helpers.DELETE_ALL_OCCURRENCES
import com.simplemobiletools.calendar.pro.helpers.DELETE_FUTURE_OCCURRENCES
import com.simplemobiletools.calendar.pro.helpers.DELETE_SELECTED_OCCURRENCE
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>, hasRepeatableEvent: Boolean, val callback: (deleteRule: Int) -> Unit) {
class DeleteEventDialog(val activity: Activity, eventIds: List<Long>, hasRepeatableEvent: Boolean, val callback: (deleteRule: Int) -> Unit) {
val dialog: AlertDialog?
init {

View File

@ -1,12 +1,12 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.extensions.*
import kotlinx.android.synthetic.main.dialog_event_type.view.*
@ -16,7 +16,7 @@ class EditEventTypeDialog(val activity: Activity, var eventType: EventType? = nu
init {
if (eventType == null)
eventType = EventType(0, "", activity.config.primaryColor)
eventType = EventType(null, "", activity.config.primaryColor)
val view = activity.layoutInflater.inflate(R.layout.dialog_event_type, null).apply {
setupColor(type_color)
@ -45,36 +45,9 @@ class EditEventTypeDialog(val activity: Activity, var eventType: EventType? = nu
activity.setupDialogStuff(view, this, if (isNewEvent) R.string.add_new_type else R.string.edit_type) {
showKeyboard(view.type_title)
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
eventType!!.id = if (isNewEvent) {
activity.dbHelper.insertEventType(eventType!!)
} else {
activity.dbHelper.updateEventType(eventType!!)
}
if (eventType!!.id != -1) {
dismiss()
callback(eventType!!)
} else {
activity.toast(R.string.editing_calendar_failed)
}
Thread {
eventTypeConfirmed(view.type_title.value, this)
}.start()
}
}
}
@ -83,4 +56,36 @@ class EditEventTypeDialog(val activity: Activity, var eventType: EventType? = nu
private fun setupColor(view: ImageView) {
view.setFillWithStroke(eventType!!.color, activity.config.backgroundColor)
}
private fun eventTypeConfirmed(title: String, dialog: AlertDialog) {
val eventIdWithTitle = activity.eventsHelper.getEventTypeIdWithTitle(title)
var isEventTypeTitleTaken = isNewEvent && eventIdWithTitle != -1L
if (!isEventTypeTitleTaken) {
isEventTypeTitleTaken = !isNewEvent && eventType!!.id != eventIdWithTitle && eventIdWithTitle != -1L
}
if (title.isEmpty()) {
activity.toast(R.string.title_empty)
return
} else if (isEventTypeTitleTaken) {
activity.toast(R.string.type_already_exists)
return
}
eventType!!.title = title
if (eventType!!.caldavCalendarId != 0) {
eventType!!.caldavDisplayName = title
}
eventType!!.id = activity.eventsHelper.insertOrUpdateEventTypeSync(eventType!!)
if (eventType!!.id != -1L) {
activity.runOnUiThread {
dialog.dismiss()
callback(eventType!!)
}
} else {
activity.toast(R.string.editing_calendar_failed)
}
}
}

View File

@ -1,9 +1,9 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.dialog_edit_repeating_event.view.*

View File

@ -1,36 +1,34 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.appcompat.app.AlertDialog
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.adapters.FilterEventTypeAdapter
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.commons.extensions.*
import kotlinx.android.synthetic.main.dialog_export_events.view.*
import java.io.File
import java.util.*
class ExportEventsDialog(val activity: SimpleActivity, val path: String, val callback: (exportPastEvents: Boolean, file: File, eventTypes: HashSet<String>) -> Unit) {
class ExportEventsDialog(val activity: SimpleActivity, val path: String, val callback: (exportPastEvents: Boolean, file: File, eventTypes: ArrayList<Long>) -> 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("${activity.getString(R.string.events)}_${activity.getCurrentFormattedDateTime()}")
activity.dbHelper.getEventTypes {
activity.eventsHelper.getEventTypes(activity) {
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()
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
}
val margin = activity.resources.getDimension(R.dimen.normal_margin).toInt()
(export_events_checkbox.layoutParams as LinearLayout.LayoutParams).leftMargin = margin
}
}
}
@ -51,7 +49,7 @@ class ExportEventsDialog(val activity: SimpleActivity, val path: String, val cal
return@setOnClickListener
}
val eventTypes = (view.export_events_types_list.adapter as FilterEventTypeAdapter).getSelectedItemsSet()
val eventTypes = (view.export_events_types_list.adapter as FilterEventTypeAdapter).getSelectedItemsList()
callback(view.export_events_checkbox.isChecked, file, eventTypes)
dismiss()
}

View File

@ -0,0 +1,38 @@
package com.simplemobiletools.calendar.pro.dialogs
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.adapters.FilterEventTypeAdapter
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.dialog_filter_event_types.view.*
class FilterEventTypesDialog(val activity: SimpleActivity, val callback: () -> Unit) {
private lateinit var dialog: AlertDialog
private val view = activity.layoutInflater.inflate(R.layout.dialog_filter_event_types, null)
init {
activity.eventsHelper.getEventTypes(activity) {
val displayEventTypes = activity.config.displayEventTypes
view.filter_event_types_list.adapter = FilterEventTypeAdapter(activity, it, 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).getSelectedItemsList().map { it.toString() }.toHashSet()
if (activity.config.displayEventTypes != selectedItems) {
activity.config.displayEventTypes = selectedItems
callback()
}
dialog.dismiss()
}
}

View File

@ -1,50 +1,59 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventTypesDB
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.helpers.IcsImporter
import com.simplemobiletools.calendar.pro.helpers.IcsImporter.ImportResult.*
import com.simplemobiletools.calendar.pro.helpers.REGULAR_EVENT_TYPE_ID
import com.simplemobiletools.commons.extensions.setFillWithStroke
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
var currEventTypeId = REGULAR_EVENT_TYPE_ID
var currEventTypeCalDAVCalendarId = 0
val config = activity.config
init {
val config = activity.config
if (activity.dbHelper.getEventType(config.lastUsedLocalEventTypeId) == null) {
config.lastUsedLocalEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
}
val isLastCaldavCalendarOK = config.caldavSync && config.getSyncedCalendarIdsAsList().contains(config.lastUsedCaldavCalendarId.toString())
currEventTypeId = if (isLastCaldavCalendarOK) {
val lastUsedCalDAVCalendar = activity.dbHelper.getEventTypeWithCalDAVCalendarId(config.lastUsedCaldavCalendarId)
if (lastUsedCalDAVCalendar != null) {
currEventTypeCalDAVCalendarId = config.lastUsedCaldavCalendarId
lastUsedCalDAVCalendar.id
} else {
DBHelper.REGULAR_EVENT_TYPE_ID
Thread {
if (activity.eventTypesDB.getEventTypeWithId(config.lastUsedLocalEventTypeId) == null) {
config.lastUsedLocalEventTypeId = REGULAR_EVENT_TYPE_ID
}
} else {
config.lastUsedLocalEventTypeId
}
val isLastCaldavCalendarOK = config.caldavSync && config.getSyncedCalendarIdsAsList().contains(config.lastUsedCaldavCalendarId)
currEventTypeId = if (isLastCaldavCalendarOK) {
val lastUsedCalDAVCalendar = activity.eventsHelper.getEventTypeWithCalDAVCalendarId(config.lastUsedCaldavCalendarId)
if (lastUsedCalDAVCalendar != null) {
currEventTypeCalDAVCalendarId = config.lastUsedCaldavCalendarId
lastUsedCalDAVCalendar.id!!
} else {
REGULAR_EVENT_TYPE_ID
}
} else {
config.lastUsedLocalEventTypeId
}
activity.runOnUiThread {
initDialog()
}
}.start()
}
private fun initDialog() {
val view = (activity.layoutInflater.inflate(R.layout.dialog_import_events, null) as ViewGroup).apply {
updateEventType(this)
import_event_type_holder.setOnClickListener {
SelectEventTypeDialog(activity, currEventTypeId, true) {
currEventTypeId = it.id
currEventTypeId = it.id!!
currEventTypeCalDAVCalendarId = it.caldavCalendarId
config.lastUsedLocalEventTypeId = it.id
config.lastUsedLocalEventTypeId = it.id!!
config.lastUsedCaldavCalendarId = it.caldavCalendarId
updateEventType(this)
@ -58,6 +67,7 @@ class ImportEventsDialog(val activity: SimpleActivity, val path: String, val cal
.create().apply {
activity.setupDialogStuff(view, this, R.string.import_events) {
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(null)
activity.toast(R.string.importing)
Thread {
val overrideFileEventTypes = view.import_events_checkbox.isChecked
@ -71,9 +81,13 @@ class ImportEventsDialog(val activity: SimpleActivity, val path: String, val cal
}
private fun updateEventType(view: ViewGroup) {
val eventType = activity.dbHelper.getEventType(currEventTypeId)
view.import_event_type_title.text = eventType!!.getDisplayTitle()
view.import_event_type_color.setFillWithStroke(eventType.color, activity.config.backgroundColor)
Thread {
val eventType = activity.eventTypesDB.getEventTypeWithId(currEventTypeId)
activity.runOnUiThread {
view.import_event_type_title.text = eventType!!.getDisplayTitle()
view.import_event_type_color.setFillWithStroke(eventType.color, activity.config.backgroundColor)
}
}.start()
}
private fun handleParseResult(result: IcsImporter.ImportResult) {

View File

@ -1,14 +1,14 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import android.app.DatePickerDialog
import android.view.View
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.helpers.getNowSeconds
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.helpers.getNowSeconds
import com.simplemobiletools.commons.extensions.getDialogTheme
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.value
@ -16,7 +16,7 @@ import kotlinx.android.synthetic.main.dialog_repeat_limit_type_picker.view.*
import org.joda.time.DateTime
import java.util.*
class RepeatLimitTypePickerDialog(val activity: Activity, var repeatLimit: Int, val startTS: Int, val callback: (repeatLimit: Int) -> Unit) {
class RepeatLimitTypePickerDialog(val activity: Activity, var repeatLimit: Long, val startTS: Long, val callback: (repeatLimit: Long) -> Unit) {
lateinit var dialog: AlertDialog
var view: View
@ -76,14 +76,14 @@ class RepeatLimitTypePickerDialog(val activity: Activity, var repeatLimit: Int,
} else {
"-$count"
}
callback(count.toInt())
callback(count.toLong())
}
}
dialog.dismiss()
}
private fun showRepetitionLimitDialog() {
val repeatLimitDateTime = Formatter.getDateTimeFromTS(if (repeatLimit != 0) repeatLimit else getNowSeconds())
val repeatLimitDateTime = Formatter.getDateTimeFromTS(if (repeatLimit != 0L) repeatLimit else getNowSeconds())
val datepicker = DatePickerDialog(activity, activity.getDialogTheme(), repetitionLimitDateSetListener, repeatLimitDateTime.year,
repeatLimitDateTime.monthOfYear - 1, repeatLimitDateTime.dayOfMonth)

View File

@ -1,9 +1,9 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.views.MyAppCompatCheckbox
import kotlinx.android.synthetic.main.dialog_vertical_linear_layout.view.*

View File

@ -1,14 +1,14 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.text.TextUtils
import android.view.ViewGroup
import android.widget.RelativeLayout
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SwitchCompat
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.CalDAVHandler
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.calDAVHelper
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.calendar_item_account.view.*
import kotlinx.android.synthetic.main.calendar_item_calendar.view.*
@ -21,7 +21,7 @@ class SelectCalendarsDialog(val activity: SimpleActivity, val callback: () -> Un
init {
val ids = activity.config.getSyncedCalendarIdsAsList()
val calendars = CalDAVHandler(activity.applicationContext).getCalDAVCalendars(activity)
val calendars = activity.calDAVHelper.getCalDAVCalendars("", true)
val sorted = calendars.sortedWith(compareBy({ it.accountName }, { it.displayName }))
sorted.forEach {
if (prevAccount != it.accountName) {
@ -29,7 +29,7 @@ class SelectCalendarsDialog(val activity: SimpleActivity, val callback: () -> Un
addCalendarItem(false, it.accountName)
}
addCalendarItem(true, it.displayName, it.id, ids.contains(it.id.toString()))
addCalendarItem(true, it.displayName, it.id, ids.contains(it.id))
}
dialog = AlertDialog.Builder(activity)

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import android.graphics.Color
@ -6,11 +6,11 @@ import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.RadioGroup
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.helpers.STORED_LOCALLY_ONLY
import com.simplemobiletools.calendar.models.CalDAVCalendar
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.helpers.STORED_LOCALLY_ONLY
import com.simplemobiletools.calendar.pro.models.CalDAVCalendar
import com.simplemobiletools.commons.extensions.setFillWithStroke
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.updateTextColors
@ -26,21 +26,23 @@ class SelectEventCalendarDialog(val activity: Activity, val calendars: List<CalD
val view = activity.layoutInflater.inflate(R.layout.dialog_select_radio_group, null) as ViewGroup
radioGroup = view.dialog_radio_group
activity.dbHelper.getEventTypes {
Thread {
calendars.forEach {
val localEventType = activity.eventsHelper.getEventTypeWithCalDAVCalendarId(it.id)
if (localEventType != null) {
it.color = localEventType.color
}
}
activity.runOnUiThread {
calendars.forEach {
val localEventType = activity.dbHelper.getEventTypeWithCalDAVCalendarId(it.id)
if (localEventType != null) {
it.color = localEventType.color
}
addRadioButton(it.getFullTitle(), it.id, it.color)
}
addRadioButton(activity.getString(R.string.store_locally_only), STORED_LOCALLY_ONLY, Color.TRANSPARENT)
wasInit = true
activity.updateTextColors(view.dialog_radio_holder)
}
}
}.start()
dialog = AlertDialog.Builder(activity)
.create().apply {

View File

@ -1,14 +1,14 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.RadioGroup
import androidx.appcompat.app.AlertDialog
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.calDAVHelper
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.extensions.setFillWithStroke
import com.simplemobiletools.commons.extensions.setupDialogStuff
@ -19,7 +19,7 @@ class SelectEventTypeColorDialog(val activity: Activity, val eventType: EventTyp
private val dialog: AlertDialog?
private val radioGroup: RadioGroup
private var wasInit = false
private val colors = CalDAVHandler(activity.applicationContext).getAvailableCalDAVCalendarColors(eventType)
private val colors = activity.calDAVHelper.getAvailableCalDAVCalendarColors(eventType)
init {
val view = activity.layoutInflater.inflate(R.layout.dialog_select_event_type_color, null) as ViewGroup

View File

@ -1,14 +1,14 @@
package com.simplemobiletools.calendar.dialogs
package com.simplemobiletools.calendar.pro.dialogs
import android.app.Activity
import android.graphics.Color
import android.view.ViewGroup
import android.widget.RadioGroup
import androidx.appcompat.app.AlertDialog
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.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.setFillWithStroke
import com.simplemobiletools.commons.extensions.setupDialogStuff
@ -18,9 +18,9 @@ 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 showCalDAVCalendars: Boolean,
class SelectEventTypeDialog(val activity: Activity, val currEventType: Long, val showCalDAVCalendars: Boolean,
val callback: (eventType: EventType) -> Unit) {
private val NEW_TYPE_ID = -2
private val NEW_TYPE_ID = -2L
private val dialog: AlertDialog?
private val radioGroup: RadioGroup
@ -31,7 +31,7 @@ class SelectEventTypeDialog(val activity: Activity, val currEventType: Int, val
val view = activity.layoutInflater.inflate(R.layout.dialog_select_radio_group, null) as ViewGroup
radioGroup = view.dialog_radio_group
activity.dbHelper.getEventTypes {
activity.eventsHelper.getEventTypes(activity) {
eventTypes = it
activity.runOnUiThread {
eventTypes.filter { showCalDAVCalendars || it.caldavCalendarId == 0 }.forEach {
@ -55,7 +55,7 @@ class SelectEventTypeDialog(val activity: Activity, val currEventType: Int, val
(view.dialog_radio_button as MyCompatRadioButton).apply {
text = eventType.getDisplayTitle()
isChecked = eventType.id == currEventType
id = eventType.id
id = eventType.id!!.toInt()
}
if (eventType.color != Color.TRANSPARENT) {

View File

@ -1,10 +1,11 @@
package com.simplemobiletools.calendar.extensions
package com.simplemobiletools.calendar.pro.extensions
import android.app.Activity
import com.simplemobiletools.calendar.BuildConfig
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.dialogs.CustomEventRepeatIntervalDialog
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.pro.BuildConfig
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.dialogs.CustomEventRepeatIntervalDialog
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.hideKeyboard
@ -15,19 +16,21 @@ import java.io.File
import java.util.TreeSet
import kotlin.collections.ArrayList
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, false) {
if (it == IcsExporter.ExportResult.EXPORT_OK) {
sharePathIntent(file.absolutePath, BuildConfig.APPLICATION_ID)
fun BaseSimpleActivity.shareEvents(ids: List<Long>) {
Thread {
val file = getTempFile()
if (file == null) {
toast(R.string.unknown_error_occurred)
return@Thread
}
}
val events = eventsDB.getEventsWithIds(ids) as ArrayList<Event>
IcsExporter().exportEvents(this, file, events, false) {
if (it == IcsExporter.ExportResult.EXPORT_OK) {
sharePathIntent(file.absolutePath, BuildConfig.APPLICATION_ID)
}
}
}.start()
}
fun BaseSimpleActivity.getTempFile(): File? {

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.extensions
package com.simplemobiletools.calendar.pro.extensions
import android.accounts.Account
import android.annotation.SuppressLint
@ -9,7 +9,6 @@ import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.database.ContentObserver
import android.media.AudioAttributes
import android.net.Uri
import android.os.Bundle
@ -21,16 +20,18 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.app.AlarmManagerCompat
import androidx.core.app.NotificationCompat
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.activities.SnoozeReminderActivity
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.models.*
import com.simplemobiletools.calendar.receivers.CalDAVSyncReceiver
import com.simplemobiletools.calendar.receivers.NotificationReceiver
import com.simplemobiletools.calendar.services.SnoozeService
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.EventActivity
import com.simplemobiletools.calendar.pro.activities.SnoozeReminderActivity
import com.simplemobiletools.calendar.pro.databases.EventsDatabase
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.interfaces.EventTypesDao
import com.simplemobiletools.calendar.pro.interfaces.EventsDao
import com.simplemobiletools.calendar.pro.models.*
import com.simplemobiletools.calendar.pro.receivers.CalDAVSyncReceiver
import com.simplemobiletools.calendar.pro.receivers.NotificationReceiver
import com.simplemobiletools.calendar.pro.services.SnoozeService
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.SILENT
import com.simplemobiletools.commons.helpers.WEEK_SECONDS
@ -39,12 +40,13 @@ import com.simplemobiletools.commons.helpers.isOreoPlus
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.joda.time.LocalDate
import java.text.SimpleDateFormat
import java.util.*
val Context.config: Config get() = Config.newInstance(applicationContext)
val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext)
val Context.eventsDB: EventsDao get() = EventsDatabase.getInstance(applicationContext).EventsDao()
val Context.eventTypesDB: EventTypesDao get() = EventsDatabase.getInstance(applicationContext).EventTypesDao()
val Context.eventsHelper: EventsHelper get() = EventsHelper(this)
val Context.calDAVHelper: CalDAVHelper get() = CalDAVHelper(this)
fun Context.updateWidgets() {
val widgetIDs = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(ComponentName(applicationContext, MyWidgetMonthlyProvider::class.java))
@ -71,47 +73,53 @@ fun Context.updateListWidget() {
}
fun Context.scheduleAllEvents() {
val events = dbHelper.getEventsAtReboot()
val events = eventsDB.getEventsAtReboot(getNowSeconds())
events.forEach {
scheduleNextEventReminder(it, dbHelper)
scheduleNextEventReminder(it, false)
}
}
fun Context.scheduleNextEventReminder(event: Event, dbHelper: DBHelper, activity: SimpleActivity? = null) {
fun Context.scheduleNextEventReminder(event: Event, showToasts: Boolean) {
if (event.getReminders().isEmpty()) {
activity?.toast(R.string.saving)
if (showToasts) {
toast(R.string.saving)
}
return
}
val now = getNowSeconds()
val reminderSeconds = event.getReminders().reversed().map { it * 60 }
dbHelper.getEvents(now, now + YEAR, event.id, false) {
eventsHelper.getEvents(now, now + YEAR, event.id!!, false) {
if (it.isNotEmpty()) {
for (curEvent in it) {
for (curReminder in reminderSeconds) {
if (curEvent.getEventStartTS() - curReminder > now) {
scheduleEventIn((curEvent.getEventStartTS() - curReminder) * 1000L, curEvent, activity)
scheduleEventIn((curEvent.getEventStartTS() - curReminder) * 1000L, curEvent, showToasts)
return@getEvents
}
}
}
}
activity?.toast(R.string.saving)
if (showToasts) {
toast(R.string.saving)
}
}
}
fun Context.scheduleEventIn(notifTS: Long, event: Event, activity: SimpleActivity? = null) {
fun Context.scheduleEventIn(notifTS: Long, event: Event, showToasts: Boolean) {
if (notifTS < System.currentTimeMillis()) {
activity?.toast(R.string.saving)
if (showToasts) {
toast(R.string.saving)
}
return
}
val newNotifTS = notifTS + 1000
if (activity != null) {
if (showToasts) {
val secondsTillNotification = (newNotifTS - System.currentTimeMillis()) / 1000
val msg = String.format(getString(R.string.reminder_triggers_in), formatSecondsToTimeString(secondsTillNotification.toInt()))
activity.toast(msg)
toast(msg)
}
val pendingIntent = getNotificationIntent(applicationContext, event)
@ -119,15 +127,15 @@ fun Context.scheduleEventIn(notifTS: Long, event: Event, activity: SimpleActivit
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, newNotifTS, pendingIntent)
}
fun Context.cancelNotification(id: Int) {
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(id)
fun Context.cancelNotification(id: Long) {
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(id.toInt())
}
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)
return PendingIntent.getBroadcast(context, event.id!!.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
fun Context.getRepetitionText(seconds: Int) = when (seconds) {
@ -147,7 +155,7 @@ fun Context.getRepetitionText(seconds: Int) = when (seconds) {
}
fun Context.notifyRunningEvents() {
dbHelper.getRunningEvents().filter { it.getReminders().isNotEmpty() }.forEach {
eventsHelper.getRunningEvents().filter { it.getReminders().isNotEmpty() }.forEach {
notifyEvent(it)
}
}
@ -159,7 +167,7 @@ fun Context.notifyEvent(originalEvent: Event) {
var eventStartTS = if (event.getIsAllDay()) Formatter.getDayStartTS(Formatter.getDayCodeFromTS(event.startTS)) else event.startTS
// make sure refer to the proper repeatable event instance with "Tomorrow", or the specific date
if (event.repeatInterval != 0 && eventStartTS - event.reminder1Minutes * 60 < currentSeconds) {
val events = dbHelper.getRepeatableEventsFor(currentSeconds - WEEK_SECONDS, currentSeconds + YEAR_SECONDS, event.id)
val events = eventsHelper.getRepeatableEventsFor(currentSeconds - WEEK_SECONDS, currentSeconds + YEAR_SECONDS, event.id!!)
for (currEvent in events) {
eventStartTS = if (currEvent.getIsAllDay()) Formatter.getDayStartTS(Formatter.getDayCodeFromTS(currEvent.startTS)) else currEvent.startTS
if (eventStartTS - currEvent.reminder1Minutes * 60 > currentSeconds) {
@ -186,7 +194,7 @@ fun Context.notifyEvent(originalEvent: Event) {
val content = "$displayedStartDate $timeRange $descriptionOrLocation".trim()
val notification = getNotification(pendingIntent, event, content)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(event.id, notification)
notificationManager.notify(event.id!!.toInt(), notification)
}
@SuppressLint("NewApi")
@ -235,6 +243,7 @@ fun Context.getNotification(pendingIntent: PendingIntent, event: Event, content:
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setDefaults(Notification.DEFAULT_LIGHTS)
.setCategory(Notification.CATEGORY_EVENT)
.setAutoCancel(true)
.setSound(Uri.parse(soundUri), config.reminderAudioStream)
.setChannelId(channelId)
@ -262,7 +271,7 @@ 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)
return PendingIntent.getActivity(context, event.id!!.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun getSnoozePendingIntent(context: Context, event: Event): PendingIntent {
@ -270,17 +279,16 @@ private fun getSnoozePendingIntent(context: Context, event: Event): PendingInten
val intent = Intent(context, snoozeClass).setAction("Snooze")
intent.putExtra(EVENT_ID, event.id)
return if (context.config.useSameSnooze) {
PendingIntent.getService(context, event.id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
PendingIntent.getService(context, event.id!!.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
} else {
PendingIntent.getActivity(context, event.id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
PendingIntent.getActivity(context, event.id!!.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
fun Context.rescheduleReminder(event: Event?, minutes: Int) {
if (event != null) {
applicationContext.scheduleEventIn(System.currentTimeMillis() + minutes * 60000, event)
val manager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.cancel(event.id)
applicationContext.scheduleEventIn(System.currentTimeMillis() + minutes * 60000, event, false)
cancelNotification(event.id!!)
}
}
@ -292,7 +300,7 @@ fun Context.launchNewEventIntent(dayCode: String = Formatter.getTodayCode()) {
}
}
fun Context.getNewEventTimestampFromCode(dayCode: String): Int {
fun Context.getNewEventTimestampFromCode(dayCode: String): Long {
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)
@ -300,14 +308,12 @@ fun Context.getNewEventTimestampFromCode(dayCode: String): Int {
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.getSyncedCalDAVCalendars() = calDAVHelper.getCalDAVCalendars(config.caldavSyncedCalendarIDs, false)
fun Context.recheckCalDAVCalendars(callback: () -> Unit) {
if (config.caldavSync) {
Thread {
CalDAVHandler(applicationContext).refreshCalendars(null, callback)
calDAVHelper.refreshCalendars(false, callback)
updateWidgets()
}.start()
}
@ -329,32 +335,6 @@ fun Context.scheduleCalDAVSync(activate: Boolean) {
}
}
fun Context.syncCalDAVCalendars(activity: SimpleActivity?, calDAVSyncObserver: ContentObserver) {
Thread {
val uri = CalendarContract.Calendars.CONTENT_URI
contentResolver.unregisterContentObserver(calDAVSyncObserver)
contentResolver.registerContentObserver(uri, false, calDAVSyncObserver)
refreshCalDAVCalendars(activity, config.caldavSyncedCalendarIDs)
}.start()
}
fun Context.refreshCalDAVCalendars(activity: SimpleActivity?, ids: String) {
val uri = CalendarContract.Calendars.CONTENT_URI
val accounts = HashSet<Account>()
val calendars = CalDAVHandler(applicationContext).getCalDAVCalendars(activity, ids)
calendars.forEach {
accounts.add(Account(it.accountName, it.accountType))
}
Bundle().apply {
putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true)
putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true)
accounts.forEach {
ContentResolver.requestSync(it, uri.authority, this)
}
}
}
fun Context.addDayNumber(rawTextColor: Int, day: DayMonthly, linearLayout: LinearLayout, dayLabelHeight: Int, callback: (Int) -> Unit) {
var textColor = rawTextColor
if (!day.isThisMonth)
@ -429,27 +409,43 @@ fun Context.getEventListItems(events: List<Event>): ArrayList<ListItem> {
listItems.add(listSection)
prevCode = code
}
val listEvent = ListEvent(it.id, it.startTS, it.endTS, it.title, it.description, it.getIsAllDay(), it.color, it.location, it.isPastEvent, it.repeatInterval > 0)
val listEvent = ListEvent(it.id!!, it.startTS, it.endTS, it.title, it.description, it.getIsAllDay(), it.color, it.location, it.isPastEvent, it.repeatInterval > 0)
listItems.add(listEvent)
}
return listItems
}
fun Context.handleEventDeleting(eventIds: List<Int>, timestamps: List<Int>, action: Int) {
fun Context.handleEventDeleting(eventIds: List<Long>, timestamps: List<Long>, action: Int) {
when (action) {
DELETE_SELECTED_OCCURRENCE -> {
eventIds.forEachIndexed { index, value ->
dbHelper.addEventRepeatException(value, timestamps[index], true)
eventsHelper.addEventRepetitionException(value, timestamps[index], true)
}
}
DELETE_FUTURE_OCCURRENCES -> {
eventIds.forEachIndexed { index, value ->
dbHelper.addEventRepeatLimit(value, timestamps[index])
eventsHelper.addEventRepeatLimit(value, timestamps[index])
}
}
DELETE_ALL_OCCURRENCES -> {
val eventIDs = Array(eventIds.size) { i -> (eventIds[i].toString()) }
dbHelper.deleteEvents(eventIDs, true)
eventsHelper.deleteEvents(eventIds.toMutableList(), true)
}
}
}
fun Context.refreshCalDAVCalendars(ids: String, showToasts: Boolean) {
val uri = CalendarContract.Calendars.CONTENT_URI
val accounts = HashSet<Account>()
val calendars = calDAVHelper.getCalDAVCalendars(ids, showToasts)
calendars.forEach {
accounts.add(Account(it.accountName, it.accountType))
}
Bundle().apply {
putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true)
putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true)
accounts.forEach {
ContentResolver.requestSync(it, uri.authority, this)
}
}
}

View File

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

View File

@ -0,0 +1,11 @@
package com.simplemobiletools.calendar.pro.extensions
import com.simplemobiletools.calendar.pro.helpers.MONTH
import com.simplemobiletools.calendar.pro.helpers.WEEK
import com.simplemobiletools.calendar.pro.helpers.YEAR
fun Int.isXWeeklyRepetition() = this != 0 && this % WEEK == 0
fun Int.isXMonthlyRepetition() = this != 0 && this % MONTH == 0
fun Int.isXYearlyRepetition() = this != 0 && this % YEAR == 0

View File

@ -0,0 +1,10 @@
package com.simplemobiletools.calendar.pro.extensions
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.models.Event
fun Long.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
}

View File

@ -0,0 +1,16 @@
package com.simplemobiletools.calendar.pro.extensions
import com.simplemobiletools.calendar.pro.helpers.CHOPPED_LIST_DEFAULT_SIZE
// inspired by https://stackoverflow.com/questions/2895342/java-how-can-i-split-an-arraylist-in-multiple-small-arraylists/2895365#2895365
fun MutableList<Long>.getChoppedList(chunkSize: Int = CHOPPED_LIST_DEFAULT_SIZE): ArrayList<ArrayList<Long>> {
val parts = ArrayList<ArrayList<Long>>()
val listSize = this.size
var i = 0
while (i < listSize) {
val newList = subList(i, Math.min(listSize, i + chunkSize)).toMutableList() as ArrayList<Long>
parts.add(newList)
i += chunkSize
}
return parts
}

View File

@ -1,3 +1,3 @@
package com.simplemobiletools.calendar.extensions
package com.simplemobiletools.calendar.pro.extensions
fun String.getMonthCode() = if (length == 8) substring(0, 6) else ""

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.extensions
package com.simplemobiletools.calendar.pro.extensions
import android.content.res.Resources
import android.graphics.Bitmap

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.content.Intent
import android.os.Bundle
@ -9,18 +9,18 @@ import android.widget.DatePicker
import android.widget.RelativeLayout
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import com.simplemobiletools.calendar.R
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.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.NavigationListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.EventActivity
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.adapters.DayEventsAdapter
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.helpers.DAY_CODE
import com.simplemobiletools.calendar.pro.helpers.EVENT_ID
import com.simplemobiletools.calendar.pro.helpers.EVENT_OCCURRENCE_TS
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.interfaces.NavigationListener
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.getDialogTheme
import com.simplemobiletools.commons.extensions.setupDialogStuff
@ -105,7 +105,7 @@ class DayFragment : Fragment() {
fun updateCalendar() {
val startTS = Formatter.getDayStartTS(mDayCode)
val endTS = Formatter.getDayEndTS(mDayCode)
context?.dbHelper?.getEvents(startTS, endTS, applyTypeFilter = true) {
context?.eventsHelper?.getEvents(startTS, endTS) {
receivedEvents(it)
}
}

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
@ -6,13 +6,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.viewpager.widget.ViewPager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.MainActivity
import com.simplemobiletools.calendar.adapters.MyDayPagerAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.adapters.MyDayPagerAdapter
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.helpers.DAY_CODE
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.interfaces.NavigationListener
import com.simplemobiletools.commons.extensions.updateActionBarTitle
import com.simplemobiletools.commons.views.MyViewPager
import kotlinx.android.synthetic.main.fragment_days_holder.view.*

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.content.Intent
import android.graphics.drawable.ColorDrawable
@ -6,17 +6,17 @@ import android.os.Bundle
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.MainActivity
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.adapters.EventListAdapter
import com.simplemobiletools.calendar.extensions.*
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.Event
import com.simplemobiletools.calendar.models.ListEvent
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.EventActivity
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.adapters.EventListAdapter
import com.simplemobiletools.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.helpers.EVENT_ID
import com.simplemobiletools.calendar.pro.helpers.EVENT_OCCURRENCE_TS
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.ListEvent
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.MONTH_SECONDS
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
@ -30,8 +30,8 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
private var MIN_EVENTS_TRESHOLD = 30
private var mEvents = ArrayList<Event>()
private var minFetchedTS = 0
private var maxFetchedTS = 0
private var minFetchedTS = 0L
private var maxFetchedTS = 0L
private var wereInitialEventsAdded = false
private var use24HourFormat = false
@ -76,7 +76,7 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
maxFetchedTS = DateTime().plusMonths(6).seconds()
}
context!!.dbHelper.getEvents(minFetchedTS, maxFetchedTS, applyTypeFilter = true) {
context!!.eventsHelper.getEvents(minFetchedTS, maxFetchedTS) {
if (it.size >= MIN_EVENTS_TRESHOLD) {
receivedEvents(it, false)
} else {
@ -84,7 +84,7 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
minFetchedTS -= FETCH_INTERVAL
maxFetchedTS += FETCH_INTERVAL
}
context!!.dbHelper.getEvents(minFetchedTS, maxFetchedTS, applyTypeFilter = true) {
context!!.eventsHelper.getEvents(minFetchedTS, maxFetchedTS) {
mEvents = it
receivedEvents(mEvents, false, !wereInitialEventsAdded)
}
@ -150,7 +150,7 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
private fun fetchPreviousPeriod() {
val oldMinFetchedTS = minFetchedTS - 1
minFetchedTS -= FETCH_INTERVAL
context!!.dbHelper.getEvents(minFetchedTS, oldMinFetchedTS, applyTypeFilter = true) {
context!!.eventsHelper.getEvents(minFetchedTS, oldMinFetchedTS) {
mEvents.addAll(0, it)
receivedEvents(mEvents, false)
}
@ -159,7 +159,7 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
private fun fetchNextPeriod(scrollAfterUpdating: Boolean) {
val oldMaxFetchedTS = maxFetchedTS + 1
maxFetchedTS += FETCH_INTERVAL
context!!.dbHelper.getEvents(oldMaxFetchedTS, maxFetchedTS, applyTypeFilter = true) {
context!!.eventsHelper.getEvents(oldMaxFetchedTS, maxFetchedTS) {
mEvents.addAll(it)
receivedEvents(mEvents, scrollAfterUpdating)
}

View File

@ -1,25 +1,25 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.content.Context
import android.content.res.Resources
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.appcompat.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.MainActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.Config
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.helpers.MonthlyCalendarImpl
import com.simplemobiletools.calendar.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.models.DayMonthly
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.helpers.Config
import com.simplemobiletools.calendar.pro.helpers.DAY_CODE
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.helpers.MonthlyCalendarImpl
import com.simplemobiletools.calendar.pro.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.pro.interfaces.NavigationListener
import com.simplemobiletools.calendar.pro.models.DayMonthly
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.beGone
import com.simplemobiletools.commons.extensions.getDialogTheme

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
@ -6,14 +6,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.viewpager.widget.ViewPager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.MainActivity
import com.simplemobiletools.calendar.adapters.MyMonthPagerAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.getMonthCode
import com.simplemobiletools.calendar.helpers.DAY_CODE
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.adapters.MyMonthPagerAdapter
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.getMonthCode
import com.simplemobiletools.calendar.pro.helpers.DAY_CODE
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.interfaces.NavigationListener
import com.simplemobiletools.commons.extensions.updateActionBarTitle
import com.simplemobiletools.commons.views.MyViewPager
import kotlinx.android.synthetic.main.fragment_months_holder.view.*

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import androidx.fragment.app.Fragment

View File

@ -1,11 +1,10 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.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.util.SparseIntArray
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@ -13,18 +12,19 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.collection.LongSparseArray
import androidx.fragment.app.Fragment
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.WeekFragmentListener
import com.simplemobiletools.calendar.interfaces.WeeklyCalendar
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.views.MyScrollView
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.EventActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.interfaces.WeekFragmentListener
import com.simplemobiletools.calendar.pro.interfaces.WeeklyCalendar
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.views.MyScrollView
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.DAY_SECONDS
import com.simplemobiletools.commons.helpers.WEEK_SECONDS
@ -39,7 +39,7 @@ class WeekFragment : Fragment(), WeeklyCalendar {
private val PLUS_FADEOUT_DELAY = 5000L
var mListener: WeekFragmentListener? = null
private var mWeekTimestamp = 0
private var mWeekTimestamp = 0L
private var mRowHeight = 0f
private var minScrollY = -1
private var maxScrollY = -1
@ -56,26 +56,26 @@ class WeekFragment : Fragment(), WeeklyCalendar {
private var events = ArrayList<Event>()
private var allDayHolders = ArrayList<RelativeLayout>()
private var allDayRows = ArrayList<HashSet<Int>>()
private var eventTypeColors = SparseIntArray()
private var eventTypeColors = LongSparseArray<Int>()
lateinit var inflater: LayoutInflater
lateinit var mView: View
lateinit var mScrollView: MyScrollView
lateinit var mCalendar: WeeklyCalendarImpl
lateinit var mRes: Resources
lateinit var mConfig: Config
private lateinit var inflater: LayoutInflater
private lateinit var mView: View
private lateinit var mScrollView: MyScrollView
private lateinit var mCalendar: WeeklyCalendarImpl
private lateinit var mRes: Resources
private lateinit var mConfig: Config
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
context!!.dbHelper.getEventTypes {
it.map { eventTypeColors.put(it.id, it.color) }
context!!.eventsHelper.getEventTypes(activity!!) {
it.map { eventTypeColors.put(it.id!!, it.color) }
}
mRes = context!!.resources
mConfig = context!!.config
mRowHeight = mRes.getDimension(R.dimen.weekly_view_row_height)
minScrollY = (mRowHeight * mConfig.startWeeklyAt).toInt()
mWeekTimestamp = arguments!!.getInt(WEEK_START_TIMESTAMP)
mWeekTimestamp = arguments!!.getLong(WEEK_START_TIMESTAMP)
dimPastEvents = mConfig.dimPastEvents
primaryColor = context!!.getAdjustedPrimaryColor()
allDayRows.add(HashSet())
@ -353,10 +353,14 @@ class WeekFragment : Fragment(), WeeklyCalendar {
val minTS = Math.max(startDateTime.seconds(), mWeekTimestamp)
val maxTS = Math.min(endDateTime.seconds(), mWeekTimestamp + WEEK_SECONDS)
val daysCnt = Days.daysBetween(Formatter.getDateTimeFromTS(minTS).toLocalDate(), Formatter.getDateTimeFromTS(maxTS).toLocalDate()).days
if (minTS == maxTS) {
return
}
val daysCnt = Days.daysBetween(Formatter.getDateTimeFromTS(minTS).toLocalDate(), Formatter.getDateTimeFromTS(maxTS).toLocalDate()).days
val startDateTimeInWeek = Formatter.getDateTimeFromTS(minTS)
val firstDayIndex = (startDateTimeInWeek.dayOfWeek - if (mConfig.isSundayFirst) 0 else 1) % 7
var doesEventFit: Boolean
val cnt = allDayRows.size - 1
var wasEventHandled = false

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
@ -7,15 +7,15 @@ import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.viewpager.widget.ViewPager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.MainActivity
import com.simplemobiletools.calendar.adapters.MyWeekPagerAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.helpers.WEEK_START_DATE_TIME
import com.simplemobiletools.calendar.interfaces.WeekFragmentListener
import com.simplemobiletools.calendar.views.MyScrollView
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.adapters.MyWeekPagerAdapter
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.calendar.pro.helpers.WEEK_START_DATE_TIME
import com.simplemobiletools.calendar.pro.interfaces.WeekFragmentListener
import com.simplemobiletools.calendar.pro.views.MyScrollView
import com.simplemobiletools.commons.extensions.updateActionBarSubtitle
import com.simplemobiletools.commons.extensions.updateActionBarTitle
import com.simplemobiletools.commons.helpers.WEEK_SECONDS
@ -28,14 +28,14 @@ class WeekFragmentsHolder : MyFragmentHolder(), WeekFragmentListener {
private var weekHolder: ViewGroup? = null
private var defaultWeeklyPage = 0
private var thisWeekTS = 0
private var currentWeekTS = 0
private var thisWeekTS = 0L
private var currentWeekTS = 0L
private var isGoToTodayVisible = false
private var weekScrollY = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val dateTimeString = arguments?.getString(WEEK_START_DATE_TIME) ?: ""
val dateTimeString = arguments?.getString(WEEK_START_DATE_TIME) ?: return
currentWeekTS = (DateTime.parse(dateTimeString) ?: DateTime()).seconds()
thisWeekTS = currentWeekTS
}
@ -95,15 +95,15 @@ class WeekFragmentsHolder : MyFragmentHolder(), WeekFragmentListener {
updateActionBarTitle()
}
private fun getWeekTimestamps(targetSeconds: Int): List<Int> {
val weekTSs = ArrayList<Int>(PREFILLED_WEEKS)
private fun getWeekTimestamps(targetSeconds: Long): List<Long> {
val weekTSs = ArrayList<Long>(PREFILLED_WEEKS)
for (i in -PREFILLED_WEEKS / 2..PREFILLED_WEEKS / 2) {
weekTSs.add(Formatter.getDateTimeFromTS(targetSeconds).plusWeeks(i).seconds())
}
return weekTSs
}
private fun setupWeeklyActionbarTitle(timestamp: Int) {
private fun setupWeeklyActionbarTitle(timestamp: Long) {
val startDateTime = Formatter.getDateTimeFromTS(timestamp)
val endDateTime = Formatter.getDateTimeFromTS(timestamp + WEEK_SECONDS)
val startMonthName = Formatter.getMonthName(context!!, startDateTime.monthOfYear)

View File

@ -1,21 +1,21 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.content.res.Resources
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.MainActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.YEAR_LABEL
import com.simplemobiletools.calendar.helpers.YearlyCalendarImpl
import com.simplemobiletools.calendar.interfaces.YearlyCalendar
import com.simplemobiletools.calendar.models.DayYearly
import com.simplemobiletools.calendar.views.SmallMonthView
import androidx.fragment.app.Fragment
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.helpers.YEAR_LABEL
import com.simplemobiletools.calendar.pro.helpers.YearlyCalendarImpl
import com.simplemobiletools.calendar.pro.interfaces.YearlyCalendar
import com.simplemobiletools.calendar.pro.models.DayYearly
import com.simplemobiletools.calendar.pro.views.SmallMonthView
import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
import com.simplemobiletools.commons.extensions.updateTextColors
import kotlinx.android.synthetic.main.fragment_year.view.*

View File

@ -1,16 +1,16 @@
package com.simplemobiletools.calendar.fragments
package com.simplemobiletools.calendar.pro.fragments
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import androidx.viewpager.widget.ViewPager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.MainActivity
import com.simplemobiletools.calendar.adapters.MyYearPagerAdapter
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.Formatter
import androidx.viewpager.widget.ViewPager
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.adapters.MyYearPagerAdapter
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.helpers.Formatter
import com.simplemobiletools.commons.extensions.updateActionBarTitle
import com.simplemobiletools.commons.views.MyViewPager
import kotlinx.android.synthetic.main.fragment_years_holder.view.*

View File

@ -1,5 +1,6 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.annotation.SuppressLint
import android.content.ContentUris
import android.content.ContentValues
import android.content.Context
@ -7,39 +8,48 @@ 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.refreshCalDAVCalendars
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.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.models.CalDAVCalendar
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.calendar.pro.objects.States.isUpdatingCalDAV
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 calDAVCalendars = getCalDAVCalendars(activity, context.config.caldavSyncedCalendarIDs)
for (calendar in calDAVCalendars) {
val localEventType = context.dbHelper.getEventTypeWithCalDAVCalendarId(calendar.id) ?: continue
localEventType.apply {
title = calendar.displayName
caldavDisplayName = calendar.displayName
caldavEmail = calendar.accountName
context.dbHelper.updateLocalEventType(this)
}
class CalDAVHelper(val context: Context) {
private val eventsHelper = context.eventsHelper
CalDAVHandler(context).fetchCalDAVCalendarEvents(calendar.id, localEventType.id, activity)
fun refreshCalendars(showToasts: Boolean, callback: () -> Unit) {
if (isUpdatingCalDAV) {
return
}
isUpdatingCalDAV = true
try {
val calDAVCalendars = getCalDAVCalendars(context.config.caldavSyncedCalendarIDs, showToasts)
for (calendar in calDAVCalendars) {
val localEventType = eventsHelper.getEventTypeWithCalDAVCalendarId(calendar.id) ?: continue
localEventType.apply {
title = calendar.displayName
caldavDisplayName = calendar.displayName
caldavEmail = calendar.accountName
eventsHelper.insertOrUpdateEventTypeSync(this)
}
fetchCalDAVCalendarEvents(calendar.id, localEventType.id!!, showToasts)
}
context.scheduleCalDAVSync(true)
callback()
} finally {
isUpdatingCalDAV = false
}
context.scheduleCalDAVSync(true)
callback()
}
fun getCalDAVCalendars(activity: SimpleActivity? = null, ids: String = ""): List<CalDAVCalendar> {
@SuppressLint("MissingPermission")
fun getCalDAVCalendars(ids: String, showToasts: Boolean): List<CalDAVCalendar> {
val calendars = ArrayList<CalDAVCalendar>()
if (!context.hasPermission(PERMISSION_WRITE_CALENDAR) || !context.hasPermission(PERMISSION_READ_CALENDAR)) {
return calendars
@ -73,7 +83,9 @@ class CalDAVHandler(val context: Context) {
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity?.showErrorToast(e)
if (showToasts) {
context.showErrorToast(e)
}
} finally {
cursor?.close()
}
@ -98,6 +110,7 @@ class CalDAVHandler(val context: Context) {
}
}
@SuppressLint("MissingPermission")
private fun getEventTypeColorKey(eventType: EventType): Int {
val uri = CalendarContract.Colors.CONTENT_URI
val projection = arrayOf(CalendarContract.Colors.COLOR_KEY)
@ -117,6 +130,7 @@ class CalDAVHandler(val context: Context) {
return -1
}
@SuppressLint("MissingPermission")
fun getAvailableCalDAVCalendarColors(eventType: EventType): ArrayList<Int> {
val colors = SparseIntArray()
val uri = CalendarContract.Colors.CONTENT_URI
@ -147,10 +161,11 @@ class CalDAVHandler(val context: Context) {
return sortedColors
}
private fun fetchCalDAVCalendarEvents(calendarId: Int, eventTypeId: Int, activity: SimpleActivity?) {
@SuppressLint("MissingPermission")
private fun fetchCalDAVCalendarEvents(calendarId: Int, eventTypeId: Long, showToasts: Boolean) {
val importIdsMap = HashMap<String, Event>()
val fetchedEventIds = ArrayList<String>()
val existingEvents = context.dbHelper.getEventsFromCalDAVCalendar(calendarId)
val existingEvents = context.eventsDB.getEventsFromCalDAVCalendar("$CALDAV-$calendarId")
existingEvents.forEach {
importIdsMap[it.importId] = it
}
@ -179,8 +194,8 @@ class CalDAVHandler(val context: Context) {
val id = cursor.getLongValue(CalendarContract.Events._ID)
val title = cursor.getStringValue(CalendarContract.Events.TITLE) ?: ""
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 startTS = cursor.getLongValue(CalendarContract.Events.DTSTART) / 1000L
var endTS = cursor.getLongValue(CalendarContract.Events.DTEND) / 1000L
val allDay = cursor.getIntValue(CalendarContract.Events.ALL_DAY)
val rrule = cursor.getStringValue(CalendarContract.Events.RRULE) ?: ""
val location = cursor.getStringValue(CalendarContract.Events.EVENT_LOCATION) ?: ""
@ -188,7 +203,7 @@ class CalDAVHandler(val context: Context) {
val originalInstanceTime = cursor.getLongValue(CalendarContract.Events.ORIGINAL_INSTANCE_TIME)
val reminders = getCalDAVEventReminders(id)
if (endTS == 0) {
if (endTS == 0L) {
val duration = cursor.getStringValue(CalendarContract.Events.DURATION) ?: ""
endTS = startTS + Parser().parseDurationSeconds(duration)
}
@ -196,9 +211,9 @@ class CalDAVHandler(val context: Context) {
val importId = getCalDAVEventImportId(calendarId, id)
val source = "$CALDAV-$calendarId"
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 = source, location = location)
val event = Event(null, startTS, endTS, title, location, description, reminders.getOrElse(0) { -1 },
reminders.getOrElse(1) { -1 }, reminders.getOrElse(2) { -1 }, repeatRule.repeatInterval, repeatRule.repeatRule,
repeatRule.repeatLimit, ArrayList(), importId, allDay, eventTypeId, source = source)
if (event.getIsAllDay()) {
event.startTS = Formatter.getShiftedImportTimestamp(event.startTS)
@ -209,60 +224,68 @@ class CalDAVHandler(val context: Context) {
}
fetchedEventIds.add(importId)
// if the event is an exception from another events repeat rule, find the original parent event
if (originalInstanceTime != 0L) {
val parentImportId = "$source-$originalId"
val parentEvent = context.eventsDB.getEventWithImportId(parentImportId)
val originalDayCode = Formatter.getDayCodeFromTS(originalInstanceTime / 1000L)
if (parentEvent != null && !parentEvent.repetitionExceptions.contains(originalDayCode)) {
event.parentId = parentEvent.id!!
parentEvent.addRepetitionException(originalDayCode)
eventsHelper.insertEvent(parentEvent, false, false)
event.parentId = parentEvent.id!!
eventsHelper.insertEvent(event, false, false)
continue
}
}
if (importIdsMap.containsKey(event.importId)) {
val existingEvent = importIdsMap[importId]
val originalEventId = existingEvent!!.id
existingEvent.apply {
this.id = 0
this.id = null
color = 0
ignoreEventOccurrences = ArrayList()
lastUpdated = 0L
offset = ""
repetitionExceptions = ArrayList()
}
if (existingEvent.hashCode() != event.hashCode() && title.isNotEmpty()) {
event.id = originalEventId
context.dbHelper.update(event, false)
eventsHelper.updateEvent(event, false, false)
}
} else {
// if the event is an exception from another events repeat rule, find the original parent event
if (originalInstanceTime != 0L) {
val parentImportId = "$source-$originalId"
val parentEventId = context.dbHelper.getEventIdWithImportId(parentImportId)
if (parentEventId != 0) {
event.parentId = parentEventId
context.dbHelper.addEventRepeatException(parentEventId, (originalInstanceTime / 1000).toInt(), false, event.importId)
}
}
if (title.isNotEmpty()) {
context.dbHelper.insert(event, false) {
importIdsMap[event.importId] = event
}
importIdsMap[event.importId] = event
eventsHelper.insertEvent(event, false, false)
}
}
} while (cursor.moveToNext())
}
} catch (e: Exception) {
activity?.showErrorToast(e)
if (showToasts) {
context.showErrorToast(e)
}
} finally {
cursor?.close()
}
val eventIdsToDelete = ArrayList<String>()
val eventIdsToDelete = ArrayList<Long>()
importIdsMap.keys.filter { !fetchedEventIds.contains(it) }.forEach {
val caldavEventId = it
existingEvents.forEach {
if (it.importId == caldavEventId) {
eventIdsToDelete.add(it.id.toString())
eventIdsToDelete.add(it.id!!)
}
}
}
context.dbHelper.deleteEvents(eventIdsToDelete.toTypedArray(), false)
eventsHelper.deleteEvents(eventIdsToDelete.toMutableList(), false)
}
@SuppressLint("MissingPermission")
fun insertCalDAVEvent(event: Event) {
val uri = CalendarContract.Events.CONTENT_URI
val values = fillEventContentValues(event)
@ -291,6 +314,7 @@ class CalDAVHandler(val context: Context) {
refreshCalDAVCalendar(event)
}
@SuppressLint("MissingPermission")
private fun setupCalDAVEventReminders(event: Event) {
clearEventReminders(event)
event.getReminders().forEach {
@ -304,7 +328,7 @@ class CalDAVHandler(val context: Context) {
}
private fun setupCalDAVEventImportId(event: Event) {
context.dbHelper.updateEventImportIdAndSource(event.id, event.importId, "$CALDAV-${event.getCalDAVCalendarId()}")
context.eventsDB.updateEventImportIdAndSource(event.importId, "$CALDAV-${event.getCalDAVCalendarId()}", event.id!!)
}
private fun fillEventContentValues(event: Event): ContentValues {
@ -338,6 +362,7 @@ class CalDAVHandler(val context: Context) {
}
}
@SuppressLint("MissingPermission")
private fun clearEventReminders(event: Event) {
val selection = "${Reminders.EVENT_ID} = ?"
val selectionArgs = arrayOf(event.getCalDAVEventId().toString())
@ -349,14 +374,13 @@ class CalDAVHandler(val context: Context) {
val dur = Math.max(1, (event.endTS - event.startTS) / DAY)
"P${dur}D"
} else {
Parser().getDurationCode((event.endTS - event.startTS) / 60)
Parser().getDurationCode((event.endTS - event.startTS) / 60L)
}
}
fun deleteCalDAVCalendarEvents(calendarId: Long) {
val events = context.dbHelper.getCalDAVCalendarEvents(calendarId)
val eventIds = events.map { it.id.toString() }.toTypedArray()
context.dbHelper.deleteEvents(eventIds, false)
val eventIds = context.eventsDB.getCalDAVCalendarEvents("$CALDAV-$calendarId").toMutableList()
eventsHelper.deleteEvents(eventIds, false)
}
fun deleteCalDAVEvent(event: Event) {
@ -369,7 +393,8 @@ class CalDAVHandler(val context: Context) {
refreshCalDAVCalendar(event)
}
fun insertEventRepeatException(event: Event, occurrenceTS: Int): Long {
@SuppressLint("MissingPermission")
fun insertEventRepeatException(event: Event, occurrenceTS: Long): Long {
val uri = CalendarContract.Events.CONTENT_URI
val values = fillEventRepeatExceptionValues(event, occurrenceTS)
val newUri = context.contentResolver.insert(uri, values)
@ -377,7 +402,7 @@ class CalDAVHandler(val context: Context) {
return java.lang.Long.parseLong(newUri.lastPathSegment)
}
private fun fillEventRepeatExceptionValues(event: Event, occurrenceTS: Int): ContentValues {
private fun fillEventRepeatExceptionValues(event: Event, occurrenceTS: Long): ContentValues {
return ContentValues().apply {
put(CalendarContract.Events.CALENDAR_ID, event.getCalDAVCalendarId())
put(CalendarContract.Events.DTSTART, occurrenceTS)
@ -388,6 +413,7 @@ class CalDAVHandler(val context: Context) {
}
}
@SuppressLint("MissingPermission")
private fun getCalDAVEventReminders(eventId: Long): List<Int> {
val reminders = ArrayList<Int>()
val uri = CalendarContract.Reminders.CONTENT_URI
@ -415,5 +441,5 @@ class CalDAVHandler(val context: Context) {
private fun getCalDAVEventImportId(calendarId: Int, eventId: Long) = "$CALDAV-$calendarId-$eventId"
private fun refreshCalDAVCalendar(event: Event) = context.refreshCalDAVCalendars(null, event.getCalDAVCalendarId().toString())
private fun refreshCalDAVCalendar(event: Event) = context.refreshCalDAVCalendars(event.getCalDAVCalendarId().toString(), false)
}

View File

@ -1,9 +1,9 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.content.Context
import android.media.AudioManager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.scheduleCalDAVSync
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.scheduleCalDAVSync
import com.simplemobiletools.commons.extensions.getDefaultAlarmTitle
import com.simplemobiletools.commons.extensions.getDefaultAlarmUri
import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_NOTIFICATION
@ -95,9 +95,9 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(LAST_USED_CALDAV_CALENDAR, getSyncedCalendarIdsAsList().first().toInt())
set(calendarId) = prefs.edit().putInt(LAST_USED_CALDAV_CALENDAR, calendarId).apply()
var lastUsedLocalEventTypeId: Int
get() = prefs.getInt(LAST_USED_LOCAL_EVENT_TYPE_ID, DBHelper.REGULAR_EVENT_TYPE_ID)
set(lastUsedLocalEventTypeId) = prefs.edit().putInt(LAST_USED_LOCAL_EVENT_TYPE_ID, lastUsedLocalEventTypeId).apply()
var lastUsedLocalEventTypeId: Long
get() = prefs.getLong(LAST_USED_LOCAL_EVENT_TYPE_ID, REGULAR_EVENT_TYPE_ID)
set(lastUsedLocalEventTypeId) = prefs.edit().putLong(LAST_USED_LOCAL_EVENT_TYPE_ID, lastUsedLocalEventTypeId).apply()
var reminderAudioStream: Int
get() = prefs.getInt(REMINDER_AUDIO_STREAM, AudioManager.STREAM_ALARM)
@ -119,7 +119,9 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(DIM_PAST_EVENTS, true)
set(dimPastEvents) = prefs.edit().putBoolean(DIM_PAST_EVENTS, dimPastEvents).apply()
fun getSyncedCalendarIdsAsList() = caldavSyncedCalendarIDs.split(",").filter { it.trim().isNotEmpty() } as ArrayList<String>
fun getSyncedCalendarIdsAsList() = caldavSyncedCalendarIDs.split(",").filter { it.trim().isNotEmpty() }.map { Integer.parseInt(it) }.toMutableList() as ArrayList<Int>
fun getDisplayEventTypessAsList() = displayEventTypes.map { it.toLong() }.toMutableList() as ArrayList<Long>
fun addDisplayEventType(type: String) {
addDisplayEventTypes(HashSet<String>(Arrays.asList(type)))

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
const val LOW_ALPHA = .3f
const val MEDIUM_ALPHA = .6f
@ -15,6 +15,8 @@ const val NEW_EVENT_SET_HOUR_DURATION = "new_event_set_hour_duration"
const val WEEK_START_DATE_TIME = "week_start_date_time"
const val CALDAV = "Caldav"
const val VIEW_TO_OPEN = "view_to_open"
const val REGULAR_EVENT_TYPE_ID = 1L
const val CHOPPED_LIST_DEFAULT_SIZE = 100
const val MONTHLY_VIEW = 1
const val YEARLY_VIEW = 2
@ -74,6 +76,7 @@ const val REPEAT_ORDER_WEEKDAY = 4 // i.e. every 4th sunday
// special event flags
const val FLAG_ALL_DAY = 1
const val FLAG_IS_PAST_EVENT = 2
// constants related to ICS file exporting / importing
const val BEGIN_CALENDAR = "BEGIN:VCALENDAR"
@ -101,6 +104,8 @@ const val BYDAY = "BYDAY"
const val BYMONTHDAY = "BYMONTHDAY"
const val BYMONTH = "BYMONTH"
const val LOCATION = "LOCATION"
const val RECURRENCE_ID = "RECURRENCE-ID"
const val SEQUENCE = "SEQUENCE"
// this tag isn't a standard ICS tag, but there's no official way of adding a category color in an ics file
const val CATEGORY_COLOR = "CATEGORY_COLOR:"
@ -141,4 +146,4 @@ const val DELETE_SELECTED_OCCURRENCE = 0
const val DELETE_FUTURE_OCCURRENCES = 1
const val DELETE_ALL_OCCURRENCES = 2
fun getNowSeconds() = (System.currentTimeMillis() / 1000).toInt()
fun getNowSeconds() = System.currentTimeMillis() / 1000L

View File

@ -0,0 +1,16 @@
package com.simplemobiletools.calendar.pro.helpers
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
class Converters {
private val gson = Gson()
private val stringType = object : TypeToken<List<String>>() {}.type
@TypeConverter
fun jsonToStringList(value: String) = gson.fromJson<ArrayList<String>>(value, stringType)
@TypeConverter
fun stringListToJson(list: ArrayList<String>) = gson.toJson(list)
}

View File

@ -0,0 +1,399 @@
package com.simplemobiletools.calendar.pro.helpers
import android.app.Activity
import android.content.Context
import androidx.collection.LongSparseArray
import com.simplemobiletools.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType
class EventsHelper(val context: Context) {
private val config = context.config
private val eventsDB = context.eventsDB
private val eventTypesDB = context.eventTypesDB
fun getEventTypes(activity: Activity, callback: (notes: ArrayList<EventType>) -> Unit) {
Thread {
val eventTypes = eventTypesDB.getEventTypes().toMutableList() as ArrayList<EventType>
activity.runOnUiThread {
callback(eventTypes)
}
}.start()
}
fun getEventTypesSync() = eventTypesDB.getEventTypes().toMutableList() as ArrayList<EventType>
fun insertOrUpdateEventType(activity: Activity, eventType: EventType, callback: ((newEventTypeId: Long) -> Unit)? = null) {
Thread {
val eventTypeId = insertOrUpdateEventTypeSync(eventType)
activity.runOnUiThread {
callback?.invoke(eventTypeId)
}
}.start()
}
fun insertOrUpdateEventTypeSync(eventType: EventType): Long {
if (eventType.id != null && eventType.id!! > 0 && eventType.caldavCalendarId != 0) {
context.calDAVHelper.updateCalDAVCalendar(eventType)
}
val newId = eventTypesDB.insertOrUpdate(eventType)
if (eventType.id == null) {
config.addDisplayEventType(newId.toString())
}
return newId
}
fun getEventTypeIdWithTitle(title: String) = eventTypesDB.getEventTypeIdWithTitle(title) ?: -1L
fun getEventTypeWithCalDAVCalendarId(calendarId: Int) = eventTypesDB.getEventTypeWithCalDAVCalendarId(calendarId)
fun deleteEventTypes(eventTypes: ArrayList<EventType>, deleteEvents: Boolean) {
val typesToDelete = eventTypes.asSequence().filter { it.caldavCalendarId == 0 && it.id != REGULAR_EVENT_TYPE_ID }.toMutableList()
val deleteIds = typesToDelete.map { it.id }.toMutableList()
val deletedSet = deleteIds.map { it.toString() }.toHashSet()
config.removeDisplayEventTypes(deletedSet)
if (deleteIds.isEmpty()) {
return
}
for (eventTypeId in deleteIds) {
if (deleteEvents) {
deleteEventsWithType(eventTypeId!!)
} else {
eventsDB.resetEventsWithType(eventTypeId!!)
}
}
eventTypesDB.deleteEventTypes(typesToDelete)
}
fun insertEvent(event: Event, addToCalDAV: Boolean, showToasts: Boolean, callback: ((id: Long) -> Unit)? = null) {
if (event.startTS > event.endTS) {
callback?.invoke(0)
return
}
event.id = eventsDB.insertOrUpdate(event)
context.updateWidgets()
context.scheduleNextEventReminder(event, showToasts)
if (addToCalDAV && event.source != SOURCE_SIMPLE_CALENDAR && config.caldavSync) {
context.calDAVHelper.insertCalDAVEvent(event)
}
callback?.invoke(event.id!!)
}
fun insertEvents(events: ArrayList<Event>, addToCalDAV: Boolean) {
try {
for (event in events) {
if (event.startTS > event.endTS) {
continue
}
event.id = eventsDB.insertOrUpdate(event)
context.scheduleNextEventReminder(event, false)
if (addToCalDAV && event.source != SOURCE_SIMPLE_CALENDAR && event.source != SOURCE_IMPORTED_ICS && config.caldavSync) {
context.calDAVHelper.insertCalDAVEvent(event)
}
}
} finally {
context.updateWidgets()
}
}
fun updateEvent(event: Event, updateAtCalDAV: Boolean, showToasts: Boolean, callback: (() -> Unit)? = null) {
eventsDB.insertOrUpdate(event)
context.updateWidgets()
context.scheduleNextEventReminder(event, showToasts)
if (updateAtCalDAV && event.source != SOURCE_SIMPLE_CALENDAR && config.caldavSync) {
context.calDAVHelper.updateCalDAVEvent(event)
}
callback?.invoke()
}
fun deleteAllEvents() {
Thread {
val eventIds = eventsDB.getEventIds().toMutableList()
deleteEvents(eventIds, true)
}.start()
}
fun deleteEvent(id: Long, deleteFromCalDAV: Boolean) = deleteEvents(arrayListOf(id), deleteFromCalDAV)
fun deleteEvents(ids: MutableList<Long>, deleteFromCalDAV: Boolean) {
if (ids.isEmpty()) {
return
}
ids.getChoppedList().forEach {
val eventsWithImportId = eventsDB.getEventsByIdsWithImportIds(it)
eventsDB.deleteEvents(it)
it.forEach {
context.cancelNotification(it)
}
if (deleteFromCalDAV && config.caldavSync) {
eventsWithImportId.forEach {
context.calDAVHelper.deleteCalDAVEvent(it)
}
}
deleteChildEvents(it, deleteFromCalDAV)
context.updateWidgets()
}
}
private fun deleteChildEvents(ids: MutableList<Long>, deleteFromCalDAV: Boolean) {
val childIds = eventsDB.getEventIdsWithParentIds(ids).toMutableList()
if (childIds.isNotEmpty()) {
deleteEvents(childIds, deleteFromCalDAV)
}
}
private fun deleteEventsWithType(eventTypeId: Long) {
val eventIds = eventsDB.getEventIdsByEventType(eventTypeId).toMutableList()
deleteEvents(eventIds, true)
}
fun addEventRepeatLimit(eventId: Long, limitTS: Long) {
val time = Formatter.getDateTimeFromTS(limitTS)
eventsDB.updateEventRepetitionLimit(limitTS - time.hourOfDay, eventId)
if (config.caldavSync) {
val event = eventsDB.getEventWithId(eventId)
if (event?.getCalDAVCalendarId() != 0) {
context.calDAVHelper.updateCalDAVEvent(event!!)
}
}
}
fun doEventTypesContainEvents(eventTypeIds: ArrayList<Long>, callback: (contain: Boolean) -> Unit) {
Thread {
val eventIds = eventsDB.getEventIdsByEventType(eventTypeIds)
callback(eventIds.isNotEmpty())
}.start()
}
fun getEventsWithSearchQuery(text: String, activity: Activity, callback: (searchedText: String, events: List<Event>) -> Unit) {
Thread {
val searchQuery = "%$text%"
val events = eventsDB.getEventsForSearch(searchQuery)
val displayEventTypes = config.displayEventTypes
val filteredEvents = events.filter { displayEventTypes.contains(it.eventType.toString()) }
activity.runOnUiThread {
callback(text, filteredEvents)
}
}.start()
}
fun addEventRepetitionException(parentEventId: Long, occurrenceTS: Long, addToCalDAV: Boolean) {
Thread {
val parentEvent = eventsDB.getEventWithId(parentEventId) ?: return@Thread
var repetitionExceptions = parentEvent.repetitionExceptions
repetitionExceptions.add(Formatter.getDayCodeFromTS(occurrenceTS))
repetitionExceptions = repetitionExceptions.distinct().toMutableList() as ArrayList<String>
eventsDB.updateEventRepetitionExceptions(repetitionExceptions, parentEventId)
context.scheduleNextEventReminder(parentEvent, false)
if (addToCalDAV && config.caldavSync) {
context.calDAVHelper.insertEventRepeatException(parentEvent, occurrenceTS)
}
}.start()
}
fun getEvents(fromTS: Long, toTS: Long, eventId: Long = -1L, applyTypeFilter: Boolean = true, callback: (events: ArrayList<Event>) -> Unit) {
Thread {
getEventsSync(fromTS, toTS, eventId, applyTypeFilter, callback)
}.start()
}
fun getEventsSync(fromTS: Long, toTS: Long, eventId: Long = -1L, applyTypeFilter: Boolean, callback: (events: ArrayList<Event>) -> Unit) {
var events = if (applyTypeFilter) {
val displayEventTypes = context.config.displayEventTypes
if (displayEventTypes.isEmpty()) {
callback(ArrayList())
return
} else {
eventsDB.getOneTimeEventsFromToWithTypes(toTS, fromTS, context.config.getDisplayEventTypessAsList()).toMutableList() as ArrayList<Event>
}
} else {
if (eventId == -1L) {
eventsDB.getOneTimeEventsFromTo(toTS, fromTS).toMutableList() as ArrayList<Event>
} else {
eventsDB.getOneTimeEventFromToWithId(eventId, toTS, fromTS).toMutableList() as ArrayList<Event>
}
}
events.addAll(getRepeatableEventsFor(fromTS, toTS, eventId, applyTypeFilter))
events = events
.asSequence()
.distinct()
.filterNot { it.repetitionExceptions.contains(Formatter.getDayCodeFromTS(it.startTS)) }
.toMutableList() as ArrayList<Event>
val eventTypeColors = LongSparseArray<Int>()
context.eventTypesDB.getEventTypes().forEach {
eventTypeColors.put(it.id!!, it.color)
}
events.forEach {
it.updateIsPastEvent()
it.color = eventTypeColors.get(it.eventType)!!
}
callback(events)
}
fun getRepeatableEventsFor(fromTS: Long, toTS: Long, eventId: Long = -1L, applyTypeFilter: Boolean = false): List<Event> {
val events = if (applyTypeFilter) {
val displayEventTypes = context.config.displayEventTypes
if (displayEventTypes.isEmpty()) {
return ArrayList()
} else {
eventsDB.getRepeatableEventsFromToWithTypes(toTS, context.config.getDisplayEventTypessAsList()).toMutableList() as ArrayList<Event>
}
} else {
if (eventId == -1L) {
eventsDB.getRepeatableEventsFromToWithTypes(toTS).toMutableList() as ArrayList<Event>
} else {
eventsDB.getRepeatableEventFromToWithId(eventId, toTS).toMutableList() as ArrayList<Event>
}
}
val startTimes = LongSparseArray<Long>()
val newEvents = ArrayList<Event>()
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 getEventsRepeatingXTimes(fromTS: Long, toTS: Long, startTimes: LongSparseArray<Long>, 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 (event.isOnProperWeek(startTimes)) {
if (event.endTS >= fromTS) {
event.copy().apply {
updateIsPastEvent()
color = event.color
events.add(this)
}
}
event.repeatLimit++
}
}
} else {
if (event.endTS >= fromTS) {
event.copy().apply {
updateIsPastEvent()
color = event.color
events.add(this)
}
} else if (event.getIsAllDay()) {
val dayCode = Formatter.getDayCodeFromTS(fromTS)
val endDayCode = Formatter.getDayCodeFromTS(event.endTS)
if (dayCode == endDayCode) {
event.copy().apply {
updateIsPastEvent()
color = event.color
events.add(this)
}
}
}
event.repeatLimit++
}
event.addIntervalTime(original)
}
return events
}
private fun getEventsRepeatingTillDateOrForever(fromTS: Long, toTS: Long, startTimes: LongSparseArray<Long>, event: Event): ArrayList<Event> {
val original = event.copy()
val events = ArrayList<Event>()
while (event.startTS <= toTS && (event.repeatLimit == 0L || event.repeatLimit >= event.startTS)) {
if (event.endTS >= fromTS) {
if (event.repeatInterval.isXWeeklyRepetition()) {
if (event.startTS.isTsOnProperDay(event)) {
if (event.isOnProperWeek(startTimes)) {
event.copy().apply {
updateIsPastEvent()
color = event.color
events.add(this)
}
}
}
} else {
event.copy().apply {
updateIsPastEvent()
color = event.color
events.add(this)
}
}
}
if (event.getIsAllDay()) {
if (event.repeatInterval.isXWeeklyRepetition()) {
if (event.endTS >= toTS && event.startTS.isTsOnProperDay(event)) {
if (event.isOnProperWeek(startTimes)) {
event.copy().apply {
updateIsPastEvent()
color = event.color
events.add(this)
}
}
}
} else {
val dayCode = Formatter.getDayCodeFromTS(fromTS)
val endDayCode = Formatter.getDayCodeFromTS(event.endTS)
if (dayCode == endDayCode) {
event.copy().apply {
updateIsPastEvent()
color = event.color
events.add(this)
}
}
}
}
event.addIntervalTime(original)
}
return events
}
fun getRunningEvents(): List<Event> {
val ts = getNowSeconds()
val events = eventsDB.getOneTimeEventsFromTo(ts, ts).toMutableList() as ArrayList<Event>
events.addAll(getRepeatableEventsFor(ts, ts))
return events
}
fun getEventsToExport(includePast: Boolean, eventTypes: ArrayList<Long>): ArrayList<Event> {
val currTS = getNowSeconds()
var events = ArrayList<Event>()
if (includePast) {
events.addAll(eventsDB.getAllEventsWithTypes(eventTypes))
} else {
events.addAll(eventsDB.getOneTimeFutureEventsWithTypes(currTS, eventTypes))
events.addAll(eventsDB.getRepeatableFutureEventsWithTypes(currTS, eventTypes))
}
events = events.distinctBy { it.id } as ArrayList<Event>
return events
}
}

View File

@ -1,9 +1,9 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.content.Context
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.seconds
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.joda.time.LocalDate
@ -46,7 +46,7 @@ object Formatter {
date
}
fun getLongestDate(ts: Int) = getDateTimeFromTS(ts).toString(LONGEST_PATTERN)
fun getLongestDate(ts: Long) = getDateTimeFromTS(ts).toString(LONGEST_PATTERN)
fun getDate(context: Context, dateTime: DateTime, addDayOfWeek: Boolean = true) = getDayTitle(context, getDayCodeFromDateTime(dateTime), addDayOfWeek)
@ -58,7 +58,7 @@ object Formatter {
return "$month $day $year"
}
fun getTodayCode() = Formatter.getDayCodeFromTS(getNowSeconds())
fun getTodayCode() = getDayCodeFromTS(getNowSeconds())
fun getHours(context: Context, dateTime: DateTime) = dateTime.toString(getHourPattern(context))
@ -68,7 +68,7 @@ object Formatter {
fun getLocalDateTimeFromCode(dayCode: String) = DateTimeFormat.forPattern(DAYCODE_PATTERN).withZone(DateTimeZone.getDefault()).parseLocalDate(dayCode).toDateTimeAtStartOfDay()
fun getTimeFromTS(context: Context, ts: Int) = getTime(context, getDateTimeFromTS(ts))
fun getTimeFromTS(context: Context, ts: Long) = getTime(context, getDateTimeFromTS(ts))
fun getDayStartTS(dayCode: String) = getLocalDateTimeFromCode(dayCode).seconds()
@ -76,11 +76,11 @@ object Formatter {
fun getDayCodeFromDateTime(dateTime: DateTime) = dateTime.toString(DAYCODE_PATTERN)
fun getDateFromTS(ts: Int) = LocalDate(ts * 1000L, DateTimeZone.getDefault())
fun getDateFromTS(ts: Long) = LocalDate(ts * 1000L, DateTimeZone.getDefault())
fun getDateTimeFromTS(ts: Int) = DateTime(ts * 1000L, DateTimeZone.getDefault())
fun getDateTimeFromTS(ts: Long) = DateTime(ts * 1000L, DateTimeZone.getDefault())
fun getUTCDateTimeFromTS(ts: Int) = DateTime(ts * 1000L, DateTimeZone.UTC)
fun getUTCDateTimeFromTS(ts: Long) = DateTime(ts * 1000L, DateTimeZone.UTC)
// use manually translated month names, as DateFormat and Joda have issues with a lot of languages
fun getMonthName(context: Context, id: Int) = context.resources.getStringArray(R.array.months)[id - 1]
@ -94,7 +94,7 @@ object Formatter {
return "${dateTime.toString(DAYCODE_PATTERN)}T${dateTime.toString(TIME_PATTERN)}Z"
}
fun getDayCodeFromTS(ts: Int): String {
fun getDayCodeFromTS(ts: Long): String {
val daycode = getDateTimeFromTS(ts).toString(DAYCODE_PATTERN)
return if (daycode.isNotEmpty()) {
daycode
@ -103,5 +103,5 @@ object Formatter {
}
}
fun getShiftedImportTimestamp(ts: Int) = getUTCDateTimeFromTS(ts).withTime(13, 0, 0, 0).withZoneRetainFields(DateTimeZone.getDefault()).seconds()
fun getShiftedImportTimestamp(ts: Long) = getUTCDateTimeFromTS(ts).withTime(13, 0, 0, 0).withZoneRetainFields(DateTimeZone.getDefault()).seconds()
}

View File

@ -0,0 +1,101 @@
package com.simplemobiletools.calendar.pro.helpers
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.eventTypesDB
import com.simplemobiletools.calendar.pro.helpers.IcsExporter.ExportResult.*
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.getFileOutputStream
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.writeLn
import com.simplemobiletools.commons.models.FileDirItem
import java.io.BufferedWriter
import java.io.File
class IcsExporter {
enum class ExportResult {
EXPORT_FAIL, EXPORT_OK, EXPORT_PARTIAL
}
private var eventsExported = 0
private var eventsFailed = 0
fun exportEvents(activity: BaseSimpleActivity, file: File, events: ArrayList<Event>, showExportingToast: Boolean, callback: (result: ExportResult) -> Unit) {
val fileDirItem = FileDirItem(file.absolutePath, file.name)
activity.getFileOutputStream(fileDirItem, true) {
if (it == null) {
callback(EXPORT_FAIL)
return@getFileOutputStream
}
Thread {
if (showExportingToast) {
activity.toast(R.string.exporting)
}
it.bufferedWriter().use { out ->
out.writeLn(BEGIN_CALENDAR)
out.writeLn(CALENDAR_PRODID)
out.writeLn(CALENDAR_VERSION)
for (event in events) {
out.writeLn(BEGIN_EVENT)
event.title.replace("\n", "\\n").let { if (it.isNotEmpty()) out.writeLn("$SUMMARY:$it") }
event.description.replace("\n", "\\n").let { if (it.isNotEmpty()) out.writeLn("$DESCRIPTION$it") }
event.importId.let { if (it.isNotEmpty()) out.writeLn("$UID$it") }
event.eventType.let { out.writeLn("$CATEGORY_COLOR${activity.eventTypesDB.getEventTypeWithId(it)?.color}") }
event.eventType.let { out.writeLn("$CATEGORIES${activity.eventTypesDB.getEventTypeWithId(it)?.title}") }
event.lastUpdated.let { out.writeLn("$LAST_MODIFIED:${Formatter.getExportedTime(it)}") }
event.location.let { if (it.isNotEmpty()) out.writeLn("$LOCATION:$it") }
if (event.getIsAllDay()) {
out.writeLn("$DTSTART;$VALUE=$DATE:${Formatter.getDayCodeFromTS(event.startTS)}")
out.writeLn("$DTEND;$VALUE=$DATE:${Formatter.getDayCodeFromTS(event.endTS + DAY)}")
} else {
event.startTS.let { out.writeLn("$DTSTART:${Formatter.getExportedTime(it * 1000L)}") }
event.endTS.let { out.writeLn("$DTEND:${Formatter.getExportedTime(it * 1000L)}") }
}
out.writeLn("$STATUS$CONFIRMED")
Parser().getRepeatCode(event).let { if (it.isNotEmpty()) out.writeLn("$RRULE$it") }
fillReminders(event, out)
fillIgnoredOccurrences(event, out)
eventsExported++
out.writeLn(END_EVENT)
}
out.writeLn(END_CALENDAR)
}
callback(when {
eventsExported == 0 -> EXPORT_FAIL
eventsFailed > 0 -> EXPORT_PARTIAL
else -> EXPORT_OK
})
}.start()
}
}
private fun fillReminders(event: Event, out: BufferedWriter) {
checkReminder(event.reminder1Minutes, out)
checkReminder(event.reminder2Minutes, out)
checkReminder(event.reminder3Minutes, out)
}
private fun checkReminder(minutes: Int, out: BufferedWriter) {
if (minutes != -1) {
out.apply {
writeLn(BEGIN_ALARM)
writeLn("$ACTION$DISPLAY")
writeLn("$TRIGGER-${Parser().getDurationCode(minutes.toLong())}")
writeLn(END_ALARM)
}
}
}
private fun fillIgnoredOccurrences(event: Event, out: BufferedWriter) {
event.repetitionExceptions.forEach {
out.writeLn("$EXDATE:$it")
}
}
}

View File

@ -1,13 +1,13 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.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.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.eventsDB
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.helpers.IcsImporter.ImportResult.*
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType
import com.simplemobiletools.commons.extensions.areDigitsOnly
import com.simplemobiletools.commons.extensions.showErrorToast
import java.io.File
@ -17,33 +17,36 @@ class IcsImporter(val activity: SimpleActivity) {
IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL
}
private var curStart = -1
private var curEnd = -1
private var curStart = -1L
private var curEnd = -1L
private var curTitle = ""
private var curLocation = ""
private var curDescription = ""
private var curImportId = ""
private var curRecurrenceDayCode = ""
private var curFlags = 0
private var curReminderMinutes = ArrayList<Int>()
private var curRepeatExceptions = ArrayList<Int>()
private var curRepeatExceptions = ArrayList<String>()
private var curRepeatInterval = 0
private var curRepeatLimit = 0
private var curRepeatLimit = 0L
private var curRepeatRule = 0
private var curEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
private var curEventTypeId = 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 isDescription = false
private var isSequence = false
private var curReminderTriggerMinutes = -1
private val eventsHelper = activity.eventsHelper
private var eventsImported = 0
private var eventsFailed = 0
fun importEvents(path: String, defaultEventTypeId: Int, calDAVCalendarId: Int, overrideFileEventTypes: Boolean): ImportResult {
fun importEvents(path: String, defaultEventTypeId: Long, calDAVCalendarId: Int, overrideFileEventTypes: Boolean): ImportResult {
try {
val eventTypes = activity.dbHelper.getEventTypesSync()
val existingEvents = activity.dbHelper.getEventsWithImportIds()
val eventTypes = eventsHelper.getEventTypesSync()
val existingEvents = activity.eventsDB.getEventsWithImportIds().toMutableList() as ArrayList<Event>
val eventsToInsert = ArrayList<Event>()
var prevLine = ""
@ -108,7 +111,7 @@ class IcsImporter(val activity: SimpleActivity) {
}
} else if (line.startsWith(CATEGORIES) && !overrideFileEventTypes) {
val categories = line.substring(CATEGORIES.length)
tryAddCategories(categories, activity)
tryAddCategories(categories)
} else if (line.startsWith(LAST_MODIFIED)) {
curLastModified = getTimestamp(line.substring(LAST_MODIFIED.length)) * 1000L
} else if (line.startsWith(EXDATE)) {
@ -117,52 +120,72 @@ class IcsImporter(val activity: SimpleActivity) {
value = value.substring(0, value.length - 1)
}
curRepeatExceptions.add(getTimestamp(value))
curRepeatExceptions.add(Formatter.getDayCodeFromTS(getTimestamp(value)))
} else if (line.startsWith(LOCATION)) {
curLocation = getLocation(line.substring(LOCATION.length).replace("\\,", ","))
} else if (line.startsWith(RECURRENCE_ID)) {
val timestamp = getTimestamp(line.substring(RECURRENCE_ID.length))
curRecurrenceDayCode = Formatter.getDayCodeFromTS(timestamp)
} else if (line.startsWith(SEQUENCE)) {
isSequence = true
} else if (line == END_ALARM) {
if (isProperReminderAction && curReminderTriggerMinutes != -1) {
curReminderMinutes.add(curReminderTriggerMinutes)
}
} else if (line == END_EVENT) {
if (curStart != -1 && curEnd == -1) {
if (curStart != -1L && curEnd == -1L) {
curEnd = curStart
}
if (curTitle.isEmpty() || curStart == -1) {
if (curTitle.isEmpty() || curStart == -1L) {
continue
}
val eventToUpdate = existingEvents.firstOrNull { curImportId.isNotEmpty() && curImportId == it.importId }
// repeating event exceptions can have the same import id as their parents, so pick the latest event to update
val eventToUpdate = existingEvents.filter { curImportId.isNotEmpty() && curImportId == it.importId }.sortedByDescending { it.lastUpdated }.firstOrNull()
if (eventToUpdate != null && eventToUpdate.lastUpdated >= curLastModified) {
continue
}
val eventType = eventTypes.firstOrNull { it.id == curEventTypeId }
val source = if (calDAVCalendarId == 0 || eventType?.isSyncedEventType() == false) SOURCE_IMPORTED_ICS else "$CALDAV-$calDAVCalendarId"
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, curEventTypeId, lastUpdated = curLastModified,
source = source, location = curLocation)
val event = Event(null, curStart, curEnd, curTitle, curLocation, curDescription, curReminderMinutes.getOrElse(0) { -1 },
curReminderMinutes.getOrElse(1) { -1 }, curReminderMinutes.getOrElse(2) { -1 }, curRepeatInterval, curRepeatRule,
curRepeatLimit, curRepeatExceptions, curImportId, curFlags, curEventTypeId, 0, curLastModified, source)
if (event.getIsAllDay() && curEnd > curStart) {
event.endTS -= DAY
}
if (event.importId.isEmpty()) {
event.importId = event.hashCode().toString()
if (existingEvents.map { it.importId }.contains(event.importId)) {
continue
}
}
if (eventToUpdate == null) {
if (curRepeatExceptions.isEmpty()) {
eventsToInsert.add(event)
} else {
activity.dbHelper.insert(event, true) {
for (exceptionTS in curRepeatExceptions) {
activity.dbHelper.addEventRepeatException(it, exceptionTS, true)
// if an event belongs to a sequence insert it immediately, to avoid some glitches with linked events
if (isSequence) {
if (curRecurrenceDayCode.isEmpty()) {
eventsHelper.insertEvent(event, true, false)
} else {
// if an event contains the RECURRENCE-ID field, it is an exception to a recurring event, so update its parent too
val parentEvent = activity.eventsDB.getEventWithImportId(event.importId)
if (parentEvent != null && !parentEvent.repetitionExceptions.contains(curRecurrenceDayCode)) {
parentEvent.addRepetitionException(curRecurrenceDayCode)
eventsHelper.insertEvent(parentEvent, true, false)
event.parentId = parentEvent.id!!
eventsToInsert.add(event)
}
existingEvents.add(event)
}
} else {
eventsToInsert.add(event)
}
} else {
event.id = eventToUpdate.id
activity.dbHelper.update(event, true)
eventsHelper.updateEvent(event, true, false)
}
eventsImported++
resetValues()
@ -171,7 +194,7 @@ class IcsImporter(val activity: SimpleActivity) {
}
}
activity.dbHelper.insertEvents(eventsToInsert, true)
eventsHelper.insertEvents(eventsToInsert, true)
} catch (e: Exception) {
activity.showErrorToast(e, Toast.LENGTH_LONG)
eventsFailed++
@ -184,10 +207,10 @@ class IcsImporter(val activity: SimpleActivity) {
}
}
private fun getTimestamp(fullString: String): Int {
private fun getTimestamp(fullString: String): Long {
return try {
if (fullString.startsWith(';')) {
val value = fullString.substring(fullString.lastIndexOf(':') + 1)
val value = fullString.substring(fullString.lastIndexOf(':') + 1).replace(" ", "")
if (!value.contains("T")) {
curFlags = curFlags or FLAG_ALL_DAY
}
@ -211,18 +234,18 @@ class IcsImporter(val activity: SimpleActivity) {
}
}
private fun tryAddCategories(categories: String, context: Context) {
private fun tryAddCategories(categories: String) {
val eventTypeTitle = if (categories.contains(",")) {
categories.split(",")[0]
} else {
categories
}
val eventId = context.dbHelper.getEventTypeIdWithTitle(eventTypeTitle)
curEventTypeId = 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)
val eventId = eventsHelper.getEventTypeIdWithTitle(eventTypeTitle)
curEventTypeId = if (eventId == -1L) {
val newTypeColor = if (curCategoryColor == -2) activity.resources.getColor(R.color.color_primary) else curCategoryColor
val eventType = EventType(null, eventTypeTitle, newTypeColor)
eventsHelper.insertOrUpdateEventTypeSync(eventType)
} else {
eventId
}
@ -237,23 +260,25 @@ class IcsImporter(val activity: SimpleActivity) {
}
private fun resetValues() {
curStart = -1
curEnd = -1
curStart = -1L
curEnd = -1L
curTitle = ""
curLocation = ""
curDescription = ""
curImportId = ""
curRecurrenceDayCode = ""
curFlags = 0
curReminderMinutes = ArrayList()
curRepeatExceptions = ArrayList()
curRepeatInterval = 0
curRepeatLimit = 0
curRepeatLimit = 0L
curRepeatRule = 0
curEventTypeId = DBHelper.REGULAR_EVENT_TYPE_ID
curEventTypeId = REGULAR_EVENT_TYPE_ID
curLastModified = 0L
curCategoryColor = -2
curLocation = ""
isNotificationDescription = false
isProperReminderAction = false
isSequence = false
curReminderTriggerMinutes = -1
}
}

View File

@ -1,12 +1,12 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.content.Context
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
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 com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.pro.models.DayMonthly
import com.simplemobiletools.calendar.pro.models.Event
import org.joda.time.DateTime
import java.util.*
import kotlin.collections.ArrayList
@ -24,7 +24,7 @@ class MonthlyCalendarImpl(val callback: MonthlyCalendar, val context: Context) {
mTargetDate = targetDate
val startTS = mTargetDate.minusDays(7).seconds()
val endTS = mTargetDate.plusDays(43).seconds()
context.dbHelper.getEvents(startTS, endTS, applyTypeFilter = true) {
context.eventsHelper.getEvents(startTS, endTS) {
gotEvents(it)
}
}
@ -82,33 +82,31 @@ class MonthlyCalendarImpl(val callback: MonthlyCalendar, val context: Context) {
// it works more often than not, dont touch
private fun markDaysWithEvents(days: ArrayList<DayMonthly>) {
context.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)
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()
var currDay = startDateTime
var dayCode = Formatter.getDayCodeFromDateTime(currDay)
var currDayEvents = dayEvents[dayCode] ?: ArrayList()
currDayEvents.add(it)
dayEvents[dayCode] = currDayEvents
while (Formatter.getDayCodeFromDateTime(currDay) != endCode) {
currDay = currDay.plusDays(1)
dayCode = Formatter.getDayCodeFromDateTime(currDay)
currDayEvents = dayEvents[dayCode] ?: ArrayList()
currDayEvents.add(it)
dayEvents[dayCode] = currDayEvents
while (Formatter.getDayCodeFromDateTime(currDay) != endCode) {
currDay = currDay.plusDays(1)
dayCode = Formatter.getDayCodeFromDateTime(currDay)
currDayEvents = dayEvents[dayCode] ?: ArrayList()
currDayEvents.add(it)
dayEvents[dayCode] = currDayEvents
}
}
days.filter { dayEvents.keys.contains(it.code) }.forEach {
it.dayEvents = dayEvents[it.code]!!
}
callback.updateMonthlyCalendar(context, monthName, days, true, mTargetDate)
}
days.filter { dayEvents.keys.contains(it.code) }.forEach {
it.dayEvents = dayEvents[it.code]!!
}
callback.updateMonthlyCalendar(context, monthName, days, true, mTargetDate)
}
private fun isToday(targetDate: DateTime, curDayInMonth: Int): Boolean {

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
@ -8,11 +8,11 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.widget.RemoteViews
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SplashActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.launchNewEventIntent
import com.simplemobiletools.calendar.services.WidgetService
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SplashActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.launchNewEventIntent
import com.simplemobiletools.calendar.pro.services.WidgetService
import com.simplemobiletools.commons.extensions.*
import org.joda.time.DateTime

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
@ -9,12 +9,12 @@ import android.content.Intent
import android.content.res.Resources
import android.view.View
import android.widget.RemoteViews
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SplashActivity
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.launchNewEventIntent
import com.simplemobiletools.calendar.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.models.DayMonthly
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SplashActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.extensions.launchNewEventIntent
import com.simplemobiletools.calendar.pro.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.pro.models.DayMonthly
import com.simplemobiletools.commons.extensions.*
import org.joda.time.DateTime

View File

@ -1,25 +1,22 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import com.simplemobiletools.calendar.extensions.isXMonthlyRepetition
import com.simplemobiletools.calendar.extensions.isXWeeklyRepetition
import com.simplemobiletools.calendar.extensions.isXYearlyRepetition
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.RepeatRule
import com.simplemobiletools.calendar.pro.extensions.isXMonthlyRepetition
import com.simplemobiletools.calendar.pro.extensions.isXWeeklyRepetition
import com.simplemobiletools.calendar.pro.extensions.isXYearlyRepetition
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventRepetition
import com.simplemobiletools.commons.helpers.*
import org.joda.time.DateTimeZone
import org.joda.time.format.DateTimeFormat
class Parser {
// from RRULE:FREQ=DAILY;COUNT=5 to Daily, 5x...
fun parseRepeatInterval(fullString: String, startTS: Int): RepeatRule {
val parts = fullString.split(";")
fun parseRepeatInterval(fullString: String, startTS: Long): EventRepetition {
val parts = fullString.split(";").filter { it.isNotEmpty() }
var repeatInterval = 0
var repeatRule = 0
var repeatLimit = 0
if (fullString.isEmpty()) {
return RepeatRule(repeatInterval, repeatRule, repeatLimit)
}
var repeatLimit = 0L
for (part in parts) {
val keyValue = part.split("=")
@ -34,7 +31,7 @@ class Parser {
repeatRule = REPEAT_SAME_DAY
}
} else if (key == COUNT) {
repeatLimit = -value.toInt()
repeatLimit = -value.toLong()
} else if (key == UNTIL) {
repeatLimit = parseDateTimeValue(value)
} else if (key == INTERVAL) {
@ -49,7 +46,7 @@ class Parser {
repeatRule = REPEAT_LAST_DAY
}
}
return RepeatRule(repeatInterval, repeatRule, repeatLimit)
return EventRepetition(repeatInterval, repeatRule, repeatLimit)
}
private fun getFrequencySeconds(interval: String) = when (interval) {
@ -79,7 +76,7 @@ class Parser {
return newRepeatRule
}
fun parseDateTimeValue(value: String): Int {
fun parseDateTimeValue(value: String): Long {
val edited = value.replace("T", "").replace("Z", "")
return if (edited.length == 14) {
parseLongFormat(edited, value.endsWith("Z"))
@ -89,7 +86,7 @@ class Parser {
}
}
private fun parseLongFormat(digitString: String, useUTC: Boolean): Int {
private fun parseLongFormat(digitString: String, useUTC: Boolean): Long {
val dateTimeFormat = DateTimeFormat.forPattern("yyyyMMddHHmmss")
val dateTimeZone = if (useUTC) DateTimeZone.UTC else DateTimeZone.getDefault()
return dateTimeFormat.parseDateTime(digitString).withZoneRetainFields(dateTimeZone).seconds()
@ -124,7 +121,7 @@ class Parser {
}
private fun getRepeatLimitString(event: Event) = when {
event.repeatLimit == 0 -> ""
event.repeatLimit == 0L -> ""
event.repeatLimit < 0 -> ";$COUNT=${-event.repeatLimit}"
else -> ";$UNTIL=${Formatter.getDayCodeFromTS(event.repeatLimit)}"
}
@ -205,7 +202,7 @@ class Parser {
private fun getDurationValue(duration: String, char: String) = Regex("[0-9]+(?=$char)").find(duration)?.value?.toInt() ?: 0
// from 65 to P0DT1H5M0S
fun getDurationCode(minutes: Int): String {
fun getDurationCode(minutes: Long): String {
var days = 0
var hours = 0
var remainder = minutes

View File

@ -1,18 +1,18 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.content.Context
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.interfaces.WeeklyCalendar
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.interfaces.WeeklyCalendar
import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.commons.helpers.WEEK_SECONDS
import java.util.*
class WeeklyCalendarImpl(val callback: WeeklyCalendar, val context: Context) {
var mEvents = ArrayList<Event>()
fun updateWeeklyCalendar(weekStartTS: Int) {
fun updateWeeklyCalendar(weekStartTS: Long) {
val endTS = weekStartTS + WEEK_SECONDS
context.dbHelper.getEvents(weekStartTS, endTS, applyTypeFilter = true) {
context.eventsHelper.getEvents(weekStartTS, endTS) {
mEvents = it
callback.updateWeeklyCalendar(it)
}

View File

@ -1,12 +1,12 @@
package com.simplemobiletools.calendar.helpers
package com.simplemobiletools.calendar.pro.helpers
import android.content.Context
import android.util.SparseArray
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.interfaces.YearlyCalendar
import com.simplemobiletools.calendar.models.DayYearly
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.pro.extensions.eventsHelper
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.interfaces.YearlyCalendar
import com.simplemobiletools.calendar.pro.models.DayYearly
import com.simplemobiletools.calendar.pro.models.Event
import org.joda.time.DateTime
import java.util.*
@ -16,7 +16,7 @@ class YearlyCalendarImpl(val callback: YearlyCalendar, val context: Context, val
val startDateTime = DateTime().withTime(0, 0, 0, 0).withDate(year, 1, 1)
val startTS = startDateTime.seconds()
val endTS = startDateTime.plusYears(1).minusSeconds(1).seconds()
context.dbHelper.getEvents(startTS, endTS, applyTypeFilter = true) {
context.eventsHelper.getEvents(startTS, endTS) {
gotEvents(it)
}
}

View File

@ -1,6 +1,6 @@
package com.simplemobiletools.calendar.interfaces
package com.simplemobiletools.calendar.pro.interfaces
import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.calendar.pro.models.EventType
import java.util.*
interface DeleteEventTypesListener {

View File

@ -0,0 +1,28 @@
package com.simplemobiletools.calendar.pro.interfaces
import androidx.room.*
import com.simplemobiletools.calendar.pro.models.EventType
@Dao
interface EventTypesDao {
@Query("SELECT * FROM event_types ORDER BY title ASC")
fun getEventTypes(): List<EventType>
@Query("SELECT * FROM event_types WHERE id = :id")
fun getEventTypeWithId(id: Long): EventType?
@Query("SELECT id FROM event_types WHERE title = :title COLLATE NOCASE")
fun getEventTypeIdWithTitle(title: String): Long?
@Query("SELECT * FROM event_types WHERE caldav_calendar_id = :calendarId")
fun getEventTypeWithCalDAVCalendarId(calendarId: Int): EventType?
@Query("DELETE FROM event_types WHERE caldav_calendar_id IN (:ids)")
fun deleteEventTypesWithCalendarId(ids: List<Int>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrUpdate(eventType: EventType): Long
@Delete
fun deleteEventTypes(eventTypes: List<EventType>)
}

View File

@ -0,0 +1,113 @@
package com.simplemobiletools.calendar.pro.interfaces
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.simplemobiletools.calendar.pro.helpers.REGULAR_EVENT_TYPE_ID
import com.simplemobiletools.calendar.pro.helpers.SOURCE_CONTACT_ANNIVERSARY
import com.simplemobiletools.calendar.pro.helpers.SOURCE_CONTACT_BIRTHDAY
import com.simplemobiletools.calendar.pro.models.Event
@Dao
interface EventsDao {
@Query("SELECT * FROM events")
fun getAllEvents(): List<Event>
@Query("SELECT * FROM events WHERE event_type IN (:eventTypeIds)")
fun getAllEventsWithTypes(eventTypeIds: List<Long>): List<Event>
@Query("SELECT * FROM events WHERE id = :id")
fun getEventWithId(id: Long): Event?
@Query("SELECT * FROM events WHERE import_id = :importId")
fun getEventWithImportId(importId: String): Event?
@Query("SELECT * FROM events WHERE start_ts <= :toTS AND end_ts >= :fromTS AND repeat_interval = 0")
fun getOneTimeEventsFromTo(toTS: Long, fromTS: Long): List<Event>
@Query("SELECT * FROM events WHERE id = :id AND start_ts <= :toTS AND end_ts >= :fromTS AND repeat_interval = 0")
fun getOneTimeEventFromToWithId(id: Long, toTS: Long, fromTS: Long): List<Event>
@Query("SELECT * FROM events WHERE start_ts <= :toTS AND end_ts >= :fromTS AND start_ts != 0 AND repeat_interval = 0 AND event_type IN (:eventTypeIds)")
fun getOneTimeEventsFromToWithTypes(toTS: Long, fromTS: Long, eventTypeIds: List<Long>): List<Event>
@Query("SELECT * FROM events WHERE end_ts > :toTS AND repeat_interval = 0 AND event_type IN (:eventTypeIds)")
fun getOneTimeFutureEventsWithTypes(toTS: Long, eventTypeIds: List<Long>): List<Event>
@Query("SELECT * FROM events WHERE start_ts <= :toTS AND repeat_interval != 0")
fun getRepeatableEventsFromToWithTypes(toTS: Long): List<Event>
@Query("SELECT * FROM events WHERE id = :id AND start_ts <= :toTS AND repeat_interval != 0")
fun getRepeatableEventFromToWithId(id: Long, toTS: Long): List<Event>
@Query("SELECT * FROM events WHERE start_ts <= :toTS AND start_ts != 0 AND repeat_interval != 0 AND event_type IN (:eventTypeIds)")
fun getRepeatableEventsFromToWithTypes(toTS: Long, eventTypeIds: List<Long>): List<Event>
@Query("SELECT * FROM events WHERE repeat_interval != 0 AND (repeat_limit == 0 OR repeat_limit > :currTS) AND event_type IN (:eventTypeIds)")
fun getRepeatableFutureEventsWithTypes(currTS: Long, eventTypeIds: List<Long>): List<Event>
@Query("SELECT * FROM events WHERE id IN (:ids) AND import_id != \"\"")
fun getEventsByIdsWithImportIds(ids: List<Long>): List<Event>
@Query("SELECT * FROM events WHERE title LIKE :searchQuery OR location LIKE :searchQuery OR description LIKE :searchQuery")
fun getEventsForSearch(searchQuery: String): List<Event>
@Query("SELECT * FROM events WHERE source = \'$SOURCE_CONTACT_BIRTHDAY\'")
fun getBirthdays(): List<Event>
@Query("SELECT * FROM events WHERE source = \'$SOURCE_CONTACT_ANNIVERSARY\'")
fun getAnniversaries(): List<Event>
@Query("SELECT * FROM events WHERE import_id != \"\"")
fun getEventsWithImportIds(): List<Event>
@Query("SELECT * FROM events WHERE source = :source")
fun getEventsFromCalDAVCalendar(source: String): List<Event>
@Query("SELECT * FROM events WHERE id IN (:ids)")
fun getEventsWithIds(ids: List<Long>): List<Event>
//val selection = "$COL_REMINDER_MINUTES != -1 AND ($COL_START_TS > ? OR $COL_REPEAT_INTERVAL != 0) AND $COL_START_TS != 0"
@Query("SELECT * FROM events WHERE reminder_1_minutes != -1 AND (start_ts > :currentTS OR repeat_interval != 0) AND start_ts != 0")
fun getEventsAtReboot(currentTS: Long): List<Event>
@Query("SELECT id FROM events")
fun getEventIds(): List<Long>
@Query("SELECT id FROM events WHERE import_id = :importId")
fun getEventIdWithImportId(importId: String): Long?
@Query("SELECT id FROM events WHERE import_id LIKE :importId")
fun getEventIdWithLastImportId(importId: String): Long?
@Query("SELECT id FROM events WHERE event_type = :eventTypeId")
fun getEventIdsByEventType(eventTypeId: Long): List<Long>
@Query("SELECT id FROM events WHERE event_type IN (:eventTypeIds)")
fun getEventIdsByEventType(eventTypeIds: List<Long>): List<Long>
@Query("SELECT id FROM events WHERE parent_id IN (:parentIds)")
fun getEventIdsWithParentIds(parentIds: List<Long>): List<Long>
@Query("SELECT id FROM events WHERE source = :source AND import_id != \"\"")
fun getCalDAVCalendarEvents(source: String): List<Long>
@Query("UPDATE events SET event_type = $REGULAR_EVENT_TYPE_ID WHERE event_type = :eventTypeId")
fun resetEventsWithType(eventTypeId: Long)
@Query("UPDATE events SET import_id = :importId AND source = :source WHERE id = :id")
fun updateEventImportIdAndSource(importId: String, source: String, id: Long)
@Query("UPDATE events SET repeat_limit = :repeatLimit WHERE id = :id")
fun updateEventRepetitionLimit(repeatLimit: Long, id: Long)
@Query("UPDATE events SET repetition_exceptions = :repetitionExceptions WHERE id = :id")
fun updateEventRepetitionExceptions(repetitionExceptions: ArrayList<String>, id: Long)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrUpdate(event: Event): Long
@Query("DELETE FROM events WHERE id IN (:ids)")
fun deleteEvents(ids: List<Long>)
}

View File

@ -1,7 +1,7 @@
package com.simplemobiletools.calendar.interfaces
package com.simplemobiletools.calendar.pro.interfaces
import android.content.Context
import com.simplemobiletools.calendar.models.DayMonthly
import com.simplemobiletools.calendar.pro.models.DayMonthly
import org.joda.time.DateTime
interface MonthlyCalendar {

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.interfaces
package com.simplemobiletools.calendar.pro.interfaces
import org.joda.time.DateTime

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.interfaces
package com.simplemobiletools.calendar.pro.interfaces
interface WeekFragmentListener {
fun scrollTo(y: Int)

View File

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

View File

@ -1,7 +1,7 @@
package com.simplemobiletools.calendar.interfaces
package com.simplemobiletools.calendar.pro.interfaces
import android.util.SparseArray
import com.simplemobiletools.calendar.models.DayYearly
import com.simplemobiletools.calendar.pro.models.DayYearly
import java.util.*
interface YearlyCalendar {

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.models
package com.simplemobiletools.calendar.pro.models
data class CalDAVCalendar(val id: Int, val displayName: String, val accountName: String, val accountType: String, val ownerName: String,
var color: Int, val accessLevel: Int) {

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.models
package com.simplemobiletools.calendar.pro.models
data class DayMonthly(val value: Int, val isThisMonth: Boolean, val isToday: Boolean, val code: String, val weekOfYear: Int, var dayEvents: ArrayList<Event>,
var indexOnMonthView: Int)

View File

@ -1,4 +1,4 @@
package com.simplemobiletools.calendar.models
package com.simplemobiletools.calendar.pro.models
data class DayYearly(var eventColors: HashSet<Int> = HashSet()) {
fun addColor(color: Int) = eventColors.add(color)

View File

@ -1,18 +1,37 @@
package com.simplemobiletools.calendar.models
package com.simplemobiletools.calendar.pro.models
import com.simplemobiletools.calendar.extensions.seconds
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import androidx.collection.LongSparseArray
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import com.simplemobiletools.calendar.pro.extensions.seconds
import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.commons.extensions.addBitIf
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 = "", var isPastEvent: Boolean = false)
@Entity(tableName = "events", indices = [(Index(value = ["id"], unique = true))])
data class Event(
@PrimaryKey(autoGenerate = true) var id: Long?,
@ColumnInfo(name = "start_ts") var startTS: Long = 0L,
@ColumnInfo(name = "end_ts") var endTS: Long = 0L,
@ColumnInfo(name = "title") var title: String = "",
@ColumnInfo(name = "location") var location: String = "",
@ColumnInfo(name = "description") var description: String = "",
@ColumnInfo(name = "reminder_1_minutes") var reminder1Minutes: Int = -1,
@ColumnInfo(name = "reminder_2_minutes") var reminder2Minutes: Int = -1,
@ColumnInfo(name = "reminder_3_minutes") var reminder3Minutes: Int = -1,
@ColumnInfo(name = "repeat_interval") var repeatInterval: Int = 0,
@ColumnInfo(name = "repeat_rule") var repeatRule: Int = 0,
@ColumnInfo(name = "repeat_limit") var repeatLimit: Long = 0L,
@ColumnInfo(name = "repetition_exceptions") var repetitionExceptions: ArrayList<String> = ArrayList(),
@ColumnInfo(name = "import_id") var importId: String = "",
@ColumnInfo(name = "flags") var flags: Int = 0,
@ColumnInfo(name = "event_type") var eventType: Long = REGULAR_EVENT_TYPE_ID,
@ColumnInfo(name = "parent_id") var parentId: Long = 0,
@ColumnInfo(name = "last_updated") var lastUpdated: Long = 0L,
@ColumnInfo(name = "source") var source: String = SOURCE_SIMPLE_CALENDAR)
: Serializable {
companion object {
@ -20,31 +39,32 @@ data class Event(var id: Int = 0, var startTS: Int = 0, var endTS: Int = 0, var
}
fun addIntervalTime(original: Event) {
val currStart = Formatter.getDateTimeFromTS(startTS)
val oldStart = Formatter.getDateTimeFromTS(startTS)
val newStart: DateTime
newStart = when (repeatInterval) {
DAY -> currStart.plusDays(1)
DAY -> oldStart.plusDays(1)
else -> {
when {
repeatInterval % YEAR == 0 -> when (repeatRule) {
REPEAT_ORDER_WEEKDAY -> addXthDayInterval(currStart, original, false)
REPEAT_ORDER_WEEKDAY_USE_LAST -> addXthDayInterval(currStart, original, true)
else -> currStart.plusYears(repeatInterval / YEAR)
REPEAT_ORDER_WEEKDAY -> addXthDayInterval(oldStart, original, false)
REPEAT_ORDER_WEEKDAY_USE_LAST -> addXthDayInterval(oldStart, original, true)
else -> oldStart.plusYears(repeatInterval / YEAR)
}
repeatInterval % MONTH == 0 -> when (repeatRule) {
REPEAT_SAME_DAY -> addMonthsWithSameDay(currStart, original)
REPEAT_ORDER_WEEKDAY -> addXthDayInterval(currStart, original, false)
REPEAT_ORDER_WEEKDAY_USE_LAST -> addXthDayInterval(currStart, original, true)
else -> currStart.plusMonths(repeatInterval / MONTH).dayOfMonth().withMaximumValue()
REPEAT_SAME_DAY -> addMonthsWithSameDay(oldStart, original)
REPEAT_ORDER_WEEKDAY -> addXthDayInterval(oldStart, original, false)
REPEAT_ORDER_WEEKDAY_USE_LAST -> addXthDayInterval(oldStart, original, true)
else -> oldStart.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)
oldStart.plusDays(1)
}
else -> currStart.plusSeconds(repeatInterval)
else -> oldStart.plusSeconds(repeatInterval)
}
}
}
val newStartTS = newStart.seconds()
val newEndTS = newStartTS + (endTS - startTS)
startTS = newStartTS
@ -99,7 +119,7 @@ data class Event(var id: Int = 0, var startTS: Int = 0, var endTS: Int = 0, var
fun getReminders() = setOf(reminder1Minutes, reminder2Minutes, reminder3Minutes).filter { it != REMINDER_OFF }
// properly return the start time of all-day events as midnight
fun getEventStartTS(): Int {
fun getEventStartTS(): Long {
return if (getIsAllDay()) {
Formatter.getDateTimeFromTS(startTS).withTime(0, 0, 0, 0).seconds()
} else {
@ -116,4 +136,36 @@ data class Event(var id: Int = 0, var startTS: Int = 0, var endTS: Int = 0, var
}
fun getCalDAVCalendarId() = if (source.startsWith(CALDAV)) (source.split("-").lastOrNull() ?: "0").toString().toInt() else 0
// check if its the proper week, for events repeating every x weeks
// get the week number since 1970, not just in the current year
fun isOnProperWeek(startTimes: LongSparseArray<Long>): Boolean {
val initialWeekNumber = Formatter.getDateTimeFromTS(startTimes[id!!]!!).millis / (7 * 24 * 60 * 60 * 1000)
val currentWeekNumber = Formatter.getDateTimeFromTS(startTS).millis / (7 * 24 * 60 * 60 * 1000)
return (initialWeekNumber - currentWeekNumber) % (repeatInterval / WEEK) == 0L
}
fun updateIsPastEvent() {
val endTSToCheck = if (startTS < getNowSeconds() && getIsAllDay()) {
Formatter.getDayEndTS(Formatter.getDayCodeFromTS(endTS))
} else {
endTS
}
isPastEvent = endTSToCheck < getNowSeconds()
}
fun addRepetitionException(daycode: String) {
var newRepetitionExceptions = repetitionExceptions
newRepetitionExceptions.add(daycode)
newRepetitionExceptions = newRepetitionExceptions.distinct().toMutableList() as ArrayList<String>
repetitionExceptions = newRepetitionExceptions
}
var isPastEvent: Boolean
get() = flags and FLAG_IS_PAST_EVENT != 0
set(isPastEvent) {
flags = flags.addBitIf(isPastEvent, FLAG_IS_PAST_EVENT)
}
var color: Int = 0
}

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