Merge branch 'master' into feat/weekly-view-slider-setting
This commit is contained in:
commit
041c2ecbac
20 changed files with 214 additions and 56 deletions
|
@ -18,6 +18,7 @@ charset = utf-8
|
|||
indent_style = space
|
||||
indent_size = 4
|
||||
continuation_indent_size = 4
|
||||
max_line_length = 160
|
||||
|
||||
[*.xml]
|
||||
continuation_indent_size = 4
|
||||
|
|
|
@ -63,7 +63,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.github.SimpleMobileTools:Simple-Commons:1b72d7ccff'
|
||||
implementation 'com.github.SimpleMobileTools:Simple-Commons:16ae1d2c03'
|
||||
implementation 'joda-time:joda-time:2.10.3'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
|
|
|
@ -63,6 +63,7 @@ class EventActivity : SimpleActivity() {
|
|||
private val REPEAT_LIMIT = "REPEAT_LIMIT"
|
||||
private val REPEAT_RULE = "REPEAT_RULE"
|
||||
private val ATTENDEES = "ATTENDEES"
|
||||
private val AVAILABILITY = "AVAILABILITY"
|
||||
private val EVENT_TYPE_ID = "EVENT_TYPE_ID"
|
||||
private val EVENT_CALENDAR_ID = "EVENT_CALENDAR_ID"
|
||||
private val SELECT_TIME_ZONE_INTENT = 1
|
||||
|
@ -89,6 +90,7 @@ class EventActivity : SimpleActivity() {
|
|||
private var mAttendeeAutoCompleteViews = ArrayList<MyAutoCompleteTextView>()
|
||||
private var mAvailableContacts = ArrayList<Attendee>()
|
||||
private var mSelectedContacts = ArrayList<Attendee>()
|
||||
private var mAvailability = Attendees.AVAILABILITY_BUSY
|
||||
private var mStoredEventTypes = ArrayList<EventType>()
|
||||
private var mOriginalTimeZone = DateTimeZone.getDefault().id
|
||||
private var mOriginalStartTS = 0L
|
||||
|
@ -217,6 +219,14 @@ class EventActivity : SimpleActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
event_availability.setOnClickListener {
|
||||
showAvailabilityPicker(mAvailability) {
|
||||
mAvailability = it
|
||||
updateAvailabilityText()
|
||||
updateAvailabilityImage()
|
||||
}
|
||||
}
|
||||
|
||||
event_type_holder.setOnClickListener { showEventTypeDialog() }
|
||||
event_all_day.apply {
|
||||
isChecked = mEvent.flags and FLAG_ALL_DAY != 0
|
||||
|
@ -350,6 +360,8 @@ class EventActivity : SimpleActivity() {
|
|||
|
||||
putString(ATTENDEES, getAllAttendees(false))
|
||||
|
||||
putInt(AVAILABILITY, mAvailability)
|
||||
|
||||
putLong(EVENT_TYPE_ID, mEventTypeId)
|
||||
putInt(EVENT_CALENDAR_ID, mEventCalendarId)
|
||||
}
|
||||
|
@ -376,6 +388,8 @@ class EventActivity : SimpleActivity() {
|
|||
mReminder2Type = getInt(REMINDER_2_TYPE)
|
||||
mReminder3Type = getInt(REMINDER_3_TYPE)
|
||||
|
||||
mAvailability = getInt(AVAILABILITY)
|
||||
|
||||
mRepeatInterval = getInt(REPEAT_INTERVAL)
|
||||
mRepeatRule = getInt(REPEAT_RULE)
|
||||
mRepeatLimit = getLong(REPEAT_LIMIT)
|
||||
|
@ -410,7 +424,9 @@ class EventActivity : SimpleActivity() {
|
|||
updateStartTexts()
|
||||
updateEndTexts()
|
||||
updateTimeZoneText()
|
||||
updateAttendeesVisibility()
|
||||
updateCalDAVVisibility()
|
||||
updateAvailabilityText()
|
||||
updateAvailabilityImage()
|
||||
}
|
||||
|
||||
private fun setupEditEvent() {
|
||||
|
@ -451,6 +467,7 @@ class EventActivity : SimpleActivity() {
|
|||
mRepeatRule = mEvent.repeatRule
|
||||
mEventTypeId = mEvent.eventType
|
||||
mEventCalendarId = mEvent.getCalDAVCalendarId()
|
||||
mAvailability = mEvent.availability
|
||||
|
||||
val token = object : TypeToken<List<Attendee>>() {}.type
|
||||
mAttendees = Gson().fromJson<ArrayList<Attendee>>(mEvent.attendees, token) ?: ArrayList()
|
||||
|
@ -836,17 +853,30 @@ class EventActivity : SimpleActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun showAvailabilityPicker(currentValue: Int, callback: (Int) -> Unit) {
|
||||
val items = arrayListOf(
|
||||
RadioItem(Attendees.AVAILABILITY_BUSY, getString(R.string.status_busy)),
|
||||
RadioItem(Attendees.AVAILABILITY_FREE, getString(R.string.status_free))
|
||||
)
|
||||
RadioGroupDialog(this, items, currentValue) {
|
||||
callback(it as Int)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateReminderTypeImages() {
|
||||
updateReminderTypeImage(event_reminder_1_type, Reminder(mReminder1Minutes, mReminder1Type))
|
||||
updateReminderTypeImage(event_reminder_2_type, Reminder(mReminder2Minutes, mReminder2Type))
|
||||
updateReminderTypeImage(event_reminder_3_type, Reminder(mReminder3Minutes, mReminder3Type))
|
||||
}
|
||||
|
||||
private fun updateAttendeesVisibility() {
|
||||
private fun updateCalDAVVisibility() {
|
||||
val isSyncedEvent = mEventCalendarId != STORED_LOCALLY_ONLY
|
||||
event_attendees_image.beVisibleIf(isSyncedEvent)
|
||||
event_attendees_holder.beVisibleIf(isSyncedEvent)
|
||||
event_attendees_divider.beVisibleIf(isSyncedEvent)
|
||||
event_availability_divider.beVisibleIf(isSyncedEvent)
|
||||
event_availability_image.beVisibleIf(isSyncedEvent)
|
||||
event_availability.beVisibleIf(isSyncedEvent)
|
||||
}
|
||||
|
||||
private fun updateReminderTypeImage(view: ImageView, reminder: Reminder) {
|
||||
|
@ -856,6 +886,16 @@ class EventActivity : SimpleActivity() {
|
|||
view.setImageDrawable(icon)
|
||||
}
|
||||
|
||||
private fun updateAvailabilityImage() {
|
||||
val drawable = if (mAvailability == Attendees.AVAILABILITY_FREE) R.drawable.ic_event_available else R.drawable.ic_event_occupied
|
||||
val icon = resources.getColoredDrawableWithColor(drawable, config.textColor)
|
||||
event_availability_image.setImageDrawable(icon)
|
||||
}
|
||||
|
||||
private fun updateAvailabilityText() {
|
||||
event_availability.text = if (mAvailability == Attendees.AVAILABILITY_FREE) getString(R.string.status_free) else getString(R.string.status_busy)
|
||||
}
|
||||
|
||||
private fun updateRepetitionText() {
|
||||
event_repetition.text = getRepetitionText(mRepeatInterval)
|
||||
}
|
||||
|
@ -895,7 +935,9 @@ class EventActivity : SimpleActivity() {
|
|||
config.lastUsedCaldavCalendarId = it
|
||||
updateCurrentCalendarInfo(getCalendarWithId(calendars, it))
|
||||
updateReminderTypeImages()
|
||||
updateAttendeesVisibility()
|
||||
updateCalDAVVisibility()
|
||||
updateAvailabilityText()
|
||||
updateAvailabilityImage()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1122,6 +1164,7 @@ class EventActivity : SimpleActivity() {
|
|||
lastUpdated = System.currentTimeMillis()
|
||||
source = newSource
|
||||
location = event_location.value
|
||||
availability = mAvailability
|
||||
}
|
||||
|
||||
// recreate the event if it was moved in a different CalDAV calendar
|
||||
|
@ -1648,7 +1691,7 @@ class EventActivity : SimpleActivity() {
|
|||
val textColor = config.textColor
|
||||
arrayOf(
|
||||
event_time_image, event_time_zone_image, event_repetition_image, event_reminder_image, event_type_image, event_caldav_calendar_image,
|
||||
event_reminder_1_type, event_reminder_2_type, event_reminder_3_type, event_attendees_image
|
||||
event_reminder_1_type, event_reminder_2_type, event_reminder_3_type, event_attendees_image, event_availability_image
|
||||
).forEach {
|
||||
it.applyColorFilter(textColor)
|
||||
}
|
||||
|
|
|
@ -606,13 +606,14 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
|||
val selectionArgs = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE, type.toString())
|
||||
|
||||
val dateFormats = getDateFormats()
|
||||
val yearDateFormats = getDateFormatsWithYear()
|
||||
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 eventTypeId = if (birthdays) eventsHelper.getBirthdaysEventTypeId() else eventsHelper.getAnniversariesEventTypeId()
|
||||
val source = if (birthdays) SOURCE_CONTACT_BIRTHDAY else SOURCE_CONTACT_ANNIVERSARY
|
||||
|
||||
queryCursor(uri, projection, selection, selectionArgs, showErrors = true) { cursor ->
|
||||
|
@ -624,15 +625,17 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
|||
try {
|
||||
val formatter = SimpleDateFormat(format, Locale.getDefault())
|
||||
val date = formatter.parse(startDate)
|
||||
if (date.year < 70) {
|
||||
date.year = 70
|
||||
val flags = if (format in yearDateFormats) {
|
||||
FLAG_ALL_DAY
|
||||
} else {
|
||||
FLAG_ALL_DAY or FLAG_MISSING_YEAR
|
||||
}
|
||||
|
||||
val timestamp = date.time / 1000L
|
||||
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,
|
||||
reminder3Minutes = reminders[2], importId = contactId, timeZone = DateTimeZone.getDefault().id, flags = flags,
|
||||
repeatInterval = YEAR, repeatRule = REPEAT_SAME_DAY, eventType = eventTypeId, source = source, lastUpdated = lastUpdated
|
||||
)
|
||||
|
||||
|
@ -681,7 +684,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
|||
}
|
||||
|
||||
try {
|
||||
val eventTypeId = if (birthdays) getBirthdaysEventTypeId() else getAnniversariesEventTypeId()
|
||||
val eventTypeId = if (birthdays) eventsHelper.getBirthdaysEventTypeId() else eventsHelper.getAnniversariesEventTypeId()
|
||||
val source = if (birthdays) SOURCE_CONTACT_BIRTHDAY else SOURCE_CONTACT_ANNIVERSARY
|
||||
|
||||
val existingEvents = if (birthdays) eventsDB.getBirthdays() else eventsDB.getAnniversaries()
|
||||
|
@ -743,26 +746,6 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
|||
callback(eventsFound, eventsAdded)
|
||||
}
|
||||
|
||||
private fun getBirthdaysEventTypeId(): Long {
|
||||
val birthdays = getString(R.string.birthdays)
|
||||
var eventTypeId = eventsHelper.getEventTypeIdWithTitle(birthdays)
|
||||
if (eventTypeId == -1L) {
|
||||
val eventType = EventType(null, birthdays, resources.getColor(R.color.default_birthdays_color))
|
||||
eventTypeId = eventsHelper.insertOrUpdateEventTypeSync(eventType)
|
||||
}
|
||||
return eventTypeId
|
||||
}
|
||||
|
||||
private fun getAnniversariesEventTypeId(): Long {
|
||||
val anniversaries = getString(R.string.anniversaries)
|
||||
var eventTypeId = eventsHelper.getEventTypeIdWithTitle(anniversaries)
|
||||
if (eventTypeId == -1L) {
|
||||
val eventType = EventType(null, anniversaries, resources.getColor(R.color.default_anniversaries_color))
|
||||
eventTypeId = eventsHelper.insertOrUpdateEventTypeSync(eventType)
|
||||
}
|
||||
return eventTypeId
|
||||
}
|
||||
|
||||
private fun updateView(view: Int) {
|
||||
calendar_fab.beVisibleIf(view != YEARLY_VIEW && view != WEEKLY_VIEW)
|
||||
config.storedView = view
|
||||
|
|
|
@ -17,7 +17,7 @@ import com.simplemobiletools.calendar.pro.models.Event
|
|||
import com.simplemobiletools.calendar.pro.models.EventType
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@Database(entities = [Event::class, EventType::class], version = 3)
|
||||
@Database(entities = [Event::class, EventType::class], version = 4)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class EventsDatabase : RoomDatabase() {
|
||||
|
||||
|
@ -41,6 +41,7 @@ abstract class EventsDatabase : RoomDatabase() {
|
|||
})
|
||||
.addMigrations(MIGRATION_1_2)
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
.addMigrations(MIGRATION_3_4)
|
||||
.build()
|
||||
db!!.openHelper.setWriteAheadLoggingEnabled(true)
|
||||
}
|
||||
|
@ -80,5 +81,13 @@ abstract class EventsDatabase : RoomDatabase() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val MIGRATION_3_4 = object : Migration(3, 4) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.apply {
|
||||
execSQL("ALTER TABLE events ADD COLUMN availability INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,7 +170,9 @@ class CalDAVHelper(val context: Context) {
|
|||
Events.EVENT_LOCATION,
|
||||
Events.EVENT_TIMEZONE,
|
||||
Events.CALENDAR_TIME_ZONE,
|
||||
Events.DELETED)
|
||||
Events.DELETED,
|
||||
Events.AVAILABILITY
|
||||
)
|
||||
|
||||
val selection = "${Events.CALENDAR_ID} = $calendarId"
|
||||
context.queryCursor(uri, projection, selection, showErrors = showToasts) { cursor ->
|
||||
|
@ -191,6 +193,7 @@ class CalDAVHelper(val context: Context) {
|
|||
val originalInstanceTime = cursor.getLongValue(Events.ORIGINAL_INSTANCE_TIME)
|
||||
val reminders = getCalDAVEventReminders(id)
|
||||
val attendees = Gson().toJson(getCalDAVEventAttendees(id))
|
||||
val availability = cursor.getIntValue(Events.AVAILABILITY)
|
||||
|
||||
if (endTS == 0L) {
|
||||
val duration = cursor.getStringValue(Events.DURATION) ?: ""
|
||||
|
@ -210,7 +213,7 @@ class CalDAVHelper(val context: Context) {
|
|||
reminder2?.minutes ?: REMINDER_OFF, reminder3?.minutes ?: REMINDER_OFF, reminder1?.type
|
||||
?: REMINDER_NOTIFICATION, reminder2?.type ?: REMINDER_NOTIFICATION, reminder3?.type
|
||||
?: REMINDER_NOTIFICATION, repeatRule.repeatInterval, repeatRule.repeatRule,
|
||||
repeatRule.repeatLimit, ArrayList(), attendees, importId, eventTimeZone, allDay, eventTypeId, source = source)
|
||||
repeatRule.repeatLimit, ArrayList(), attendees, importId, eventTimeZone, allDay, eventTypeId, source = source, availability = availability)
|
||||
|
||||
if (event.getIsAllDay()) {
|
||||
event.startTS = Formatter.getShiftedImportTimestamp(event.startTS)
|
||||
|
@ -382,6 +385,7 @@ class CalDAVHelper(val context: Context) {
|
|||
put(Events.EVENT_TIMEZONE, event.getTimeZoneString())
|
||||
put(Events.EVENT_LOCATION, event.location)
|
||||
put(Events.STATUS, Events.STATUS_CONFIRMED)
|
||||
put(Events.AVAILABILITY, event.availability)
|
||||
|
||||
val repeatRule = Parser().getRepeatCode(event)
|
||||
if (repeatRule.isEmpty()) {
|
||||
|
|
|
@ -94,6 +94,7 @@ const val REPEAT_ORDER_WEEKDAY = 4 // i.e. every 4th sunday
|
|||
// special event flags
|
||||
const val FLAG_ALL_DAY = 1
|
||||
const val FLAG_IS_PAST_EVENT = 2
|
||||
const val FLAG_MISSING_YEAR = 4
|
||||
|
||||
// constants related to ICS file exporting / importing
|
||||
const val BEGIN_CALENDAR = "BEGIN:VCALENDAR"
|
||||
|
@ -113,6 +114,7 @@ const val SUMMARY = "SUMMARY"
|
|||
const val DESCRIPTION = "DESCRIPTION:"
|
||||
const val UID = "UID:"
|
||||
const val ACTION = "ACTION:"
|
||||
const val TRANSP = "TRANSP:"
|
||||
const val ATTENDEE = "ATTENDEE:"
|
||||
const val MAILTO = "mailto:"
|
||||
const val TRIGGER = "TRIGGER"
|
||||
|
@ -130,6 +132,7 @@ const val SEQUENCE = "SEQUENCE"
|
|||
// this tag isn't a standard ICS tag, but there's no official way of adding a category color in an ics file
|
||||
const val CATEGORY_COLOR = "X-SMT-CATEGORY-COLOR:"
|
||||
const val CATEGORY_COLOR_LEGACY = "CATEGORY_COLOR:"
|
||||
const val MISSING_YEAR = "X-SMT-MISSING-YEAR:"
|
||||
|
||||
const val DISPLAY = "DISPLAY"
|
||||
const val EMAIL = "EMAIL"
|
||||
|
@ -154,6 +157,9 @@ const val FR = "FR"
|
|||
const val SA = "SA"
|
||||
const val SU = "SU"
|
||||
|
||||
const val OPAQUE = "OPAQUE"
|
||||
const val TRANSPARENT = "TRANSPARENT"
|
||||
|
||||
const val SOURCE_SIMPLE_CALENDAR = "simple-calendar"
|
||||
const val SOURCE_IMPORTED_ICS = "imported-ics"
|
||||
const val SOURCE_CONTACT_BIRTHDAY = "contact-birthday"
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simplemobiletools.calendar.pro.helpers
|
|||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import androidx.collection.LongSparseArray
|
||||
import com.simplemobiletools.calendar.pro.R
|
||||
import com.simplemobiletools.calendar.pro.extensions.*
|
||||
import com.simplemobiletools.calendar.pro.models.Event
|
||||
import com.simplemobiletools.calendar.pro.models.EventType
|
||||
|
@ -259,6 +260,9 @@ class EventsHelper(val context: Context) {
|
|||
}
|
||||
|
||||
fun getEventsSync(fromTS: Long, toTS: Long, eventId: Long = -1L, applyTypeFilter: Boolean, callback: (events: ArrayList<Event>) -> Unit) {
|
||||
val birthDayEventId = getBirthdaysEventTypeId(createIfNotExists = false)
|
||||
val anniversaryEventId = getAnniversariesEventTypeId(createIfNotExists = false)
|
||||
|
||||
var events = if (applyTypeFilter) {
|
||||
val displayEventTypes = context.config.displayEventTypes
|
||||
if (displayEventTypes.isEmpty()) {
|
||||
|
@ -294,12 +298,46 @@ class EventsHelper(val context: Context) {
|
|||
|
||||
events.forEach {
|
||||
it.updateIsPastEvent()
|
||||
val originalEvent = eventsDB.getEventWithId(it.id!!)
|
||||
if (originalEvent != null &&
|
||||
(birthDayEventId != -1L && it.eventType == birthDayEventId) or
|
||||
(anniversaryEventId != -1L && it.eventType == anniversaryEventId)
|
||||
) {
|
||||
val eventStartDate = Formatter.getDateFromTS(it.startTS)
|
||||
val originalEventStartDate = Formatter.getDateFromTS(originalEvent.startTS)
|
||||
if (it.hasMissingYear().not()) {
|
||||
val years = (eventStartDate.year - originalEventStartDate.year).coerceAtLeast(0)
|
||||
if (years > 0) {
|
||||
it.title = "${it.title} ($years)"
|
||||
}
|
||||
}
|
||||
}
|
||||
it.color = eventTypeColors.get(it.eventType) ?: config.primaryColor
|
||||
}
|
||||
|
||||
callback(events)
|
||||
}
|
||||
|
||||
fun getBirthdaysEventTypeId(createIfNotExists: Boolean = true): Long {
|
||||
val birthdays = context.getString(R.string.birthdays)
|
||||
var eventTypeId = getEventTypeIdWithTitle(birthdays)
|
||||
if (eventTypeId == -1L && createIfNotExists) {
|
||||
val eventType = EventType(null, birthdays, context.resources.getColor(R.color.default_birthdays_color))
|
||||
eventTypeId = insertOrUpdateEventTypeSync(eventType)
|
||||
}
|
||||
return eventTypeId
|
||||
}
|
||||
|
||||
fun getAnniversariesEventTypeId(createIfNotExists: Boolean = true): Long {
|
||||
val anniversaries = context.getString(R.string.anniversaries)
|
||||
var eventTypeId = getEventTypeIdWithTitle(anniversaries)
|
||||
if (eventTypeId == -1L && createIfNotExists) {
|
||||
val eventType = EventType(null, anniversaries, context.resources.getColor(R.color.default_anniversaries_color))
|
||||
eventTypeId = insertOrUpdateEventTypeSync(eventType)
|
||||
}
|
||||
return eventTypeId
|
||||
}
|
||||
|
||||
fun getRepeatableEventsFor(fromTS: Long, toTS: Long, eventId: Long = -1L, applyTypeFilter: Boolean = false): List<Event> {
|
||||
val events = if (applyTypeFilter) {
|
||||
val displayEventTypes = context.config.displayEventTypes
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.simplemobiletools.calendar.pro.helpers
|
||||
|
||||
import android.provider.CalendarContract.Events
|
||||
import com.simplemobiletools.calendar.pro.R
|
||||
import com.simplemobiletools.calendar.pro.extensions.calDAVHelper
|
||||
import com.simplemobiletools.calendar.pro.extensions.eventTypesDB
|
||||
|
@ -23,7 +24,13 @@ class IcsExporter {
|
|||
private var eventsFailed = 0
|
||||
private var calendars = ArrayList<CalDAVCalendar>()
|
||||
|
||||
fun exportEvents(activity: BaseSimpleActivity, outputStream: OutputStream?, events: ArrayList<Event>, showExportingToast: Boolean, callback: (result: ExportResult) -> Unit) {
|
||||
fun exportEvents(
|
||||
activity: BaseSimpleActivity,
|
||||
outputStream: OutputStream?,
|
||||
events: ArrayList<Event>,
|
||||
showExportingToast: Boolean,
|
||||
callback: (result: ExportResult) -> Unit
|
||||
) {
|
||||
if (outputStream == null) {
|
||||
callback(EXPORT_FAIL)
|
||||
return
|
||||
|
@ -50,6 +57,7 @@ class IcsExporter {
|
|||
event.eventType.let { out.writeLn("$CATEGORIES${activity.eventTypesDB.getEventTypeWithId(it)?.title}") }
|
||||
event.lastUpdated.let { out.writeLn("$LAST_MODIFIED:${Formatter.getExportedTime(it)}") }
|
||||
event.location.let { out.writeLn("$LOCATION:$it") }
|
||||
event.availability.let { out.writeLn("$TRANSP${if (it == Events.AVAILABILITY_FREE) TRANSPARENT else OPAQUE}") }
|
||||
|
||||
if (event.getIsAllDay()) {
|
||||
out.writeLn("$DTSTART;$VALUE=$DATE:${Formatter.getDayCodeFromTS(event.startTS)}")
|
||||
|
@ -58,6 +66,7 @@ class IcsExporter {
|
|||
event.startTS.let { out.writeLn("$DTSTART:${Formatter.getExportedTime(it * 1000L)}") }
|
||||
event.endTS.let { out.writeLn("$DTEND:${Formatter.getExportedTime(it * 1000L)}") }
|
||||
}
|
||||
event.hasMissingYear().let { out.writeLn("$MISSING_YEAR${if (it) 1 else 0}") }
|
||||
|
||||
out.writeLn("$DTSTAMP$exportTime")
|
||||
out.writeLn("$STATUS$CONFIRMED")
|
||||
|
@ -73,11 +82,13 @@ class IcsExporter {
|
|||
out.writeLn(END_CALENDAR)
|
||||
}
|
||||
|
||||
callback(when {
|
||||
eventsExported == 0 -> EXPORT_FAIL
|
||||
eventsFailed > 0 -> EXPORT_PARTIAL
|
||||
else -> EXPORT_OK
|
||||
})
|
||||
callback(
|
||||
when {
|
||||
eventsExported == 0 -> EXPORT_FAIL
|
||||
eventsFailed > 0 -> EXPORT_PARTIAL
|
||||
else -> EXPORT_OK
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.simplemobiletools.calendar.pro.helpers
|
||||
|
||||
import android.provider.CalendarContract.Events
|
||||
import com.simplemobiletools.calendar.pro.R
|
||||
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
|
||||
import com.simplemobiletools.calendar.pro.extensions.eventsDB
|
||||
|
@ -36,6 +37,7 @@ class IcsImporter(val activity: SimpleActivity) {
|
|||
private var curEventTypeId = REGULAR_EVENT_TYPE_ID
|
||||
private var curLastModified = 0L
|
||||
private var curCategoryColor = -2
|
||||
private var curAvailability = Events.AVAILABILITY_BUSY
|
||||
private var isNotificationDescription = false
|
||||
private var isProperReminderAction = false
|
||||
private var isSequence = false
|
||||
|
@ -128,6 +130,10 @@ class IcsImporter(val activity: SimpleActivity) {
|
|||
if (color.trimStart('-').areDigitsOnly()) {
|
||||
curCategoryColor = Integer.parseInt(color)
|
||||
}
|
||||
} else if (line.startsWith(MISSING_YEAR)) {
|
||||
if (line.substring(MISSING_YEAR.length) == "1") {
|
||||
curFlags = curFlags or FLAG_MISSING_YEAR
|
||||
}
|
||||
} else if (line.startsWith(CATEGORIES) && !overrideFileEventTypes) {
|
||||
val categories = line.substring(CATEGORIES.length)
|
||||
tryAddCategories(categories)
|
||||
|
@ -156,6 +162,8 @@ class IcsImporter(val activity: SimpleActivity) {
|
|||
curRecurrenceDayCode = Formatter.getDayCodeFromTS(timestamp)
|
||||
} else if (line.startsWith(SEQUENCE)) {
|
||||
isSequence = true
|
||||
} else if (line.startsWith(TRANSP)) {
|
||||
line.substring(TRANSP.length).let { curAvailability = if (it == TRANSPARENT) Events.AVAILABILITY_FREE else Events.AVAILABILITY_BUSY }
|
||||
} else if (line.trim() == BEGIN_ALARM) {
|
||||
isNotificationDescription = true
|
||||
} else if (line.trim() == END_ALARM) {
|
||||
|
@ -218,7 +226,8 @@ class IcsImporter(val activity: SimpleActivity) {
|
|||
curEventTypeId,
|
||||
0,
|
||||
curLastModified,
|
||||
source
|
||||
source,
|
||||
curAvailability
|
||||
)
|
||||
|
||||
if (event.getIsAllDay() && curEnd > curStart) {
|
||||
|
|
|
@ -37,7 +37,8 @@ data class Event(
|
|||
@ColumnInfo(name = "event_type") var eventType: Long = REGULAR_EVENT_TYPE_ID,
|
||||
@ColumnInfo(name = "parent_id") var parentId: Long = 0,
|
||||
@ColumnInfo(name = "last_updated") var lastUpdated: Long = 0L,
|
||||
@ColumnInfo(name = "source") var source: String = SOURCE_SIMPLE_CALENDAR)
|
||||
@ColumnInfo(name = "source") var source: String = SOURCE_SIMPLE_CALENDAR,
|
||||
@ColumnInfo(name = "availability") var availability: Int = 0)
|
||||
: Serializable {
|
||||
|
||||
companion object {
|
||||
|
@ -138,6 +139,7 @@ data class Event(
|
|||
}
|
||||
|
||||
fun getIsAllDay() = flags and FLAG_ALL_DAY != 0
|
||||
fun hasMissingYear() = flags and FLAG_MISSING_YEAR != 0
|
||||
|
||||
fun getReminders() = setOf(
|
||||
Reminder(reminder1Minutes, reminder1Type),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.simplemobiletools.calendar.pro.models
|
||||
|
||||
data class MonthViewEvent(val id: Long, val title: String, val startTS: Long, val color: Int, val startDayIndex: Int, val daysCnt: Int, val originalStartDayIndex: Int,
|
||||
data class MonthViewEvent(val id: Long, val title: String, val startTS: Long, val endTS: Long, val color: Int, val startDayIndex: Int, val daysCnt: Int, val originalStartDayIndex: Int,
|
||||
val isAllDay: Boolean, val isPastEvent: Boolean)
|
||||
|
|
|
@ -121,14 +121,14 @@ class MonthView(context: Context, attrs: AttributeSet, defStyle: Int) : View(con
|
|||
val daysCnt = getEventLastingDaysCount(event)
|
||||
val validDayEvent = isDayValid(event, day.code)
|
||||
if ((lastEvent == null || lastEvent.startDayIndex + daysCnt <= day.indexOnMonthView) && !validDayEvent) {
|
||||
val monthViewEvent = MonthViewEvent(event.id!!, event.title, event.startTS, event.color, day.indexOnMonthView,
|
||||
val monthViewEvent = MonthViewEvent(event.id!!, event.title, event.startTS, event.endTS, event.color, day.indexOnMonthView,
|
||||
daysCnt, day.indexOnMonthView, event.getIsAllDay(), event.isPastEvent)
|
||||
allEvents.add(monthViewEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allEvents = allEvents.asSequence().sortedWith(compareBy({ -it.daysCnt }, { !it.isAllDay }, { it.startTS }, { it.startDayIndex }, { it.title }))
|
||||
allEvents = allEvents.asSequence().sortedWith(compareBy({ -it.daysCnt }, { !it.isAllDay }, { it.startTS }, { it.endTS }, { it.startDayIndex }, { it.title }))
|
||||
.toMutableList() as ArrayList<MonthViewEvent>
|
||||
}
|
||||
|
||||
|
|
9
app/src/main/res/drawable/ic_event_available.xml
Normal file
9
app/src/main/res/drawable/ic_event_available.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<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="@android:color/white"
|
||||
android:pathData="M19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,9h14v10zM5,7L5,5h14v2L5,7zM10.56,17.46l5.93,-5.93 -1.06,-1.06 -4.87,4.87 -2.11,-2.11 -1.06,1.06z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_event_occupied.xml
Normal file
9
app/src/main/res/drawable/ic_event_occupied.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<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="@android:color/white"
|
||||
android:pathData="M19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,9h14v10zM5,7L5,5h14v2L5,7zM8.23,16.41l1.06,1.06 2.44,-2.44 2.44,2.44 1.06,-1.06 -2.44,-2.44 2.44,-2.44 -1.06,-1.06 -2.44,2.44 -2.44,-2.44 -1.06,1.06 2.44,2.44z"/>
|
||||
</vector>
|
|
@ -430,11 +430,45 @@
|
|||
android:background="@color/divider_grey"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/event_availability_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignTop="@+id/event_availability"
|
||||
android:layout_alignBottom="@+id/event_availability"
|
||||
android:layout_marginStart="@dimen/normal_margin"
|
||||
android:padding="@dimen/medium_margin"
|
||||
android:src="@drawable/ic_event_occupied" />
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/event_availability"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/event_attendees_divider"
|
||||
android:layout_toEndOf="@+id/event_availability_image"
|
||||
android:layout_marginStart="@dimen/small_margin"
|
||||
android:layout_marginTop="@dimen/medium_margin"
|
||||
android:paddingTop="@dimen/normal_margin"
|
||||
android:paddingBottom="@dimen/normal_margin"
|
||||
android:paddingEnd="@dimen/activity_margin"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:textSize="@dimen/day_text_size"
|
||||
android:text="@string/status_busy" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/event_availability_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_below="@+id/event_availability"
|
||||
android:layout_marginTop="@dimen/medium_margin"
|
||||
android:background="@color/divider_grey"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/event_caldav_calendar_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/event_attendees_divider"
|
||||
android:layout_below="@+id/event_availability_divider"
|
||||
android:layout_alignTop="@+id/event_caldav_calendar_holder"
|
||||
android:layout_alignEnd="@+id/event_time_image"
|
||||
android:layout_alignBottom="@+id/event_caldav_calendar_holder"
|
||||
|
@ -447,7 +481,7 @@
|
|||
android:id="@+id/event_caldav_calendar_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/event_attendees_divider"
|
||||
android:layout_below="@+id/event_availability_divider"
|
||||
android:layout_toEndOf="@+id/event_caldav_calendar_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:visibility="gone">
|
||||
|
|
|
@ -217,8 +217,8 @@
|
|||
<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="no_synchronized_calendars">Es wurden keine synchronisierbaren Kalender gefunden</string>
|
||||
<string name="status_free">Free</string>
|
||||
<string name="status_busy">Busy</string>
|
||||
<string name="status_free">Verfügbar</string>
|
||||
<string name="status_busy">Beschäftigt</string>
|
||||
|
||||
<!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
|
||||
<!-- used in repetition, like "Every last Sunday" -->
|
||||
|
|
|
@ -217,8 +217,8 @@
|
|||
<string name="insufficient_permissions">您不被允许对选择的日历写入</string>
|
||||
<string name="caldav_event_not_found">未找到活动。请在应用程序设定中为对应的日历启用 CalDAV 同步。</string>
|
||||
<string name="no_synchronized_calendars">未发现可同步的日历</string>
|
||||
<string name="status_free">Free</string>
|
||||
<string name="status_busy">Busy</string>
|
||||
<string name="status_free">空闲</string>
|
||||
<string name="status_busy">繁忙</string>
|
||||
|
||||
<!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
|
||||
<!-- used in repetition, like "Every last Sunday" -->
|
||||
|
@ -302,9 +302,9 @@
|
|||
|
||||
<b>Reddit:</b>
|
||||
https://www.reddit.com/r/SimpleMobileTools
|
||||
</string>
|
||||
</string>
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
|
|
|
@ -217,8 +217,8 @@
|
|||
<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="no_synchronized_calendars">No synchronizable calendars have been found</string>
|
||||
<string name="status_free">Free</string>
|
||||
<string name="status_busy">Busy</string>
|
||||
<string name="status_free">空閒</string>
|
||||
<string name="status_busy">繁忙</string>
|
||||
|
||||
<!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
|
||||
<!-- used in repetition, like "Every last Sunday" -->
|
||||
|
|
|
@ -217,8 +217,8 @@
|
|||
<string name="insufficient_permissions">你不被允許對選擇的行事曆寫入</string>
|
||||
<string name="caldav_event_not_found">未發現活動。請在程式設定中為合適的行事曆啟用CalDAV同步。</string>
|
||||
<string name="no_synchronized_calendars">No synchronizable calendars have been found</string>
|
||||
<string name="status_free">Free</string>
|
||||
<string name="status_busy">Busy</string>
|
||||
<string name="status_free">空閒</string>
|
||||
<string name="status_busy">繁忙</string>
|
||||
|
||||
<!-- alternative versions for some languages, use the same translations if you are not sure what this means -->
|
||||
<!-- used in repetition, like "Every last Sunday" -->
|
||||
|
|
Loading…
Reference in a new issue