diff --git a/app/build.gradle b/app/build.gradle index 91b5cb4fc..5515aa3ec 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,12 +64,12 @@ android { } dependencies { - implementation 'com.simplemobiletools:commons:5.23.10' + implementation 'com.simplemobiletools:commons:5.25.22' implementation 'joda-time:joda-time:2.10.1' implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4' - kapt 'androidx.room:room-compiler:2.2.4' - implementation 'androidx.room:room-runtime:2.2.4' - annotationProcessor 'androidx.room:room-compiler:2.2.4' + kapt 'androidx.room:room-compiler:2.2.5' + implementation 'androidx.room:room-runtime:2.2.5' + annotationProcessor 'androidx.room:room-compiler:2.2.5' } diff --git a/app/src/main/assets/unitedkingdom.ics b/app/src/main/assets/unitedkingdom.ics index b426fcc87..e0cda6eab 100755 --- a/app/src/main/assets/unitedkingdom.ics +++ b/app/src/main/assets/unitedkingdom.ics @@ -10,12 +10,19 @@ END:VEVENT BEGIN:VEVENT SUMMARY:Early May Bank Holiday UID:21626542-636f-43d7-8fa9-bad05bb82dca -DTSTART;VALUE=DATE:20100503 -DTEND;VALUE=DATE:20100504 +DTSTART;VALUE=DATE:20210503 +DTEND;VALUE=DATE:20210504 RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=5;BYDAY=1MO STATUS:CONFIRMED END:VEVENT BEGIN:VEVENT +SUMMARY:Early May Bank Holiday +UID:21626542-636f-43d7-8fa9-bad05bbsds +DTSTART;VALUE=DATE:20200508 +DTEND;VALUE=DATE:20200509 +STATUS:CONFIRMED +END:VEVENT +BEGIN:VEVENT SUMMARY:Summer Bank Holiday UID:5dac6a63-e519-4ad1-a687-2fd5fccb4656 DTSTART;VALUE=DATE:20130826 @@ -47,13 +54,40 @@ UID:ca6af7456b0088abad9a69f9f620f5ac-59@gov.uk STATUS:CONFIRMED END:VEVENT BEGIN:VEVENT -DTEND;VALUE=DATE:20190420 DTSTART;VALUE=DATE:20190419 +DTEND;VALUE=DATE:20190420 SUMMARY:Good Friday UID:ca6af7456b0088abad9a69f9f620f5ac-58@gov.uk STATUS:CONFIRMED END:VEVENT BEGIN:VEVENT +DTSTART;VALUE=DATE:20200410 +DTEND;VALUE=DATE:20200411 +SUMMARY:Good Friday +UID:ca6af7456b0088abad9a69f9f620f5ac-2020-04-10-GoodFriday@gov.uk +STATUS:CONFIRMED +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20200413 +DTEND;VALUE=DATE:20200414 +SUMMARY:Easter Monday +UID:ca6af7456b0088abad9a69f9f620f5ac-2020-04-13-EasterMonday@gov.uk +STATUS:CONFIRMED +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20210402 +DTEND;VALUE=DATE:20210403 +SUMMARY:Good Friday +STATUS:CONFIRMED +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20210405 +DTEND;VALUE=DATE:20210406 +SUMMARY:Easter Monday +UID:ca6af7456b0088abad9a69f9f620f5ac-2021-04-05-EasterMonday@gov.uk +STATUS:CONFIRMED +END:VEVENT +BEGIN:VEVENT SUMMARY:Spring Bank Holiday UID:5dac6a63-e519-4ad1-a687-2fd5fccb4 DTSTART;VALUE=DATE:20130527 diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt index 715ef3580..3db68d31b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt @@ -4,13 +4,15 @@ import android.app.Activity import android.app.DatePickerDialog import android.app.TimePickerDialog import android.content.Intent -import android.database.Cursor +import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.net.Uri import android.os.Bundle -import android.provider.CalendarContract -import android.provider.ContactsContract +import android.provider.CalendarContract.Attendees +import android.provider.ContactsContract.CommonDataKinds +import android.provider.ContactsContract.CommonDataKinds.StructuredName +import android.provider.ContactsContract.Data import android.text.TextUtils import android.text.method.LinkMovementMethod import android.view.Menu @@ -86,7 +88,6 @@ class EventActivity : SimpleActivity() { private var mStoredEventTypes = ArrayList() private var mOriginalTimeZone = DateTimeZone.getDefault().id - private lateinit var mAttendeePlaceholder: Drawable private lateinit var mEventStartDateTime: DateTime private lateinit var mEventEndDateTime: DateTime private lateinit var mEvent: Event @@ -103,8 +104,6 @@ class EventActivity : SimpleActivity() { val intent = intent ?: return mDialogTheme = getDialogTheme() mWasContactsPermissionChecked = hasPermission(PERMISSION_READ_CONTACTS) - mAttendeePlaceholder = resources.getDrawable(R.drawable.attendee_circular_background) - (mAttendeePlaceholder as LayerDrawable).findDrawableByLayerId(R.id.attendee_circular_background).applyColorFilter(config.primaryColor) val eventId = intent.getLongExtra(EVENT_ID, 0L) ensureBackgroundThread { @@ -1259,9 +1258,9 @@ class EventActivity : SimpleActivity() { mAttendees.sortWith(compareBy { it.isMe }.thenBy - { it.status == CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED }.thenBy - { it.status == CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED }.thenBy - { it.status == CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE }.thenBy + { it.status == Attendees.ATTENDEE_STATUS_ACCEPTED }.thenBy + { it.status == Attendees.ATTENDEE_STATUS_DECLINED }.thenBy + { it.status == Attendees.ATTENDEE_STATUS_TENTATIVE }.thenBy { it.status }) mAttendees.reverse() @@ -1347,8 +1346,14 @@ class EventActivity : SimpleActivity() { beVisibleIf(attendee.showStatusImage()) } + event_contact_name.text = if (attendee.isMe) getString(R.string.my_status) else attendee.getPublicName() + if (attendee.isMe) { + (event_contact_name.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.START_OF, event_contact_me_status.id) + } + + val placeholder = BitmapDrawable(resources, context.getContactLetterIcon(event_contact_name.value)) event_contact_image.apply { - attendee.updateImage(applicationContext, this, mAttendeePlaceholder) + attendee.updateImage(applicationContext, this, placeholder) beVisible() } @@ -1357,11 +1362,6 @@ class EventActivity : SimpleActivity() { beGoneIf(attendee.isMe) } - event_contact_name.text = if (attendee.isMe) getString(R.string.my_status) else attendee.getPublicName() - if (attendee.isMe) { - (event_contact_name.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.START_OF, event_contact_me_status.id) - } - if (attendee.isMe) { updateAttendeeMe(this, attendee) } @@ -1373,9 +1373,9 @@ class EventActivity : SimpleActivity() { if (attendee.isMe) { event_contact_attendee.setOnClickListener { val items = arrayListOf( - RadioItem(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED, getString(R.string.going)), - RadioItem(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED, getString(R.string.not_going)), - RadioItem(CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE, getString(R.string.maybe_going)) + RadioItem(Attendees.ATTENDEE_STATUS_ACCEPTED, getString(R.string.going)), + RadioItem(Attendees.ATTENDEE_STATUS_DECLINED, getString(R.string.not_going)), + RadioItem(Attendees.ATTENDEE_STATUS_TENTATIVE, getString(R.string.maybe_going)) ) RadioGroupDialog(this@EventActivity, items, attendee.status) { @@ -1389,8 +1389,8 @@ class EventActivity : SimpleActivity() { private fun getAttendeeStatusImage(attendee: Attendee): Drawable { return resources.getDrawable(when (attendee.status) { - CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED -> R.drawable.ic_check_green - CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED -> R.drawable.ic_cross_red + Attendees.ATTENDEE_STATUS_ACCEPTED -> R.drawable.ic_check_green + Attendees.ATTENDEE_STATUS_DECLINED -> R.drawable.ic_cross_red else -> R.drawable.ic_question_yellow }) } @@ -1398,9 +1398,9 @@ class EventActivity : SimpleActivity() { private fun updateAttendeeMe(holder: RelativeLayout, attendee: Attendee) { holder.apply { event_contact_me_status.text = getString(when (attendee.status) { - CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED -> R.string.going - CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED -> R.string.not_going - CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE -> R.string.maybe_going + Attendees.ATTENDEE_STATUS_ACCEPTED -> R.string.going + Attendees.ATTENDEE_STATUS_DECLINED -> R.string.not_going + Attendees.ATTENDEE_STATUS_TENTATIVE -> R.string.maybe_going else -> R.string.invited }) @@ -1427,7 +1427,7 @@ class EventActivity : SimpleActivity() { val customEmails = mAttendeeAutoCompleteViews.filter { it.isVisible() }.map { it.value }.filter { it.isNotEmpty() }.toMutableList() as ArrayList customEmails.mapTo(attendees) { - Attendee(0, "", it, CalendarContract.Attendees.ATTENDEE_STATUS_INVITED, "", false, CalendarContract.Attendees.RELATIONSHIP_NONE) + Attendee(0, "", it, Attendees.ATTENDEE_STATUS_INVITED, "", false, Attendees.RELATIONSHIP_NONE) } attendees = attendees.distinctBy { it.email }.toMutableList() as ArrayList @@ -1435,8 +1435,8 @@ class EventActivity : SimpleActivity() { val currentCalendar = calDAVHelper.getCalDAVCalendars("", true).firstOrNull { it.id == mEventCalendarId } mAvailableContacts.firstOrNull { it.email == currentCalendar?.accountName }?.apply { attendees = attendees.filter { it.email != currentCalendar?.accountName }.toMutableList() as ArrayList - status = CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED - relationship = CalendarContract.Attendees.RELATIONSHIP_ORGANIZER + status = Attendees.ATTENDEE_STATUS_ACCEPTED + relationship = Attendees.RELATIONSHIP_ORGANIZER attendees.add(this) } } @@ -1446,85 +1446,62 @@ class EventActivity : SimpleActivity() { private fun getNames(): List { val contacts = ArrayList() - val uri = ContactsContract.Data.CONTENT_URI + val uri = Data.CONTENT_URI val projection = arrayOf( - ContactsContract.Data.CONTACT_ID, - ContactsContract.CommonDataKinds.StructuredName.PREFIX, - ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, - ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, - ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, - ContactsContract.CommonDataKinds.StructuredName.SUFFIX, - ContactsContract.CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) + Data.CONTACT_ID, + StructuredName.PREFIX, + StructuredName.GIVEN_NAME, + StructuredName.MIDDLE_NAME, + StructuredName.FAMILY_NAME, + StructuredName.SUFFIX, + StructuredName.PHOTO_THUMBNAIL_URI) - val selection = "${ContactsContract.Data.MIMETYPE} = ?" - val selectionArgs = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) + val selection = "${Data.MIMETYPE} = ?" + val selectionArgs = arrayOf(StructuredName.CONTENT_ITEM_TYPE) - var cursor: Cursor? = null - try { - cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) - if (cursor?.moveToFirst() == true) { - do { - val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) - val prefix = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX) ?: "" - val firstName = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME) ?: "" - val middleName = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME) ?: "" - val surname = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME) ?: "" - val suffix = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX) ?: "" - val photoUri = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" + queryCursor(uri, projection, selection, selectionArgs) { cursor -> + val id = cursor.getIntValue(Data.CONTACT_ID) + val prefix = cursor.getStringValue(StructuredName.PREFIX) ?: "" + val firstName = cursor.getStringValue(StructuredName.GIVEN_NAME) ?: "" + val middleName = cursor.getStringValue(StructuredName.MIDDLE_NAME) ?: "" + val surname = cursor.getStringValue(StructuredName.FAMILY_NAME) ?: "" + val suffix = cursor.getStringValue(StructuredName.SUFFIX) ?: "" + val photoUri = cursor.getStringValue(StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - val names = arrayListOf(prefix, firstName, middleName, surname, suffix).filter { it.trim().isNotEmpty() } - val fullName = TextUtils.join("", names) - if (fullName.isNotEmpty() || photoUri.isNotEmpty()) { - val contact = Attendee(id, fullName, "", CalendarContract.Attendees.ATTENDEE_STATUS_NONE, photoUri, false, CalendarContract.Attendees.RELATIONSHIP_NONE) - contacts.add(contact) - } - } while (cursor.moveToNext()) + val names = arrayListOf(prefix, firstName, middleName, surname, suffix).filter { it.trim().isNotEmpty() } + val fullName = TextUtils.join(" ", names).trim() + if (fullName.isNotEmpty() || photoUri.isNotEmpty()) { + val contact = Attendee(id, fullName, "", Attendees.ATTENDEE_STATUS_NONE, photoUri, false, Attendees.RELATIONSHIP_NONE) + contacts.add(contact) } - } catch (ignored: Exception) { - } finally { - cursor?.close() } return contacts } private fun getEmails(): ArrayList { val contacts = ArrayList() - val uri = ContactsContract.CommonDataKinds.Email.CONTENT_URI + val uri = CommonDataKinds.Email.CONTENT_URI val projection = arrayOf( - ContactsContract.Data.CONTACT_ID, - ContactsContract.CommonDataKinds.Email.DATA + Data.CONTACT_ID, + CommonDataKinds.Email.DATA ) - var cursor: Cursor? = null - try { - cursor = contentResolver.query(uri, projection, null, null, null) - if (cursor?.moveToFirst() == true) { - do { - val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) - val email = cursor.getStringValue(ContactsContract.CommonDataKinds.Email.DATA) ?: continue - val contact = Attendee(id, "", email, CalendarContract.Attendees.ATTENDEE_STATUS_NONE, "", false, CalendarContract.Attendees.RELATIONSHIP_NONE) - contacts.add(contact) - } while (cursor.moveToNext()) - } - } catch (ignored: Exception) { - } finally { - cursor?.close() + queryCursor(uri, projection) { cursor -> + val id = cursor.getIntValue(Data.CONTACT_ID) + val email = cursor.getStringValue(CommonDataKinds.Email.DATA) ?: return@queryCursor + val contact = Attendee(id, "", email, Attendees.ATTENDEE_STATUS_NONE, "", false, Attendees.RELATIONSHIP_NONE) + contacts.add(contact) } + return contacts } private fun updateIconColors() { - val textColor = config.textColor - event_time_image.applyColorFilter(textColor) - event_time_zone_image.applyColorFilter(textColor) - event_repetition_image.applyColorFilter(textColor) - event_reminder_image.applyColorFilter(textColor) - event_type_image.applyColorFilter(textColor) - event_caldav_calendar_image.applyColorFilter(textColor) event_show_on_map.applyColorFilter(getAdjustedPrimaryColor()) - event_reminder_1_type.applyColorFilter(textColor) - event_reminder_2_type.applyColorFilter(textColor) - event_reminder_3_type.applyColorFilter(textColor) - event_attendees_image.applyColorFilter(textColor) + val textColor = config.textColor + arrayOf(event_time_image, event_time_zone_image, event_repetition_image, event_reminder_image, event_type_image, event_caldav_calendar_image, + event_reminder_1_type, event_reminder_2_type, event_reminder_3_type, event_attendees_image).forEach { + it.applyColorFilter(textColor) + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/MainActivity.kt index 537e9da4e..9280193ac 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/MainActivity.kt @@ -8,13 +8,12 @@ import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.ShortcutInfo import android.content.pm.ShortcutManager -import android.database.Cursor import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Icon import android.graphics.drawable.LayerDrawable import android.net.Uri import android.os.Bundle -import android.provider.ContactsContract +import android.provider.ContactsContract.* import android.view.Menu import android.view.MenuItem import android.widget.Toast @@ -32,6 +31,8 @@ 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.helpers.IcsExporter.ExportResult +import com.simplemobiletools.calendar.pro.helpers.IcsImporter.ImportResult import com.simplemobiletools.calendar.pro.jobs.CalDAVUpdateListener import com.simplemobiletools.calendar.pro.models.Event import com.simplemobiletools.calendar.pro.models.EventType @@ -144,12 +145,8 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { storeStateVariables() updateWidgets() - if (config.storedView != EVENTS_LIST_VIEW) { - updateTextColors(calendar_coordinator) - } - search_placeholder.setTextColor(config.textColor) - search_placeholder_2.setTextColor(config.textColor) - calendar_fab.setColors(config.textColor, getAdjustedPrimaryColor(), config.backgroundColor) + updateTextColors(calendar_coordinator) + search_holder.background = ColorDrawable(config.backgroundColor) checkSwipeRefreshAvailability() checkShortcuts() @@ -179,7 +176,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { menu.apply { goToTodayButton = findItem(R.id.go_to_today) findItem(R.id.filter).isVisible = mShouldFilterBeVisible - findItem(R.id.go_to_today).isVisible = shouldGoToTodayBeVisible || config.storedView == EVENTS_LIST_VIEW + findItem(R.id.go_to_today).isVisible = (shouldGoToTodayBeVisible || config.storedView == EVENTS_LIST_VIEW) && !mIsSearchOpen findItem(R.id.go_to_date).isVisible = config.storedView != EVENTS_LIST_VIEW } @@ -188,8 +185,8 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { return true } - override fun onPrepareOptionsMenu(menu: Menu?): Boolean { - menu!!.apply { + override fun onPrepareOptionsMenu(menu: Menu): Boolean { + menu.apply { findItem(R.id.refresh_caldav_calendars).isVisible = config.caldavSync } @@ -279,6 +276,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { search_holder.beVisible() calendar_fab.beGone() searchQueryChanged("") + invalidateOptionsMenu() return true } @@ -286,6 +284,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { mIsSearchOpen = false search_holder.beGone() calendar_fab.beVisibleIf(currentFragments.last() !is YearFragmentsHolder) + invalidateOptionsMenu() return true } }) @@ -488,7 +487,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { val result = IcsImporter(this).importEvents(it as String, eventTypeId, 0, false) handleParseResult(result) - if (result != IcsImporter.ImportResult.IMPORT_FAIL) { + if (result != ImportResult.IMPORT_FAIL) { runOnUiThread { updateViewPager() } @@ -545,11 +544,11 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { } } - private fun handleParseResult(result: IcsImporter.ImportResult) { + private fun handleParseResult(result: ImportResult) { toast(when (result) { - IcsImporter.ImportResult.IMPORT_NOTHING_NEW -> R.string.no_new_items - IcsImporter.ImportResult.IMPORT_OK -> R.string.holidays_imported_successfully - IcsImporter.ImportResult.IMPORT_PARTIAL -> R.string.importing_some_holidays_failed + ImportResult.IMPORT_NOTHING_NEW -> R.string.no_new_items + ImportResult.IMPORT_OK -> R.string.holidays_imported_successfully + ImportResult.IMPORT_PARTIAL -> R.string.importing_some_holidays_failed else -> R.string.importing_holidays_failed }, Toast.LENGTH_LONG) } @@ -557,78 +556,69 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { private fun addContactEvents(birthdays: Boolean, reminders: ArrayList, callback: (Int) -> Unit) { var eventsAdded = 0 var eventsFound = 0 - val uri = ContactsContract.Data.CONTENT_URI - val projection = arrayOf(ContactsContract.Contacts.DISPLAY_NAME, - ContactsContract.CommonDataKinds.Event.CONTACT_ID, - ContactsContract.CommonDataKinds.Event.CONTACT_LAST_UPDATED_TIMESTAMP, - ContactsContract.CommonDataKinds.Event.START_DATE) + val uri = Data.CONTENT_URI + val projection = arrayOf(Contacts.DISPLAY_NAME, + CommonDataKinds.Event.CONTACT_ID, + CommonDataKinds.Event.CONTACT_LAST_UPDATED_TIMESTAMP, + CommonDataKinds.Event.START_DATE) - val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.CommonDataKinds.Event.TYPE} = ?" - val type = if (birthdays) ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY else ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY - val selectionArgs = arrayOf(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, type.toString()) - var cursor: Cursor? = null - try { - cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) - if (cursor?.moveToFirst() == true) { - val dateFormats = getDateFormats() - val existingEvents = if (birthdays) eventsDB.getBirthdays() else eventsDB.getAnniversaries() - val importIDs = HashMap() - existingEvents.forEach { - importIDs[it.importId] = it.startTS - } + val selection = "${Data.MIMETYPE} = ? AND ${CommonDataKinds.Event.TYPE} = ?" + val type = if (birthdays) CommonDataKinds.Event.TYPE_BIRTHDAY else CommonDataKinds.Event.TYPE_ANNIVERSARY + val selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE, type.toString()) - val eventTypeId = if (birthdays) getBirthdaysEventTypeId() else getAnniversariesEventTypeId() + val dateFormats = getDateFormats() + val existingEvents = if (birthdays) eventsDB.getBirthdays() else eventsDB.getAnniversaries() + val importIDs = HashMap() + existingEvents.forEach { + importIDs[it.importId] = it.startTS + } - do { - val contactId = cursor.getIntValue(ContactsContract.CommonDataKinds.Event.CONTACT_ID).toString() - val name = cursor.getStringValue(ContactsContract.Contacts.DISPLAY_NAME) - val startDate = cursor.getStringValue(ContactsContract.CommonDataKinds.Event.START_DATE) + val eventTypeId = if (birthdays) getBirthdaysEventTypeId() else getAnniversariesEventTypeId() - for (format in dateFormats) { - try { - val formatter = SimpleDateFormat(format, Locale.getDefault()) - val date = formatter.parse(startDate) - if (date.year < 70) { - date.year = 70 + queryCursor(uri, projection, selection, selectionArgs, showErrors = true) { cursor -> + val contactId = cursor.getIntValue(CommonDataKinds.Event.CONTACT_ID).toString() + val name = cursor.getStringValue(Contacts.DISPLAY_NAME) + val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE) + + for (format in dateFormats) { + try { + val formatter = SimpleDateFormat(format, Locale.getDefault()) + val date = formatter.parse(startDate) + if (date.year < 70) { + date.year = 70 + } + + val timestamp = date.time / 1000L + val source = if (birthdays) SOURCE_CONTACT_BIRTHDAY else SOURCE_CONTACT_ANNIVERSARY + val lastUpdated = cursor.getLongValue(CommonDataKinds.Event.CONTACT_LAST_UPDATED_TIMESTAMP) + val event = Event(null, timestamp, timestamp, name, reminder1Minutes = reminders[0], reminder2Minutes = reminders[1], + reminder3Minutes = reminders[2], importId = contactId, timeZone = DateTimeZone.getDefault().id, flags = FLAG_ALL_DAY, + repeatInterval = YEAR, repeatRule = REPEAT_SAME_DAY, eventType = eventTypeId, source = source, lastUpdated = lastUpdated) + + val importIDsToDelete = ArrayList() + for ((key, value) in importIDs) { + if (key == contactId && value != timestamp) { + val deleted = eventsDB.deleteBirthdayAnniversary(source, key) + if (deleted == 1) { + importIDsToDelete.add(key) } - - 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(null, timestamp, timestamp, name, reminder1Minutes = reminders[0], reminder2Minutes = reminders[1], - reminder3Minutes = reminders[2], importId = contactId, timeZone = DateTimeZone.getDefault().id, flags = FLAG_ALL_DAY, - repeatInterval = YEAR, repeatRule = REPEAT_SAME_DAY, eventType = eventTypeId, source = source, lastUpdated = lastUpdated) - - val importIDsToDelete = ArrayList() - for ((key, value) in importIDs) { - if (key == contactId && value != timestamp) { - val deleted = eventsDB.deleteBirthdayAnniversary(source, key) - if (deleted == 1) { - importIDsToDelete.add(key) - } - } - } - - importIDsToDelete.forEach { - importIDs.remove(it) - } - - eventsFound++ - if (!importIDs.containsKey(contactId)) { - eventsHelper.insertEvent(event, false, false) { - eventsAdded++ - } - } - break - } catch (e: Exception) { } } - } while (cursor.moveToNext()) + + importIDsToDelete.forEach { + importIDs.remove(it) + } + + eventsFound++ + if (!importIDs.containsKey(contactId)) { + eventsHelper.insertEvent(event, false, false) { + eventsAdded++ + } + } + break + } catch (e: Exception) { + } } - } catch (e: Exception) { - showErrorToast(e) - } finally { - cursor?.close() } runOnUiThread { @@ -839,8 +829,8 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener { } else { IcsExporter().exportEvents(this, outputStream, events, true) { toast(when (it) { - IcsExporter.ExportResult.EXPORT_OK -> R.string.exporting_successful - IcsExporter.ExportResult.EXPORT_PARTIAL -> R.string.exporting_some_entries_failed + ExportResult.EXPORT_OK -> R.string.exporting_successful + ExportResult.EXPORT_PARTIAL -> R.string.exporting_some_entries_failed else -> R.string.exporting_failed }) } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/SettingsActivity.kt index be53e9e29..ca5075a33 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/SettingsActivity.kt @@ -3,7 +3,6 @@ package com.simplemobiletools.calendar.pro.activities import android.app.Activity import android.app.TimePickerDialog import android.content.Intent -import android.content.res.Resources import android.media.AudioManager import android.os.Bundle import android.view.Menu @@ -28,13 +27,11 @@ class SettingsActivity : SimpleActivity() { private val GET_RINGTONE_URI = 1 private val PICK_IMPORT_SOURCE_INTENT = 2 - lateinit var res: Resources private var mStoredPrimaryColor = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_settings) - res = resources mStoredPrimaryColor = config.primaryColor } @@ -351,10 +348,10 @@ class SettingsActivity : SimpleActivity() { settings_reminder_audio_stream.text = getAudioStreamText() settings_reminder_audio_stream_holder.setOnClickListener { val items = arrayListOf( - RadioItem(AudioManager.STREAM_ALARM, res.getString(R.string.alarm_stream)), - RadioItem(AudioManager.STREAM_SYSTEM, res.getString(R.string.system_stream)), - RadioItem(AudioManager.STREAM_NOTIFICATION, res.getString(R.string.notification_stream)), - RadioItem(AudioManager.STREAM_RING, res.getString(R.string.ring_stream))) + RadioItem(AudioManager.STREAM_ALARM, getString(R.string.alarm_stream)), + RadioItem(AudioManager.STREAM_SYSTEM, getString(R.string.system_stream)), + RadioItem(AudioManager.STREAM_NOTIFICATION, getString(R.string.notification_stream)), + RadioItem(AudioManager.STREAM_RING, getString(R.string.ring_stream))) RadioGroupDialog(this@SettingsActivity, items, config.reminderAudioStream) { config.reminderAudioStream = it as Int @@ -487,10 +484,10 @@ class SettingsActivity : SimpleActivity() { settings_font_size.text = getFontSizeText() settings_font_size_holder.setOnClickListener { val items = arrayListOf( - RadioItem(FONT_SIZE_SMALL, res.getString(R.string.small)), - RadioItem(FONT_SIZE_MEDIUM, res.getString(R.string.medium)), - RadioItem(FONT_SIZE_LARGE, res.getString(R.string.large)), - RadioItem(FONT_SIZE_EXTRA_LARGE, res.getString(R.string.extra_large))) + RadioItem(FONT_SIZE_SMALL, getString(R.string.small)), + RadioItem(FONT_SIZE_MEDIUM, getString(R.string.medium)), + RadioItem(FONT_SIZE_LARGE, getString(R.string.large)), + RadioItem(FONT_SIZE_EXTRA_LARGE, getString(R.string.extra_large))) RadioGroupDialog(this@SettingsActivity, items, config.fontSize) { config.fontSize = it as Int @@ -513,12 +510,12 @@ class SettingsActivity : SimpleActivity() { settings_list_widget_view_to_open.text = getDefaultViewText() settings_list_widget_view_to_open_holder.setOnClickListener { val items = arrayListOf( - RadioItem(DAILY_VIEW, res.getString(R.string.daily_view)), - RadioItem(WEEKLY_VIEW, res.getString(R.string.weekly_view)), - RadioItem(MONTHLY_VIEW, res.getString(R.string.monthly_view)), - RadioItem(YEARLY_VIEW, res.getString(R.string.yearly_view)), - RadioItem(EVENTS_LIST_VIEW, res.getString(R.string.simple_event_list)), - RadioItem(LAST_VIEW, res.getString(R.string.last_view))) + RadioItem(DAILY_VIEW, getString(R.string.daily_view)), + RadioItem(WEEKLY_VIEW, getString(R.string.weekly_view)), + RadioItem(MONTHLY_VIEW, getString(R.string.monthly_view)), + RadioItem(YEARLY_VIEW, getString(R.string.yearly_view)), + RadioItem(EVENTS_LIST_VIEW, getString(R.string.simple_event_list)), + RadioItem(LAST_VIEW, getString(R.string.last_view))) RadioGroupDialog(this@SettingsActivity, items, config.listWidgetViewToOpen) { config.listWidgetViewToOpen = it as Int diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/adapters/AutoCompleteTextViewAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/adapters/AutoCompleteTextViewAdapter.kt index 55ed5ffcc..62c2ab030 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/adapters/AutoCompleteTextViewAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/adapters/AutoCompleteTextViewAdapter.kt @@ -1,6 +1,6 @@ package com.simplemobiletools.calendar.pro.adapters -import android.graphics.drawable.LayerDrawable +import android.graphics.drawable.BitmapDrawable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -8,19 +8,13 @@ import android.widget.ArrayAdapter import android.widget.Filter 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.Attendee -import com.simplemobiletools.commons.extensions.applyColorFilter +import com.simplemobiletools.commons.extensions.getContactLetterIcon import com.simplemobiletools.commons.extensions.normalizeString import kotlinx.android.synthetic.main.item_autocomplete_email_name.view.* class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: ArrayList) : ArrayAdapter(activity, 0, contacts) { var resultList = ArrayList() - private var placeholder = activity.resources.getDrawable(R.drawable.attendee_circular_background) - - init { - (placeholder as LayerDrawable).findDrawableByLayerId(R.id.attendee_circular_background).applyColorFilter(activity.config.primaryColor) - } override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val contact = resultList[position] @@ -30,6 +24,13 @@ class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: Ar listItem = LayoutInflater.from(activity).inflate(layout, parent, false) } + val nameToUse = when { + contact.name.isNotEmpty() -> contact.name + contact.email.isNotEmpty() -> contact.email + else -> "S" + } + + val placeholder = BitmapDrawable(activity.resources, context.getContactLetterIcon(nameToUse)) listItem!!.apply { tag = contact.name.isNotEmpty() item_autocomplete_name?.text = contact.name diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/SelectCalendarsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/SelectCalendarsDialog.kt index 3ede22ce8..b8bcebb61 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/SelectCalendarsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/SelectCalendarsDialog.kt @@ -9,19 +9,25 @@ 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.beVisibleIf import com.simplemobiletools.commons.extensions.setupDialogStuff import kotlinx.android.synthetic.main.calendar_item_account.view.* import kotlinx.android.synthetic.main.calendar_item_calendar.view.* import kotlinx.android.synthetic.main.dialog_select_calendars.view.* class SelectCalendarsDialog(val activity: SimpleActivity, val callback: () -> Unit) { - var prevAccount = "" - var dialog: AlertDialog - var view = (activity.layoutInflater.inflate(R.layout.dialog_select_calendars, null) as ViewGroup) + private var prevAccount = "" + private var dialog: AlertDialog + private var view = (activity.layoutInflater.inflate(R.layout.dialog_select_calendars, null) as ViewGroup) init { val ids = activity.config.getSyncedCalendarIdsAsList() val calendars = activity.calDAVHelper.getCalDAVCalendars("", true) + view.apply { + dialog_select_calendars_placeholder.beVisibleIf(calendars.isEmpty()) + dialog_select_calendars_holder.beVisibleIf(calendars.isNotEmpty()) + } + val sorted = calendars.sortedWith(compareBy({ it.accountName }, { it.displayName })) sorted.forEach { if (prevAccount != it.accountName) { @@ -41,8 +47,8 @@ class SelectCalendarsDialog(val activity: SimpleActivity, val callback: () -> Un } private fun addCalendarItem(isEvent: Boolean, text: String, tag: Int = 0, shouldCheck: Boolean = false) { - val calendarItem = activity.layoutInflater.inflate(if (isEvent) R.layout.calendar_item_calendar else R.layout.calendar_item_account, - view.dialog_select_calendars_holder, false) + val layout = if (isEvent) R.layout.calendar_item_calendar else R.layout.calendar_item_account + val calendarItem = activity.layoutInflater.inflate(layout, view.dialog_select_calendars_holder, false) if (isEvent) { calendarItem.calendar_item_calendar_switch.apply { diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt index 0e78589bf..c57d5f99b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt @@ -262,7 +262,7 @@ fun Context.getNotification(pendingIntent: PendingIntent, event: Event, content: val builder = NotificationCompat.Builder(this, channelId) .setContentTitle(contentTitle) .setContentText(contentText) - .setSmallIcon(R.drawable.ic_calendar) + .setSmallIcon(R.drawable.ic_calendar_vector) .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_MAX) .setDefaults(Notification.DEFAULT_LIGHTS) diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt index 7c6a04fcc..888fd503b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt @@ -4,9 +4,7 @@ import android.annotation.SuppressLint import android.content.ContentUris import android.content.ContentValues import android.content.Context -import android.database.Cursor -import android.provider.CalendarContract -import android.provider.CalendarContract.Reminders +import android.provider.CalendarContract.* import android.util.SparseIntArray import com.google.gson.Gson import com.google.gson.reflect.TypeToken @@ -22,6 +20,7 @@ import org.joda.time.format.DateTimeFormat import java.util.* import kotlin.collections.ArrayList +@SuppressLint("MissingPermission") class CalDAVHelper(val context: Context) { private val eventsHelper = context.eventsHelper @@ -58,45 +57,34 @@ class CalDAVHelper(val context: Context) { return calendars } - val uri = CalendarContract.Calendars.CONTENT_URI + val uri = Calendars.CONTENT_URI val projection = arrayOf( - CalendarContract.Calendars._ID, - CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, - CalendarContract.Calendars.ACCOUNT_NAME, - CalendarContract.Calendars.ACCOUNT_TYPE, - CalendarContract.Calendars.OWNER_ACCOUNT, - CalendarContract.Calendars.CALENDAR_COLOR, - CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL) + Calendars._ID, + Calendars.CALENDAR_DISPLAY_NAME, + Calendars.ACCOUNT_NAME, + Calendars.ACCOUNT_TYPE, + Calendars.OWNER_ACCOUNT, + Calendars.CALENDAR_COLOR, + Calendars.CALENDAR_ACCESS_LEVEL) - val selection = if (ids.trim().isNotEmpty()) "${CalendarContract.Calendars._ID} IN ($ids)" else null - var cursor: Cursor? = null - try { - cursor = context.contentResolver.query(uri, projection, selection, null, null) - if (cursor?.moveToFirst() == true) { - do { - val id = cursor.getIntValue(CalendarContract.Calendars._ID) - val displayName = cursor.getStringValue(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME) - val accountName = cursor.getStringValue(CalendarContract.Calendars.ACCOUNT_NAME) - val accountType = cursor.getStringValue(CalendarContract.Calendars.ACCOUNT_TYPE) - val ownerName = cursor.getStringValue(CalendarContract.Calendars.OWNER_ACCOUNT) ?: "" - val color = cursor.getIntValue(CalendarContract.Calendars.CALENDAR_COLOR) - val accessLevel = cursor.getIntValue(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL) - val calendar = CalDAVCalendar(id, displayName, accountName, accountType, ownerName, color, accessLevel) - calendars.add(calendar) - } while (cursor.moveToNext()) - } - } catch (e: Exception) { - if (showToasts) { - context.showErrorToast(e) - } - } finally { - cursor?.close() + val selection = if (ids.trim().isNotEmpty()) "${Calendars._ID} IN ($ids)" else null + context.queryCursor(uri, projection, selection, showErrors = showToasts) { cursor -> + val id = cursor.getIntValue(Calendars._ID) + val displayName = cursor.getStringValue(Calendars.CALENDAR_DISPLAY_NAME) + val accountName = cursor.getStringValue(Calendars.ACCOUNT_NAME) + val accountType = cursor.getStringValue(Calendars.ACCOUNT_TYPE) + val ownerName = cursor.getStringValue(Calendars.OWNER_ACCOUNT) ?: "" + val color = cursor.getIntValue(Calendars.CALENDAR_COLOR) + val accessLevel = cursor.getIntValue(Calendars.CALENDAR_ACCESS_LEVEL) + val calendar = CalDAVCalendar(id, displayName, accountName, accountType, ownerName, color, accessLevel) + calendars.add(calendar) } + return calendars } fun updateCalDAVCalendar(eventType: EventType) { - val uri = CalendarContract.Calendars.CONTENT_URI + val uri = Calendars.CONTENT_URI val values = fillCalendarContentValues(eventType) val newUri = ContentUris.withAppendedId(uri, eventType.caldavCalendarId.toLong()) try { @@ -108,26 +96,23 @@ class CalDAVHelper(val context: Context) { private fun fillCalendarContentValues(eventType: EventType): ContentValues { val colorKey = getEventTypeColorKey(eventType) return ContentValues().apply { - put(CalendarContract.Calendars.CALENDAR_COLOR_KEY, colorKey) - put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, eventType.title) + put(Calendars.CALENDAR_COLOR_KEY, colorKey) + put(Calendars.CALENDAR_DISPLAY_NAME, eventType.title) } } @SuppressLint("MissingPermission") private fun getEventTypeColorKey(eventType: EventType): Int { - val uri = CalendarContract.Colors.CONTENT_URI - val projection = arrayOf(CalendarContract.Colors.COLOR_KEY) - val selection = "${CalendarContract.Colors.COLOR_TYPE} = ? AND ${CalendarContract.Colors.COLOR} = ? AND ${CalendarContract.Colors.ACCOUNT_NAME} = ?" - val selectionArgs = arrayOf(CalendarContract.Colors.TYPE_CALENDAR.toString(), eventType.color.toString(), eventType.caldavEmail) + val uri = Colors.CONTENT_URI + val projection = arrayOf(Colors.COLOR_KEY) + val selection = "${Colors.COLOR_TYPE} = ? AND ${Colors.COLOR} = ? AND ${Colors.ACCOUNT_NAME} = ?" + val selectionArgs = arrayOf(Colors.TYPE_CALENDAR.toString(), eventType.color.toString(), eventType.caldavEmail) - var cursor: Cursor? = null - try { - cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) - if (cursor?.moveToFirst() == true) { - return cursor.getStringValue(CalendarContract.Colors.COLOR_KEY).toInt() + val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) + cursor?.use { + if (cursor.moveToFirst()) { + return cursor.getStringValue(Colors.COLOR_KEY).toInt() } - } finally { - cursor?.close() } return -1 @@ -136,23 +121,15 @@ class CalDAVHelper(val context: Context) { @SuppressLint("MissingPermission") fun getAvailableCalDAVCalendarColors(eventType: EventType): ArrayList { val colors = SparseIntArray() - val uri = CalendarContract.Colors.CONTENT_URI - val projection = arrayOf(CalendarContract.Colors.COLOR, CalendarContract.Colors.COLOR_KEY) - val selection = "${CalendarContract.Colors.COLOR_TYPE} = ? AND ${CalendarContract.Colors.ACCOUNT_NAME} = ?" - val selectionArgs = arrayOf(CalendarContract.Colors.TYPE_CALENDAR.toString(), eventType.caldavEmail) + val uri = Colors.CONTENT_URI + val projection = arrayOf(Colors.COLOR, Colors.COLOR_KEY) + val selection = "${Colors.COLOR_TYPE} = ? AND ${Colors.ACCOUNT_NAME} = ?" + val selectionArgs = arrayOf(Colors.TYPE_CALENDAR.toString(), eventType.caldavEmail) - var cursor: Cursor? = null - try { - cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) - if (cursor?.moveToFirst() == true) { - do { - val colorKey = cursor.getIntValue(CalendarContract.Colors.COLOR_KEY) - val color = cursor.getIntValue(CalendarContract.Colors.COLOR) - colors.put(colorKey, color) - } while (cursor.moveToNext()) - } - } finally { - cursor?.close() + context.queryCursor(uri, projection, selection, selectionArgs) { cursor -> + val colorKey = cursor.getIntValue(Colors.COLOR_KEY) + val color = cursor.getIntValue(Colors.COLOR) + colors.put(colorKey, color) } var sortedColors = ArrayList(colors.size()) @@ -173,151 +150,139 @@ class CalDAVHelper(val context: Context) { importIdsMap[it.importId] = it } - val uri = CalendarContract.Events.CONTENT_URI + val uri = Events.CONTENT_URI val projection = arrayOf( - CalendarContract.Events._ID, - CalendarContract.Events.TITLE, - CalendarContract.Events.DESCRIPTION, - CalendarContract.Events.DTSTART, - CalendarContract.Events.DTEND, - CalendarContract.Events.DURATION, - CalendarContract.Events.EXDATE, - CalendarContract.Events.ALL_DAY, - CalendarContract.Events.RRULE, - CalendarContract.Events.ORIGINAL_ID, - CalendarContract.Events.ORIGINAL_INSTANCE_TIME, - CalendarContract.Events.EVENT_LOCATION, - CalendarContract.Events.EVENT_TIMEZONE, - CalendarContract.Events.CALENDAR_TIME_ZONE, - CalendarContract.Events.DELETED) + Events._ID, + Events.TITLE, + Events.DESCRIPTION, + Events.DTSTART, + Events.DTEND, + Events.DURATION, + Events.EXDATE, + Events.ALL_DAY, + Events.RRULE, + Events.ORIGINAL_ID, + Events.ORIGINAL_INSTANCE_TIME, + Events.EVENT_LOCATION, + Events.EVENT_TIMEZONE, + Events.CALENDAR_TIME_ZONE, + Events.DELETED) - val selection = "${CalendarContract.Events.CALENDAR_ID} = $calendarId" - var cursor: Cursor? = null - try { - cursor = context.contentResolver.query(uri, projection, selection, null, null) - if (cursor?.moveToFirst() == true) { - do { - val deleted = cursor.getIntValue(CalendarContract.Events.DELETED) - if (deleted == 1) { - continue - } + val selection = "${Events.CALENDAR_ID} = $calendarId" + context.queryCursor(uri, projection, selection, showErrors = showToasts) { cursor -> + val deleted = cursor.getIntValue(Events.DELETED) + if (deleted == 1) { + return@queryCursor + } - 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) / 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) ?: "" - val originalId = cursor.getStringValue(CalendarContract.Events.ORIGINAL_ID) - val originalInstanceTime = cursor.getLongValue(CalendarContract.Events.ORIGINAL_INSTANCE_TIME) - val reminders = getCalDAVEventReminders(id) - val attendees = Gson().toJson(getCalDAVEventAttendees(id)) + val id = cursor.getLongValue(Events._ID) + val title = cursor.getStringValue(Events.TITLE) ?: "" + val description = cursor.getStringValue(Events.DESCRIPTION) ?: "" + val startTS = cursor.getLongValue(Events.DTSTART) / 1000L + var endTS = cursor.getLongValue(Events.DTEND) / 1000L + val allDay = cursor.getIntValue(Events.ALL_DAY) + val rrule = cursor.getStringValue(Events.RRULE) ?: "" + val location = cursor.getStringValue(Events.EVENT_LOCATION) ?: "" + val originalId = cursor.getStringValue(Events.ORIGINAL_ID) + val originalInstanceTime = cursor.getLongValue(Events.ORIGINAL_INSTANCE_TIME) + val reminders = getCalDAVEventReminders(id) + val attendees = Gson().toJson(getCalDAVEventAttendees(id)) - if (endTS == 0L) { - val duration = cursor.getStringValue(CalendarContract.Events.DURATION) ?: "" - endTS = startTS + Parser().parseDurationSeconds(duration) - } + if (endTS == 0L) { + val duration = cursor.getStringValue(Events.DURATION) ?: "" + endTS = startTS + Parser().parseDurationSeconds(duration) + } - val reminder1 = reminders.getOrNull(0) - val reminder2 = reminders.getOrNull(1) - val reminder3 = reminders.getOrNull(2) - val importId = getCalDAVEventImportId(calendarId, id) - val eventTimeZone = cursor.getStringValue(CalendarContract.Events.EVENT_TIMEZONE) - ?: cursor.getStringValue(CalendarContract.Events.CALENDAR_TIME_ZONE) ?: DateTimeZone.getDefault().id + val reminder1 = reminders.getOrNull(0) + val reminder2 = reminders.getOrNull(1) + val reminder3 = reminders.getOrNull(2) + val importId = getCalDAVEventImportId(calendarId, id) + val eventTimeZone = cursor.getStringValue(Events.EVENT_TIMEZONE) + ?: cursor.getStringValue(Events.CALENDAR_TIME_ZONE) ?: DateTimeZone.getDefault().id - val source = "$CALDAV-$calendarId" - val repeatRule = Parser().parseRepeatInterval(rrule, startTS) - val event = Event(null, startTS, endTS, title, location, description, reminder1?.minutes ?: REMINDER_OFF, - reminder2?.minutes ?: REMINDER_OFF, reminder3?.minutes ?: REMINDER_OFF, reminder1?.type - ?: REMINDER_NOTIFICATION, reminder2?.type ?: REMINDER_NOTIFICATION, reminder3?.type - ?: REMINDER_NOTIFICATION, repeatRule.repeatInterval, repeatRule.repeatRule, - repeatRule.repeatLimit, ArrayList(), attendees, importId, eventTimeZone, allDay, eventTypeId, source = source) + val source = "$CALDAV-$calendarId" + val repeatRule = Parser().parseRepeatInterval(rrule, startTS) + val event = Event(null, startTS, endTS, title, location, description, reminder1?.minutes ?: REMINDER_OFF, + reminder2?.minutes ?: REMINDER_OFF, reminder3?.minutes ?: REMINDER_OFF, reminder1?.type + ?: REMINDER_NOTIFICATION, reminder2?.type ?: REMINDER_NOTIFICATION, reminder3?.type + ?: REMINDER_NOTIFICATION, repeatRule.repeatInterval, repeatRule.repeatRule, + repeatRule.repeatLimit, ArrayList(), attendees, importId, eventTimeZone, allDay, eventTypeId, source = source) - if (event.getIsAllDay()) { - event.startTS = Formatter.getShiftedImportTimestamp(event.startTS) - event.endTS = Formatter.getShiftedImportTimestamp(event.endTS) - if (event.endTS > event.startTS) { - event.endTS -= DAY - } - } + if (event.getIsAllDay()) { + event.startTS = Formatter.getShiftedImportTimestamp(event.startTS) + event.endTS = Formatter.getShiftedImportTimestamp(event.endTS) + if (event.endTS > event.startTS) { + event.endTS -= DAY + } + } - fetchedEventIds.add(importId) + 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) + // 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!! - event.addRepetitionException(originalDayCode) - eventsHelper.insertEvent(event, false, false) - continue - } - } + event.parentId = parentEvent.id!! + event.addRepetitionException(originalDayCode) + eventsHelper.insertEvent(event, false, false) + return@queryCursor + } + } - // some calendars add repeatable event exceptions with using the "exdate" field, not by creating a child event that is an exception - val exdate = cursor.getStringValue(CalendarContract.Events.EXDATE) ?: "" - if (exdate.length > 8) { - val lines = exdate.split("\n") - for (line in lines) { - val dates = line.split(",") - dates.forEach { - if (it.endsWith("Z")) { - // convert for example "20190216T230000Z" to "20190217000000" in Slovakia in a weird way - val formatter = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss'Z'") - val offset = DateTimeZone.getDefault().getOffset(System.currentTimeMillis()) - val dt = formatter.parseDateTime(it).plusMillis(offset) - val daycode = Formatter.getDayCodeFromDateTime(dt) - event.repetitionExceptions.add(daycode) - } else { - var potentialTS = it.substring(0, 8) - if (potentialTS.areDigitsOnly()) { - event.repetitionExceptions.add(potentialTS) - } else if (it.contains(";")) { - potentialTS = it.substringAfter(";").substring(0, 8) - event.repetitionExceptions.add(potentialTS) - } - } + // some calendars add repeatable event exceptions with using the "exdate" field, not by creating a child event that is an exception + val exdate = cursor.getStringValue(Events.EXDATE) ?: "" + if (exdate.length > 8) { + val lines = exdate.split("\n") + for (line in lines) { + val dates = line.split(",") + dates.forEach { + if (it.endsWith("Z")) { + // convert for example "20190216T230000Z" to "20190217000000" in Slovakia in a weird way + val formatter = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss'Z'") + val offset = DateTimeZone.getDefault().getOffset(System.currentTimeMillis()) + val dt = formatter.parseDateTime(it).plusMillis(offset) + val daycode = Formatter.getDayCodeFromDateTime(dt) + event.repetitionExceptions.add(daycode) + } else { + var potentialTS = it.substring(0, 8) + if (potentialTS.areDigitsOnly()) { + event.repetitionExceptions.add(potentialTS) + } else if (it.contains(";")) { + potentialTS = it.substringAfter(";").substring(0, 8) + event.repetitionExceptions.add(potentialTS) } } } - - if (importIdsMap.containsKey(event.importId)) { - val existingEvent = importIdsMap[importId] - val originalEventId = existingEvent!!.id - - existingEvent.apply { - this.id = null - color = 0 - lastUpdated = 0L - repetitionExceptions = ArrayList() - } - - if (existingEvent.hashCode() != event.hashCode() && title.isNotEmpty()) { - event.id = originalEventId - eventsHelper.updateEvent(event, false, false) - } - } else { - if (title.isNotEmpty()) { - importIdsMap[event.importId] = event - eventsHelper.insertEvent(event, false, false) - } - } - } while (cursor.moveToNext()) + } } - } catch (e: Exception) { - if (showToasts) { - context.showErrorToast(e) + + if (importIdsMap.containsKey(event.importId)) { + val existingEvent = importIdsMap[importId] + val originalEventId = existingEvent!!.id + + existingEvent.apply { + this.id = null + color = 0 + lastUpdated = 0L + repetitionExceptions = ArrayList() + } + + if (existingEvent.hashCode() != event.hashCode() && title.isNotEmpty()) { + event.id = originalEventId + eventsHelper.updateEvent(event, false, false) + } + } else { + if (title.isNotEmpty()) { + importIdsMap[event.importId] = event + eventsHelper.insertEvent(event, false, false) + } } - } finally { - cursor?.close() } val eventIdsToDelete = ArrayList() @@ -335,7 +300,7 @@ class CalDAVHelper(val context: Context) { @SuppressLint("MissingPermission") fun insertCalDAVEvent(event: Event) { - val uri = CalendarContract.Events.CONTENT_URI + val uri = Events.CONTENT_URI val values = fillEventContentValues(event) val newUri = context.contentResolver.insert(uri, values) @@ -350,7 +315,7 @@ class CalDAVHelper(val context: Context) { } fun updateCalDAVEvent(event: Event) { - val uri = CalendarContract.Events.CONTENT_URI + val uri = Events.CONTENT_URI val values = fillEventContentValues(event) val eventRemoteID = event.getCalDAVEventId() event.importId = getCalDAVEventImportId(event.getCalDAVCalendarId(), eventRemoteID) @@ -386,15 +351,15 @@ class CalDAVHelper(val context: Context) { val attendees = Gson().fromJson>(event.attendees, object : TypeToken>() {}.type) ?: ArrayList() attendees.forEach { val contentValues = ContentValues().apply { - put(CalendarContract.Attendees.ATTENDEE_NAME, it.name) - put(CalendarContract.Attendees.ATTENDEE_EMAIL, it.email) - put(CalendarContract.Attendees.ATTENDEE_STATUS, it.status) - put(CalendarContract.Attendees.ATTENDEE_RELATIONSHIP, it.relationship) - put(CalendarContract.Attendees.EVENT_ID, event.getCalDAVEventId()) + put(Attendees.ATTENDEE_NAME, it.name) + put(Attendees.ATTENDEE_EMAIL, it.email) + put(Attendees.ATTENDEE_STATUS, it.status) + put(Attendees.ATTENDEE_RELATIONSHIP, it.relationship) + put(Attendees.EVENT_ID, event.getCalDAVEventId()) } try { - context.contentResolver.insert(CalendarContract.Attendees.CONTENT_URI, contentValues) + context.contentResolver.insert(Attendees.CONTENT_URI, contentValues) } catch (e: Exception) { context.toast(R.string.unknown_error_occurred) } @@ -407,31 +372,31 @@ class CalDAVHelper(val context: Context) { private fun fillEventContentValues(event: Event): ContentValues { return ContentValues().apply { - put(CalendarContract.Events.CALENDAR_ID, event.getCalDAVCalendarId()) - put(CalendarContract.Events.TITLE, event.title) - put(CalendarContract.Events.DESCRIPTION, event.description) - put(CalendarContract.Events.DTSTART, event.startTS * 1000L) - put(CalendarContract.Events.ALL_DAY, if (event.getIsAllDay()) 1 else 0) - put(CalendarContract.Events.EVENT_TIMEZONE, event.getTimeZoneString()) - put(CalendarContract.Events.EVENT_LOCATION, event.location) - put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CONFIRMED) + put(Events.CALENDAR_ID, event.getCalDAVCalendarId()) + put(Events.TITLE, event.title) + put(Events.DESCRIPTION, event.description) + put(Events.DTSTART, event.startTS * 1000L) + put(Events.ALL_DAY, if (event.getIsAllDay()) 1 else 0) + put(Events.EVENT_TIMEZONE, event.getTimeZoneString()) + put(Events.EVENT_LOCATION, event.location) + put(Events.STATUS, Events.STATUS_CONFIRMED) val repeatRule = Parser().getRepeatCode(event) if (repeatRule.isEmpty()) { - putNull(CalendarContract.Events.RRULE) + putNull(Events.RRULE) } else { - put(CalendarContract.Events.RRULE, repeatRule) + put(Events.RRULE, repeatRule) } if (event.getIsAllDay() && event.endTS >= event.startTS) event.endTS += DAY if (event.repeatInterval > 0) { - put(CalendarContract.Events.DURATION, getDurationCode(event)) - putNull(CalendarContract.Events.DTEND) + put(Events.DURATION, getDurationCode(event)) + putNull(Events.DTEND) } else { - put(CalendarContract.Events.DTEND, event.endTS * 1000L) - putNull(CalendarContract.Events.DURATION) + put(Events.DTEND, event.endTS * 1000L) + putNull(Events.DURATION) } } } @@ -443,9 +408,9 @@ class CalDAVHelper(val context: Context) { } private fun clearEventAttendees(event: Event) { - val selection = "${CalendarContract.Attendees.EVENT_ID} = ?" + val selection = "${Attendees.EVENT_ID} = ?" val selectionArgs = arrayOf(event.getCalDAVEventId().toString()) - context.contentResolver.delete(CalendarContract.Attendees.CONTENT_URI, selection, selectionArgs) + context.contentResolver.delete(Attendees.CONTENT_URI, selection, selectionArgs) } private fun getDurationCode(event: Event): String { @@ -463,7 +428,7 @@ class CalDAVHelper(val context: Context) { } fun deleteCalDAVEvent(event: Event) { - val uri = CalendarContract.Events.CONTENT_URI + val uri = Events.CONTENT_URI val contentUri = ContentUris.withAppendedId(uri, event.getCalDAVEventId()) try { context.contentResolver.delete(contentUri, null, null) @@ -473,7 +438,7 @@ class CalDAVHelper(val context: Context) { } fun insertEventRepeatException(event: Event, occurrenceTS: Long) { - val uri = CalendarContract.Events.CONTENT_URI + val uri = Events.CONTENT_URI val values = fillEventRepeatExceptionValues(event, occurrenceTS) try { context.contentResolver.insert(uri, values) @@ -485,13 +450,13 @@ class CalDAVHelper(val context: Context) { private fun fillEventRepeatExceptionValues(event: Event, occurrenceTS: Long): ContentValues { return ContentValues().apply { - put(CalendarContract.Events.CALENDAR_ID, event.getCalDAVCalendarId()) - put(CalendarContract.Events.DTSTART, occurrenceTS) - put(CalendarContract.Events.DTEND, occurrenceTS + (event.endTS - event.startTS)) - put(CalendarContract.Events.ORIGINAL_ID, event.getCalDAVEventId()) - put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().id.toString()) - put(CalendarContract.Events.ORIGINAL_INSTANCE_TIME, occurrenceTS * 1000L) - put(CalendarContract.Events.EXDATE, Formatter.getDayCodeFromTS(occurrenceTS)) + put(Events.CALENDAR_ID, event.getCalDAVCalendarId()) + put(Events.DTSTART, occurrenceTS) + put(Events.DTEND, occurrenceTS + (event.endTS - event.startTS)) + put(Events.ORIGINAL_ID, event.getCalDAVEventId()) + put(Events.EVENT_TIMEZONE, TimeZone.getDefault().id.toString()) + put(Events.ORIGINAL_INSTANCE_TIME, occurrenceTS * 1000L) + put(Events.EXDATE, Formatter.getDayCodeFromTS(occurrenceTS)) } } @@ -502,51 +467,38 @@ class CalDAVHelper(val context: Context) { Reminders.MINUTES, Reminders.METHOD) val selection = "${Reminders.EVENT_ID} = $eventId" - var cursor: Cursor? = null - try { - cursor = context.contentResolver.query(uri, projection, selection, null, null) - if (cursor?.moveToFirst() == true) { - do { - val minutes = cursor.getIntValue(Reminders.MINUTES) - val method = cursor.getIntValue(Reminders.METHOD) - if (method == Reminders.METHOD_ALERT || method == Reminders.METHOD_EMAIL) { - val type = if (method == Reminders.METHOD_EMAIL) REMINDER_EMAIL else REMINDER_NOTIFICATION - val reminder = Reminder(minutes, type) - reminders.add(reminder) - } - } while (cursor.moveToNext()) + + context.queryCursor(uri, projection, selection) { cursor -> + val minutes = cursor.getIntValue(Reminders.MINUTES) + val method = cursor.getIntValue(Reminders.METHOD) + if (method == Reminders.METHOD_ALERT || method == Reminders.METHOD_EMAIL) { + val type = if (method == Reminders.METHOD_EMAIL) REMINDER_EMAIL else REMINDER_NOTIFICATION + val reminder = Reminder(minutes, type) + reminders.add(reminder) } - } finally { - cursor?.close() } + return reminders.sortedBy { it.minutes } } private fun getCalDAVEventAttendees(eventId: Long): List { val attendees = ArrayList() - val uri = CalendarContract.Attendees.CONTENT_URI + val uri = Attendees.CONTENT_URI val projection = arrayOf( - CalendarContract.Attendees.ATTENDEE_NAME, - CalendarContract.Attendees.ATTENDEE_EMAIL, - CalendarContract.Attendees.ATTENDEE_STATUS, - CalendarContract.Attendees.ATTENDEE_RELATIONSHIP) - val selection = "${CalendarContract.Attendees.EVENT_ID} = $eventId" - var cursor: Cursor? = null - try { - cursor = context.contentResolver.query(uri, projection, selection, null, null) - if (cursor?.moveToFirst() == true) { - do { - val name = cursor.getStringValue(CalendarContract.Attendees.ATTENDEE_NAME) ?: "" - val email = cursor.getStringValue(CalendarContract.Attendees.ATTENDEE_EMAIL) ?: "" - val status = cursor.getIntValue(CalendarContract.Attendees.ATTENDEE_STATUS) - val relationship = cursor.getIntValue(CalendarContract.Attendees.ATTENDEE_RELATIONSHIP) - val attendee = Attendee(0, name, email, status, "", false, relationship) - attendees.add(attendee) - } while (cursor.moveToNext()) - } - } finally { - cursor?.close() + Attendees.ATTENDEE_NAME, + Attendees.ATTENDEE_EMAIL, + Attendees.ATTENDEE_STATUS, + Attendees.ATTENDEE_RELATIONSHIP) + val selection = "${Attendees.EVENT_ID} = $eventId" + context.queryCursor(uri, projection, selection) { cursor -> + val name = cursor.getStringValue(Attendees.ATTENDEE_NAME) ?: "" + val email = cursor.getStringValue(Attendees.ATTENDEE_EMAIL) ?: "" + val status = cursor.getIntValue(Attendees.ATTENDEE_STATUS) + val relationship = cursor.getIntValue(Attendees.ATTENDEE_RELATIONSHIP) + val attendee = Attendee(0, name, email, status, "", false, relationship) + attendees.add(attendee) } + return attendees } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt index 87b21ef2b..fbfd5821f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt @@ -3,7 +3,6 @@ package com.simplemobiletools.calendar.pro.helpers import android.app.Activity import android.content.Context import androidx.collection.LongSparseArray -import com.simplemobiletools.calendar.pro.R import com.simplemobiletools.calendar.pro.extensions.* import com.simplemobiletools.calendar.pro.models.Event import com.simplemobiletools.calendar.pro.models.EventType @@ -203,6 +202,17 @@ class EventsHelper(val context: Context) { val events = eventsDB.getEventsForSearch(searchQuery) val displayEventTypes = config.displayEventTypes val filteredEvents = events.filter { displayEventTypes.contains(it.eventType.toString()) } + + val eventTypeColors = LongSparseArray() + eventTypesDB.getEventTypes().forEach { + eventTypeColors.put(it.id!!, it.color) + } + + filteredEvents.forEach { + it.updateIsPastEvent() + it.color = eventTypeColors.get(it.eventType) ?: config.primaryColor + } + activity.runOnUiThread { callback(text, filteredEvents) } @@ -261,10 +271,9 @@ class EventsHelper(val context: Context) { eventTypeColors.put(it.id!!, it.color) } - val primaryColor = context.resources.getColor(R.color.color_primary) events.forEach { it.updateIsPastEvent() - it.color = eventTypeColors.get(it.eventType) ?: primaryColor + it.color = eventTypeColors.get(it.eventType) ?: config.primaryColor } callback(events) diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/IcsImporter.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/IcsImporter.kt index 7bf358760..31ff3a369 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/IcsImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/IcsImporter.kt @@ -1,6 +1,5 @@ package com.simplemobiletools.calendar.pro.helpers -import android.widget.Toast import com.simplemobiletools.calendar.pro.R import com.simplemobiletools.calendar.pro.activities.SimpleActivity import com.simplemobiletools.calendar.pro.extensions.eventsDB @@ -110,7 +109,7 @@ class IcsImporter(val activity: SimpleActivity) { curImportId = line.substring(UID.length).trim() } else if (line.startsWith(RRULE)) { curRrule = line.substring(RRULE.length) - // some RRULRs need to know the events start datetime. If it's yet unknown, postpone RRULE parsing + // some RRULEs need to know the events start datetime. If it's yet unknown, postpone RRULE parsing if (curStart != -1L) { parseRepeatRule() } @@ -227,7 +226,7 @@ class IcsImporter(val activity: SimpleActivity) { eventsHelper.insertEvents(eventsToInsert, true) } catch (e: Exception) { - activity.showErrorToast(e, Toast.LENGTH_LONG) + activity.showErrorToast(e) eventsFailed++ } @@ -248,7 +247,9 @@ class IcsImporter(val activity: SimpleActivity) { return try { if (fullString.startsWith(';')) { val value = fullString.substring(fullString.lastIndexOf(':') + 1).replace(" ", "") - if (!value.contains("T")) { + if (value.isEmpty()) { + return 0 + } else if (!value.contains("T")) { curFlags = curFlags or FLAG_ALL_DAY } @@ -257,7 +258,7 @@ class IcsImporter(val activity: SimpleActivity) { Parser().parseDateTimeValue(fullString.substring(1)) } } catch (e: Exception) { - activity.showErrorToast(e, Toast.LENGTH_LONG) + activity.showErrorToast(e) eventsFailed++ -1 } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt index 6091ecd61..81e480568 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt @@ -40,6 +40,12 @@ class Parser { if (interval.areDigitsOnly() && interval.toInt() % 7 == 0) { val dateTime = Formatter.getDateTimeFromTS(startTS) repeatRule = Math.pow(2.0, (dateTime.dayOfWeek - 1).toDouble()).toInt() + } else if (fullString.contains("BYDAY")) { + // some services use weekly repetition for repeating on specific week days, some use daily + // make these produce the same result + // RRULE:FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR + // RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR + repeatInterval = WEEK_SECONDS } } } else if (key == COUNT) { diff --git a/app/src/main/res/drawable-hdpi/ic_calendar.png b/app/src/main/res/drawable-hdpi/ic_calendar.png deleted file mode 100644 index fd7bdc0a5..000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_calendar.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_calendar.png b/app/src/main/res/drawable-xhdpi/ic_calendar.png deleted file mode 100644 index 2e3cd13c4..000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_calendar.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_calendar.png b/app/src/main/res/drawable-xxhdpi/ic_calendar.png deleted file mode 100644 index 0e3a7cf03..000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_calendar.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_calendar.png b/app/src/main/res/drawable-xxxhdpi/ic_calendar.png deleted file mode 100644 index 47247db25..000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_calendar.png and /dev/null differ diff --git a/app/src/main/res/drawable/attendee_circular_background.xml b/app/src/main/res/drawable/attendee_circular_background.xml deleted file mode 100644 index 8101204b6..000000000 --- a/app/src/main/res/drawable/attendee_circular_background.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_calendar_vector.xml b/app/src/main/res/drawable/ic_calendar_vector.xml new file mode 100644 index 000000000..f07e6b2c5 --- /dev/null +++ b/app/src/main/res/drawable/ic_calendar_vector.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_group_vector.xml b/app/src/main/res/drawable/ic_group_vector.xml deleted file mode 100644 index 120218d2c..000000000 --- a/app/src/main/res/drawable/ic_group_vector.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_event.xml b/app/src/main/res/layout/activity_event.xml index cf59d9d0f..7d34c0e94 100644 --- a/app/src/main/res/layout/activity_event.xml +++ b/app/src/main/res/layout/activity_event.xml @@ -408,7 +408,7 @@ android:layout_marginStart="@dimen/normal_margin" android:layout_marginTop="@dimen/small_margin" android:padding="@dimen/medium_margin" - android:src="@drawable/ic_group_vector"/> + android:src="@drawable/ic_people_vector"/> - + android:layout_height="match_parent" /> @@ -27,7 +26,7 @@ android:contentDescription="@string/new_event" android:src="@drawable/ic_plus_vector" app:backgroundTint="@color/color_primary" - app:rippleColor="@color/pressed_item_foreground"/> + app:rippleColor="@color/pressed_item_foreground" /> + android:textSize="@dimen/bigger_text_size" + android:textStyle="italic" /> + android:textSize="@dimen/bigger_text_size" + android:textStyle="italic" /> + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" /> diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index a9be6b66f..328573932 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -120,13 +120,6 @@ - - - - - - - - - - - - - - - - - - - + android:textSize="@dimen/normal_text_size" + tools:text="Account" /> diff --git a/app/src/main/res/layout/dialog_select_calendars.xml b/app/src/main/res/layout/dialog_select_calendars.xml index c0c66b1c7..199045e39 100644 --- a/app/src/main/res/layout/dialog_select_calendars.xml +++ b/app/src/main/res/layout/dialog_select_calendars.xml @@ -1,16 +1,29 @@ - - + android:layout_height="wrap_content"> - + + + + + diff --git a/app/src/main/res/layout/fragment_event_list.xml b/app/src/main/res/layout/fragment_event_list.xml index 4a8e940e2..12c629e6c 100644 --- a/app/src/main/res/layout/fragment_event_list.xml +++ b/app/src/main/res/layout/fragment_event_list.xml @@ -1,6 +1,5 @@ - + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" /> + android:textStyle="italic" + android:visibility="gone" /> + android:visibility="gone" /> diff --git a/app/src/main/res/layout/item_autocomplete_email.xml b/app/src/main/res/layout/item_autocomplete_email.xml index 56fd8b08f..6545ebc38 100644 --- a/app/src/main/res/layout/item_autocomplete_email.xml +++ b/app/src/main/res/layout/item_autocomplete_email.xml @@ -27,6 +27,7 @@ android:lines="1" android:maxLines="1" android:paddingStart="@dimen/medium_margin" + android:paddingEnd="@dimen/medium_margin" android:singleLine="true" android:textSize="@dimen/bigger_text_size" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/layout/item_autocomplete_email_name.xml b/app/src/main/res/layout/item_autocomplete_email_name.xml index c11ab5886..a98d0dfe1 100644 --- a/app/src/main/res/layout/item_autocomplete_email_name.xml +++ b/app/src/main/res/layout/item_autocomplete_email_name.xml @@ -1,6 +1,5 @@ - + app:layout_constraintTop_toTopOf="parent" /> + tools:text="Simple Mobile" /> + tools:text="hello@simplemobiletools.com" /> diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index ccc26c703..9f7a67ce5 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -207,6 +207,7 @@ اختر لون مختلف (يمكن تطبيقه محليا فقط) لا يمكنك التعديل في هذا التقويم مناسبة غير موجودة. من فضلك فَعّل مُزامنة CalDAV للحصول على التقويم المناسب من الإعدادات. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index e68ff44e1..6bdba1b9c 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 61efafc04..d0fcd91b5 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -211,6 +211,7 @@ একটি আলাদা রঙ সিলেক্ট করুন(কেবল স্থানীয়ভাবে প্রয়োগ করা যেতে পারে) আপনার সিলেক্টেড ক্যালেন্ডারে লেখার অনুমতি নেই ইভেন্ট পাওয়া যায় নি। অ্যাপ্লিকেশন সেটিংসে উপযুক্ত ক্যালেন্ডারের জন্য দয়া করে CalDAV সিঙ্ক সক্ষম করুন। + No synchronizable calendars have been found diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index d803a6c23..7ce249a46 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 76c8ea489..cc0aaf214 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -207,6 +207,7 @@ Zvolit jinou barvu (možná bude nastavena pouze lokálně) Nemáte oprávnění pro zápis do zvoleného kalendáře Událost nenalezena. Prosím, povolte CalDAV synchronizaci příslušného kalendáře v nastavení aplikace. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index f188ed30f..658f93de6 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -207,6 +207,7 @@ Vælg en anden farve (den kan være tilføjet lokalt) Du har ikke tilladelse til at skrive i den valgte kalender Begivenheden blev ikke fundet. Aktiver CalDAV-synkronisering med den relevante kalender i app-indstillingerne. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ecbf787f9..13acab114 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -207,6 +207,7 @@ Wähle eine andere Farbe (wird möglicherweise nur lokal angewendet) Dir fehlt die Berechtigung zum Ändern des gewählten Kalenders Der Termin wurde nicht gefunden. Bitte aktiviere die Synchronisierung für den Kalender in den Einstellungen. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 901a4ac64..19cf123de 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -207,6 +207,7 @@ Επιλέξτε διαφορετικό χρώμα (μπορεί να εφαρμοστεί μόνο τοπικά) Δεν επιτρέπεται η εγγραφή στο επιλεγμένο ημερολόγιο Δεν βρέθηκε Εκδήλωση. Παρακαλώ ενεργοποιήστε το συγχρονισμό CalDAV του Ημερολογίου από τις ρυθμίσεις της εφαρμογής. + Δεν μπόρεσαν να βρεθούν συγχρονισμένα Ημερολόγια diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 05e07080d..c21dde904 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -207,6 +207,7 @@ Seleccionar un color diferente (localmente) No tiene permiso para modificar el calendario Evento no encontrado. Habilite la sincronización de CalDAV para los calendarios en la configuración. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index ab9e859f7..06945e6b1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -208,6 +208,7 @@ Sélectionnez une couleur différente (peut être appliqué localement uniquement) Vous n\’êtes pas autorisé à écrire dans l\’agenda sélectionné Événement introuvable. Veuillez activer la synchronisation CalDAV pour le calendrier approprié dans les paramètres de l’application. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 3e24e9375..852725c1b 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -207,6 +207,7 @@ Escolle un color diferente (pode que só se aplique localmente) Non tes permiso para escribir no calendario seleccionado Evento non atopado. Activa a sincronización de CalDAV para o calendario apropiado nos axustes da aplicación. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index c7c7f4474..1316c78a8 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -207,6 +207,7 @@ בחירת צבע שונה (ייתכן שיישמר מקומית בלבד) לא קיימת הרשאת כתיבה ליומנים הנבחרים Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 15b17c9a2..af156a9b2 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 9fc8aecbd..a38b19485 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -207,6 +207,7 @@ Odaberite drugu boju (može se primijeniti samo lokalno) Nije vam dopušteno pisati u odabranom kalendaru Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 055f4726c..9d9883de1 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 25338348f..c275bb6a4 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -207,6 +207,7 @@ Pilih warna yang berbeda (mungkin hanya diterapkan secara lokal) Anda tidak diizinkan untuk membuat/mengubah acara pada kalender yang dipilih Acara tidak ditemukan. Silakan aktifkan sinkronisasi CalDAV untuk kalender terkait di dalam pengaturan aplikasi. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 25338348f..c275bb6a4 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -207,6 +207,7 @@ Pilih warna yang berbeda (mungkin hanya diterapkan secara lokal) Anda tidak diizinkan untuk membuat/mengubah acara pada kalender yang dipilih Acara tidak ditemukan. Silakan aktifkan sinkronisasi CalDAV untuk kalender terkait di dalam pengaturan aplikasi. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index e83d7e221..c41c3069f 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -207,6 +207,7 @@ Seleziona un colore differente (potrebbe essere applicato solamente in locale) Non si hanno i permessi per scrivere nel calendario selezionato Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index aa37231b5..9d678930c 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -207,6 +207,7 @@ בחירת צבע שונה (ייתכן שיישמר מקומית בלבד) לא קיימת הרשאת כתיבה ליומנים הנבחרים Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index dbfcc278c..c10641c0c 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index f621e2a61..0dd2eb08d 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -207,6 +207,7 @@ 다른 색상을 선택해주세요(로컬에만 적용 가능) 선택한 캘린더에 작성할 수 없습니다. 일정을 찾을 수 없습니다. 앱 설정에서 해당 캘린더에 대해 CalDAV 동기화를 활성화해주세요. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index d92e1c56e..f1ca91e7a 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 297378842..4e2b3cc75 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -207,6 +207,7 @@ Izvēlieties citu krāsu (var tikt izmantota tikai lokāli) Jums izvēlētajā kalendārā rakstīt nav ļauts Notikums nav atrasts. Lūdzu, lietotnes iestatījumos iespējojiet CalDAV sinhronizāciju attiecīgajam kalendāram. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 0fd38b5a0..2cdfc4e8b 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index e5c8d0d6d..30c083ce2 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -207,6 +207,7 @@ Kies een andere kleur (mogelijk alleen voor dit apparaat) Kan geen wijzigingen aanbrengen in deze agenda Afspraak niet gevonden. Schakel via Instellingen de CalDAV-synchronisatie in voor deze agenda. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index ad3d1906f..2386c228c 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index e75e8bca9..e84beaec8 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1c57cd002..7df090b64 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 25f1f275b..465d61eaf 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -207,6 +207,7 @@ Selecione uma cor diferente (pode ser aplicada apenas localmente) Não tem permissão para escrever no calendário selecionado Evento não encontrado. Ative a sincronização CalDAV para os calendários apropriados nas definições. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index bb1e1ebc3..04bd9e3de 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -207,6 +207,7 @@ Выберите другой цвет (применяется локально) Запись в выбранный календарь запрещена Событие не найдено. Пожалуйста, включите CalDAV-синхронизацию для соответствующего календаря в настройках приложения. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 512395ce4..17ccbb24a 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -207,6 +207,7 @@ Zvoliť inú farbu (možno bude aplikovaná iba lokálne) Nemáte dostatočné oprávnenie na písanie do zvoleného kalendára Udalosť nebola nájdená. Prosím povoľte CalDAV synchronizáciu príslušného kalendára v nastaveniach aplikácie. + Nenašli sa žiadne synchronizovateľné kalendáre diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 17192eef5..193d5e6d7 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -207,6 +207,7 @@ Välj en annan färg (tillämpas kanske bara lokalt) Du har inte behörighet att redigera den valda kalendern Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 4961c7b4e..cd847ce5e 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -207,6 +207,7 @@ Farklı bir renk seçin (yalnızca yerel olarak uygulanabilir) Seçili takvime yazmanıza izin verilmiyor Etkinlik bulunamadı. Lütfen uygulama ayarlarından uygun takvim için CalDAV senkronizasyonunu etkinleştirin. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 3115e511a..e1d45fffe 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -207,6 +207,7 @@ Обрати інший колір (можна застосувати лише локально) Ви не можете редагувати обраний календар Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 56240c26c..da7dae207 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -207,6 +207,7 @@     选择不同的颜色 (只能被添加于本机端)     你不被允许对选择的行事历写入 Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found           diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 0e2f3e6fe..b1d91a4c6 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -207,6 +207,7 @@ 選擇不同的顏色 (只能被添加於本機端) 你不被允許對選擇的行事曆寫入 Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index dca9d4cd6..cd1cc10ab 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -207,6 +207,7 @@ 選擇不同的顏色 (只能被添加於本機端) 你不被允許對選擇的行事曆寫入 未發現活動。請在程式設定中為合適的行事曆啟用CalDAV同步。 + No synchronizable calendars have been found diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 172ff5675..f2f9fbb5b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -207,6 +207,7 @@ Select a different color (might be applied locally only) You are not allowed to write in the selected calendar Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings. + No synchronizable calendars have been found diff --git a/build.gradle b/build.gradle index ad2a02639..8fed03cc2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.70' + ext.kotlin_version = '1.3.72' repositories { google() @@ -10,7 +10,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.6.1' + classpath 'com.android.tools.build:gradle:3.6.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "de.timfreiheit.resourceplaceholders:placeholders:0.3" diff --git a/fastlane/metadata/android/en-US/images/app_icon.png b/fastlane/metadata/android/en-US/images/app_icon.png new file mode 100644 index 000000000..ff67802d3 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/app_icon.png differ