Merge pull request #32 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2020-04-17 23:02:36 +03:00 committed by GitHub
commit 56a74d80be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 554 additions and 605 deletions

View file

@ -64,12 +64,12 @@ android {
} }
dependencies { dependencies {
implementation 'com.simplemobiletools:commons:5.23.10' implementation 'com.simplemobiletools:commons:5.25.22'
implementation 'joda-time:joda-time:2.10.1' implementation 'joda-time:joda-time:2.10.1'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
kapt 'androidx.room:room-compiler:2.2.4' kapt 'androidx.room:room-compiler:2.2.5'
implementation 'androidx.room:room-runtime:2.2.4' implementation 'androidx.room:room-runtime:2.2.5'
annotationProcessor 'androidx.room:room-compiler:2.2.4' annotationProcessor 'androidx.room:room-compiler:2.2.5'
} }

View file

@ -10,12 +10,19 @@ END:VEVENT
BEGIN:VEVENT BEGIN:VEVENT
SUMMARY:Early May Bank Holiday SUMMARY:Early May Bank Holiday
UID:21626542-636f-43d7-8fa9-bad05bb82dca UID:21626542-636f-43d7-8fa9-bad05bb82dca
DTSTART;VALUE=DATE:20100503 DTSTART;VALUE=DATE:20210503
DTEND;VALUE=DATE:20100504 DTEND;VALUE=DATE:20210504
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=5;BYDAY=1MO RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=5;BYDAY=1MO
STATUS:CONFIRMED STATUS:CONFIRMED
END:VEVENT END:VEVENT
BEGIN: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 SUMMARY:Summer Bank Holiday
UID:5dac6a63-e519-4ad1-a687-2fd5fccb4656 UID:5dac6a63-e519-4ad1-a687-2fd5fccb4656
DTSTART;VALUE=DATE:20130826 DTSTART;VALUE=DATE:20130826
@ -47,13 +54,40 @@ UID:ca6af7456b0088abad9a69f9f620f5ac-59@gov.uk
STATUS:CONFIRMED STATUS:CONFIRMED
END:VEVENT END:VEVENT
BEGIN:VEVENT BEGIN:VEVENT
DTEND;VALUE=DATE:20190420
DTSTART;VALUE=DATE:20190419 DTSTART;VALUE=DATE:20190419
DTEND;VALUE=DATE:20190420
SUMMARY:Good Friday SUMMARY:Good Friday
UID:ca6af7456b0088abad9a69f9f620f5ac-58@gov.uk UID:ca6af7456b0088abad9a69f9f620f5ac-58@gov.uk
STATUS:CONFIRMED STATUS:CONFIRMED
END:VEVENT END:VEVENT
BEGIN: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 SUMMARY:Spring Bank Holiday
UID:5dac6a63-e519-4ad1-a687-2fd5fccb4 UID:5dac6a63-e519-4ad1-a687-2fd5fccb4
DTSTART;VALUE=DATE:20130527 DTSTART;VALUE=DATE:20130527

View file

@ -4,13 +4,15 @@ import android.app.Activity
import android.app.DatePickerDialog import android.app.DatePickerDialog
import android.app.TimePickerDialog import android.app.TimePickerDialog
import android.content.Intent import android.content.Intent
import android.database.Cursor import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable import android.graphics.drawable.LayerDrawable
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.CalendarContract import android.provider.CalendarContract.Attendees
import android.provider.ContactsContract import android.provider.ContactsContract.CommonDataKinds
import android.provider.ContactsContract.CommonDataKinds.StructuredName
import android.provider.ContactsContract.Data
import android.text.TextUtils import android.text.TextUtils
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.Menu import android.view.Menu
@ -86,7 +88,6 @@ class EventActivity : SimpleActivity() {
private var mStoredEventTypes = ArrayList<EventType>() private var mStoredEventTypes = ArrayList<EventType>()
private var mOriginalTimeZone = DateTimeZone.getDefault().id private var mOriginalTimeZone = DateTimeZone.getDefault().id
private lateinit var mAttendeePlaceholder: Drawable
private lateinit var mEventStartDateTime: DateTime private lateinit var mEventStartDateTime: DateTime
private lateinit var mEventEndDateTime: DateTime private lateinit var mEventEndDateTime: DateTime
private lateinit var mEvent: Event private lateinit var mEvent: Event
@ -103,8 +104,6 @@ class EventActivity : SimpleActivity() {
val intent = intent ?: return val intent = intent ?: return
mDialogTheme = getDialogTheme() mDialogTheme = getDialogTheme()
mWasContactsPermissionChecked = hasPermission(PERMISSION_READ_CONTACTS) 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) val eventId = intent.getLongExtra(EVENT_ID, 0L)
ensureBackgroundThread { ensureBackgroundThread {
@ -1259,9 +1258,9 @@ class EventActivity : SimpleActivity() {
mAttendees.sortWith(compareBy<Attendee> mAttendees.sortWith(compareBy<Attendee>
{ it.isMe }.thenBy { it.isMe }.thenBy
{ it.status == CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED }.thenBy { it.status == Attendees.ATTENDEE_STATUS_ACCEPTED }.thenBy
{ it.status == CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED }.thenBy { it.status == Attendees.ATTENDEE_STATUS_DECLINED }.thenBy
{ it.status == CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE }.thenBy { it.status == Attendees.ATTENDEE_STATUS_TENTATIVE }.thenBy
{ it.status }) { it.status })
mAttendees.reverse() mAttendees.reverse()
@ -1347,8 +1346,14 @@ class EventActivity : SimpleActivity() {
beVisibleIf(attendee.showStatusImage()) 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 { event_contact_image.apply {
attendee.updateImage(applicationContext, this, mAttendeePlaceholder) attendee.updateImage(applicationContext, this, placeholder)
beVisible() beVisible()
} }
@ -1357,11 +1362,6 @@ class EventActivity : SimpleActivity() {
beGoneIf(attendee.isMe) 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) { if (attendee.isMe) {
updateAttendeeMe(this, attendee) updateAttendeeMe(this, attendee)
} }
@ -1373,9 +1373,9 @@ class EventActivity : SimpleActivity() {
if (attendee.isMe) { if (attendee.isMe) {
event_contact_attendee.setOnClickListener { event_contact_attendee.setOnClickListener {
val items = arrayListOf( val items = arrayListOf(
RadioItem(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED, getString(R.string.going)), RadioItem(Attendees.ATTENDEE_STATUS_ACCEPTED, getString(R.string.going)),
RadioItem(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED, getString(R.string.not_going)), RadioItem(Attendees.ATTENDEE_STATUS_DECLINED, getString(R.string.not_going)),
RadioItem(CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE, getString(R.string.maybe_going)) RadioItem(Attendees.ATTENDEE_STATUS_TENTATIVE, getString(R.string.maybe_going))
) )
RadioGroupDialog(this@EventActivity, items, attendee.status) { RadioGroupDialog(this@EventActivity, items, attendee.status) {
@ -1389,8 +1389,8 @@ class EventActivity : SimpleActivity() {
private fun getAttendeeStatusImage(attendee: Attendee): Drawable { private fun getAttendeeStatusImage(attendee: Attendee): Drawable {
return resources.getDrawable(when (attendee.status) { return resources.getDrawable(when (attendee.status) {
CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED -> R.drawable.ic_check_green Attendees.ATTENDEE_STATUS_ACCEPTED -> R.drawable.ic_check_green
CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED -> R.drawable.ic_cross_red Attendees.ATTENDEE_STATUS_DECLINED -> R.drawable.ic_cross_red
else -> R.drawable.ic_question_yellow else -> R.drawable.ic_question_yellow
}) })
} }
@ -1398,9 +1398,9 @@ class EventActivity : SimpleActivity() {
private fun updateAttendeeMe(holder: RelativeLayout, attendee: Attendee) { private fun updateAttendeeMe(holder: RelativeLayout, attendee: Attendee) {
holder.apply { holder.apply {
event_contact_me_status.text = getString(when (attendee.status) { event_contact_me_status.text = getString(when (attendee.status) {
CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED -> R.string.going Attendees.ATTENDEE_STATUS_ACCEPTED -> R.string.going
CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED -> R.string.not_going Attendees.ATTENDEE_STATUS_DECLINED -> R.string.not_going
CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE -> R.string.maybe_going Attendees.ATTENDEE_STATUS_TENTATIVE -> R.string.maybe_going
else -> R.string.invited 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<String> val customEmails = mAttendeeAutoCompleteViews.filter { it.isVisible() }.map { it.value }.filter { it.isNotEmpty() }.toMutableList() as ArrayList<String>
customEmails.mapTo(attendees) { 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<Attendee> attendees = attendees.distinctBy { it.email }.toMutableList() as ArrayList<Attendee>
@ -1435,8 +1435,8 @@ class EventActivity : SimpleActivity() {
val currentCalendar = calDAVHelper.getCalDAVCalendars("", true).firstOrNull { it.id == mEventCalendarId } val currentCalendar = calDAVHelper.getCalDAVCalendars("", true).firstOrNull { it.id == mEventCalendarId }
mAvailableContacts.firstOrNull { it.email == currentCalendar?.accountName }?.apply { mAvailableContacts.firstOrNull { it.email == currentCalendar?.accountName }?.apply {
attendees = attendees.filter { it.email != currentCalendar?.accountName }.toMutableList() as ArrayList<Attendee> attendees = attendees.filter { it.email != currentCalendar?.accountName }.toMutableList() as ArrayList<Attendee>
status = CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED status = Attendees.ATTENDEE_STATUS_ACCEPTED
relationship = CalendarContract.Attendees.RELATIONSHIP_ORGANIZER relationship = Attendees.RELATIONSHIP_ORGANIZER
attendees.add(this) attendees.add(this)
} }
} }
@ -1446,85 +1446,62 @@ class EventActivity : SimpleActivity() {
private fun getNames(): List<Attendee> { private fun getNames(): List<Attendee> {
val contacts = ArrayList<Attendee>() val contacts = ArrayList<Attendee>()
val uri = ContactsContract.Data.CONTENT_URI val uri = Data.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
ContactsContract.Data.CONTACT_ID, Data.CONTACT_ID,
ContactsContract.CommonDataKinds.StructuredName.PREFIX, StructuredName.PREFIX,
ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, StructuredName.GIVEN_NAME,
ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, StructuredName.MIDDLE_NAME,
ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, StructuredName.FAMILY_NAME,
ContactsContract.CommonDataKinds.StructuredName.SUFFIX, StructuredName.SUFFIX,
ContactsContract.CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) StructuredName.PHOTO_THUMBNAIL_URI)
val selection = "${ContactsContract.Data.MIMETYPE} = ?" val selection = "${Data.MIMETYPE} = ?"
val selectionArgs = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) val selectionArgs = arrayOf(StructuredName.CONTENT_ITEM_TYPE)
var cursor: Cursor? = null queryCursor(uri, projection, selection, selectionArgs) { cursor ->
try { val id = cursor.getIntValue(Data.CONTACT_ID)
cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) val prefix = cursor.getStringValue(StructuredName.PREFIX) ?: ""
if (cursor?.moveToFirst() == true) { val firstName = cursor.getStringValue(StructuredName.GIVEN_NAME) ?: ""
do { val middleName = cursor.getStringValue(StructuredName.MIDDLE_NAME) ?: ""
val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val surname = cursor.getStringValue(StructuredName.FAMILY_NAME) ?: ""
val prefix = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX) ?: "" val suffix = cursor.getStringValue(StructuredName.SUFFIX) ?: ""
val firstName = cursor.getStringValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME) ?: "" val photoUri = cursor.getStringValue(StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
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) ?: ""
val names = arrayListOf(prefix, firstName, middleName, surname, suffix).filter { it.trim().isNotEmpty() } val names = arrayListOf(prefix, firstName, middleName, surname, suffix).filter { it.trim().isNotEmpty() }
val fullName = TextUtils.join("", names) val fullName = TextUtils.join(" ", names).trim()
if (fullName.isNotEmpty() || photoUri.isNotEmpty()) { if (fullName.isNotEmpty() || photoUri.isNotEmpty()) {
val contact = Attendee(id, fullName, "", CalendarContract.Attendees.ATTENDEE_STATUS_NONE, photoUri, false, CalendarContract.Attendees.RELATIONSHIP_NONE) val contact = Attendee(id, fullName, "", Attendees.ATTENDEE_STATUS_NONE, photoUri, false, Attendees.RELATIONSHIP_NONE)
contacts.add(contact) contacts.add(contact)
}
} while (cursor.moveToNext())
} }
} catch (ignored: Exception) {
} finally {
cursor?.close()
} }
return contacts return contacts
} }
private fun getEmails(): ArrayList<Attendee> { private fun getEmails(): ArrayList<Attendee> {
val contacts = ArrayList<Attendee>() val contacts = ArrayList<Attendee>()
val uri = ContactsContract.CommonDataKinds.Email.CONTENT_URI val uri = CommonDataKinds.Email.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
ContactsContract.Data.CONTACT_ID, Data.CONTACT_ID,
ContactsContract.CommonDataKinds.Email.DATA CommonDataKinds.Email.DATA
) )
var cursor: Cursor? = null queryCursor(uri, projection) { cursor ->
try { val id = cursor.getIntValue(Data.CONTACT_ID)
cursor = contentResolver.query(uri, projection, null, null, null) val email = cursor.getStringValue(CommonDataKinds.Email.DATA) ?: return@queryCursor
if (cursor?.moveToFirst() == true) { val contact = Attendee(id, "", email, Attendees.ATTENDEE_STATUS_NONE, "", false, Attendees.RELATIONSHIP_NONE)
do { contacts.add(contact)
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()
} }
return contacts return contacts
} }
private fun updateIconColors() { 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_show_on_map.applyColorFilter(getAdjustedPrimaryColor())
event_reminder_1_type.applyColorFilter(textColor) val textColor = config.textColor
event_reminder_2_type.applyColorFilter(textColor) arrayOf(event_time_image, event_time_zone_image, event_repetition_image, event_reminder_image, event_type_image, event_caldav_calendar_image,
event_reminder_3_type.applyColorFilter(textColor) event_reminder_1_type, event_reminder_2_type, event_reminder_3_type, event_attendees_image).forEach {
event_attendees_image.applyColorFilter(textColor) it.applyColorFilter(textColor)
}
} }
} }

View file

@ -8,13 +8,12 @@ import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager import android.content.pm.ShortcutManager
import android.database.Cursor
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.graphics.drawable.LayerDrawable import android.graphics.drawable.LayerDrawable
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.ContactsContract import android.provider.ContactsContract.*
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.widget.Toast 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.fragments.*
import com.simplemobiletools.calendar.pro.helpers.* import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter 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.jobs.CalDAVUpdateListener
import com.simplemobiletools.calendar.pro.models.Event import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType import com.simplemobiletools.calendar.pro.models.EventType
@ -144,12 +145,8 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
storeStateVariables() storeStateVariables()
updateWidgets() updateWidgets()
if (config.storedView != EVENTS_LIST_VIEW) { updateTextColors(calendar_coordinator)
updateTextColors(calendar_coordinator)
}
search_placeholder.setTextColor(config.textColor)
search_placeholder_2.setTextColor(config.textColor)
calendar_fab.setColors(config.textColor, getAdjustedPrimaryColor(), config.backgroundColor)
search_holder.background = ColorDrawable(config.backgroundColor) search_holder.background = ColorDrawable(config.backgroundColor)
checkSwipeRefreshAvailability() checkSwipeRefreshAvailability()
checkShortcuts() checkShortcuts()
@ -179,7 +176,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
menu.apply { menu.apply {
goToTodayButton = findItem(R.id.go_to_today) goToTodayButton = findItem(R.id.go_to_today)
findItem(R.id.filter).isVisible = mShouldFilterBeVisible 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 findItem(R.id.go_to_date).isVisible = config.storedView != EVENTS_LIST_VIEW
} }
@ -188,8 +185,8 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
return true return true
} }
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu): Boolean {
menu!!.apply { menu.apply {
findItem(R.id.refresh_caldav_calendars).isVisible = config.caldavSync findItem(R.id.refresh_caldav_calendars).isVisible = config.caldavSync
} }
@ -279,6 +276,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
search_holder.beVisible() search_holder.beVisible()
calendar_fab.beGone() calendar_fab.beGone()
searchQueryChanged("") searchQueryChanged("")
invalidateOptionsMenu()
return true return true
} }
@ -286,6 +284,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
mIsSearchOpen = false mIsSearchOpen = false
search_holder.beGone() search_holder.beGone()
calendar_fab.beVisibleIf(currentFragments.last() !is YearFragmentsHolder) calendar_fab.beVisibleIf(currentFragments.last() !is YearFragmentsHolder)
invalidateOptionsMenu()
return true return true
} }
}) })
@ -488,7 +487,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
val result = IcsImporter(this).importEvents(it as String, eventTypeId, 0, false) val result = IcsImporter(this).importEvents(it as String, eventTypeId, 0, false)
handleParseResult(result) handleParseResult(result)
if (result != IcsImporter.ImportResult.IMPORT_FAIL) { if (result != ImportResult.IMPORT_FAIL) {
runOnUiThread { runOnUiThread {
updateViewPager() updateViewPager()
} }
@ -545,11 +544,11 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
} }
} }
private fun handleParseResult(result: IcsImporter.ImportResult) { private fun handleParseResult(result: ImportResult) {
toast(when (result) { toast(when (result) {
IcsImporter.ImportResult.IMPORT_NOTHING_NEW -> R.string.no_new_items ImportResult.IMPORT_NOTHING_NEW -> R.string.no_new_items
IcsImporter.ImportResult.IMPORT_OK -> R.string.holidays_imported_successfully ImportResult.IMPORT_OK -> R.string.holidays_imported_successfully
IcsImporter.ImportResult.IMPORT_PARTIAL -> R.string.importing_some_holidays_failed ImportResult.IMPORT_PARTIAL -> R.string.importing_some_holidays_failed
else -> R.string.importing_holidays_failed else -> R.string.importing_holidays_failed
}, Toast.LENGTH_LONG) }, Toast.LENGTH_LONG)
} }
@ -557,78 +556,69 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
private fun addContactEvents(birthdays: Boolean, reminders: ArrayList<Int>, callback: (Int) -> Unit) { private fun addContactEvents(birthdays: Boolean, reminders: ArrayList<Int>, callback: (Int) -> Unit) {
var eventsAdded = 0 var eventsAdded = 0
var eventsFound = 0 var eventsFound = 0
val uri = ContactsContract.Data.CONTENT_URI val uri = Data.CONTENT_URI
val projection = arrayOf(ContactsContract.Contacts.DISPLAY_NAME, val projection = arrayOf(Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.CONTACT_ID, CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.CONTACT_LAST_UPDATED_TIMESTAMP, CommonDataKinds.Event.CONTACT_LAST_UPDATED_TIMESTAMP,
ContactsContract.CommonDataKinds.Event.START_DATE) CommonDataKinds.Event.START_DATE)
val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.CommonDataKinds.Event.TYPE} = ?" val selection = "${Data.MIMETYPE} = ? AND ${CommonDataKinds.Event.TYPE} = ?"
val type = if (birthdays) ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY else ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY val type = if (birthdays) CommonDataKinds.Event.TYPE_BIRTHDAY else CommonDataKinds.Event.TYPE_ANNIVERSARY
val selectionArgs = arrayOf(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, type.toString()) val selectionArgs = arrayOf(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<String, Long>()
existingEvents.forEach {
importIDs[it.importId] = it.startTS
}
val eventTypeId = if (birthdays) getBirthdaysEventTypeId() else getAnniversariesEventTypeId() val dateFormats = getDateFormats()
val existingEvents = if (birthdays) eventsDB.getBirthdays() else eventsDB.getAnniversaries()
val importIDs = HashMap<String, Long>()
existingEvents.forEach {
importIDs[it.importId] = it.startTS
}
do { val eventTypeId = if (birthdays) getBirthdaysEventTypeId() else getAnniversariesEventTypeId()
val contactId = cursor.getIntValue(ContactsContract.CommonDataKinds.Event.CONTACT_ID).toString()
val name = cursor.getStringValue(ContactsContract.Contacts.DISPLAY_NAME)
val startDate = cursor.getStringValue(ContactsContract.CommonDataKinds.Event.START_DATE)
for (format in dateFormats) { queryCursor(uri, projection, selection, selectionArgs, showErrors = true) { cursor ->
try { val contactId = cursor.getIntValue(CommonDataKinds.Event.CONTACT_ID).toString()
val formatter = SimpleDateFormat(format, Locale.getDefault()) val name = cursor.getStringValue(Contacts.DISPLAY_NAME)
val date = formatter.parse(startDate) val startDate = cursor.getStringValue(CommonDataKinds.Event.START_DATE)
if (date.year < 70) {
date.year = 70 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<String>()
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<String>()
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 { runOnUiThread {
@ -839,8 +829,8 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
} else { } else {
IcsExporter().exportEvents(this, outputStream, events, true) { IcsExporter().exportEvents(this, outputStream, events, true) {
toast(when (it) { toast(when (it) {
IcsExporter.ExportResult.EXPORT_OK -> R.string.exporting_successful ExportResult.EXPORT_OK -> R.string.exporting_successful
IcsExporter.ExportResult.EXPORT_PARTIAL -> R.string.exporting_some_entries_failed ExportResult.EXPORT_PARTIAL -> R.string.exporting_some_entries_failed
else -> R.string.exporting_failed else -> R.string.exporting_failed
}) })
} }

View file

@ -3,7 +3,6 @@ package com.simplemobiletools.calendar.pro.activities
import android.app.Activity import android.app.Activity
import android.app.TimePickerDialog import android.app.TimePickerDialog
import android.content.Intent import android.content.Intent
import android.content.res.Resources
import android.media.AudioManager import android.media.AudioManager
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
@ -28,13 +27,11 @@ class SettingsActivity : SimpleActivity() {
private val GET_RINGTONE_URI = 1 private val GET_RINGTONE_URI = 1
private val PICK_IMPORT_SOURCE_INTENT = 2 private val PICK_IMPORT_SOURCE_INTENT = 2
lateinit var res: Resources
private var mStoredPrimaryColor = 0 private var mStoredPrimaryColor = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings) setContentView(R.layout.activity_settings)
res = resources
mStoredPrimaryColor = config.primaryColor mStoredPrimaryColor = config.primaryColor
} }
@ -351,10 +348,10 @@ class SettingsActivity : SimpleActivity() {
settings_reminder_audio_stream.text = getAudioStreamText() settings_reminder_audio_stream.text = getAudioStreamText()
settings_reminder_audio_stream_holder.setOnClickListener { settings_reminder_audio_stream_holder.setOnClickListener {
val items = arrayListOf( val items = arrayListOf(
RadioItem(AudioManager.STREAM_ALARM, res.getString(R.string.alarm_stream)), RadioItem(AudioManager.STREAM_ALARM, getString(R.string.alarm_stream)),
RadioItem(AudioManager.STREAM_SYSTEM, res.getString(R.string.system_stream)), RadioItem(AudioManager.STREAM_SYSTEM, getString(R.string.system_stream)),
RadioItem(AudioManager.STREAM_NOTIFICATION, res.getString(R.string.notification_stream)), RadioItem(AudioManager.STREAM_NOTIFICATION, getString(R.string.notification_stream)),
RadioItem(AudioManager.STREAM_RING, res.getString(R.string.ring_stream))) RadioItem(AudioManager.STREAM_RING, getString(R.string.ring_stream)))
RadioGroupDialog(this@SettingsActivity, items, config.reminderAudioStream) { RadioGroupDialog(this@SettingsActivity, items, config.reminderAudioStream) {
config.reminderAudioStream = it as Int config.reminderAudioStream = it as Int
@ -487,10 +484,10 @@ class SettingsActivity : SimpleActivity() {
settings_font_size.text = getFontSizeText() settings_font_size.text = getFontSizeText()
settings_font_size_holder.setOnClickListener { settings_font_size_holder.setOnClickListener {
val items = arrayListOf( val items = arrayListOf(
RadioItem(FONT_SIZE_SMALL, res.getString(R.string.small)), RadioItem(FONT_SIZE_SMALL, getString(R.string.small)),
RadioItem(FONT_SIZE_MEDIUM, res.getString(R.string.medium)), RadioItem(FONT_SIZE_MEDIUM, getString(R.string.medium)),
RadioItem(FONT_SIZE_LARGE, res.getString(R.string.large)), RadioItem(FONT_SIZE_LARGE, getString(R.string.large)),
RadioItem(FONT_SIZE_EXTRA_LARGE, res.getString(R.string.extra_large))) RadioItem(FONT_SIZE_EXTRA_LARGE, getString(R.string.extra_large)))
RadioGroupDialog(this@SettingsActivity, items, config.fontSize) { RadioGroupDialog(this@SettingsActivity, items, config.fontSize) {
config.fontSize = it as Int 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.text = getDefaultViewText()
settings_list_widget_view_to_open_holder.setOnClickListener { settings_list_widget_view_to_open_holder.setOnClickListener {
val items = arrayListOf( val items = arrayListOf(
RadioItem(DAILY_VIEW, res.getString(R.string.daily_view)), RadioItem(DAILY_VIEW, getString(R.string.daily_view)),
RadioItem(WEEKLY_VIEW, res.getString(R.string.weekly_view)), RadioItem(WEEKLY_VIEW, getString(R.string.weekly_view)),
RadioItem(MONTHLY_VIEW, res.getString(R.string.monthly_view)), RadioItem(MONTHLY_VIEW, getString(R.string.monthly_view)),
RadioItem(YEARLY_VIEW, res.getString(R.string.yearly_view)), RadioItem(YEARLY_VIEW, getString(R.string.yearly_view)),
RadioItem(EVENTS_LIST_VIEW, res.getString(R.string.simple_event_list)), RadioItem(EVENTS_LIST_VIEW, getString(R.string.simple_event_list)),
RadioItem(LAST_VIEW, res.getString(R.string.last_view))) RadioItem(LAST_VIEW, getString(R.string.last_view)))
RadioGroupDialog(this@SettingsActivity, items, config.listWidgetViewToOpen) { RadioGroupDialog(this@SettingsActivity, items, config.listWidgetViewToOpen) {
config.listWidgetViewToOpen = it as Int config.listWidgetViewToOpen = it as Int

View file

@ -1,6 +1,6 @@
package com.simplemobiletools.calendar.pro.adapters package com.simplemobiletools.calendar.pro.adapters
import android.graphics.drawable.LayerDrawable import android.graphics.drawable.BitmapDrawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -8,19 +8,13 @@ import android.widget.ArrayAdapter
import android.widget.Filter import android.widget.Filter
import com.simplemobiletools.calendar.pro.R import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.calendar.pro.models.Attendee 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 com.simplemobiletools.commons.extensions.normalizeString
import kotlinx.android.synthetic.main.item_autocomplete_email_name.view.* import kotlinx.android.synthetic.main.item_autocomplete_email_name.view.*
class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: ArrayList<Attendee>) : ArrayAdapter<Attendee>(activity, 0, contacts) { class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: ArrayList<Attendee>) : ArrayAdapter<Attendee>(activity, 0, contacts) {
var resultList = ArrayList<Attendee>() var resultList = ArrayList<Attendee>()
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 { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val contact = resultList[position] val contact = resultList[position]
@ -30,6 +24,13 @@ class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: Ar
listItem = LayoutInflater.from(activity).inflate(layout, parent, false) 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 { listItem!!.apply {
tag = contact.name.isNotEmpty() tag = contact.name.isNotEmpty()
item_autocomplete_name?.text = contact.name item_autocomplete_name?.text = contact.name

View file

@ -9,19 +9,25 @@ import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.calDAVHelper import com.simplemobiletools.calendar.pro.extensions.calDAVHelper
import com.simplemobiletools.calendar.pro.extensions.config import com.simplemobiletools.calendar.pro.extensions.config
import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.calendar_item_account.view.* import kotlinx.android.synthetic.main.calendar_item_account.view.*
import kotlinx.android.synthetic.main.calendar_item_calendar.view.* import kotlinx.android.synthetic.main.calendar_item_calendar.view.*
import kotlinx.android.synthetic.main.dialog_select_calendars.view.* import kotlinx.android.synthetic.main.dialog_select_calendars.view.*
class SelectCalendarsDialog(val activity: SimpleActivity, val callback: () -> Unit) { class SelectCalendarsDialog(val activity: SimpleActivity, val callback: () -> Unit) {
var prevAccount = "" private var prevAccount = ""
var dialog: AlertDialog private var dialog: AlertDialog
var view = (activity.layoutInflater.inflate(R.layout.dialog_select_calendars, null) as ViewGroup) private var view = (activity.layoutInflater.inflate(R.layout.dialog_select_calendars, null) as ViewGroup)
init { init {
val ids = activity.config.getSyncedCalendarIdsAsList() val ids = activity.config.getSyncedCalendarIdsAsList()
val calendars = activity.calDAVHelper.getCalDAVCalendars("", true) 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 })) val sorted = calendars.sortedWith(compareBy({ it.accountName }, { it.displayName }))
sorted.forEach { sorted.forEach {
if (prevAccount != it.accountName) { 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) { 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, val layout = if (isEvent) R.layout.calendar_item_calendar else R.layout.calendar_item_account
view.dialog_select_calendars_holder, false) val calendarItem = activity.layoutInflater.inflate(layout, view.dialog_select_calendars_holder, false)
if (isEvent) { if (isEvent) {
calendarItem.calendar_item_calendar_switch.apply { calendarItem.calendar_item_calendar_switch.apply {

View file

@ -262,7 +262,7 @@ fun Context.getNotification(pendingIntent: PendingIntent, event: Event, content:
val builder = NotificationCompat.Builder(this, channelId) val builder = NotificationCompat.Builder(this, channelId)
.setContentTitle(contentTitle) .setContentTitle(contentTitle)
.setContentText(contentText) .setContentText(contentText)
.setSmallIcon(R.drawable.ic_calendar) .setSmallIcon(R.drawable.ic_calendar_vector)
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX) .setPriority(NotificationCompat.PRIORITY_MAX)
.setDefaults(Notification.DEFAULT_LIGHTS) .setDefaults(Notification.DEFAULT_LIGHTS)

View file

@ -4,9 +4,7 @@ import android.annotation.SuppressLint
import android.content.ContentUris import android.content.ContentUris
import android.content.ContentValues import android.content.ContentValues
import android.content.Context import android.content.Context
import android.database.Cursor import android.provider.CalendarContract.*
import android.provider.CalendarContract
import android.provider.CalendarContract.Reminders
import android.util.SparseIntArray import android.util.SparseIntArray
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
@ -22,6 +20,7 @@ import org.joda.time.format.DateTimeFormat
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@SuppressLint("MissingPermission")
class CalDAVHelper(val context: Context) { class CalDAVHelper(val context: Context) {
private val eventsHelper = context.eventsHelper private val eventsHelper = context.eventsHelper
@ -58,45 +57,34 @@ class CalDAVHelper(val context: Context) {
return calendars return calendars
} }
val uri = CalendarContract.Calendars.CONTENT_URI val uri = Calendars.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
CalendarContract.Calendars._ID, Calendars._ID,
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, Calendars.CALENDAR_DISPLAY_NAME,
CalendarContract.Calendars.ACCOUNT_NAME, Calendars.ACCOUNT_NAME,
CalendarContract.Calendars.ACCOUNT_TYPE, Calendars.ACCOUNT_TYPE,
CalendarContract.Calendars.OWNER_ACCOUNT, Calendars.OWNER_ACCOUNT,
CalendarContract.Calendars.CALENDAR_COLOR, Calendars.CALENDAR_COLOR,
CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL) Calendars.CALENDAR_ACCESS_LEVEL)
val selection = if (ids.trim().isNotEmpty()) "${CalendarContract.Calendars._ID} IN ($ids)" else null val selection = if (ids.trim().isNotEmpty()) "${Calendars._ID} IN ($ids)" else null
var cursor: Cursor? = null context.queryCursor(uri, projection, selection, showErrors = showToasts) { cursor ->
try { val id = cursor.getIntValue(Calendars._ID)
cursor = context.contentResolver.query(uri, projection, selection, null, null) val displayName = cursor.getStringValue(Calendars.CALENDAR_DISPLAY_NAME)
if (cursor?.moveToFirst() == true) { val accountName = cursor.getStringValue(Calendars.ACCOUNT_NAME)
do { val accountType = cursor.getStringValue(Calendars.ACCOUNT_TYPE)
val id = cursor.getIntValue(CalendarContract.Calendars._ID) val ownerName = cursor.getStringValue(Calendars.OWNER_ACCOUNT) ?: ""
val displayName = cursor.getStringValue(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME) val color = cursor.getIntValue(Calendars.CALENDAR_COLOR)
val accountName = cursor.getStringValue(CalendarContract.Calendars.ACCOUNT_NAME) val accessLevel = cursor.getIntValue(Calendars.CALENDAR_ACCESS_LEVEL)
val accountType = cursor.getStringValue(CalendarContract.Calendars.ACCOUNT_TYPE) val calendar = CalDAVCalendar(id, displayName, accountName, accountType, ownerName, color, accessLevel)
val ownerName = cursor.getStringValue(CalendarContract.Calendars.OWNER_ACCOUNT) ?: "" calendars.add(calendar)
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()
} }
return calendars return calendars
} }
fun updateCalDAVCalendar(eventType: EventType) { fun updateCalDAVCalendar(eventType: EventType) {
val uri = CalendarContract.Calendars.CONTENT_URI val uri = Calendars.CONTENT_URI
val values = fillCalendarContentValues(eventType) val values = fillCalendarContentValues(eventType)
val newUri = ContentUris.withAppendedId(uri, eventType.caldavCalendarId.toLong()) val newUri = ContentUris.withAppendedId(uri, eventType.caldavCalendarId.toLong())
try { try {
@ -108,26 +96,23 @@ class CalDAVHelper(val context: Context) {
private fun fillCalendarContentValues(eventType: EventType): ContentValues { private fun fillCalendarContentValues(eventType: EventType): ContentValues {
val colorKey = getEventTypeColorKey(eventType) val colorKey = getEventTypeColorKey(eventType)
return ContentValues().apply { return ContentValues().apply {
put(CalendarContract.Calendars.CALENDAR_COLOR_KEY, colorKey) put(Calendars.CALENDAR_COLOR_KEY, colorKey)
put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, eventType.title) put(Calendars.CALENDAR_DISPLAY_NAME, eventType.title)
} }
} }
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
private fun getEventTypeColorKey(eventType: EventType): Int { private fun getEventTypeColorKey(eventType: EventType): Int {
val uri = CalendarContract.Colors.CONTENT_URI val uri = Colors.CONTENT_URI
val projection = arrayOf(CalendarContract.Colors.COLOR_KEY) val projection = arrayOf(Colors.COLOR_KEY)
val selection = "${CalendarContract.Colors.COLOR_TYPE} = ? AND ${CalendarContract.Colors.COLOR} = ? AND ${CalendarContract.Colors.ACCOUNT_NAME} = ?" val selection = "${Colors.COLOR_TYPE} = ? AND ${Colors.COLOR} = ? AND ${Colors.ACCOUNT_NAME} = ?"
val selectionArgs = arrayOf(CalendarContract.Colors.TYPE_CALENDAR.toString(), eventType.color.toString(), eventType.caldavEmail) val selectionArgs = arrayOf(Colors.TYPE_CALENDAR.toString(), eventType.color.toString(), eventType.caldavEmail)
var cursor: Cursor? = null val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
try { cursor?.use {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) if (cursor.moveToFirst()) {
if (cursor?.moveToFirst() == true) { return cursor.getStringValue(Colors.COLOR_KEY).toInt()
return cursor.getStringValue(CalendarContract.Colors.COLOR_KEY).toInt()
} }
} finally {
cursor?.close()
} }
return -1 return -1
@ -136,23 +121,15 @@ class CalDAVHelper(val context: Context) {
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun getAvailableCalDAVCalendarColors(eventType: EventType): ArrayList<Int> { fun getAvailableCalDAVCalendarColors(eventType: EventType): ArrayList<Int> {
val colors = SparseIntArray() val colors = SparseIntArray()
val uri = CalendarContract.Colors.CONTENT_URI val uri = Colors.CONTENT_URI
val projection = arrayOf(CalendarContract.Colors.COLOR, CalendarContract.Colors.COLOR_KEY) val projection = arrayOf(Colors.COLOR, Colors.COLOR_KEY)
val selection = "${CalendarContract.Colors.COLOR_TYPE} = ? AND ${CalendarContract.Colors.ACCOUNT_NAME} = ?" val selection = "${Colors.COLOR_TYPE} = ? AND ${Colors.ACCOUNT_NAME} = ?"
val selectionArgs = arrayOf(CalendarContract.Colors.TYPE_CALENDAR.toString(), eventType.caldavEmail) val selectionArgs = arrayOf(Colors.TYPE_CALENDAR.toString(), eventType.caldavEmail)
var cursor: Cursor? = null context.queryCursor(uri, projection, selection, selectionArgs) { cursor ->
try { val colorKey = cursor.getIntValue(Colors.COLOR_KEY)
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) val color = cursor.getIntValue(Colors.COLOR)
if (cursor?.moveToFirst() == true) { colors.put(colorKey, color)
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()
} }
var sortedColors = ArrayList<Int>(colors.size()) var sortedColors = ArrayList<Int>(colors.size())
@ -173,151 +150,139 @@ class CalDAVHelper(val context: Context) {
importIdsMap[it.importId] = it importIdsMap[it.importId] = it
} }
val uri = CalendarContract.Events.CONTENT_URI val uri = Events.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
CalendarContract.Events._ID, Events._ID,
CalendarContract.Events.TITLE, Events.TITLE,
CalendarContract.Events.DESCRIPTION, Events.DESCRIPTION,
CalendarContract.Events.DTSTART, Events.DTSTART,
CalendarContract.Events.DTEND, Events.DTEND,
CalendarContract.Events.DURATION, Events.DURATION,
CalendarContract.Events.EXDATE, Events.EXDATE,
CalendarContract.Events.ALL_DAY, Events.ALL_DAY,
CalendarContract.Events.RRULE, Events.RRULE,
CalendarContract.Events.ORIGINAL_ID, Events.ORIGINAL_ID,
CalendarContract.Events.ORIGINAL_INSTANCE_TIME, Events.ORIGINAL_INSTANCE_TIME,
CalendarContract.Events.EVENT_LOCATION, Events.EVENT_LOCATION,
CalendarContract.Events.EVENT_TIMEZONE, Events.EVENT_TIMEZONE,
CalendarContract.Events.CALENDAR_TIME_ZONE, Events.CALENDAR_TIME_ZONE,
CalendarContract.Events.DELETED) Events.DELETED)
val selection = "${CalendarContract.Events.CALENDAR_ID} = $calendarId" val selection = "${Events.CALENDAR_ID} = $calendarId"
var cursor: Cursor? = null context.queryCursor(uri, projection, selection, showErrors = showToasts) { cursor ->
try { val deleted = cursor.getIntValue(Events.DELETED)
cursor = context.contentResolver.query(uri, projection, selection, null, null) if (deleted == 1) {
if (cursor?.moveToFirst() == true) { return@queryCursor
do { }
val deleted = cursor.getIntValue(CalendarContract.Events.DELETED)
if (deleted == 1) {
continue
}
val id = cursor.getLongValue(CalendarContract.Events._ID) val id = cursor.getLongValue(Events._ID)
val title = cursor.getStringValue(CalendarContract.Events.TITLE) ?: "" val title = cursor.getStringValue(Events.TITLE) ?: ""
val description = cursor.getStringValue(CalendarContract.Events.DESCRIPTION) ?: "" val description = cursor.getStringValue(Events.DESCRIPTION) ?: ""
val startTS = cursor.getLongValue(CalendarContract.Events.DTSTART) / 1000L val startTS = cursor.getLongValue(Events.DTSTART) / 1000L
var endTS = cursor.getLongValue(CalendarContract.Events.DTEND) / 1000L var endTS = cursor.getLongValue(Events.DTEND) / 1000L
val allDay = cursor.getIntValue(CalendarContract.Events.ALL_DAY) val allDay = cursor.getIntValue(Events.ALL_DAY)
val rrule = cursor.getStringValue(CalendarContract.Events.RRULE) ?: "" val rrule = cursor.getStringValue(Events.RRULE) ?: ""
val location = cursor.getStringValue(CalendarContract.Events.EVENT_LOCATION) ?: "" val location = cursor.getStringValue(Events.EVENT_LOCATION) ?: ""
val originalId = cursor.getStringValue(CalendarContract.Events.ORIGINAL_ID) val originalId = cursor.getStringValue(Events.ORIGINAL_ID)
val originalInstanceTime = cursor.getLongValue(CalendarContract.Events.ORIGINAL_INSTANCE_TIME) val originalInstanceTime = cursor.getLongValue(Events.ORIGINAL_INSTANCE_TIME)
val reminders = getCalDAVEventReminders(id) val reminders = getCalDAVEventReminders(id)
val attendees = Gson().toJson(getCalDAVEventAttendees(id)) val attendees = Gson().toJson(getCalDAVEventAttendees(id))
if (endTS == 0L) { if (endTS == 0L) {
val duration = cursor.getStringValue(CalendarContract.Events.DURATION) ?: "" val duration = cursor.getStringValue(Events.DURATION) ?: ""
endTS = startTS + Parser().parseDurationSeconds(duration) endTS = startTS + Parser().parseDurationSeconds(duration)
} }
val reminder1 = reminders.getOrNull(0) val reminder1 = reminders.getOrNull(0)
val reminder2 = reminders.getOrNull(1) val reminder2 = reminders.getOrNull(1)
val reminder3 = reminders.getOrNull(2) val reminder3 = reminders.getOrNull(2)
val importId = getCalDAVEventImportId(calendarId, id) val importId = getCalDAVEventImportId(calendarId, id)
val eventTimeZone = cursor.getStringValue(CalendarContract.Events.EVENT_TIMEZONE) val eventTimeZone = cursor.getStringValue(Events.EVENT_TIMEZONE)
?: cursor.getStringValue(CalendarContract.Events.CALENDAR_TIME_ZONE) ?: DateTimeZone.getDefault().id ?: cursor.getStringValue(Events.CALENDAR_TIME_ZONE) ?: DateTimeZone.getDefault().id
val source = "$CALDAV-$calendarId" val source = "$CALDAV-$calendarId"
val repeatRule = Parser().parseRepeatInterval(rrule, startTS) val repeatRule = Parser().parseRepeatInterval(rrule, startTS)
val event = Event(null, startTS, endTS, title, location, description, reminder1?.minutes ?: REMINDER_OFF, val event = Event(null, startTS, endTS, title, location, description, reminder1?.minutes ?: REMINDER_OFF,
reminder2?.minutes ?: REMINDER_OFF, reminder3?.minutes ?: REMINDER_OFF, reminder1?.type reminder2?.minutes ?: REMINDER_OFF, reminder3?.minutes ?: REMINDER_OFF, reminder1?.type
?: REMINDER_NOTIFICATION, reminder2?.type ?: REMINDER_NOTIFICATION, reminder3?.type ?: REMINDER_NOTIFICATION, reminder2?.type ?: REMINDER_NOTIFICATION, reminder3?.type
?: REMINDER_NOTIFICATION, repeatRule.repeatInterval, repeatRule.repeatRule, ?: REMINDER_NOTIFICATION, repeatRule.repeatInterval, repeatRule.repeatRule,
repeatRule.repeatLimit, ArrayList(), attendees, importId, eventTimeZone, allDay, eventTypeId, source = source) repeatRule.repeatLimit, ArrayList(), attendees, importId, eventTimeZone, allDay, eventTypeId, source = source)
if (event.getIsAllDay()) { if (event.getIsAllDay()) {
event.startTS = Formatter.getShiftedImportTimestamp(event.startTS) event.startTS = Formatter.getShiftedImportTimestamp(event.startTS)
event.endTS = Formatter.getShiftedImportTimestamp(event.endTS) event.endTS = Formatter.getShiftedImportTimestamp(event.endTS)
if (event.endTS > event.startTS) { if (event.endTS > event.startTS) {
event.endTS -= DAY 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 the event is an exception from another events repeat rule, find the original parent event
if (originalInstanceTime != 0L) { if (originalInstanceTime != 0L) {
val parentImportId = "$source-$originalId" val parentImportId = "$source-$originalId"
val parentEvent = context.eventsDB.getEventWithImportId(parentImportId) val parentEvent = context.eventsDB.getEventWithImportId(parentImportId)
val originalDayCode = Formatter.getDayCodeFromTS(originalInstanceTime / 1000L) val originalDayCode = Formatter.getDayCodeFromTS(originalInstanceTime / 1000L)
if (parentEvent != null && !parentEvent.repetitionExceptions.contains(originalDayCode)) { if (parentEvent != null && !parentEvent.repetitionExceptions.contains(originalDayCode)) {
event.parentId = parentEvent.id!! event.parentId = parentEvent.id!!
parentEvent.addRepetitionException(originalDayCode) parentEvent.addRepetitionException(originalDayCode)
eventsHelper.insertEvent(parentEvent, false, false) eventsHelper.insertEvent(parentEvent, false, false)
event.parentId = parentEvent.id!! event.parentId = parentEvent.id!!
event.addRepetitionException(originalDayCode) event.addRepetitionException(originalDayCode)
eventsHelper.insertEvent(event, false, false) eventsHelper.insertEvent(event, false, false)
continue return@queryCursor
} }
} }
// some calendars add repeatable event exceptions with using the "exdate" field, not by creating a child event that is an exception // 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) ?: "" val exdate = cursor.getStringValue(Events.EXDATE) ?: ""
if (exdate.length > 8) { if (exdate.length > 8) {
val lines = exdate.split("\n") val lines = exdate.split("\n")
for (line in lines) { for (line in lines) {
val dates = line.split(",") val dates = line.split(",")
dates.forEach { dates.forEach {
if (it.endsWith("Z")) { if (it.endsWith("Z")) {
// convert for example "20190216T230000Z" to "20190217000000" in Slovakia in a weird way // convert for example "20190216T230000Z" to "20190217000000" in Slovakia in a weird way
val formatter = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss'Z'") val formatter = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss'Z'")
val offset = DateTimeZone.getDefault().getOffset(System.currentTimeMillis()) val offset = DateTimeZone.getDefault().getOffset(System.currentTimeMillis())
val dt = formatter.parseDateTime(it).plusMillis(offset) val dt = formatter.parseDateTime(it).plusMillis(offset)
val daycode = Formatter.getDayCodeFromDateTime(dt) val daycode = Formatter.getDayCodeFromDateTime(dt)
event.repetitionExceptions.add(daycode) event.repetitionExceptions.add(daycode)
} else { } else {
var potentialTS = it.substring(0, 8) var potentialTS = it.substring(0, 8)
if (potentialTS.areDigitsOnly()) { if (potentialTS.areDigitsOnly()) {
event.repetitionExceptions.add(potentialTS) event.repetitionExceptions.add(potentialTS)
} else if (it.contains(";")) { } else if (it.contains(";")) {
potentialTS = it.substringAfter(";").substring(0, 8) potentialTS = it.substringAfter(";").substring(0, 8)
event.repetitionExceptions.add(potentialTS) 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) { if (importIdsMap.containsKey(event.importId)) {
context.showErrorToast(e) 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<Long>() val eventIdsToDelete = ArrayList<Long>()
@ -335,7 +300,7 @@ class CalDAVHelper(val context: Context) {
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun insertCalDAVEvent(event: Event) { fun insertCalDAVEvent(event: Event) {
val uri = CalendarContract.Events.CONTENT_URI val uri = Events.CONTENT_URI
val values = fillEventContentValues(event) val values = fillEventContentValues(event)
val newUri = context.contentResolver.insert(uri, values) val newUri = context.contentResolver.insert(uri, values)
@ -350,7 +315,7 @@ class CalDAVHelper(val context: Context) {
} }
fun updateCalDAVEvent(event: Event) { fun updateCalDAVEvent(event: Event) {
val uri = CalendarContract.Events.CONTENT_URI val uri = Events.CONTENT_URI
val values = fillEventContentValues(event) val values = fillEventContentValues(event)
val eventRemoteID = event.getCalDAVEventId() val eventRemoteID = event.getCalDAVEventId()
event.importId = getCalDAVEventImportId(event.getCalDAVCalendarId(), eventRemoteID) event.importId = getCalDAVEventImportId(event.getCalDAVCalendarId(), eventRemoteID)
@ -386,15 +351,15 @@ class CalDAVHelper(val context: Context) {
val attendees = Gson().fromJson<ArrayList<Attendee>>(event.attendees, object : TypeToken<List<Attendee>>() {}.type) ?: ArrayList() val attendees = Gson().fromJson<ArrayList<Attendee>>(event.attendees, object : TypeToken<List<Attendee>>() {}.type) ?: ArrayList()
attendees.forEach { attendees.forEach {
val contentValues = ContentValues().apply { val contentValues = ContentValues().apply {
put(CalendarContract.Attendees.ATTENDEE_NAME, it.name) put(Attendees.ATTENDEE_NAME, it.name)
put(CalendarContract.Attendees.ATTENDEE_EMAIL, it.email) put(Attendees.ATTENDEE_EMAIL, it.email)
put(CalendarContract.Attendees.ATTENDEE_STATUS, it.status) put(Attendees.ATTENDEE_STATUS, it.status)
put(CalendarContract.Attendees.ATTENDEE_RELATIONSHIP, it.relationship) put(Attendees.ATTENDEE_RELATIONSHIP, it.relationship)
put(CalendarContract.Attendees.EVENT_ID, event.getCalDAVEventId()) put(Attendees.EVENT_ID, event.getCalDAVEventId())
} }
try { try {
context.contentResolver.insert(CalendarContract.Attendees.CONTENT_URI, contentValues) context.contentResolver.insert(Attendees.CONTENT_URI, contentValues)
} catch (e: Exception) { } catch (e: Exception) {
context.toast(R.string.unknown_error_occurred) context.toast(R.string.unknown_error_occurred)
} }
@ -407,31 +372,31 @@ class CalDAVHelper(val context: Context) {
private fun fillEventContentValues(event: Event): ContentValues { private fun fillEventContentValues(event: Event): ContentValues {
return ContentValues().apply { return ContentValues().apply {
put(CalendarContract.Events.CALENDAR_ID, event.getCalDAVCalendarId()) put(Events.CALENDAR_ID, event.getCalDAVCalendarId())
put(CalendarContract.Events.TITLE, event.title) put(Events.TITLE, event.title)
put(CalendarContract.Events.DESCRIPTION, event.description) put(Events.DESCRIPTION, event.description)
put(CalendarContract.Events.DTSTART, event.startTS * 1000L) put(Events.DTSTART, event.startTS * 1000L)
put(CalendarContract.Events.ALL_DAY, if (event.getIsAllDay()) 1 else 0) put(Events.ALL_DAY, if (event.getIsAllDay()) 1 else 0)
put(CalendarContract.Events.EVENT_TIMEZONE, event.getTimeZoneString()) put(Events.EVENT_TIMEZONE, event.getTimeZoneString())
put(CalendarContract.Events.EVENT_LOCATION, event.location) put(Events.EVENT_LOCATION, event.location)
put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CONFIRMED) put(Events.STATUS, Events.STATUS_CONFIRMED)
val repeatRule = Parser().getRepeatCode(event) val repeatRule = Parser().getRepeatCode(event)
if (repeatRule.isEmpty()) { if (repeatRule.isEmpty()) {
putNull(CalendarContract.Events.RRULE) putNull(Events.RRULE)
} else { } else {
put(CalendarContract.Events.RRULE, repeatRule) put(Events.RRULE, repeatRule)
} }
if (event.getIsAllDay() && event.endTS >= event.startTS) if (event.getIsAllDay() && event.endTS >= event.startTS)
event.endTS += DAY event.endTS += DAY
if (event.repeatInterval > 0) { if (event.repeatInterval > 0) {
put(CalendarContract.Events.DURATION, getDurationCode(event)) put(Events.DURATION, getDurationCode(event))
putNull(CalendarContract.Events.DTEND) putNull(Events.DTEND)
} else { } else {
put(CalendarContract.Events.DTEND, event.endTS * 1000L) put(Events.DTEND, event.endTS * 1000L)
putNull(CalendarContract.Events.DURATION) putNull(Events.DURATION)
} }
} }
} }
@ -443,9 +408,9 @@ class CalDAVHelper(val context: Context) {
} }
private fun clearEventAttendees(event: Event) { private fun clearEventAttendees(event: Event) {
val selection = "${CalendarContract.Attendees.EVENT_ID} = ?" val selection = "${Attendees.EVENT_ID} = ?"
val selectionArgs = arrayOf(event.getCalDAVEventId().toString()) 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 { private fun getDurationCode(event: Event): String {
@ -463,7 +428,7 @@ class CalDAVHelper(val context: Context) {
} }
fun deleteCalDAVEvent(event: Event) { fun deleteCalDAVEvent(event: Event) {
val uri = CalendarContract.Events.CONTENT_URI val uri = Events.CONTENT_URI
val contentUri = ContentUris.withAppendedId(uri, event.getCalDAVEventId()) val contentUri = ContentUris.withAppendedId(uri, event.getCalDAVEventId())
try { try {
context.contentResolver.delete(contentUri, null, null) context.contentResolver.delete(contentUri, null, null)
@ -473,7 +438,7 @@ class CalDAVHelper(val context: Context) {
} }
fun insertEventRepeatException(event: Event, occurrenceTS: Long) { fun insertEventRepeatException(event: Event, occurrenceTS: Long) {
val uri = CalendarContract.Events.CONTENT_URI val uri = Events.CONTENT_URI
val values = fillEventRepeatExceptionValues(event, occurrenceTS) val values = fillEventRepeatExceptionValues(event, occurrenceTS)
try { try {
context.contentResolver.insert(uri, values) context.contentResolver.insert(uri, values)
@ -485,13 +450,13 @@ class CalDAVHelper(val context: Context) {
private fun fillEventRepeatExceptionValues(event: Event, occurrenceTS: Long): ContentValues { private fun fillEventRepeatExceptionValues(event: Event, occurrenceTS: Long): ContentValues {
return ContentValues().apply { return ContentValues().apply {
put(CalendarContract.Events.CALENDAR_ID, event.getCalDAVCalendarId()) put(Events.CALENDAR_ID, event.getCalDAVCalendarId())
put(CalendarContract.Events.DTSTART, occurrenceTS) put(Events.DTSTART, occurrenceTS)
put(CalendarContract.Events.DTEND, occurrenceTS + (event.endTS - event.startTS)) put(Events.DTEND, occurrenceTS + (event.endTS - event.startTS))
put(CalendarContract.Events.ORIGINAL_ID, event.getCalDAVEventId()) put(Events.ORIGINAL_ID, event.getCalDAVEventId())
put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().id.toString()) put(Events.EVENT_TIMEZONE, TimeZone.getDefault().id.toString())
put(CalendarContract.Events.ORIGINAL_INSTANCE_TIME, occurrenceTS * 1000L) put(Events.ORIGINAL_INSTANCE_TIME, occurrenceTS * 1000L)
put(CalendarContract.Events.EXDATE, Formatter.getDayCodeFromTS(occurrenceTS)) put(Events.EXDATE, Formatter.getDayCodeFromTS(occurrenceTS))
} }
} }
@ -502,51 +467,38 @@ class CalDAVHelper(val context: Context) {
Reminders.MINUTES, Reminders.MINUTES,
Reminders.METHOD) Reminders.METHOD)
val selection = "${Reminders.EVENT_ID} = $eventId" val selection = "${Reminders.EVENT_ID} = $eventId"
var cursor: Cursor? = null
try { context.queryCursor(uri, projection, selection) { cursor ->
cursor = context.contentResolver.query(uri, projection, selection, null, null) val minutes = cursor.getIntValue(Reminders.MINUTES)
if (cursor?.moveToFirst() == true) { val method = cursor.getIntValue(Reminders.METHOD)
do { if (method == Reminders.METHOD_ALERT || method == Reminders.METHOD_EMAIL) {
val minutes = cursor.getIntValue(Reminders.MINUTES) val type = if (method == Reminders.METHOD_EMAIL) REMINDER_EMAIL else REMINDER_NOTIFICATION
val method = cursor.getIntValue(Reminders.METHOD) val reminder = Reminder(minutes, type)
if (method == Reminders.METHOD_ALERT || method == Reminders.METHOD_EMAIL) { reminders.add(reminder)
val type = if (method == Reminders.METHOD_EMAIL) REMINDER_EMAIL else REMINDER_NOTIFICATION
val reminder = Reminder(minutes, type)
reminders.add(reminder)
}
} while (cursor.moveToNext())
} }
} finally {
cursor?.close()
} }
return reminders.sortedBy { it.minutes } return reminders.sortedBy { it.minutes }
} }
private fun getCalDAVEventAttendees(eventId: Long): List<Attendee> { private fun getCalDAVEventAttendees(eventId: Long): List<Attendee> {
val attendees = ArrayList<Attendee>() val attendees = ArrayList<Attendee>()
val uri = CalendarContract.Attendees.CONTENT_URI val uri = Attendees.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
CalendarContract.Attendees.ATTENDEE_NAME, Attendees.ATTENDEE_NAME,
CalendarContract.Attendees.ATTENDEE_EMAIL, Attendees.ATTENDEE_EMAIL,
CalendarContract.Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS,
CalendarContract.Attendees.ATTENDEE_RELATIONSHIP) Attendees.ATTENDEE_RELATIONSHIP)
val selection = "${CalendarContract.Attendees.EVENT_ID} = $eventId" val selection = "${Attendees.EVENT_ID} = $eventId"
var cursor: Cursor? = null context.queryCursor(uri, projection, selection) { cursor ->
try { val name = cursor.getStringValue(Attendees.ATTENDEE_NAME) ?: ""
cursor = context.contentResolver.query(uri, projection, selection, null, null) val email = cursor.getStringValue(Attendees.ATTENDEE_EMAIL) ?: ""
if (cursor?.moveToFirst() == true) { val status = cursor.getIntValue(Attendees.ATTENDEE_STATUS)
do { val relationship = cursor.getIntValue(Attendees.ATTENDEE_RELATIONSHIP)
val name = cursor.getStringValue(CalendarContract.Attendees.ATTENDEE_NAME) ?: "" val attendee = Attendee(0, name, email, status, "", false, relationship)
val email = cursor.getStringValue(CalendarContract.Attendees.ATTENDEE_EMAIL) ?: "" attendees.add(attendee)
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()
} }
return attendees return attendees
} }

View file

@ -3,7 +3,6 @@ package com.simplemobiletools.calendar.pro.helpers
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import androidx.collection.LongSparseArray import androidx.collection.LongSparseArray
import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.extensions.* import com.simplemobiletools.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.models.Event import com.simplemobiletools.calendar.pro.models.Event
import com.simplemobiletools.calendar.pro.models.EventType import com.simplemobiletools.calendar.pro.models.EventType
@ -203,6 +202,17 @@ class EventsHelper(val context: Context) {
val events = eventsDB.getEventsForSearch(searchQuery) val events = eventsDB.getEventsForSearch(searchQuery)
val displayEventTypes = config.displayEventTypes val displayEventTypes = config.displayEventTypes
val filteredEvents = events.filter { displayEventTypes.contains(it.eventType.toString()) } val filteredEvents = events.filter { displayEventTypes.contains(it.eventType.toString()) }
val eventTypeColors = LongSparseArray<Int>()
eventTypesDB.getEventTypes().forEach {
eventTypeColors.put(it.id!!, it.color)
}
filteredEvents.forEach {
it.updateIsPastEvent()
it.color = eventTypeColors.get(it.eventType) ?: config.primaryColor
}
activity.runOnUiThread { activity.runOnUiThread {
callback(text, filteredEvents) callback(text, filteredEvents)
} }
@ -261,10 +271,9 @@ class EventsHelper(val context: Context) {
eventTypeColors.put(it.id!!, it.color) eventTypeColors.put(it.id!!, it.color)
} }
val primaryColor = context.resources.getColor(R.color.color_primary)
events.forEach { events.forEach {
it.updateIsPastEvent() it.updateIsPastEvent()
it.color = eventTypeColors.get(it.eventType) ?: primaryColor it.color = eventTypeColors.get(it.eventType) ?: config.primaryColor
} }
callback(events) callback(events)

View file

@ -1,6 +1,5 @@
package com.simplemobiletools.calendar.pro.helpers package com.simplemobiletools.calendar.pro.helpers
import android.widget.Toast
import com.simplemobiletools.calendar.pro.R import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.SimpleActivity import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.extensions.eventsDB import com.simplemobiletools.calendar.pro.extensions.eventsDB
@ -110,7 +109,7 @@ class IcsImporter(val activity: SimpleActivity) {
curImportId = line.substring(UID.length).trim() curImportId = line.substring(UID.length).trim()
} else if (line.startsWith(RRULE)) { } else if (line.startsWith(RRULE)) {
curRrule = line.substring(RRULE.length) 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) { if (curStart != -1L) {
parseRepeatRule() parseRepeatRule()
} }
@ -227,7 +226,7 @@ class IcsImporter(val activity: SimpleActivity) {
eventsHelper.insertEvents(eventsToInsert, true) eventsHelper.insertEvents(eventsToInsert, true)
} catch (e: Exception) { } catch (e: Exception) {
activity.showErrorToast(e, Toast.LENGTH_LONG) activity.showErrorToast(e)
eventsFailed++ eventsFailed++
} }
@ -248,7 +247,9 @@ class IcsImporter(val activity: SimpleActivity) {
return try { return try {
if (fullString.startsWith(';')) { if (fullString.startsWith(';')) {
val value = fullString.substring(fullString.lastIndexOf(':') + 1).replace(" ", "") 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 curFlags = curFlags or FLAG_ALL_DAY
} }
@ -257,7 +258,7 @@ class IcsImporter(val activity: SimpleActivity) {
Parser().parseDateTimeValue(fullString.substring(1)) Parser().parseDateTimeValue(fullString.substring(1))
} }
} catch (e: Exception) { } catch (e: Exception) {
activity.showErrorToast(e, Toast.LENGTH_LONG) activity.showErrorToast(e)
eventsFailed++ eventsFailed++
-1 -1
} }

View file

@ -40,6 +40,12 @@ class Parser {
if (interval.areDigitsOnly() && interval.toInt() % 7 == 0) { if (interval.areDigitsOnly() && interval.toInt() % 7 == 0) {
val dateTime = Formatter.getDateTimeFromTS(startTS) val dateTime = Formatter.getDateTimeFromTS(startTS)
repeatRule = Math.pow(2.0, (dateTime.dayOfWeek - 1).toDouble()).toInt() 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) { } else if (key == COUNT) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/attendee_circular_background">
<shape android:shape="oval">
<solid android:color="@color/color_primary"/>
</shape>
</item>
<item
android:bottom="@dimen/medium_margin"
android:drawable="@drawable/ic_person_vector"
android:left="@dimen/medium_margin"
android:right="@dimen/medium_margin"
android:top="@dimen/medium_margin"/>
</layer-list>

File diff suppressed because one or more lines are too long

View file

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
</vector>

View file

@ -408,7 +408,7 @@
android:layout_marginStart="@dimen/normal_margin" android:layout_marginStart="@dimen/normal_margin"
android:layout_marginTop="@dimen/small_margin" android:layout_marginTop="@dimen/small_margin"
android:padding="@dimen/medium_margin" android:padding="@dimen/medium_margin"
android:src="@drawable/ic_group_vector"/> android:src="@drawable/ic_people_vector"/>
<LinearLayout <LinearLayout
android:id="@+id/event_attendees_holder" android:id="@+id/event_attendees_holder"
@ -435,9 +435,10 @@
android:layout_below="@+id/event_attendees_divider" android:layout_below="@+id/event_attendees_divider"
android:layout_alignTop="@+id/event_caldav_calendar_holder" android:layout_alignTop="@+id/event_caldav_calendar_holder"
android:layout_alignBottom="@+id/event_caldav_calendar_holder" android:layout_alignBottom="@+id/event_caldav_calendar_holder"
android:layout_alignEnd="@+id/event_time_image"
android:layout_marginStart="@dimen/normal_margin" android:layout_marginStart="@dimen/normal_margin"
android:padding="@dimen/medium_margin" android:padding="@dimen/medium_margin"
android:src="@drawable/ic_calendar" android:src="@drawable/ic_calendar_vector"
android:visibility="gone"/> android:visibility="gone"/>
<RelativeLayout <RelativeLayout

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/calendar_coordinator" android:id="@+id/calendar_coordinator"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -14,7 +13,7 @@
<FrameLayout <FrameLayout
android:id="@+id/fragments_holder" android:id="@+id/fragments_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@ -27,7 +26,7 @@
android:contentDescription="@string/new_event" android:contentDescription="@string/new_event"
android:src="@drawable/ic_plus_vector" android:src="@drawable/ic_plus_vector"
app:backgroundTint="@color/color_primary" app:backgroundTint="@color/color_primary"
app:rippleColor="@color/pressed_item_foreground"/> app:rippleColor="@color/pressed_item_foreground" />
<RelativeLayout <RelativeLayout
android:id="@+id/search_holder" android:id="@+id/search_holder"
@ -43,11 +42,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/activity_margin" android:layout_marginTop="@dimen/activity_margin"
android:alpha="0.8"
android:gravity="center" android:gravity="center"
android:paddingStart="@dimen/activity_margin" android:paddingStart="@dimen/activity_margin"
android:paddingEnd="@dimen/activity_margin" android:paddingEnd="@dimen/activity_margin"
android:text="@string/no_items_found" android:text="@string/no_items_found"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"
android:textStyle="italic" />
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/search_placeholder_2" android:id="@+id/search_placeholder_2"
@ -55,13 +56,15 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/search_placeholder" android:layout_below="@+id/search_placeholder"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:alpha="0.8"
android:gravity="center" android:gravity="center"
android:paddingBottom="@dimen/medium_margin"
android:paddingStart="@dimen/activity_margin" android:paddingStart="@dimen/activity_margin"
android:paddingEnd="@dimen/activity_margin"
android:paddingTop="@dimen/medium_margin" android:paddingTop="@dimen/medium_margin"
android:paddingEnd="@dimen/activity_margin"
android:paddingBottom="@dimen/medium_margin"
android:text="@string/type_2_characters" android:text="@string/type_2_characters"
android:textSize="@dimen/bigger_text_size"/> android:textSize="@dimen/bigger_text_size"
android:textStyle="italic" />
<com.simplemobiletools.commons.views.MyRecyclerView <com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/search_results_list" android:id="@+id/search_results_list"
@ -69,7 +72,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" />
</RelativeLayout> </RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -120,13 +120,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/reminders_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/reminders_label" android:id="@+id/reminders_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -298,13 +291,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/caldav_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/caldav_label" android:id="@+id/caldav_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -381,13 +367,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/new_events_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/new_events_label" android:id="@+id/new_events_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -612,13 +591,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/weekly_view_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/weekly_view_label" android:id="@+id/weekly_view_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -661,13 +633,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/monthly_view_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/monthly_view_label" android:id="@+id/monthly_view_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -721,13 +686,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/events_list_view_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/simple_event_list_label" android:id="@+id/simple_event_list_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -791,13 +749,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/widgets_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/widgets_label" android:id="@+id/widgets_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -890,13 +841,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/events_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/events_label" android:id="@+id/events_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -971,13 +915,6 @@
</RelativeLayout> </RelativeLayout>
<View
android:id="@+id/migrating_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/migrating_label" android:id="@+id/migrating_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -1,16 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/calendar_item_account" android:id="@+id/calendar_item_account"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin"
android:layout_marginLeft="@dimen/big_margin"
android:layout_marginStart="@dimen/big_margin" android:layout_marginStart="@dimen/big_margin"
android:layout_marginTop="@dimen/activity_margin" android:layout_marginTop="@dimen/activity_margin"
android:alpha="0.6" android:layout_marginBottom="@dimen/activity_margin"
android:alpha="0.8"
android:textAllCaps="true" android:textAllCaps="true"
android:textColor="@color/divider_grey" android:textSize="@dimen/normal_text_size"
android:textSize="@dimen/small_text_size" tools:text="Account" />
tools:text="Account"/>

View file

@ -1,16 +1,29 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_select_calendars_scrollview" android:id="@+id/dialog_select_calendars_scrollview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/activity_margin"> android:paddingTop="@dimen/activity_margin">
<LinearLayout <RelativeLayout
android:id="@+id/dialog_select_calendars_holder" android:id="@+id/dialog_select_calendars_wrapper"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:orientation="vertical">
</LinearLayout> <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/dialog_select_calendars_placeholder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:alpha="0.8"
android:text="@string/no_synchronized_calendars"
android:textStyle="italic" />
<LinearLayout
android:id="@+id/dialog_select_calendars_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</RelativeLayout>
</ScrollView> </ScrollView>

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/calendar_events_list_holder" android:id="@+id/calendar_events_list_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -15,7 +14,7 @@
android:paddingTop="@dimen/medium_margin" android:paddingTop="@dimen/medium_margin"
android:scrollbars="vertical" android:scrollbars="vertical"
android:visibility="gone" android:visibility="gone"
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" />
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/calendar_empty_list_placeholder" android:id="@+id/calendar_empty_list_placeholder"
@ -23,24 +22,26 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/activity_margin" android:layout_marginTop="@dimen/activity_margin"
android:alpha="0.8"
android:gravity="center" android:gravity="center"
android:paddingStart="@dimen/activity_margin" android:paddingStart="@dimen/activity_margin"
android:paddingEnd="@dimen/activity_margin" android:paddingEnd="@dimen/activity_margin"
android:text="@string/no_upcoming_events" android:text="@string/no_upcoming_events"
android:textSize="@dimen/bigger_text_size" android:textSize="@dimen/bigger_text_size"
android:visibility="gone"/> android:textStyle="italic"
android:visibility="gone" />
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/calendar_empty_list_placeholder_2" android:id="@+id/calendar_empty_list_placeholder_2"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/calendar_empty_list_placeholder" android:layout_below="@+id/calendar_empty_list_placeholder"
android:background="?attr/selectableItemBackground"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:gravity="center" android:gravity="center"
android:paddingBottom="@dimen/medium_margin" android:padding="@dimen/activity_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/create_new_event" android:text="@string/create_new_event"
android:textSize="@dimen/bigger_text_size" android:textSize="@dimen/bigger_text_size"
android:visibility="gone"/> android:visibility="gone" />
</RelativeLayout> </RelativeLayout>

View file

@ -27,6 +27,7 @@
android:lines="1" android:lines="1"
android:maxLines="1" android:maxLines="1"
android:paddingStart="@dimen/medium_margin" android:paddingStart="@dimen/medium_margin"
android:paddingEnd="@dimen/medium_margin"
android:singleLine="true" android:singleLine="true"
android:textSize="@dimen/bigger_text_size" android:textSize="@dimen/bigger_text_size"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/item_autocomplete_holder" android:id="@+id/item_autocomplete_holder"
@ -17,7 +16,7 @@
android:layout_height="@dimen/avatar_size" android:layout_height="@dimen/avatar_size"
android:layout_margin="@dimen/tiny_margin" android:layout_margin="@dimen/tiny_margin"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/> app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:id="@+id/item_autocomplete_name" android:id="@+id/item_autocomplete_name"
@ -26,6 +25,7 @@
android:lines="1" android:lines="1"
android:maxLines="1" android:maxLines="1"
android:paddingStart="@dimen/medium_margin" android:paddingStart="@dimen/medium_margin"
android:paddingEnd="@dimen/medium_margin"
android:singleLine="true" android:singleLine="true"
android:textSize="@dimen/bigger_text_size" android:textSize="@dimen/bigger_text_size"
app:layout_constraintBottom_toTopOf="@+id/item_autocomplete_email" app:layout_constraintBottom_toTopOf="@+id/item_autocomplete_email"
@ -33,7 +33,7 @@
app:layout_constraintStart_toEndOf="@+id/item_autocomplete_image" app:layout_constraintStart_toEndOf="@+id/item_autocomplete_image"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" app:layout_constraintVertical_chainStyle="packed"
tools:text="Simple Mobile"/> tools:text="Simple Mobile" />
<TextView <TextView
android:id="@+id/item_autocomplete_email" android:id="@+id/item_autocomplete_email"
@ -45,12 +45,13 @@
android:lines="1" android:lines="1"
android:maxLines="1" android:maxLines="1"
android:paddingStart="@dimen/medium_margin" android:paddingStart="@dimen/medium_margin"
android:paddingEnd="@dimen/medium_margin"
android:singleLine="true" android:singleLine="true"
android:textSize="@dimen/normal_text_size" android:textSize="@dimen/normal_text_size"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/item_autocomplete_image" app:layout_constraintStart_toEndOf="@+id/item_autocomplete_image"
app:layout_constraintTop_toBottomOf="@+id/item_autocomplete_name" app:layout_constraintTop_toBottomOf="@+id/item_autocomplete_name"
tools:text="hello@simplemobiletools.com"/> tools:text="hello@simplemobiletools.com" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">اختر لون مختلف (يمكن تطبيقه محليا فقط)</string> <string name="select_a_different_caldav_color">اختر لون مختلف (يمكن تطبيقه محليا فقط)</string>
<string name="insufficient_permissions">لا يمكنك التعديل في هذا التقويم</string> <string name="insufficient_permissions">لا يمكنك التعديل في هذا التقويم</string>
<string name="caldav_event_not_found">مناسبة غير موجودة. من فضلك فَعّل مُزامنة CalDAV للحصول على التقويم المناسب من الإعدادات.</string> <string name="caldav_event_not_found">مناسبة غير موجودة. من فضلك فَعّل مُزامنة CalDAV للحصول على التقويم المناسب من الإعدادات.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -211,6 +211,7 @@
<string name="select_a_different_caldav_color">একটি আলাদা রঙ সিলেক্ট করুন(কেবল স্থানীয়ভাবে প্রয়োগ করা যেতে পারে)</string> <string name="select_a_different_caldav_color">একটি আলাদা রঙ সিলেক্ট করুন(কেবল স্থানীয়ভাবে প্রয়োগ করা যেতে পারে)</string>
<string name="insufficient_permissions">আপনার সিলেক্টেড ক্যালেন্ডারে লেখার অনুমতি নেই</string> <string name="insufficient_permissions">আপনার সিলেক্টেড ক্যালেন্ডারে লেখার অনুমতি নেই</string>
<string name="caldav_event_not_found">ইভেন্ট পাওয়া যায় নি। অ্যাপ্লিকেশন সেটিংসে উপযুক্ত ক্যালেন্ডারের জন্য দয়া করে CalDAV সিঙ্ক সক্ষম করুন।</string> <string name="caldav_event_not_found">ইভেন্ট পাওয়া যায় নি। অ্যাপ্লিকেশন সেটিংসে উপযুক্ত ক্যালেন্ডারের জন্য দয়া করে CalDAV সিঙ্ক সক্ষম করুন।</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Zvolit jinou barvu (možná bude nastavena pouze lokálně)</string> <string name="select_a_different_caldav_color">Zvolit jinou barvu (možná bude nastavena pouze lokálně)</string>
<string name="insufficient_permissions">Nemáte oprávnění pro zápis do zvoleného kalendáře</string> <string name="insufficient_permissions">Nemáte oprávnění pro zápis do zvoleného kalendáře</string>
<string name="caldav_event_not_found">Událost nenalezena. Prosím, povolte CalDAV synchronizaci příslušného kalendáře v nastavení aplikace.</string> <string name="caldav_event_not_found">Událost nenalezena. Prosím, povolte CalDAV synchronizaci příslušného kalendáře v nastavení aplikace.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Vælg en anden farve (den kan være tilføjet lokalt)</string> <string name="select_a_different_caldav_color">Vælg en anden farve (den kan være tilføjet lokalt)</string>
<string name="insufficient_permissions">Du har ikke tilladelse til at skrive i den valgte kalender</string> <string name="insufficient_permissions">Du har ikke tilladelse til at skrive i den valgte kalender</string>
<string name="caldav_event_not_found">Begivenheden blev ikke fundet. Aktiver CalDAV-synkronisering med den relevante kalender i app-indstillingerne.</string> <string name="caldav_event_not_found">Begivenheden blev ikke fundet. Aktiver CalDAV-synkronisering med den relevante kalender i app-indstillingerne.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Wähle eine andere Farbe (wird möglicherweise nur lokal angewendet)</string> <string name="select_a_different_caldav_color">Wähle eine andere Farbe (wird möglicherweise nur lokal angewendet)</string>
<string name="insufficient_permissions">Dir fehlt die Berechtigung zum Ändern des gewählten Kalenders</string> <string name="insufficient_permissions">Dir fehlt die Berechtigung zum Ändern des gewählten Kalenders</string>
<string name="caldav_event_not_found">Der Termin wurde nicht gefunden. Bitte aktiviere die Synchronisierung für den Kalender in den Einstellungen.</string> <string name="caldav_event_not_found">Der Termin wurde nicht gefunden. Bitte aktiviere die Synchronisierung für den Kalender in den Einstellungen.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Επιλέξτε διαφορετικό χρώμα (μπορεί να εφαρμοστεί μόνο τοπικά)</string> <string name="select_a_different_caldav_color">Επιλέξτε διαφορετικό χρώμα (μπορεί να εφαρμοστεί μόνο τοπικά)</string>
<string name="insufficient_permissions">Δεν επιτρέπεται η εγγραφή στο επιλεγμένο ημερολόγιο</string> <string name="insufficient_permissions">Δεν επιτρέπεται η εγγραφή στο επιλεγμένο ημερολόγιο</string>
<string name="caldav_event_not_found">Δεν βρέθηκε Εκδήλωση. Παρακαλώ ενεργοποιήστε το συγχρονισμό CalDAV του Ημερολογίου από τις ρυθμίσεις της εφαρμογής.</string> <string name="caldav_event_not_found">Δεν βρέθηκε Εκδήλωση. Παρακαλώ ενεργοποιήστε το συγχρονισμό CalDAV του Ημερολογίου από τις ρυθμίσεις της εφαρμογής.</string>
<string name="no_synchronized_calendars">Δεν μπόρεσαν να βρεθούν συγχρονισμένα Ημερολόγια</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Seleccionar un color diferente (localmente)</string> <string name="select_a_different_caldav_color">Seleccionar un color diferente (localmente)</string>
<string name="insufficient_permissions">No tiene permiso para modificar el calendario</string> <string name="insufficient_permissions">No tiene permiso para modificar el calendario</string>
<string name="caldav_event_not_found">Evento no encontrado. Habilite la sincronización de CalDAV para los calendarios en la configuración.</string> <string name="caldav_event_not_found">Evento no encontrado. Habilite la sincronización de CalDAV para los calendarios en la configuración.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -208,6 +208,7 @@
<string name="select_a_different_caldav_color">Sélectionnez une couleur différente (peut être appliqué localement uniquement)</string> <string name="select_a_different_caldav_color">Sélectionnez une couleur différente (peut être appliqué localement uniquement)</string>
<string name="insufficient_permissions">Vous n\êtes pas autorisé à écrire dans l\agenda sélectionné</string> <string name="insufficient_permissions">Vous n\êtes pas autorisé à écrire dans l\agenda sélectionné</string>
<string name="caldav_event_not_found">Événement introuvable. Veuillez activer la synchronisation CalDAV pour le calendrier approprié dans les paramètres de lapplication.</string> <string name="caldav_event_not_found">Événement introuvable. Veuillez activer la synchronisation CalDAV pour le calendrier approprié dans les paramètres de lapplication.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Escolle un color diferente (pode que só se aplique localmente)</string> <string name="select_a_different_caldav_color">Escolle un color diferente (pode que só se aplique localmente)</string>
<string name="insufficient_permissions">Non tes permiso para escribir no calendario seleccionado</string> <string name="insufficient_permissions">Non tes permiso para escribir no calendario seleccionado</string>
<string name="caldav_event_not_found">Evento non atopado. Activa a sincronización de CalDAV para o calendario apropiado nos axustes da aplicación.</string> <string name="caldav_event_not_found">Evento non atopado. Activa a sincronización de CalDAV para o calendario apropiado nos axustes da aplicación.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">בחירת צבע שונה (ייתכן שיישמר מקומית בלבד)</string> <string name="select_a_different_caldav_color">בחירת צבע שונה (ייתכן שיישמר מקומית בלבד)</string>
<string name="insufficient_permissions">לא קיימת הרשאת כתיבה ליומנים הנבחרים</string> <string name="insufficient_permissions">לא קיימת הרשאת כתיבה ליומנים הנבחרים</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Odaberite drugu boju (može se primijeniti samo lokalno)</string> <string name="select_a_different_caldav_color">Odaberite drugu boju (može se primijeniti samo lokalno)</string>
<string name="insufficient_permissions">Nije vam dopušteno pisati u odabranom kalendaru</string> <string name="insufficient_permissions">Nije vam dopušteno pisati u odabranom kalendaru</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Pilih warna yang berbeda (mungkin hanya diterapkan secara lokal)</string> <string name="select_a_different_caldav_color">Pilih warna yang berbeda (mungkin hanya diterapkan secara lokal)</string>
<string name="insufficient_permissions">Anda tidak diizinkan untuk membuat/mengubah acara pada kalender yang dipilih</string> <string name="insufficient_permissions">Anda tidak diizinkan untuk membuat/mengubah acara pada kalender yang dipilih</string>
<string name="caldav_event_not_found">Acara tidak ditemukan. Silakan aktifkan sinkronisasi CalDAV untuk kalender terkait di dalam pengaturan aplikasi.</string> <string name="caldav_event_not_found">Acara tidak ditemukan. Silakan aktifkan sinkronisasi CalDAV untuk kalender terkait di dalam pengaturan aplikasi.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Pilih warna yang berbeda (mungkin hanya diterapkan secara lokal)</string> <string name="select_a_different_caldav_color">Pilih warna yang berbeda (mungkin hanya diterapkan secara lokal)</string>
<string name="insufficient_permissions">Anda tidak diizinkan untuk membuat/mengubah acara pada kalender yang dipilih</string> <string name="insufficient_permissions">Anda tidak diizinkan untuk membuat/mengubah acara pada kalender yang dipilih</string>
<string name="caldav_event_not_found">Acara tidak ditemukan. Silakan aktifkan sinkronisasi CalDAV untuk kalender terkait di dalam pengaturan aplikasi.</string> <string name="caldav_event_not_found">Acara tidak ditemukan. Silakan aktifkan sinkronisasi CalDAV untuk kalender terkait di dalam pengaturan aplikasi.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Seleziona un colore differente (potrebbe essere applicato solamente in locale)</string> <string name="select_a_different_caldav_color">Seleziona un colore differente (potrebbe essere applicato solamente in locale)</string>
<string name="insufficient_permissions">Non si hanno i permessi per scrivere nel calendario selezionato</string> <string name="insufficient_permissions">Non si hanno i permessi per scrivere nel calendario selezionato</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">בחירת צבע שונה (ייתכן שיישמר מקומית בלבד)</string> <string name="select_a_different_caldav_color">בחירת צבע שונה (ייתכן שיישמר מקומית בלבד)</string>
<string name="insufficient_permissions">לא קיימת הרשאת כתיבה ליומנים הנבחרים</string> <string name="insufficient_permissions">לא קיימת הרשאת כתיבה ליומנים הנבחרים</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">다른 색상을 선택해주세요(로컬에만 적용 가능)</string> <string name="select_a_different_caldav_color">다른 색상을 선택해주세요(로컬에만 적용 가능)</string>
<string name="insufficient_permissions">선택한 캘린더에 작성할 수 없습니다.</string> <string name="insufficient_permissions">선택한 캘린더에 작성할 수 없습니다.</string>
<string name="caldav_event_not_found">일정을 찾을 수 없습니다. 앱 설정에서 해당 캘린더에 대해 CalDAV 동기화를 활성화해주세요.</string> <string name="caldav_event_not_found">일정을 찾을 수 없습니다. 앱 설정에서 해당 캘린더에 대해 CalDAV 동기화를 활성화해주세요.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Izvēlieties citu krāsu (var tikt izmantota tikai lokāli)</string> <string name="select_a_different_caldav_color">Izvēlieties citu krāsu (var tikt izmantota tikai lokāli)</string>
<string name="insufficient_permissions">Jums izvēlētajā kalendārā rakstīt nav ļauts</string> <string name="insufficient_permissions">Jums izvēlētajā kalendārā rakstīt nav ļauts</string>
<string name="caldav_event_not_found">Notikums nav atrasts. Lūdzu, lietotnes iestatījumos iespējojiet CalDAV sinhronizāciju attiecīgajam kalendāram.</string> <string name="caldav_event_not_found">Notikums nav atrasts. Lūdzu, lietotnes iestatījumos iespējojiet CalDAV sinhronizāciju attiecīgajam kalendāram.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Kies een andere kleur (mogelijk alleen voor dit apparaat)</string> <string name="select_a_different_caldav_color">Kies een andere kleur (mogelijk alleen voor dit apparaat)</string>
<string name="insufficient_permissions">Kan geen wijzigingen aanbrengen in deze agenda</string> <string name="insufficient_permissions">Kan geen wijzigingen aanbrengen in deze agenda</string>
<string name="caldav_event_not_found">Afspraak niet gevonden. Schakel via Instellingen de CalDAV-synchronisatie in voor deze agenda.</string> <string name="caldav_event_not_found">Afspraak niet gevonden. Schakel via Instellingen de CalDAV-synchronisatie in voor deze agenda.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Selecione uma cor diferente (pode ser aplicada apenas localmente)</string> <string name="select_a_different_caldav_color">Selecione uma cor diferente (pode ser aplicada apenas localmente)</string>
<string name="insufficient_permissions">Não tem permissão para escrever no calendário selecionado</string> <string name="insufficient_permissions">Não tem permissão para escrever no calendário selecionado</string>
<string name="caldav_event_not_found">Evento não encontrado. Ative a sincronização CalDAV para os calendários apropriados nas definições.</string> <string name="caldav_event_not_found">Evento não encontrado. Ative a sincronização CalDAV para os calendários apropriados nas definições.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Выберите другой цвет (применяется локально)</string> <string name="select_a_different_caldav_color">Выберите другой цвет (применяется локально)</string>
<string name="insufficient_permissions">Запись в выбранный календарь запрещена</string> <string name="insufficient_permissions">Запись в выбранный календарь запрещена</string>
<string name="caldav_event_not_found">Событие не найдено. Пожалуйста, включите CalDAV-синхронизацию для соответствующего календаря в настройках приложения.</string> <string name="caldav_event_not_found">Событие не найдено. Пожалуйста, включите CalDAV-синхронизацию для соответствующего календаря в настройках приложения.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Zvoliť inú farbu (možno bude aplikovaná iba lokálne)</string> <string name="select_a_different_caldav_color">Zvoliť inú farbu (možno bude aplikovaná iba lokálne)</string>
<string name="insufficient_permissions">Nemáte dostatočné oprávnenie na písanie do zvoleného kalendára</string> <string name="insufficient_permissions">Nemáte dostatočné oprávnenie na písanie do zvoleného kalendára</string>
<string name="caldav_event_not_found">Udalosť nebola nájdená. Prosím povoľte CalDAV synchronizáciu príslušného kalendára v nastaveniach aplikácie.</string> <string name="caldav_event_not_found">Udalosť nebola nájdená. Prosím povoľte CalDAV synchronizáciu príslušného kalendára v nastaveniach aplikácie.</string>
<string name="no_synchronized_calendars">Nenašli sa žiadne synchronizovateľné kalendáre</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Välj en annan färg (tillämpas kanske bara lokalt)</string> <string name="select_a_different_caldav_color">Välj en annan färg (tillämpas kanske bara lokalt)</string>
<string name="insufficient_permissions">Du har inte behörighet att redigera den valda kalendern</string> <string name="insufficient_permissions">Du har inte behörighet att redigera den valda kalendern</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Farklı bir renk seçin (yalnızca yerel olarak uygulanabilir)</string> <string name="select_a_different_caldav_color">Farklı bir renk seçin (yalnızca yerel olarak uygulanabilir)</string>
<string name="insufficient_permissions">Seçili takvime yazmanıza izin verilmiyor</string> <string name="insufficient_permissions">Seçili takvime yazmanıza izin verilmiyor</string>
<string name="caldav_event_not_found">Etkinlik bulunamadı. Lütfen uygulama ayarlarından uygun takvim için CalDAV senkronizasyonunu etkinleştirin.</string> <string name="caldav_event_not_found">Etkinlik bulunamadı. Lütfen uygulama ayarlarından uygun takvim için CalDAV senkronizasyonunu etkinleştirin.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Обрати інший колір (можна застосувати лише локально)</string> <string name="select_a_different_caldav_color">Обрати інший колір (можна застосувати лише локально)</string>
<string name="insufficient_permissions">Ви не можете редагувати обраний календар</string> <string name="insufficient_permissions">Ви не можете редагувати обраний календар</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
    <string name="select_a_different_caldav_color">选择不同的颜色 (只能被添加于本机端)</string>     <string name="select_a_different_caldav_color">选择不同的颜色 (只能被添加于本机端)</string>
    <string name="insufficient_permissions">你不被允许对选择的行事历写入</string>     <string name="insufficient_permissions">你不被允许对选择的行事历写入</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
    <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->     <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
    <!-- used in repetition, like "Every last Sunday" -->     <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">選擇不同的顏色 (只能被添加於本機端)</string> <string name="select_a_different_caldav_color">選擇不同的顏色 (只能被添加於本機端)</string>
<string name="insufficient_permissions">你不被允許對選擇的行事曆寫入</string> <string name="insufficient_permissions">你不被允許對選擇的行事曆寫入</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">選擇不同的顏色 (只能被添加於本機端)</string> <string name="select_a_different_caldav_color">選擇不同的顏色 (只能被添加於本機端)</string>
<string name="insufficient_permissions">你不被允許對選擇的行事曆寫入</string> <string name="insufficient_permissions">你不被允許對選擇的行事曆寫入</string>
<string name="caldav_event_not_found">未發現活動。請在程式設定中為合適的行事曆啟用CalDAV同步。</string> <string name="caldav_event_not_found">未發現活動。請在程式設定中為合適的行事曆啟用CalDAV同步。</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -207,6 +207,7 @@
<string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string> <string name="select_a_different_caldav_color">Select a different color (might be applied locally only)</string>
<string name="insufficient_permissions">You are not allowed to write in the selected calendar</string> <string name="insufficient_permissions">You are not allowed to write in the selected calendar</string>
<string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string> <string name="caldav_event_not_found">Event not found. Please enable CalDAV sync for the appropriate calendar in the app settings.</string>
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
<!-- alternative versions for some languages, use the same translations if you are not sure what this means --> <!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
<!-- used in repetition, like "Every last Sunday" --> <!-- used in repetition, like "Every last Sunday" -->

View file

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.70' ext.kotlin_version = '1.3.72'
repositories { repositories {
google() google()
@ -10,7 +10,7 @@ buildscript {
} }
dependencies { 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 "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "de.timfreiheit.resourceplaceholders:placeholders:0.3" classpath "de.timfreiheit.resourceplaceholders:placeholders:0.3"

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB