diff --git a/CHANGELOG.md b/CHANGELOG.md
index 595808544..3d6e2f0f4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,30 @@
Changelog
==========
+Version 3.4.2 *(2018-04-13)*
+----------------------------
+
+ * Hide public notification content if desired so (by fraang)
+ * Added optional grid on the monthly view
+ * Allow exporting events on SD cards
+ * Allow selecting No Sound as a reminder sound
+ * Set default event status for CalDAV events as Confirmed
+
+Version 3.4.1 *(2018-03-30)*
+----------------------------
+
+ * Reworked custom notification sound, should be more reliable
+ * Fixed some glitches related to the monthly view
+ * Misc smaller bugfixes and stability improvements
+
+Version 3.4.0 *(2018-02-28)*
+----------------------------
+
+ * Rewrote the monthly view
+ * Improved the performance at importing events from ics files
+ * Added many new country holidays
+ * Handle some new third party intents
+
Version 3.3.2 *(2018-02-21)*
----------------------------
diff --git a/app/build.gradle b/app/build.gradle
index 9ed92cbc7..02719d1fe 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,8 +10,8 @@ android {
applicationId "com.simplemobiletools.calendar"
minSdkVersion 16
targetSdkVersion 27
- versionCode 115
- versionName "3.3.2"
+ versionCode 118
+ versionName "3.4.2"
multiDexEnabled true
setProperty("archivesBaseName", "calendar")
}
@@ -46,11 +46,10 @@ ext {
}
dependencies {
- implementation 'com.simplemobiletools:commons:3.15.6'
+ implementation 'com.simplemobiletools:commons:3.18.23'
implementation 'joda-time:joda-time:2.9.9'
implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'com.android.support:multidex:1.0.3'
- implementation 'com.google.code.gson:gson:2.8.2'
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c8f601054..4378de2f1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,6 +26,7 @@
@@ -34,7 +35,9 @@
-
+
@@ -61,6 +64,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/MainActivity.kt
index bd4d4eb6e..3617d07d5 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/MainActivity.kt
@@ -63,12 +63,15 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
private var mStoredDayCode = ""
private var mStoredIsSundayFirst = false
private var mStoredUse24HourFormat = false
- private var mStoredUseEnglish = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
appLaunched()
+
+ // just get a reference to the database to make sure it is created properly
+ dbHelper
+
checkWhatsNewDialog()
calendar_fab.beVisibleIf(config.storedView != YEARLY_VIEW)
calendar_fab.setOnClickListener {
@@ -83,8 +86,20 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
if (intent?.action == Intent.ACTION_VIEW && intent.data != null) {
val uri = intent.data
if (uri.authority == "com.android.calendar") {
- // clicking date on a third party widget: content://com.android.calendar/time/1507309245683
- if (intent?.extras?.getBoolean("DETAIL_VIEW", false) == true) {
+ if (uri.path.startsWith("/events")) {
+ // intents like content://com.android.calendar/events/1756
+ val eventId = uri.lastPathSegment
+ val id = dbHelper.getEventIdWithLastImportId(eventId)
+ if (id != 0) {
+ Intent(this, EventActivity::class.java).apply {
+ putExtra(EVENT_ID, id)
+ startActivity(this)
+ }
+ } else {
+ toast(R.string.unknown_error_occurred)
+ }
+ } else if (intent?.extras?.getBoolean("DETAIL_VIEW", false) == true) {
+ // clicking date on a third party widget: content://com.android.calendar/time/1507309245683
val timestamp = uri.pathSegments.last()
if (timestamp.areDigitsOnly()) {
openDayAt(timestamp.toLong())
@@ -111,11 +126,6 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
override fun onResume() {
super.onResume()
- if (mStoredUseEnglish != config.useEnglish) {
- restartActivity()
- return
- }
-
if (mStoredTextColor != config.textColor || mStoredBackgroundColor != config.backgroundColor || mStoredPrimaryColor != config.primaryColor
|| mStoredDayCode != Formatter.getTodayCode(applicationContext)) {
updateViewPager()
@@ -126,7 +136,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
}
if (config.storedView == WEEKLY_VIEW) {
- if (mStoredIsSundayFirst != config.isSundayFirst || mStoredUse24HourFormat != config.use24hourFormat) {
+ if (mStoredIsSundayFirst != config.isSundayFirst || mStoredUse24HourFormat != config.use24HourFormat) {
updateViewPager()
}
}
@@ -199,14 +209,19 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
}
}
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ setIntent(intent)
+ checkOpenIntents()
+ }
+
private fun storeStateVariables() {
config.apply {
- mStoredUseEnglish = useEnglish
mStoredIsSundayFirst = isSundayFirst
mStoredTextColor = textColor
mStoredPrimaryColor = primaryColor
mStoredBackgroundColor = backgroundColor
- mStoredUse24HourFormat = use24hourFormat
+ mStoredUse24HourFormat = use24HourFormat
}
mStoredDayCode = Formatter.getTodayCode(applicationContext)
}
@@ -647,8 +662,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
if (events.isEmpty()) {
toast(R.string.no_entries_for_exporting)
} else {
- toast(R.string.exporting)
- IcsExporter().exportEvents(this, file, events as ArrayList) {
+ IcsExporter().exportEvents(this, file, events as ArrayList, true) {
toast(when (it) {
IcsExporter.ExportResult.EXPORT_OK -> R.string.exporting_successful
IcsExporter.ExportResult.EXPORT_PARTIAL -> R.string.exporting_some_entries_failed
@@ -673,7 +687,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
FAQItem(getString(R.string.faq_1_title), getString(R.string.faq_1_text)),
FAQItem(getString(R.string.faq_2_title), getString(R.string.faq_2_text)))
- startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_JODA or LICENSE_STETHO or LICENSE_MULTISELECT or LICENSE_LEAK_CANARY,
+ startAboutActivity(R.string.app_name, LICENSE_JODA or LICENSE_STETHO or LICENSE_MULTISELECT or LICENSE_LEAK_CANARY,
BuildConfig.VERSION_NAME, faqItems)
}
@@ -730,7 +744,10 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
put("Bolivia", "bolivia.ics")
put("Brasil", "brazil.ics")
put("Canada", "canada.ics")
+ put("China", "china.ics")
+ put("Colombia", "colombia.ics")
put("Česká republika", "czech.ics")
+ put("Danmark", "denmark.ics")
put("Deutschland", "germany.ics")
put("Eesti", "estonia.ics")
put("España", "spain.ics")
@@ -738,10 +755,17 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
put("France", "france.ics")
put("Hanguk", "southkorea.ics")
put("Hellas", "greece.ics")
+ put("Hrvatska", "croatia.ics")
put("India", "india.ics")
+ put("Indonesia", "indonesia.ics")
put("Ísland", "iceland.ics")
put("Italia", "italy.ics")
+ put("Latvija", "latvia.ics")
+ put("Lietuva", "lithuania.ics")
+ put("Luxemburg", "luxembourg.ics")
+ put("Makedonija", "macedonia.ics")
put("Magyarország", "hungary.ics")
+ put("México", "mexico.ics")
put("Nederland", "netherlands.ics")
put("日本", "japan.ics")
put("Norge", "norway.ics")
@@ -750,11 +774,15 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
put("Polska", "poland.ics")
put("Portugal", "portugal.ics")
put("Россия", "russia.ics")
+ put("România", "romania.ics")
put("Schweiz", "switzerland.ics")
+ put("Srbija", "serbia.ics")
put("Slovenija", "slovenia.ics")
put("Slovensko", "slovakia.ics")
+ put("South Africa", "southafrica.ics")
put("Suomi", "finland.ics")
put("Sverige", "sweden.ics")
+ put("Ukraine", "ukraine.ics")
put("United Kingdom", "unitedkingdom.ics")
put("United States", "unitedstates.ics")
@@ -794,6 +822,7 @@ class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
add(Release(86, R.string.release_86))
add(Release(88, R.string.release_88))
add(Release(98, R.string.release_98))
+ add(Release(117, R.string.release_117))
checkWhatsNew(this, BuildConfig.VERSION_CODE)
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/ManageEventTypesActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/ManageEventTypesActivity.kt
index 02829afcc..808c50369 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/ManageEventTypesActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/ManageEventTypesActivity.kt
@@ -35,7 +35,6 @@ class ManageEventTypesActivity : SimpleActivity(), DeleteEventTypesListener {
val adapter = ManageEventTypesAdapter(this, it, this, manage_event_types_list) {
showEventTypeDialog(it as EventType)
}
- adapter.setupDragListener(true)
manage_event_types_list.adapter = adapter
}
}
@@ -62,11 +61,13 @@ class ManageEventTypesActivity : SimpleActivity(), DeleteEventTypesListener {
}
}
- dbHelper.deleteEventTypes(eventTypes, deleteEvents) {
- if (it == 0) {
- toast(R.string.unknown_error_occurred)
+ Thread {
+ dbHelper.deleteEventTypes(eventTypes, deleteEvents) {
+ if (it == 0) {
+ toast(R.string.unknown_error_occurred)
+ }
}
- }
+ }.start()
return true
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt
index c91c6fe72..7fb8743bd 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt
@@ -2,12 +2,9 @@ package com.simplemobiletools.calendar.activities
import android.content.Intent
import android.content.res.Resources
-import android.media.RingtoneManager
-import android.net.Uri
+import android.media.AudioManager
import android.os.Bundle
-import android.os.Parcelable
import android.text.TextUtils
-import com.simplemobiletools.calendar.BuildConfig
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.dialogs.SelectCalendarsDialog
import com.simplemobiletools.calendar.extensions.*
@@ -19,12 +16,14 @@ import com.simplemobiletools.calendar.models.EventType
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.CustomIntervalPickerDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
+import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog
import com.simplemobiletools.commons.extensions.*
+import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_NOTIFICATION
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CALENDAR
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CALENDAR
+import com.simplemobiletools.commons.models.AlarmSound
import com.simplemobiletools.commons.models.RadioItem
import kotlinx.android.synthetic.main.activity_settings.*
-import java.io.File
import java.util.*
class SettingsActivity : SimpleActivity() {
@@ -53,6 +52,7 @@ class SettingsActivity : SimpleActivity() {
setupDeleteAllEvents()
setupReplaceDescription()
setupWeekNumbers()
+ setupShowGrid()
setupWeeklyStart()
setupWeeklyEnd()
setupVibrate()
@@ -102,7 +102,7 @@ class SettingsActivity : SimpleActivity() {
settings_use_english_holder.setOnClickListener {
settings_use_english.toggle()
config.useEnglish = settings_use_english.isChecked
- useEnglishToggled()
+ System.exit(0)
}
}
@@ -113,10 +113,10 @@ class SettingsActivity : SimpleActivity() {
}
private fun setupHourFormat() {
- settings_hour_format.isChecked = config.use24hourFormat
+ settings_hour_format.isChecked = config.use24HourFormat
settings_hour_format_holder.setOnClickListener {
settings_hour_format.toggle()
- config.use24hourFormat = settings_hour_format.isChecked
+ config.use24HourFormat = settings_hour_format.isChecked
}
}
@@ -268,36 +268,45 @@ class SettingsActivity : SimpleActivity() {
}
private fun setupWeekNumbers() {
- settings_week_numbers.isChecked = config.displayWeekNumbers
+ settings_week_numbers.isChecked = config.showWeekNumbers
settings_week_numbers_holder.setOnClickListener {
settings_week_numbers.toggle()
- config.displayWeekNumbers = settings_week_numbers.isChecked
+ config.showWeekNumbers = settings_week_numbers.isChecked
+ }
+ }
+
+ private fun setupShowGrid() {
+ settings_show_grid.isChecked = config.showGrid
+ settings_show_grid_holder.setOnClickListener {
+ settings_show_grid.toggle()
+ config.showGrid = settings_show_grid.isChecked
}
}
private fun setupReminderSound() {
- val noRingtone = res.getString(R.string.no_ringtone_selected)
- if (config.reminderSound.isEmpty()) {
- settings_reminder_sound.text = noRingtone
- } else {
- settings_reminder_sound.text = RingtoneManager.getRingtone(this, Uri.parse(config.reminderSound))?.getTitle(this) ?: noRingtone
- }
+ settings_reminder_sound.text = config.reminderSoundTitle
settings_reminder_sound_holder.setOnClickListener {
- Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
- putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
- putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, res.getString(R.string.reminder_sound))
- putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(config.reminderSound))
-
- if (resolveActivity(packageManager) != null)
- startActivityForResult(this, GET_RINGTONE_URI)
- else {
- toast(R.string.no_ringtone_picker)
+ SelectAlarmSoundDialog(this, config.reminderSoundUri, AudioManager.STREAM_NOTIFICATION, GET_RINGTONE_URI, ALARM_SOUND_TYPE_NOTIFICATION, false,
+ onAlarmPicked = {
+ if (it != null) {
+ updateReminderSound(it)
+ }
+ }, onAlarmSoundDeleted = {
+ if (it.uri == config.reminderSoundUri) {
+ val defaultAlarm = getDefaultAlarmSound(ALARM_SOUND_TYPE_NOTIFICATION)
+ updateReminderSound(defaultAlarm)
}
- }
+ })
}
}
+ private fun updateReminderSound(alarmSound: AlarmSound) {
+ config.reminderSoundTitle = alarmSound.title
+ config.reminderSoundUri = alarmSound.uri
+ settings_reminder_sound.text = alarmSound.title
+ }
+
private fun setupVibrate() {
settings_vibrate.isChecked = config.vibrateOnReminder
settings_vibrate_holder.setOnClickListener {
@@ -319,8 +328,8 @@ class SettingsActivity : SimpleActivity() {
private fun setupSnoozeTime() {
updateSnoozeTime()
settings_snooze_time_holder.setOnClickListener {
- showPickIntervalDialog(config.snoozeTime, true) {
- config.snoozeTime = it
+ showPickSecondsDialogHelper(config.snoozeTime, true) {
+ config.snoozeTime = it / 60
updateSnoozeTime()
}
}
@@ -381,24 +390,10 @@ class SettingsActivity : SimpleActivity() {
})
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
- if (resultCode == RESULT_OK) {
- if (requestCode == GET_RINGTONE_URI) {
- var uri = resultData?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
-
- if (uri == null) {
- config.reminderSound = ""
- } else {
- try {
- if ((uri as Uri).scheme == "file") {
- uri = getFilePublicUri(File(uri.path), BuildConfig.APPLICATION_ID)
- }
- settings_reminder_sound.text = RingtoneManager.getRingtone(this, uri)?.getTitle(this)
- config.reminderSound = uri.toString()
- } catch (e: Exception) {
- showErrorToast(e)
- }
- }
- }
+ super.onActivityResult(requestCode, resultCode, resultData)
+ if (requestCode == GET_RINGTONE_URI && resultCode == RESULT_OK && resultData != null) {
+ val newAlarmSound = storeNewYourAlarmSound(resultData)
+ updateReminderSound(newAlarmSound)
}
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SnoozeReminderActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SnoozeReminderActivity.kt
index 75f7c0431..455a6313d 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SnoozeReminderActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SnoozeReminderActivity.kt
@@ -6,17 +6,17 @@ import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.extensions.rescheduleReminder
import com.simplemobiletools.calendar.helpers.EVENT_ID
-import com.simplemobiletools.commons.extensions.showPickIntervalDialog
+import com.simplemobiletools.commons.extensions.showPickSecondsDialogHelper
class SnoozeReminderActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- showPickIntervalDialog(config.snoozeTime, true, cancelCallback = { dialogCancelled() }) {
+ showPickSecondsDialogHelper(config.snoozeTime, true, cancelCallback = { dialogCancelled() }) {
val eventId = intent.getIntExtra(EVENT_ID, 0)
val event = dbHelper.getEventWithId(eventId)
- config.snoozeTime = it
- rescheduleReminder(event, it)
+ config.snoozeTime = it / 60
+ rescheduleReminder(event, it / 60)
finishActivity()
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetListConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetListConfigureActivity.kt
index e852a590d..90727f041 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetListConfigureActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetListConfigureActivity.kt
@@ -106,15 +106,15 @@ class WidgetListConfigureActivity : SimpleActivity() {
}
private fun pickBackgroundColor() {
- ColorPickerDialog(this, mBgColorWithoutTransparency) {
- mBgColorWithoutTransparency = it
+ ColorPickerDialog(this, mBgColorWithoutTransparency) { wasPositivePressed, color ->
+ mBgColorWithoutTransparency = color
updateBgColor()
}
}
private fun pickTextColor() {
- ColorPickerDialog(this, mTextColor) {
- mTextColorWithoutTransparency = it
+ ColorPickerDialog(this, mTextColor) { wasPositivePressed, color ->
+ mTextColorWithoutTransparency = color
updateColors()
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetMonthlyConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetMonthlyConfigureActivity.kt
index 311976787..c391626b7 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetMonthlyConfigureActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/WidgetMonthlyConfigureActivity.kt
@@ -88,7 +88,7 @@ class WidgetMonthlyConfigureActivity : SimpleActivity(), MonthlyCalendar {
config_bg_seekbar.progress = (mBgAlpha * 100).toInt()
updateBgColor()
- MonthlyCalendarImpl(this, applicationContext).updateMonthlyCalendar(DateTime(), false)
+ MonthlyCalendarImpl(this, applicationContext).updateMonthlyCalendar(DateTime().withDayOfMonth(1), false)
}
private fun saveConfig() {
@@ -110,15 +110,15 @@ class WidgetMonthlyConfigureActivity : SimpleActivity(), MonthlyCalendar {
}
private fun pickBackgroundColor() {
- ColorPickerDialog(this, mBgColorWithoutTransparency) {
- mBgColorWithoutTransparency = it
+ ColorPickerDialog(this, mBgColorWithoutTransparency) { wasPositivePressed, color ->
+ mBgColorWithoutTransparency = color
updateBgColor()
}
}
private fun pickTextColor() {
- ColorPickerDialog(this, mTextColor) {
- mTextColorWithoutTransparency = it
+ ColorPickerDialog(this, mTextColor) { wasPositivePressed, color ->
+ mTextColorWithoutTransparency = color
updateColors()
updateDays()
}
@@ -154,7 +154,7 @@ class WidgetMonthlyConfigureActivity : SimpleActivity(), MonthlyCalendar {
private fun updateDays() {
val len = mDays!!.size
- if (applicationContext.config.displayWeekNumbers) {
+ if (applicationContext.config.showWeekNumbers) {
week_num.setTextColor(mTextColor)
week_num.beVisible()
@@ -194,7 +194,7 @@ class WidgetMonthlyConfigureActivity : SimpleActivity(), MonthlyCalendar {
}
}
- override fun updateMonthlyCalendar(context: Context, month: String, days: List, checkedEvents: Boolean) {
+ override fun updateMonthlyCalendar(context: Context, month: String, days: ArrayList, checkedEvents: Boolean) {
runOnUiThread {
mDays = days
top_value.text = month
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/DayEventsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/DayEventsAdapter.kt
index 733ae78c8..2343f3567 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/DayEventsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/DayEventsAdapter.kt
@@ -24,6 +24,10 @@ class DayEventsAdapter(activity: SimpleActivity, val events: ArrayList, r
private var allDayString = resources.getString(R.string.all_day)
private var replaceDescriptionWithLocation = activity.config.replaceDescription
+ init {
+ setupDragListener(true)
+ }
+
override fun getActionMenuId() = R.menu.cab_day
override fun prepareActionMode(menu: Menu) {}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/EventListAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/EventListAdapter.kt
index df29b56fc..8d3a8c29a 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/EventListAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/adapters/EventListAdapter.kt
@@ -35,7 +35,7 @@ class EventListAdapter(activity: SimpleActivity, val listItems: ArrayList, val listener: DeleteEventTypesListener?, recyclerView: MyRecyclerView,
itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, null, itemClick) {
+ init {
+ setupDragListener(true)
+ }
+
override fun getActionMenuId() = R.menu.cab_event_type
override fun prepareActionMode(menu: Menu) {}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/DeleteEventDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/DeleteEventDialog.kt
index 9654b4885..5c88fc256 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/DeleteEventDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/DeleteEventDialog.kt
@@ -29,8 +29,8 @@ class DeleteEventDialog(val activity: Activity, eventIds: List, val callbac
.setPositiveButton(R.string.yes, { dialog, which -> dialogConfirmed(view as ViewGroup, hasRepeatableEvent) })
.setNegativeButton(R.string.no, null)
.create().apply {
- activity.setupDialogStuff(view, this)
- }
+ activity.setupDialogStuff(view, this)
+ }
}
private fun dialogConfirmed(view: ViewGroup, hasRepeatableEvent: Boolean) {
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ExportEventsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ExportEventsDialog.kt
index f478833f2..37f487556 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ExportEventsDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ExportEventsDialog.kt
@@ -39,26 +39,26 @@ class ExportEventsDialog(val activity: SimpleActivity, val path: String, val cal
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
- activity.setupDialogStuff(view, this, R.string.export_events) {
- getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
- val filename = view.export_events_filename.value
- when {
- filename.isEmpty() -> activity.toast(R.string.empty_name)
- filename.isAValidFilename() -> {
- val file = File(path, "$filename.ics")
- if (file.exists()) {
- activity.toast(R.string.name_taken)
- return@setOnClickListener
- }
+ activity.setupDialogStuff(view, this, R.string.export_events) {
+ getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
+ val filename = view.export_events_filename.value
+ when {
+ filename.isEmpty() -> activity.toast(R.string.empty_name)
+ filename.isAValidFilename() -> {
+ val file = File(path, "$filename.ics")
+ if (file.exists()) {
+ activity.toast(R.string.name_taken)
+ return@setOnClickListener
+ }
- val eventTypes = (view.export_events_types_list.adapter as FilterEventTypeAdapter).getSelectedItemsSet()
- callback(view.export_events_checkbox.isChecked, file, eventTypes)
- dismiss()
+ val eventTypes = (view.export_events_types_list.adapter as FilterEventTypeAdapter).getSelectedItemsSet()
+ callback(view.export_events_checkbox.isChecked, file, eventTypes)
+ dismiss()
+ }
+ else -> activity.toast(R.string.invalid_name)
+ }
}
- else -> activity.toast(R.string.invalid_name)
}
}
- }
- }
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/FilterEventTypesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/FilterEventTypesDialog.kt
index 71c24a62d..e609c84be 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/FilterEventTypesDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/FilterEventTypesDialog.kt
@@ -22,8 +22,8 @@ class FilterEventTypesDialog(val activity: SimpleActivity, val callback: () -> U
.setPositiveButton(R.string.ok, { dialogInterface, i -> confirmEventTypes() })
.setNegativeButton(R.string.cancel, null)
.create().apply {
- activity.setupDialogStuff(view, this, R.string.filter_events_by_type)
- }
+ activity.setupDialogStuff(view, this, R.string.filter_events_by_type)
+ }
}
private fun confirmEventTypes() {
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ImportEventsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ImportEventsDialog.kt
index 0b6993ed8..d7ef3f293 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ImportEventsDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/ImportEventsDialog.kt
@@ -34,17 +34,17 @@ class ImportEventsDialog(val activity: SimpleActivity, val path: String, val cal
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
- activity.setupDialogStuff(view, this, R.string.import_events) {
- getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
- activity.toast(R.string.importing)
- Thread {
- val result = IcsImporter(activity).importEvents(path, currEventTypeId, currEventTypeCalDAVCalendarId)
- handleParseResult(result)
- dismiss()
- }.start()
+ activity.setupDialogStuff(view, this, R.string.import_events) {
+ getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
+ activity.toast(R.string.importing)
+ Thread {
+ val result = IcsImporter(activity).importEvents(path, currEventTypeId, currEventTypeCalDAVCalendarId)
+ handleParseResult(result)
+ dismiss()
+ }.start()
+ }
+ }
}
- }
- }
}
private fun updateEventType(view: ViewGroup) {
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt
index bb8f43a9d..44b9915e1 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt
@@ -36,8 +36,8 @@ class SelectCalendarsDialog(val activity: SimpleActivity, val callback: () -> Un
.setPositiveButton(R.string.ok, { dialogInterface, i -> confirmSelection() })
.setNegativeButton(R.string.cancel, null)
.create().apply {
- activity.setupDialogStuff(view, this, R.string.select_caldav_calendars)
- }
+ activity.setupDialogStuff(view, this, R.string.select_caldav_calendars)
+ }
}
private fun addCalendarItem(isEvent: Boolean, text: String, tag: Int = 0, shouldCheck: Boolean = false) {
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectEventCalendarDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectEventCalendarDialog.kt
index 3a6ecc790..b442a5dda 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectEventCalendarDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectEventCalendarDialog.kt
@@ -39,8 +39,8 @@ class SelectEventCalendarDialog(val activity: Activity, val calendars: List
+ eventType!!.color = color
setupColor(type_color)
}
} else {
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Activity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Activity.kt
index 4acabf970..600770afb 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Activity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Activity.kt
@@ -23,7 +23,7 @@ fun BaseSimpleActivity.shareEvents(ids: List) {
}
val events = dbHelper.getEventsWithIds(ids)
- IcsExporter().exportEvents(this, file, events) {
+ IcsExporter().exportEvents(this, file, events, false) {
if (it == IcsExporter.ExportResult.EXPORT_OK) {
sharePathIntent(file.absolutePath, BuildConfig.APPLICATION_ID)
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt
index 2dc798663..98f689d9b 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt
@@ -10,16 +10,18 @@ import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.database.ContentObserver
+import android.media.AudioAttributes
+import android.media.AudioManager
import android.net.Uri
import android.os.Bundle
import android.provider.CalendarContract
+import android.support.v4.app.AlarmManagerCompat
import android.support.v4.app.NotificationCompat
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
-import com.simplemobiletools.calendar.BuildConfig
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.activities.SimpleActivity
@@ -31,14 +33,11 @@ import com.simplemobiletools.calendar.receivers.CalDAVSyncReceiver
import com.simplemobiletools.calendar.receivers.NotificationReceiver
import com.simplemobiletools.calendar.services.SnoozeService
import com.simplemobiletools.commons.extensions.*
-import com.simplemobiletools.commons.helpers.isKitkatPlus
-import com.simplemobiletools.commons.helpers.isLollipopPlus
-import com.simplemobiletools.commons.helpers.isMarshmallowPlus
+import com.simplemobiletools.commons.helpers.SILENT
import com.simplemobiletools.commons.helpers.isOreoPlus
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.joda.time.LocalDate
-import java.io.File
import java.text.SimpleDateFormat
import java.util.*
@@ -49,12 +48,11 @@ val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext)
fun Context.getNowSeconds() = (System.currentTimeMillis() / 1000).toInt()
fun Context.updateWidgets() {
- val widgetsCnt = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(ComponentName(applicationContext, MyWidgetMonthlyProvider::class.java))
- if (widgetsCnt.isNotEmpty()) {
- val ids = intArrayOf(R.xml.widget_monthly_info)
+ val widgetIDs = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(ComponentName(applicationContext, MyWidgetMonthlyProvider::class.java))
+ if (widgetIDs.isNotEmpty()) {
Intent(applicationContext, MyWidgetMonthlyProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
- putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
+ putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIDs)
sendBroadcast(this)
}
}
@@ -63,12 +61,11 @@ fun Context.updateWidgets() {
}
fun Context.updateListWidget() {
- val widgetsCnt = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(ComponentName(applicationContext, MyWidgetListProvider::class.java))
- if (widgetsCnt.isNotEmpty()) {
- val ids = intArrayOf(R.xml.widget_list_info)
+ val widgetIDs = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(ComponentName(applicationContext, MyWidgetListProvider::class.java))
+ if (widgetIDs.isNotEmpty()) {
Intent(applicationContext, MyWidgetListProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
- putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
+ putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIDs)
sendBroadcast(this)
}
}
@@ -109,12 +106,7 @@ fun Context.scheduleEventIn(notifTS: Long, event: Event) {
val pendingIntent = getNotificationIntent(applicationContext, event)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
-
- when {
- isMarshmallowPlus() -> alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, notifTS, pendingIntent)
- isKitkatPlus() -> alarmManager.setExact(AlarmManager.RTC_WAKEUP, notifTS, pendingIntent)
- else -> alarmManager.set(AlarmManager.RTC_WAKEUP, notifTS, pendingIntent)
- }
+ AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, notifTS, pendingIntent)
}
fun Context.cancelNotification(id: Int) {
@@ -159,69 +151,77 @@ fun Context.notifyEvent(event: Event) {
val startTime = Formatter.getTimeFromTS(applicationContext, event.startTS)
val endTime = Formatter.getTimeFromTS(applicationContext, event.endTS)
val startDate = Formatter.getDateFromTS(event.startTS)
- val displayedStartDate: String
- if (startDate == LocalDate.now()) {
- displayedStartDate = ""
- } else if (startDate == LocalDate.now().plusDays(1)) {
- displayedStartDate = getString(R.string.tomorrow)
- } else /* At least 2 days in the future */ {
- displayedStartDate = Formatter.getDayAndMonth(startDate)
+ val displayedStartDate = when (startDate) {
+ LocalDate.now() -> ""
+ LocalDate.now().plusDays(1) -> getString(R.string.tomorrow)
+ else -> "${Formatter.getDateFromCode(this, Formatter.getDayCodeFromTS(event.startTS))},"
}
+
val timeRange = if (event.getIsAllDay()) getString(R.string.all_day) else getFormattedEventTime(startTime, endTime)
val descriptionOrLocation = if (config.replaceDescription) event.location else event.description
- val content = arrayOf(displayedStartDate, timeRange, descriptionOrLocation).joinToString(" ")
- val notification = getNotification(applicationContext, pendingIntent, event, content)
+ val content = "$displayedStartDate $timeRange $descriptionOrLocation".trim()
+ val notification = getNotification(pendingIntent, event, content)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(event.id, notification)
}
@SuppressLint("NewApi")
-private fun getNotification(context: Context, pendingIntent: PendingIntent, event: Event, content: String): Notification {
- val channelId = "reminder_channel"
+fun Context.getNotification(pendingIntent: PendingIntent, event: Event, content: String, publicVersion: Boolean = false): Notification {
+ var soundUri = config.reminderSoundUri
+ if (soundUri == SILENT) {
+ soundUri = ""
+ } else {
+ grantReadUriPermission(soundUri)
+ }
+
+ val channelId = "my_reminder_channel_$soundUri"
if (isOreoPlus()) {
- val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- val name = context.resources.getString(R.string.event_reminders)
+ val audioAttributes = AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
+ .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+ .build()
+
+ val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ val name = resources.getString(R.string.event_reminders)
val importance = NotificationManager.IMPORTANCE_HIGH
NotificationChannel(channelId, name, importance).apply {
enableLights(true)
lightColor = event.color
enableVibration(false)
+ setSound(Uri.parse(soundUri), audioAttributes)
notificationManager.createNotificationChannel(this)
}
}
- var soundUri = Uri.parse(context.config.reminderSound)
- if (soundUri.scheme == "file") {
- try {
- soundUri = context.getFilePublicUri(File(soundUri.path), BuildConfig.APPLICATION_ID)
- } catch (ignored: Exception) {
- }
- }
+ val contentTitle = if (publicVersion) resources.getString(R.string.app_name) else event.title
+ val contentText = if (publicVersion) resources.getString(R.string.public_event_notification_text) else content
- val builder = NotificationCompat.Builder(context)
- .setContentTitle(event.title)
- .setContentText(content)
+ val builder = NotificationCompat.Builder(this)
+ .setContentTitle(contentTitle)
+ .setContentText(contentText)
.setSmallIcon(R.drawable.ic_calendar)
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_LIGHTS)
.setAutoCancel(true)
- .setSound(soundUri)
+ .setSound(Uri.parse(soundUri), AudioManager.STREAM_NOTIFICATION)
.setChannelId(channelId)
- .addAction(R.drawable.ic_snooze, context.getString(R.string.snooze), getSnoozePendingIntent(context, event))
+ .addAction(R.drawable.ic_snooze, getString(R.string.snooze), getSnoozePendingIntent(this, event))
- if (isLollipopPlus()) {
- builder.setVisibility(Notification.VISIBILITY_PUBLIC)
+ if (config.vibrateOnReminder) {
+ builder.setVibrate(longArrayOf(0, 300, 300, 300))
}
- if (context.config.vibrateOnReminder) {
- builder.setVibrate(longArrayOf(0, 300, 300, 300))
+ if (!publicVersion) {
+ builder.setPublicVersion(getNotification(pendingIntent, event, content, true))
}
return builder.build()
}
-private fun getFormattedEventTime(startTime: String, endTime: String) = if (startTime == endTime) startTime else "$startTime\u2013$endTime"
+private fun getFormattedEventTime(startTime: String, endTime: String) = if (startTime == endTime) startTime else "$startTime \u2013 $endTime"
private fun getPendingIntent(context: Context, event: Event): PendingIntent {
val intent = Intent(context, EventActivity::class.java)
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/DayFragment.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/DayFragment.kt
index 4e2b04304..52e8d4d8f 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/DayFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/DayFragment.kt
@@ -94,8 +94,8 @@ class DayFragment : Fragment() {
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok) { dialog, which -> positivePressed(dateTime, datePicker) }
.create().apply {
- activity?.setupDialogStuff(view, this)
- }
+ activity?.setupDialogStuff(view, this)
+ }
}
private fun positivePressed(dateTime: DateTime, datePicker: DatePicker) {
@@ -123,7 +123,7 @@ class DayFragment : Fragment() {
lastHash = newHash
val replaceDescription = context!!.config.replaceDescription
- val sorted = ArrayList(filtered.sortedWith(compareBy({ it.startTS }, { it.endTS }, { it.title }, {
+ val sorted = ArrayList(filtered.sortedWith(compareBy({ !it.getIsAllDay() }, { it.startTS }, { it.endTS }, { it.title }, {
if (replaceDescription) it.location else it.description
})))
@@ -139,7 +139,6 @@ class DayFragment : Fragment() {
DayEventsAdapter(activity as SimpleActivity, events, mHolder.day_events) {
editEvent(it as Event)
}.apply {
- setupDragListener(true)
addVerticalDividers(true)
mHolder.day_events.adapter = this
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/EventListFragment.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/EventListFragment.kt
index 1ebc35680..34e312867 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/EventListFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/EventListFragment.kt
@@ -36,7 +36,7 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
mView.calendar_empty_list_placeholder.text = placeholderText
mView.background = ColorDrawable(context!!.config.backgroundColor)
mView.calendar_events_list_holder?.id = (System.currentTimeMillis() % 100000).toInt()
- use24HourFormat = context!!.config.use24hourFormat
+ use24HourFormat = context!!.config.use24HourFormat
updateActionBarTitle()
return mView
}
@@ -44,7 +44,7 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
override fun onResume() {
super.onResume()
checkEvents()
- val use24Hour = context!!.config.use24hourFormat
+ val use24Hour = context!!.config.use24HourFormat
if (use24Hour != use24HourFormat) {
use24HourFormat = use24Hour
(mView.calendar_events_list.adapter as? EventListAdapter)?.toggle24HourFormat(use24HourFormat)
@@ -53,7 +53,7 @@ class EventListFragment : MyFragmentHolder(), RefreshRecyclerViewListener {
override fun onPause() {
super.onPause()
- use24HourFormat = context!!.config.use24hourFormat
+ use24HourFormat = context!!.config.use24HourFormat
}
private fun checkEvents() {
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragment.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragment.kt
index 6c43546d5..2db429489 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragment.kt
@@ -9,13 +9,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.DatePicker
-import android.widget.LinearLayout
import android.widget.RelativeLayout
-import android.widget.TextView
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.MainActivity
-import com.simplemobiletools.calendar.extensions.addDayEvents
-import com.simplemobiletools.calendar.extensions.addDayNumber
import com.simplemobiletools.calendar.extensions.config
import com.simplemobiletools.calendar.helpers.Config
import com.simplemobiletools.calendar.helpers.DAY_CODE
@@ -24,8 +20,10 @@ import com.simplemobiletools.calendar.helpers.MonthlyCalendarImpl
import com.simplemobiletools.calendar.interfaces.MonthlyCalendar
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.models.DayMonthly
-import com.simplemobiletools.commons.extensions.*
-import kotlinx.android.synthetic.main.first_row.*
+import com.simplemobiletools.commons.extensions.applyColorFilter
+import com.simplemobiletools.commons.extensions.beGone
+import com.simplemobiletools.commons.extensions.getDialogTheme
+import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.fragment_month.view.*
import kotlinx.android.synthetic.main.top_navigation.view.*
import org.joda.time.DateTime
@@ -33,9 +31,9 @@ import org.joda.time.DateTime
class MonthFragment : Fragment(), MonthlyCalendar {
private var mTextColor = 0
private var mSundayFirst = false
+ private var mShowWeekNumbers = false
private var mDayCode = ""
private var mPackageName = ""
- private var mDayLabelHeight = 0
private var mLastHash = 0L
private var mCalendar: MonthlyCalendarImpl? = null
@@ -52,10 +50,9 @@ class MonthFragment : Fragment(), MonthlyCalendar {
mHolder = view.month_calendar_holder
mDayCode = arguments!!.getString(DAY_CODE)
mConfig = context!!.config
- mSundayFirst = mConfig.isSundayFirst
+ storeStateVariables()
setupButtons()
- setupLabels()
mCalendar = MonthlyCalendarImpl(this, context!!)
return view
@@ -63,14 +60,13 @@ class MonthFragment : Fragment(), MonthlyCalendar {
override fun onPause() {
super.onPause()
- mSundayFirst = context!!.config.isSundayFirst
+ storeStateVariables()
}
override fun onResume() {
super.onResume()
- if (mConfig.isSundayFirst != mSundayFirst) {
- mSundayFirst = mConfig.isSundayFirst
- setupLabels()
+ if (mConfig.showWeekNumbers != mShowWeekNumbers) {
+ mLastHash = -1L
}
mCalendar!!.apply {
@@ -78,14 +74,22 @@ class MonthFragment : Fragment(), MonthlyCalendar {
getDays(false) // prefill the screen asap, even if without events
}
+ storeStateVariables()
updateCalendar()
}
+ private fun storeStateVariables() {
+ mConfig.apply {
+ mSundayFirst = isSundayFirst
+ mShowWeekNumbers = showWeekNumbers
+ }
+ }
+
fun updateCalendar() {
mCalendar?.updateMonthlyCalendar(Formatter.getDateTimeFromCode(mDayCode))
}
- override fun updateMonthlyCalendar(context: Context, month: String, days: List, checkedEvents: Boolean) {
+ override fun updateMonthlyCalendar(context: Context, month: String, days: ArrayList, checkedEvents: Boolean) {
val newHash = month.hashCode() + days.hashCode().toLong()
if ((mLastHash != 0L && !checkedEvents) || mLastHash == newHash) {
return
@@ -153,51 +157,9 @@ class MonthFragment : Fragment(), MonthlyCalendar {
listener?.goToDateTime(newDateTime)
}
- private fun setupLabels() {
- val letters = context!!.resources.getStringArray(R.array.week_day_letters)
- for (i in 0..6) {
- var index = i
- if (mSundayFirst) {
- index = (index + 6) % letters.size
- }
-
- mHolder.findViewById(mRes.getIdentifier("label_$i", "id", mPackageName)).apply {
- setTextColor(mTextColor)
- text = letters[index]
- }
- }
- }
-
- private fun updateDays(days: List) {
- val displayWeekNumbers = mConfig.displayWeekNumbers
- val len = days.size
-
- if (week_num == null)
- return
-
- week_num.setTextColor(mTextColor)
- week_num.beVisibleIf(displayWeekNumbers)
-
- for (i in 0..5) {
- mHolder.findViewById(mRes.getIdentifier("week_num_$i", "id", mPackageName)).apply {
- text = "${days[i * 7 + 3].weekOfYear}:" // fourth day of the week matters
- setTextColor(mTextColor)
- beVisibleIf(displayWeekNumbers)
- }
- }
-
- val dividerMargin = mRes.displayMetrics.density.toInt()
- for (i in 0 until len) {
- mHolder.findViewById(mRes.getIdentifier("day_$i", "id", mPackageName)).apply {
- val day = days[i]
- setOnClickListener {
- (activity as MainActivity).openDayFromMonthly(Formatter.getDateTimeFromCode(day.code))
- }
-
- removeAllViews()
- context.addDayNumber(mTextColor, day, this, mDayLabelHeight) { mDayLabelHeight = it }
- context.addDayEvents(day, this, mRes, dividerMargin)
- }
+ private fun updateDays(days: ArrayList) {
+ mHolder.month_view_wrapper.updateDays(days) {
+ (activity as MainActivity).openDayFromMonthly(Formatter.getDateTimeFromCode(it.code))
}
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragmentsHolder.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragmentsHolder.kt
index a22bfe593..7f71acd7e 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragmentsHolder.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/MonthFragmentsHolder.kt
@@ -72,7 +72,7 @@ class MonthFragmentsHolder : MyFragmentHolder(), NavigationListener {
private fun getMonths(code: String): List {
val months = ArrayList(PREFILLED_MONTHS)
- val today = Formatter.getDateTimeFromCode(code)
+ val today = Formatter.getDateTimeFromCode(code).withDayOfMonth(1)
for (i in -PREFILLED_MONTHS / 2..PREFILLED_MONTHS / 2) {
months.add(Formatter.getDayCodeFromDateTime(today.plusMonths(i)))
}
@@ -108,5 +108,5 @@ class MonthFragmentsHolder : MyFragmentHolder(), NavigationListener {
(activity as MainActivity).supportActionBar?.title = getString(R.string.app_launcher_name)
}
- override fun getNewEventDayCode() = currentDayCode
+ override fun getNewEventDayCode() = if (shouldGoToTodayBeVisible()) currentDayCode else todayDayCode
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/WeekFragment.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/WeekFragment.kt
index 2cd5070ab..661e9656f 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/WeekFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/fragments/WeekFragment.kt
@@ -143,7 +143,9 @@ class WeekFragment : Fragment(), WeeklyCalendar {
val todayCode = Formatter.getDayCodeFromDateTime(DateTime())
for (i in 0..6) {
val dayCode = Formatter.getDayCodeFromDateTime(curDay)
- val dayLetter = getDayLetter(curDay.dayOfWeek)
+ val dayLetters = mRes.getStringArray(R.array.week_day_letters).toList() as ArrayList
+ val dayLetter = dayLetters[curDay.dayOfWeek - 1]
+
mView.findViewById(mRes.getIdentifier("week_day_label_$i", "id", context!!.packageName)).apply {
text = "$dayLetter\n${curDay.dayOfMonth}"
setTextColor(if (todayCode == dayCode) primaryColor else textColor)
@@ -155,18 +157,6 @@ class WeekFragment : Fragment(), WeeklyCalendar {
}
}
- private fun getDayLetter(pos: Int): String {
- return mRes.getString(when (pos) {
- 1 -> R.string.monday_letter
- 2 -> R.string.tuesday_letter
- 3 -> R.string.wednesday_letter
- 4 -> R.string.thursday_letter
- 5 -> R.string.friday_letter
- 6 -> R.string.saturday_letter
- else -> R.string.sunday_letter
- })
- }
-
private fun checkScrollLimits(y: Int) {
if (minScrollY != -1 && y < minScrollY) {
mScrollView.scrollY = minScrollY
@@ -359,10 +349,10 @@ class WeekFragment : Fragment(), WeeklyCalendar {
val minTS = Math.max(startDateTime.seconds(), mWeekTimestamp)
val maxTS = Math.min(endDateTime.seconds(), mWeekTimestamp + WEEK_SECONDS)
- val startDateTimeInWeek = Formatter.getDateTimeFromTS(minTS)
- val firstDayIndex = (startDateTimeInWeek.dayOfWeek - if (context!!.config.isSundayFirst) 0 else 1) % 7
val daysCnt = Days.daysBetween(Formatter.getDateTimeFromTS(minTS).toLocalDate(), Formatter.getDateTimeFromTS(maxTS).toLocalDate()).days
+ val startDateTimeInWeek = Formatter.getDateTimeFromTS(minTS)
+ val firstDayIndex = (startDateTimeInWeek.dayOfWeek - if (context!!.config.isSundayFirst) 0 else 1) % 7
var doesEventFit: Boolean
val cnt = allDayRows.size - 1
var wasEventHandled = false
@@ -383,7 +373,7 @@ class WeekFragment : Fragment(), WeeklyCalendar {
wasEventHandled = true
} else if (index == cnt) {
if (allDayRows.size == index + 1) {
- allDayRows.add(HashSet())
+ allDayRows.add(HashSet())
addNewLine()
drawAtLine++
wasEventHandled = true
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/CalDAVHandler.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/CalDAVHandler.kt
index b699e4d36..b812d5b26 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/CalDAVHandler.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/CalDAVHandler.kt
@@ -361,6 +361,7 @@ class CalDAVHandler(val context: Context) {
put(CalendarContract.Events.RRULE, Parser().getRepeatCode(event))
put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().toString())
put(CalendarContract.Events.EVENT_LOCATION, event.location)
+ put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CONFIRMED)
if (event.getIsAllDay() && event.endTS > event.startTS)
event.endTS += DAY
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Config.kt
index 919659d9f..8fd699de6 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Config.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Config.kt
@@ -1,9 +1,11 @@
package com.simplemobiletools.calendar.helpers
import android.content.Context
-import android.media.RingtoneManager
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.scheduleCalDAVSync
+import com.simplemobiletools.commons.extensions.getDefaultAlarmTitle
+import com.simplemobiletools.commons.extensions.getDefaultAlarmUri
+import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_NOTIFICATION
import com.simplemobiletools.commons.helpers.BaseConfig
import java.util.*
@@ -12,9 +14,9 @@ class Config(context: Context) : BaseConfig(context) {
fun newInstance(context: Context) = Config(context)
}
- var displayWeekNumbers: Boolean
+ var showWeekNumbers: Boolean
get() = prefs.getBoolean(WEEK_NUMBERS, false)
- set(displayWeekNumbers) = prefs.edit().putBoolean(WEEK_NUMBERS, displayWeekNumbers).apply()
+ set(showWeekNumbers) = prefs.edit().putBoolean(WEEK_NUMBERS, showWeekNumbers).apply()
var startWeeklyAt: Int
get() = prefs.getInt(START_WEEKLY_AT, 7)
@@ -28,9 +30,13 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(VIBRATE, false)
set(vibrate) = prefs.edit().putBoolean(VIBRATE, vibrate).apply()
- var reminderSound: String
- get() = prefs.getString(REMINDER_SOUND, getDefaultNotificationSound())
- set(path) = prefs.edit().putString(REMINDER_SOUND, path).apply()
+ var reminderSoundUri: String
+ get() = prefs.getString(REMINDER_SOUND_URI, context.getDefaultAlarmUri(ALARM_SOUND_TYPE_NOTIFICATION).toString())
+ set(reminderSoundUri) = prefs.edit().putString(REMINDER_SOUND_URI, reminderSoundUri).apply()
+
+ var reminderSoundTitle: String
+ get() = prefs.getString(REMINDER_SOUND_TITLE, context.getDefaultAlarmTitle(ALARM_SOUND_TYPE_NOTIFICATION))
+ set(reminderSoundTitle) = prefs.edit().putString(REMINDER_SOUND_TITLE, reminderSoundTitle).apply()
var storedView: Int
get() = prefs.getInt(VIEW, MONTHLY_VIEW)
@@ -79,6 +85,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(REPLACE_DESCRIPTION, false)
set(replaceDescription) = prefs.edit().putBoolean(REPLACE_DESCRIPTION, replaceDescription).apply()
+ var showGrid: Boolean
+ get() = prefs.getBoolean(SHOW_GRID, false)
+ set(showGrid) = prefs.edit().putBoolean(SHOW_GRID, showGrid).apply()
+
fun getSyncedCalendarIdsAsList() = caldavSyncedCalendarIDs.split(",").filter { it.trim().isNotEmpty() } as ArrayList
fun addDisplayEventType(type: String) {
@@ -97,14 +107,6 @@ class Config(context: Context) : BaseConfig(context) {
displayEventTypes = currDisplayEventTypes
}
- private fun getDefaultNotificationSound(): String {
- return try {
- RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_NOTIFICATION)?.toString() ?: ""
- } catch (e: Exception) {
- ""
- }
- }
-
fun getFontSize() = when (fontSize) {
FONT_SIZE_SMALL -> getSmallFontSize()
FONT_SIZE_MEDIUM -> getMediumFontSize()
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Constants.kt
index 844d6f4cc..ab8956029 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Constants.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Constants.kt
@@ -37,7 +37,8 @@ const val WEEK_NUMBERS = "week_numbers"
const val START_WEEKLY_AT = "start_weekly_at"
const val END_WEEKLY_AT = "end_weekly_at"
const val VIBRATE = "vibrate"
-const val REMINDER_SOUND = "reminder_sound"
+const val REMINDER_SOUND_URI = "reminder_sound_uri"
+const val REMINDER_SOUND_TITLE = "reminder_sound_title"
const val VIEW = "view"
const val REMINDER_MINUTES = "reminder_minutes"
const val REMINDER_MINUTES_2 = "reminder_minutes_2"
@@ -49,6 +50,7 @@ const val CALDAV_SYNCED_CALENDAR_IDS = "caldav_synced_calendar_ids"
const val LAST_USED_CALDAV_CALENDAR = "last_used_caldav_calendar"
const val DISPLAY_PAST_EVENTS = "display_past_events"
const val REPLACE_DESCRIPTION = "replace_description"
+const val SHOW_GRID = "show_grid"
// repeat_rule for monthly repetition
const val REPEAT_MONTH_SAME_DAY = 1 // ie 25th every month
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/DBHelper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/DBHelper.kt
index 99ae0a221..acff07eac 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/DBHelper.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/DBHelper.kt
@@ -225,6 +225,35 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
callback(event.id)
}
+ fun insertEvents(events: ArrayList, addToCalDAV: Boolean) {
+ mDb.beginTransaction()
+ try {
+ for (event in events) {
+ if (event.startTS > event.endTS) {
+ continue
+ }
+
+ val eventValues = fillEventValues(event)
+ val id = mDb.insert(MAIN_TABLE_NAME, null, eventValues)
+ event.id = id.toInt()
+
+ if (event.repeatInterval != 0 && event.parentId == 0) {
+ val metaValues = fillMetaValues(event)
+ mDb.insert(META_TABLE_NAME, null, metaValues)
+ }
+
+ context.scheduleNextEventReminder(event, this)
+ if (addToCalDAV && event.source != SOURCE_SIMPLE_CALENDAR && context.config.caldavSync) {
+ CalDAVHandler(context).insertCalDAVEvent(event)
+ }
+ }
+ mDb.setTransactionSuccessful()
+ } finally {
+ mDb.endTransaction()
+ context.updateWidgets()
+ }
+ }
+
fun update(event: Event, updateAtCalDAV: Boolean, callback: (() -> Unit)? = null) {
val values = fillEventValues(event)
val selection = "$COL_ID = ?"
@@ -605,6 +634,18 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
}
}
+ fun getEventIdWithLastImportId(id: String): Int {
+ val selection = "$MAIN_TABLE_NAME.$COL_IMPORT_ID LIKE ?"
+ val selectionArgs = arrayOf("%-$id")
+ val cursor = getEventsCursor(selection, selectionArgs)
+ val events = fillEvents(cursor)
+ return if (events.isNotEmpty()) {
+ events.minBy { it.id }?.id ?: 0
+ } else {
+ 0
+ }
+ }
+
fun getEventsWithSearchQuery(text: String, callback: (searchedText: String, events: List) -> Unit) {
Thread {
val searchQuery = "%$text%"
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Formatter.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Formatter.kt
index 1605e164a..0bfe927db 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Formatter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/Formatter.kt
@@ -9,7 +9,6 @@ import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.joda.time.LocalDate
import org.joda.time.format.DateTimeFormat
-import java.text.DateFormat
object Formatter {
val DAYCODE_PATTERN = "YYYYMMdd"
@@ -89,9 +88,9 @@ object Formatter {
fun getYear(dateTime: DateTime) = dateTime.toString(YEAR_PATTERN)
- fun getHourPattern(context: Context) = if (context.config.use24hourFormat) PATTERN_HOURS_24 else PATTERN_HOURS_12
+ fun getHourPattern(context: Context) = if (context.config.use24HourFormat) PATTERN_HOURS_24 else PATTERN_HOURS_12
- fun getTimePattern(context: Context) = if (context.config.use24hourFormat) PATTERN_TIME_24 else PATTERN_TIME_12
+ fun getTimePattern(context: Context) = if (context.config.use24HourFormat) PATTERN_TIME_24 else PATTERN_TIME_12
fun getExportedTime(ts: Long): String {
val dateTime = DateTime(ts, DateTimeZone.UTC)
@@ -108,6 +107,4 @@ object Formatter {
}
fun getShiftedImportTimestamp(ts: Int) = getUTCDateTimeFromTS(ts).withTime(13, 0, 0, 0).withZoneRetainFields(DateTimeZone.getDefault()).seconds()
-
- fun getDayAndMonth(localDate: LocalDate) = localDate.toString("dd.MM.")
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsExporter.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsExporter.kt
index b5f72072b..472c967f6 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsExporter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsExporter.kt
@@ -1,10 +1,12 @@
package com.simplemobiletools.calendar.helpers
+import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.dbHelper
import com.simplemobiletools.calendar.helpers.IcsExporter.ExportResult.*
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.getFileOutputStream
+import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.writeLn
import com.simplemobiletools.commons.models.FileDirItem
import java.io.BufferedWriter
@@ -18,14 +20,18 @@ class IcsExporter {
private var eventsExported = 0
private var eventsFailed = 0
- fun exportEvents(activity: BaseSimpleActivity, file: File, events: ArrayList, callback: (result: ExportResult) -> Unit) {
+ fun exportEvents(activity: BaseSimpleActivity, file: File, events: ArrayList, showExportingToast: Boolean, callback: (result: ExportResult) -> Unit) {
val fileDirItem = FileDirItem(file.absolutePath, file.name)
- activity.getFileOutputStream(fileDirItem) {
+ activity.getFileOutputStream(fileDirItem, true) {
if (it == null) {
callback(EXPORT_FAIL)
return@getFileOutputStream
}
+ if (showExportingToast) {
+ activity.toast(R.string.exporting)
+ }
+
it.bufferedWriter().use { out ->
out.writeLn(BEGIN_CALENDAR)
out.writeLn(CALENDAR_PRODID)
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsImporter.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsImporter.kt
index 947254241..eff91f071 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsImporter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/IcsImporter.kt
@@ -43,6 +43,7 @@ class IcsImporter(val activity: SimpleActivity) {
fun importEvents(path: String, defaultEventType: Int, calDAVCalendarId: Int): ImportResult {
try {
val existingEvents = activity.dbHelper.getEventsWithImportIds()
+ val eventsToInsert = ArrayList()
var prevLine = ""
val inputStream = if (path.contains("/")) {
@@ -131,7 +132,6 @@ class IcsImporter(val activity: SimpleActivity) {
continue
}
-
val eventToUpdate = existingEvents.firstOrNull { curImportId.isNotEmpty() && curImportId == it.importId }
if (eventToUpdate != null && eventToUpdate.lastUpdated >= curLastModified) {
continue
@@ -148,11 +148,15 @@ class IcsImporter(val activity: SimpleActivity) {
}
if (eventToUpdate == null) {
- activity.dbHelper.insert(event, true) {
- for (exceptionTS in curRepeatExceptions) {
- activity.dbHelper.addEventRepeatException(it, exceptionTS, true)
+ if (curRepeatExceptions.isEmpty()) {
+ eventsToInsert.add(event)
+ } else {
+ activity.dbHelper.insert(event, true) {
+ for (exceptionTS in curRepeatExceptions) {
+ activity.dbHelper.addEventRepeatException(it, exceptionTS, true)
+ }
+ existingEvents.add(event)
}
- existingEvents.add(event)
}
} else {
event.id = eventToUpdate.id
@@ -164,6 +168,8 @@ class IcsImporter(val activity: SimpleActivity) {
prevLine = line
}
}
+
+ activity.dbHelper.insertEvents(eventsToInsert, true)
} catch (e: Exception) {
activity.showErrorToast(e, Toast.LENGTH_LONG)
eventsFailed++
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MonthlyCalendarImpl.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MonthlyCalendarImpl.kt
index 5e43361e7..2c6fa6b5d 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MonthlyCalendarImpl.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MonthlyCalendarImpl.kt
@@ -25,8 +25,8 @@ class MonthlyCalendarImpl(val mCallback: MonthlyCalendar, val mContext: Context)
fun updateMonthlyCalendar(targetDate: DateTime, filterEventTypes: Boolean = true) {
mFilterEventTypes = filterEventTypes
mTargetDate = targetDate
- val startTS = mTargetDate.minusMonths(1).seconds()
- val endTS = mTargetDate.plusMonths(1).seconds()
+ val startTS = mTargetDate.minusDays(7).seconds()
+ val endTS = mTargetDate.plusDays(43).seconds()
mContext.dbHelper.getEvents(startTS, endTS) {
gotEvents(it as ArrayList)
}
@@ -47,7 +47,7 @@ class MonthlyCalendarImpl(val mCallback: MonthlyCalendar, val mContext: Context)
var isThisMonth = false
var isToday: Boolean
var value = prevMonthDays - firstDayIndex + 1
- var curDay: DateTime = mTargetDate
+ var curDay = mTargetDate
for (i in 0 until DAYS_CNT) {
when {
@@ -67,11 +67,11 @@ class MonthlyCalendarImpl(val mCallback: MonthlyCalendar, val mContext: Context)
}
}
- isToday = isThisMonth && isToday(mTargetDate, value)
+ isToday = isToday(curDay, value)
val newDay = curDay.withDayOfMonth(value)
val dayCode = Formatter.getDayCodeFromDateTime(newDay)
- val day = DayMonthly(value, isThisMonth, isToday, dayCode, newDay.weekOfWeekyear, ArrayList())
+ val day = DayMonthly(value, isThisMonth, isToday, dayCode, newDay.weekOfWeekyear, ArrayList(), i)
days.add(day)
value++
}
@@ -94,14 +94,16 @@ class MonthlyCalendarImpl(val mCallback: MonthlyCalendar, val mContext: Context)
var currDay = startDateTime
var dayCode = Formatter.getDayCodeFromDateTime(currDay)
- var currDayEvents = (dayEvents[dayCode] ?: ArrayList()).apply { add(it) }
- dayEvents.put(dayCode, currDayEvents)
+ var currDayEvents = dayEvents[dayCode] ?: ArrayList()
+ currDayEvents.add(it)
+ dayEvents[dayCode] = currDayEvents
while (Formatter.getDayCodeFromDateTime(currDay) != endCode) {
currDay = currDay.plusDays(1)
dayCode = Formatter.getDayCodeFromDateTime(currDay)
- currDayEvents = (dayEvents[dayCode] ?: ArrayList()).apply { add(it) }
- dayEvents.put(dayCode, currDayEvents)
+ currDayEvents = dayEvents[dayCode] ?: ArrayList()
+ currDayEvents.add(it)
+ dayEvents[dayCode] = currDayEvents
}
}
@@ -113,10 +115,8 @@ class MonthlyCalendarImpl(val mCallback: MonthlyCalendar, val mContext: Context)
}
private fun isToday(targetDate: DateTime, curDayInMonth: Int): Boolean {
- return if (curDayInMonth > targetDate.dayOfMonth().maximumValue)
- false
- else
- targetDate.withDayOfMonth(curDayInMonth).toString(Formatter.DAYCODE_PATTERN) == mToday
+ val targetMonthDays = targetDate.dayOfMonth().maximumValue
+ return targetDate.withDayOfMonth(Math.min(curDayInMonth, targetMonthDays)).toString(Formatter.DAYCODE_PATTERN) == mToday
}
private val monthName: String
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MyWidgetMonthlyProvider.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MyWidgetMonthlyProvider.kt
index 7ebff7fdd..cf707ea24 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MyWidgetMonthlyProvider.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/MyWidgetMonthlyProvider.kt
@@ -24,7 +24,7 @@ class MyWidgetMonthlyProvider : AppWidgetProvider() {
private val NEW_EVENT = "new_event"
companion object {
- private var targetDate = DateTime.now()
+ private var targetDate = DateTime.now().withDayOfMonth(1)
}
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
@@ -82,7 +82,7 @@ class MyWidgetMonthlyProvider : AppWidgetProvider() {
}
private fun updateDays(context: Context, views: RemoteViews, days: List) {
- val displayWeekNumbers = context.config.displayWeekNumbers
+ val displayWeekNumbers = context.config.showWeekNumbers
val textColor = context.config.widgetTextColor
val smallerFontSize = context.config.getFontSize() - 3f
val res = context.resources
@@ -149,7 +149,7 @@ class MyWidgetMonthlyProvider : AppWidgetProvider() {
}
private val monthlyCalendar = object : MonthlyCalendar {
- override fun updateMonthlyCalendar(context: Context, month: String, days: List, checkedEvents: Boolean) {
+ override fun updateMonthlyCalendar(context: Context, month: String, days: ArrayList, checkedEvents: Boolean) {
val largerFontSize = context.config.getFontSize() + 3f
val textColor = context.config.widgetTextColor
val resources = context.resources
@@ -182,7 +182,10 @@ class MyWidgetMonthlyProvider : AppWidgetProvider() {
val monthCode = days.firstOrNull { it.code.substring(6) == "01" }?.code ?: Formatter.getTodayCode(context)
setupAppOpenIntent(context, views, R.id.top_value, monthCode)
- appWidgetManager.updateAppWidget(it, views)
+ try {
+ appWidgetManager.updateAppWidget(it, views)
+ } catch (ignored: RuntimeException) {
+ }
}
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/interfaces/MonthlyCalendar.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/interfaces/MonthlyCalendar.kt
index 1f7c188b5..1ada47f89 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/interfaces/MonthlyCalendar.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/interfaces/MonthlyCalendar.kt
@@ -4,5 +4,5 @@ import android.content.Context
import com.simplemobiletools.calendar.models.DayMonthly
interface MonthlyCalendar {
- fun updateMonthlyCalendar(context: Context, month: String, days: List, checkedEvents: Boolean)
+ fun updateMonthlyCalendar(context: Context, month: String, days: ArrayList, checkedEvents: Boolean)
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/models/DayMonthly.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/models/DayMonthly.kt
index 8f8cfe30e..55e9d57a4 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/models/DayMonthly.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/models/DayMonthly.kt
@@ -1,6 +1,7 @@
package com.simplemobiletools.calendar.models
-data class DayMonthly(val value: Int, val isThisMonth: Boolean, val isToday: Boolean, val code: String, val weekOfYear: Int, var dayEvents: ArrayList) {
+data class DayMonthly(val value: Int, val isThisMonth: Boolean, val isToday: Boolean, val code: String, val weekOfYear: Int, var dayEvents: ArrayList,
+ var indexOnMonthView: Int) {
fun hasEvent() = dayEvents.isNotEmpty()
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/models/MonthViewEvent.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/models/MonthViewEvent.kt
new file mode 100644
index 000000000..e68b819b3
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/models/MonthViewEvent.kt
@@ -0,0 +1,4 @@
+package com.simplemobiletools.calendar.models
+
+data class MonthViewEvent(val id: Int, val title: String, val startTS: Int, val color: Int, val startDayIndex: Int, val daysCnt: Int, val originalStartDayIndex: Int,
+ val isAllDay: Boolean)
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/BootCompletedReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/BootCompletedReceiver.kt
index 96c163240..d6aec0c36 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/BootCompletedReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/BootCompletedReceiver.kt
@@ -9,11 +9,13 @@ import com.simplemobiletools.calendar.extensions.scheduleAllEvents
class BootCompletedReceiver : BroadcastReceiver() {
- override fun onReceive(context: Context, arg1: Intent) {
- context.apply {
- scheduleAllEvents()
- notifyRunningEvents()
- recheckCalDAVCalendars {}
- }
+ override fun onReceive(context: Context, intent: Intent) {
+ Thread {
+ context.apply {
+ scheduleAllEvents()
+ notifyRunningEvents()
+ recheckCalDAVCalendars {}
+ }
+ }.start()
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/NotificationReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/NotificationReceiver.kt
index 80aa2c733..3fb716f84 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/NotificationReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/receivers/NotificationReceiver.kt
@@ -15,14 +15,20 @@ class NotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
val wakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Simple Calendar")
- wakelock.acquire(5000)
+ wakelock.acquire(3000)
- context.updateListWidget()
+ Thread {
+ handleIntent(context, intent)
+ }.start()
+ }
+
+ private fun handleIntent(context: Context, intent: Intent) {
val id = intent.getIntExtra(EVENT_ID, -1)
if (id == -1) {
return
}
+ context.updateListWidget()
val event = context.dbHelper.getEventWithId(id)
if (event == null || event.getReminders().isEmpty()) {
return
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/views/MonthView.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/views/MonthView.kt
new file mode 100644
index 000000000..9b0ef9579
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/views/MonthView.kt
@@ -0,0 +1,335 @@
+package com.simplemobiletools.calendar.views
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RectF
+import android.text.TextPaint
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.util.SparseIntArray
+import android.view.View
+import com.simplemobiletools.calendar.R
+import com.simplemobiletools.calendar.extensions.config
+import com.simplemobiletools.calendar.extensions.seconds
+import com.simplemobiletools.calendar.helpers.Formatter
+import com.simplemobiletools.calendar.helpers.LOW_ALPHA
+import com.simplemobiletools.calendar.models.DayMonthly
+import com.simplemobiletools.calendar.models.Event
+import com.simplemobiletools.calendar.models.MonthViewEvent
+import com.simplemobiletools.commons.extensions.adjustAlpha
+import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
+import com.simplemobiletools.commons.extensions.getContrastColor
+import com.simplemobiletools.commons.extensions.moveLastItemToFront
+import org.joda.time.DateTime
+import org.joda.time.Days
+
+// used in the Monthly view fragment, 1 view per screen
+class MonthView(context: Context, attrs: AttributeSet, defStyle: Int) : View(context, attrs, defStyle) {
+ private val BG_CORNER_RADIUS = 4f
+ private val ROW_COUNT = 6
+
+ private var paint: Paint
+ private var eventTitlePaint: TextPaint
+ private var gridPaint: Paint
+ private var dayWidth = 0f
+ private var dayHeight = 0f
+ private var primaryColor = 0
+ private var textColor = 0
+ private var weekDaysLetterHeight = 0
+ private var eventTitleHeight = 0
+ private var currDayOfWeek = 0
+ private var smallPadding = 0
+ private var maxEventsPerDay = 0
+ private var horizontalOffset = 0
+ private var showWeekNumbers = false
+ private var allEvents = ArrayList()
+ private var bgRectF = RectF()
+ private var dayLetters = ArrayList()
+ private var days = ArrayList()
+ private var dayVerticalOffsets = SparseIntArray()
+
+ constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
+
+ init {
+ primaryColor = context.getAdjustedPrimaryColor()
+ textColor = context.config.textColor
+ showWeekNumbers = context.config.showWeekNumbers
+
+ smallPadding = resources.displayMetrics.density.toInt()
+ val normalTextSize = resources.getDimensionPixelSize(R.dimen.normal_text_size)
+ weekDaysLetterHeight = normalTextSize * 2
+
+ paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = textColor
+ textSize = normalTextSize.toFloat()
+ textAlign = Paint.Align.CENTER
+ }
+
+ gridPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = textColor.adjustAlpha(LOW_ALPHA)
+ }
+
+ val smallerTextSize = resources.getDimensionPixelSize(R.dimen.smaller_text_size)
+ eventTitleHeight = smallerTextSize
+ eventTitlePaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = textColor
+ textSize = smallerTextSize.toFloat()
+ textAlign = Paint.Align.LEFT
+ }
+
+ initWeekDayLetters()
+ setupCurrentDayOfWeekIndex()
+ }
+
+ fun updateDays(newDays: ArrayList) {
+ days = newDays
+ showWeekNumbers = context.config.showWeekNumbers
+ horizontalOffset = if (showWeekNumbers) eventTitleHeight * 2 else 0
+ initWeekDayLetters()
+ setupCurrentDayOfWeekIndex()
+ groupAllEvents()
+ invalidate()
+ }
+
+ private fun groupAllEvents() {
+ days.forEach {
+ val day = it
+ day.dayEvents.forEach {
+ val event = it
+
+ // make sure we properly handle events lasting multiple days and repeating ones
+ val lastEvent = allEvents.lastOrNull { it.id == event.id }
+ val daysCnt = getEventLastingDaysCount(event)
+ if (lastEvent == null || lastEvent.startDayIndex + daysCnt <= day.indexOnMonthView) {
+ val monthViewEvent = MonthViewEvent(event.id, event.title, event.startTS, event.color, day.indexOnMonthView,
+ daysCnt, day.indexOnMonthView, event.getIsAllDay())
+ allEvents.add(monthViewEvent)
+ }
+ }
+ }
+
+ allEvents = allEvents.sortedWith(compareBy({ -it.daysCnt }, { !it.isAllDay }, { it.startTS }, { it.startDayIndex }, { it.title })).toMutableList() as ArrayList
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ dayVerticalOffsets.clear()
+ measureDaySize(canvas)
+
+ if (context.config.showGrid) {
+ drawGrid(canvas)
+ }
+
+ addWeekDayLetters(canvas)
+ if (showWeekNumbers) {
+ addWeekNumbers(canvas)
+ }
+
+ var curId = 0
+ for (y in 0 until ROW_COUNT) {
+ for (x in 0..6) {
+ val day = days.getOrNull(curId)
+ if (day != null) {
+ dayVerticalOffsets.put(day.indexOnMonthView, dayVerticalOffsets[day.indexOnMonthView] + weekDaysLetterHeight)
+ val verticalOffset = dayVerticalOffsets[day.indexOnMonthView]
+ val xPos = x * dayWidth + horizontalOffset
+ val yPos = y * dayHeight + verticalOffset
+ val xPosCenter = xPos + dayWidth / 2
+ if (day.isToday) {
+ canvas.drawCircle(xPosCenter, yPos + paint.textSize * 0.7f, paint.textSize * 0.75f, getCirclePaint(day))
+ }
+
+ canvas.drawText(day.value.toString(), xPosCenter, yPos + paint.textSize, getTextPaint(day))
+ dayVerticalOffsets.put(day.indexOnMonthView, (verticalOffset + paint.textSize * 2).toInt())
+ }
+ curId++
+ }
+ }
+
+ drawEvents(canvas)
+ }
+
+ private fun drawGrid(canvas: Canvas) {
+ // vertical lines
+ for (i in 0..6) {
+ var lineX = i * dayWidth
+ if (showWeekNumbers) {
+ lineX += horizontalOffset
+ }
+ canvas.drawLine(lineX, 0f, lineX, canvas.height.toFloat(), gridPaint)
+ }
+
+ // horizontal lines
+ canvas.drawLine(0f, 0f, canvas.width.toFloat(), 0f, gridPaint)
+ for (i in 0..5) {
+ canvas.drawLine(0f, i * dayHeight + weekDaysLetterHeight, canvas.width.toFloat(), i * dayHeight + weekDaysLetterHeight, gridPaint)
+ }
+ }
+
+ private fun addWeekDayLetters(canvas: Canvas) {
+ for (i in 0..6) {
+ val xPos = horizontalOffset + (i + 1) * dayWidth - dayWidth / 2
+ var weekDayLetterPaint = paint
+ if (i == currDayOfWeek) {
+ weekDayLetterPaint = getColoredPaint(primaryColor)
+ }
+ canvas.drawText(dayLetters[i], xPos, weekDaysLetterHeight * 0.7f, weekDayLetterPaint)
+ }
+ }
+
+ private fun addWeekNumbers(canvas: Canvas) {
+ val weekNumberPaint = Paint(paint)
+ weekNumberPaint.textAlign = Paint.Align.RIGHT
+
+ for (i in 0 until ROW_COUNT) {
+ // fourth day of the week matters
+ val weekOfYear = days.getOrNull(i * 7 + 3)?.weekOfYear ?: 1
+ val id = "$weekOfYear:"
+
+ val yPos = i * dayHeight + weekDaysLetterHeight
+ canvas.drawText(id, horizontalOffset.toFloat() * 0.9f, yPos + paint.textSize, weekNumberPaint)
+ }
+ }
+
+ private fun measureDaySize(canvas: Canvas) {
+ dayWidth = (canvas.width - horizontalOffset) / 7f
+ dayHeight = (canvas.height - weekDaysLetterHeight) / ROW_COUNT.toFloat()
+ val availableHeightForEvents = dayHeight.toInt() - weekDaysLetterHeight
+ maxEventsPerDay = availableHeightForEvents / eventTitleHeight
+ }
+
+ private fun drawEvents(canvas: Canvas) {
+ for (event in allEvents) {
+ drawEvent(event, canvas)
+ }
+ }
+
+ private fun drawEvent(event: MonthViewEvent, canvas: Canvas) {
+ val verticalOffset = dayVerticalOffsets[event.startDayIndex]
+ val xPos = event.startDayIndex % 7 * dayWidth + horizontalOffset
+ val yPos = (event.startDayIndex / 7) * dayHeight
+ val xPosCenter = xPos + dayWidth / 2
+
+ if (verticalOffset - eventTitleHeight * 2 > dayHeight) {
+ canvas.drawText("...", xPosCenter, yPos + verticalOffset - eventTitleHeight / 2, getTextPaint(days[event.startDayIndex]))
+ return
+ }
+
+ // event background rectangle
+ val backgroundY = yPos + verticalOffset
+ val bgLeft = xPos + smallPadding
+ val bgTop = backgroundY + smallPadding - eventTitleHeight
+ var bgRight = xPos - smallPadding + dayWidth * event.daysCnt
+ val bgBottom = backgroundY + smallPadding * 2
+ if (bgRight > canvas.width.toFloat()) {
+ bgRight = canvas.width.toFloat() - smallPadding
+ val newStartDayIndex = (event.startDayIndex / 7 + 1) * 7
+ if (newStartDayIndex < 42) {
+ val newEvent = event.copy(startDayIndex = newStartDayIndex, daysCnt = event.daysCnt - (newStartDayIndex - event.startDayIndex))
+ drawEvent(newEvent, canvas)
+ }
+ }
+
+ val startDayIndex = days[event.originalStartDayIndex]
+ val endDayIndex = days[Math.min(event.startDayIndex + event.daysCnt - 1, 41)]
+ bgRectF.set(bgLeft, bgTop, bgRight, bgBottom)
+ canvas.drawRoundRect(bgRectF, BG_CORNER_RADIUS, BG_CORNER_RADIUS, getEventBackgroundColor(event, startDayIndex, endDayIndex))
+
+ drawEventTitle(event.title, canvas, xPos, yPos + verticalOffset, bgRight - bgLeft - smallPadding, event.color, startDayIndex, endDayIndex)
+
+ for (i in 0 until Math.min(event.daysCnt, 7 - event.startDayIndex % 7)) {
+ dayVerticalOffsets.put(event.startDayIndex + i, verticalOffset + eventTitleHeight + smallPadding * 2)
+ }
+ }
+
+ private fun drawEventTitle(title: String, canvas: Canvas, x: Float, y: Float, availableWidth: Float, eventColor: Int, startDay: DayMonthly, endDay: DayMonthly) {
+ val ellipsized = TextUtils.ellipsize(title, eventTitlePaint, availableWidth - smallPadding, TextUtils.TruncateAt.END)
+ canvas.drawText(title, 0, ellipsized.length, x + smallPadding * 2, y, getEventTitlePaint(eventColor, startDay, endDay))
+ }
+
+ private fun getTextPaint(startDay: DayMonthly): Paint {
+ var paintColor = textColor
+ if (startDay.isToday) {
+ paintColor = primaryColor.getContrastColor()
+ }
+
+ if (!startDay.isThisMonth) {
+ paintColor = paintColor.adjustAlpha(LOW_ALPHA)
+ }
+
+ return getColoredPaint(paintColor)
+ }
+
+ private fun getColoredPaint(color: Int): Paint {
+ val curPaint = Paint(paint)
+ curPaint.color = color
+ return curPaint
+ }
+
+ private fun getEventBackgroundColor(event: MonthViewEvent, startDay: DayMonthly, endDay: DayMonthly): Paint {
+ var paintColor = event.color
+ if (!startDay.isThisMonth && !endDay.isThisMonth) {
+ paintColor = paintColor.adjustAlpha(LOW_ALPHA)
+ }
+
+ return getColoredPaint(paintColor)
+ }
+
+ private fun getEventTitlePaint(color: Int, startDay: DayMonthly, endDay: DayMonthly): Paint {
+ var paintColor = color.getContrastColor()
+ if (!startDay.isThisMonth && !endDay.isThisMonth) {
+ paintColor = paintColor.adjustAlpha(LOW_ALPHA)
+ }
+
+ val curPaint = Paint(eventTitlePaint)
+ curPaint.color = paintColor
+ return curPaint
+ }
+
+ private fun getCirclePaint(day: DayMonthly): Paint {
+ val curPaint = Paint(paint)
+ var paintColor = primaryColor
+ if (!day.isThisMonth) {
+ paintColor = paintColor.adjustAlpha(LOW_ALPHA)
+ }
+ curPaint.color = paintColor
+ return curPaint
+ }
+
+ private fun initWeekDayLetters() {
+ dayLetters = context.resources.getStringArray(R.array.week_day_letters).toList() as ArrayList
+ if (context.config.isSundayFirst) {
+ dayLetters.moveLastItemToFront()
+ }
+ }
+
+ private fun setupCurrentDayOfWeekIndex() {
+ if (days.firstOrNull { it.isToday && it.isThisMonth } == null) {
+ currDayOfWeek = -1
+ return
+ }
+
+ currDayOfWeek = DateTime().dayOfWeek
+ if (context.config.isSundayFirst) {
+ currDayOfWeek %= 7
+ } else {
+ currDayOfWeek--
+ }
+ }
+
+ // take into account cases when an event starts on the previous screen, subtract those days
+ private fun getEventLastingDaysCount(event: Event): Int {
+ val startDateTime = Formatter.getDateTimeFromTS(event.startTS)
+ val endDateTime = Formatter.getDateTimeFromTS(event.endTS)
+ val code = days.first().code
+ val screenStartDateTime = Formatter.getDateTimeFromCode(code).toLocalDate()
+ var eventStartDateTime = Formatter.getDateTimeFromTS(startDateTime.seconds()).toLocalDate()
+ val eventEndDateTime = Formatter.getDateTimeFromTS(endDateTime.seconds()).toLocalDate()
+ val diff = Days.daysBetween(screenStartDateTime, eventStartDateTime).days
+ if (diff < 0) {
+ eventStartDateTime = screenStartDateTime
+ }
+ return Days.daysBetween(eventStartDateTime, eventEndDateTime).days + 1
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/views/MonthViewWrapper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/views/MonthViewWrapper.kt
new file mode 100644
index 000000000..0a3ff142d
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/views/MonthViewWrapper.kt
@@ -0,0 +1,99 @@
+package com.simplemobiletools.calendar.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.FrameLayout
+import com.simplemobiletools.calendar.R
+import com.simplemobiletools.calendar.extensions.config
+import com.simplemobiletools.calendar.models.DayMonthly
+import com.simplemobiletools.commons.extensions.onGlobalLayout
+import kotlinx.android.synthetic.main.month_view.view.*
+
+// used in the Monthly view fragment, 1 view per screen
+class MonthViewWrapper(context: Context, attrs: AttributeSet, defStyle: Int) : FrameLayout(context, attrs, defStyle) {
+ private var dayWidth = 0f
+ private var dayHeight = 0f
+ private var weekDaysLetterHeight = 0
+ private var wereViewsAdded = false
+ private var days = ArrayList()
+ private var inflater: LayoutInflater
+ private var monthView: MonthView
+ private var horizontalOffset = 0
+ private var dayClickCallback: ((day: DayMonthly) -> Unit)? = null
+
+ constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
+
+ init {
+ val normalTextSize = resources.getDimensionPixelSize(R.dimen.normal_text_size).toFloat()
+ weekDaysLetterHeight = 2 * normalTextSize.toInt()
+
+ inflater = LayoutInflater.from(context)
+ monthView = inflater.inflate(R.layout.month_view, this).month_view
+ setupHorizontalOffset()
+
+ onGlobalLayout {
+ if (!wereViewsAdded && days.isNotEmpty()) {
+ measureSizes()
+ addViews()
+ monthView.updateDays(days)
+ }
+ }
+ }
+
+ fun updateDays(newDays: ArrayList, callback: ((DayMonthly) -> Unit)? = null) {
+ setupHorizontalOffset()
+ measureSizes()
+ dayClickCallback = callback
+ days = newDays
+ if (dayWidth != 0f && dayHeight != 0f) {
+ addViews()
+ }
+ monthView.updateDays(days)
+ }
+
+ private fun setupHorizontalOffset() {
+ horizontalOffset = if (context.config.showWeekNumbers) resources.getDimensionPixelSize(R.dimen.smaller_text_size) * 2 else 0
+ }
+
+ private fun measureSizes() {
+ dayWidth = (width - horizontalOffset) / 7f
+
+ // avoid updating the height when coming back from a new event screen, when the keyboard was visible
+ val newHeight = (height - weekDaysLetterHeight) / 6f
+ if (newHeight > dayHeight) {
+ dayHeight = (height - weekDaysLetterHeight) / 6f
+ }
+ }
+
+ private fun addViews() {
+ removeAllViews()
+ monthView = inflater.inflate(R.layout.month_view, this).month_view
+ wereViewsAdded = true
+ var curId = 0
+ for (y in 0..5) {
+ for (x in 0..6) {
+ val day = days.getOrNull(curId)
+ if (day != null) {
+ val xPos = x * dayWidth + horizontalOffset
+ val yPos = y * dayHeight + weekDaysLetterHeight
+ addViewBackground(xPos, yPos, day)
+ }
+ curId++
+ }
+ }
+ }
+
+ private fun addViewBackground(xPos: Float, yPos: Float, day: DayMonthly) {
+ inflater.inflate(R.layout.month_view_background, this, false).apply {
+ layoutParams.width = dayWidth.toInt()
+ layoutParams.height = dayHeight.toInt()
+ x = xPos
+ y = yPos
+ setOnClickListener {
+ dayClickCallback?.invoke(day)
+ }
+ addView(this)
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/views/SmallMonthView.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/views/SmallMonthView.kt
index 9ba798b32..af53d3b8c 100644
--- a/app/src/main/kotlin/com/simplemobiletools/calendar/views/SmallMonthView.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/calendar/views/SmallMonthView.kt
@@ -14,6 +14,7 @@ import com.simplemobiletools.commons.extensions.adjustAlpha
import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
import java.util.*
+// used for displaying months at Yearly view
class SmallMonthView(context: Context, attrs: AttributeSet, defStyle: Int) : View(context, attrs, defStyle) {
private var paint: Paint
private var todayCirclePaint: Paint
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index 6fb597e5d..6df46ade7 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -494,6 +494,29 @@
+
+
+
+
+
+
-
-
-
+ android:layout_below="@+id/top_left_arrow"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_month_widget_config.xml b/app/src/main/res/layout/fragment_month_widget_config.xml
new file mode 100644
index 000000000..a7c627fdb
--- /dev/null
+++ b/app/src/main/res/layout/fragment_month_widget_config.xml
@@ -0,0 +1,505 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/month_view.xml b/app/src/main/res/layout/month_view.xml
new file mode 100644
index 000000000..0294b179d
--- /dev/null
+++ b/app/src/main/res/layout/month_view.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/app/src/main/res/layout/month_view_background.xml b/app/src/main/res/layout/month_view_background.xml
new file mode 100644
index 000000000..f7eb272d5
--- /dev/null
+++ b/app/src/main/res/layout/month_view_background.xml
@@ -0,0 +1,7 @@
+
+
diff --git a/app/src/main/res/layout/widget_config_monthly.xml b/app/src/main/res/layout/widget_config_monthly.xml
index f96a3f1d5..a62067ac6 100644
--- a/app/src/main/res/layout/widget_config_monthly.xml
+++ b/app/src/main/res/layout/widget_config_monthly.xml
@@ -9,7 +9,7 @@
Hadisə uğurla yeniləndi
Hadisələri yazıya görə sırala
Xahiş olunur məkan parametrini doldurun ki hadisədə görünsün
+ An event is upcoming
Təkrarlama
@@ -130,7 +131,7 @@
Bayram əlavə et
Milli bayramlar
Dini bayramlar
- Bayramlar uğurla yeni hadisə tipinə daxil edildi
+ Holidays have been successfully imported into the \"Holidays\" event type
Bəzi bayramları daxil etmək alınmadı
Bayramları daxil etmək alınmadı
@@ -150,6 +151,7 @@
Hadisə əlavəsini məkan ilə dəyiş
Bütün hadisələri sil
Bütün hadisələri silmək istədiyinizə əminsiniz? Bu hadisələri və parametrlərini bütövlüklə siləcək.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
Kontakt icazəsi yalnız kontakt ad günlərini və il dönümlərini daxil etmək üçün istifadə olunur.
- Bu, böyük bir tətbiq seriyasının yalnız bir hissəsidir. Digər tətbiqləri buradan əldə edə bilərsiniz http://www.simplemobiletools.com
+ Bu, böyük bir tətbiq seriyasının yalnız bir hissəsidir. Digər tətbiqləri buradan əldə edə bilərsiniz https://www.simplemobiletools.com
Addegouezh
@@ -130,7 +131,7 @@
Ouzhpennañ devezhioù gouel
Devezhioù gouel broadel
Devezhioù gouel relijiel
- An devezhioù gouel a zo bet enporzhiet en un doare darvoud nevez gant berzh
+ Holidays have been successfully imported into the \"Holidays\" event type
C\'hwitadenn en ur enporzhiañ ul lodenn eus an darvoudoù
C\'hwitadenn en ur enporzhiañ ul lodenn eus an devezhioù gouel
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
Ret eo reiñ an aotre Darempredoù evit enporzhiañ deizioù-ha-bloaz an darempredoù.
- An arload-mañ a zo ul lodenn eus un heuliad arloadoù brasoc\'h. Gallout a rit o kavout anezho war http://www.simplemobiletools.com
+ An arload-mañ a zo ul lodenn eus un heuliad arloadoù brasoc\'h. Gallout a rit o kavout anezho war https://www.simplemobiletools.com
Opakovaná událost
@@ -130,7 +131,7 @@
Přidat svátek
Státní svátky
Církevní svátky
- Svátky byly úspěšně importovány do nového typu události
+ Holidays have been successfully imported into the \"Holidays\" event type
Import některých událostí se nezdařil
Import svátků nezdařil
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- Tato aplikace je součástí větší sady aplikací. Tyto a další aplikace najdete na http://www.simplemobiletools.com
+ Tato aplikace je součástí větší sady aplikací. Tyto a další aplikace najdete na https://www.simplemobiletools.com
Gentagelse
@@ -130,7 +131,7 @@
Tilføj helligdage
Nationale helligdage
Religiøse helligdage
- Helligdage er importeret til en ny begivenhedstype
+ Helligdage er importeret til typen \"Helligdage\"
Nogle helligdages blev ikke importeret
Import af helligdage mislykkedes
@@ -150,6 +151,7 @@
Erstat beskrivelse med sted
Slet alle begivenheder
Er du sikker på at du vil slette alle begivenheder? Dine begivenhedstyper og andre indstillinger vil forblive intakte.
+ Vis i tern
CalDAV
@@ -205,7 +207,7 @@
Adgang til kontaktpersoner er nødvendig hvis du vil importere fødselsdage.
- Denne app er en enkelt del af en større serie apps. Du kan finde dem alle på siden http://www.simplemobiletools.com
+ Denne app er en enkelt del af en større serie apps. Du kan finde dem alle på siden https://www.simplemobiletools.com
Wiederholung
@@ -89,7 +90,6 @@
Erinnerung
- Morgen
vorher
Füge eine weitere Erinnerung hinzu
Ereignis Erinnerungen
@@ -131,7 +131,7 @@
Feiertage hinzufügen
Nationale Feiertage
Religiöse Feiertage
- Feiertage wurden erfolgreich in einen neuen Termintypen importiert
+ Feiertage sind erfolgreich in den \"Feiertage\"-Termintyp importiert worden
Importieren einiger Termine fehlgeschlagen
Importieren von Feiertagen fehlgeschlagen
@@ -151,6 +151,7 @@
Ersetze Terminbeschreibung mit Ort
Alle Termine löschen
Bist du sicher, dass du alle Termine löschen willst? Deine Termintypen und Einstellungen bleiben erhalten.
+ Show a grid
CalDAV
@@ -207,7 +208,7 @@
Die Kontakte-Berechtigung wird nur für das Importieren von Geburtstagen benötigt.
- Diese App ist nur eine aus einer größeren Serie von schlichten Apps. Der Rest davon findet sich auf http://www.simplemobiletools.com
+ Diese App ist nur eine aus einer größeren Serie von schlichten Apps. Der Rest davon findet sich auf https://www.simplemobiletools.com
Repetición
@@ -130,7 +131,7 @@
Añadir festivos
Fiestas nacionales
Fiestas regionales
- Los días festivos se han importado correctamente a un nuevo tipo de evento
+ Holidays have been successfully imported into the \"Holidays\" event type
Ha habido un fallo al importar eventos
Ha habido un fallo al importar días festivos
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
El permiso de contactos se usa sólo para importar los cumpleaños de los contactos.
- Esta aplicación es sólo una parte de una mayor serie de aplicaciones. Puede encontrar el resto en http://www.simplemobiletools.com
+ Esta aplicación es sólo una parte de una mayor serie de aplicaciones. Puede encontrar el resto en https://www.simplemobiletools.com
Répétition
@@ -130,7 +131,7 @@
Ajouter des jours fériés
Jours fériés nationaux
Jours fériés religieux
- Les jours fériés ont été importés dans un nouveau type d\'événement avec succès
+ Holidays have been successfully imported into the \"Holidays\" event type
L\'import de certains événements a échoué
L\'import des jours fériés a échoué
@@ -150,6 +151,7 @@
Remplacer la description de l\'événement par l\'emplacement
Supprimer tous les événements
Êtes-vous sûr de vouloir supprimer tous les événements ? Cela laissera vos types d\'événements et autres paramètres intacts.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
La permission Contacts ne sert qu\'à importer l\'anniversaire de vos contacts.
- Cette application est juste une pièce d\'une plus grosse série d\'applications. Vous pouvez trouver le reste de celles-ci à http://www.simplemobiletools.com
+ Cette application est juste une pièce d\'une plus grosse série d\'applications. Vous pouvez trouver le reste de celles-ci à https://www.simplemobiletools.com
Repetición
@@ -130,7 +131,7 @@
Engadir días festivos
Festivo nacional
Festas relixiosas
- Engadíronse correctamente os días festivos nun novo tipo de evento
+ Holidays have been successfully imported into the \"Holidays\" event type
Fallou a importación de algúns eventos
Fallou a importación de días festivos
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
O permiso aos Contactos só é preciso se quere importar os cumpleanos dos contactos.
- Esta aplicación é parte de unha serie máis grande de aplicativos. Puede atopar o resto en http://www.simplemobiletools.com
+ Esta aplicación é parte de unha serie máis grande de aplicativos. Puede atopar o resto en https://www.simplemobiletools.com
दुहराव
@@ -131,7 +132,7 @@
Add holidays
National holidays
Religious holidays
- Holidays have been successfully imported into a new event type
+ Holidays have been successfully imported into the \"Holidays\" event type
Importing some events failed
Importing holidays failed
@@ -151,6 +152,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -206,7 +208,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
+ This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
+ Mjesečni raspored
+ Popis događaja kalendara
+
+
+ Događaj
+ Uredi događaj
+ Novi događaj
+ Naslov ne može biti prazan
+ Događaj ne može završiti prije nego što počne
+ Događaj je uspješno dodan
+ Događaj je uspješno ažuriran
+ Sortiranje prema vrsti događaja
+ Ispunite lokaciju za prikazivanje na karti
+ An event is upcoming
+
+
+ Ponavljanje
+ Nema ponavljanja
+ Dnevno
+ Tjedno
+ Mjesečno
+ Godišnje
+ tjedana
+ mjeseci
+ godina
+ Ponovi do
+ Zauvijek
+ Događaj je ponovljiv
+ Odabir sadrži ponavljajuće događaje
+ Izbriši samo odabrano ponavljanje
+ Izbriši sva ponavljanja
+ Ažuriraj samo odabrano ponavljanje
+ Ažuriraj sva ponavljanja
+ Ponovi do datuma
+ Ponovi x puta
+ Ponovi zauvijek
+ puta
+ Ponavljanje
+ Ponovi na
+ Svaki dan
+ Na odabrane dane
+ Isti dan
+ Zadnji dan
+ Ponovi isti dan svaki mjesec
+ Ponovi zadnjeg dana u mjesecu
+ Ponovi svaki
+ Svaki
+ prvi
+ drugi
+ treći
+ četvrti
+ peti
+
+
+
+ Ponovi svaki
+ Svaki
+ prvi
+ drugi
+ treći
+ četvrti
+ peti
+
+
+ Rođendani
+ Dodaj rođendane za kontakt
+ Nisu pronađeni rođendani
+ Rođendani su uspješno dodani
+
+
+ Obljetnice
+ Dodaj obljetnice za kontakt
+ Nisu pronađene obljetnice
+ Obljetnice uspješno dodane
+
+
+ Podsjetnik
+ prije
+ Dodaj još jedan podsjetnik
+ Podsjetnici na događaj
+
+
+ Uvezi događaje
+ Izvezi događaje
+ Uvoz događaja iz .ics datoteke
+ Izvoz događaja u .ics datoteku
+ Zadani tip događaja
+ Izvoz prošlih događaja
+ Uključi vrste događaja
+ Naziv datoteke (bez .ics)
+
+
+ Naslov
+ Lokacija
+ Opis
+ Cjelodnevni
+
+
+ Tjedan
+
+
+ Vrste događaja
+ Dodaj novu vrstu
+ Uredi vrstu
+ Događaj s ovim naslovom već postoji
+ Boja
+ Redoviti događaj
+ Zadana vrsta događaja se ne može izbrisati
+ Odaberite vrstu događaja
+ Premjesti zahvaćene događaje u zadanu vrstu događaja
+ Trajno ukloni zahvaćene događaje
+ Da biste uklonili CalDAV kalendar, morate ga desinkronizirati
+
+
+ Praznici
+ Dodaj praznik
+ Nacionalni praznici
+ Vjerski praznici
+ Praznici su uspješno uvezeni u tip događaja \"Praznici\"
+ Uvoz nekih događaja nije uspio
+ Uvoz praznika nije uspio
+
+
+ Upravljanje vrstama događaja
+ Započni dan u
+ Završi dan u
+ Pokaži tjedne brojeve
+ Vibrirajte na obavijesti podsjetnika
+ Zvuk podsjetnika
+ Nije pronađena nijedna aplikacija koja može postaviti zvuk zvona
+ Nijedan
+ Dan ne može završiti prije nego što počne
+ CalDAV sinkronizacija
+ Popis događaja
+ Prikaži događaje iz prošlosti
+ Zamijenite opis događaja s lokacijom
+ Izbriši sve događaje
+ Jeste li sigurni da želite izbrisati sve događaje? To će ostaviti Vaše vrste događaja i druge postavke netaknutima.
+ Show a grid
+
+
+ CalDAV
+ Odaberi kalendare za sinkronizaciju
+ Upravljanje sinkroniziranim kalendarima
+ Pohrani samo lokalno
+ Osvježi CalDAV kalendare
+ Osvježavanje...
+ Osvježavanje završeno
+ Uređivanje kalendara nije uspjelo
+ Sinkronizacija...
+ Sinkronizacija završena
+
+
+
+ Ponedjeljak
+ Utorak
+ Srijeda
+ Četvrtak
+ Petak
+ Subota
+ Nedjelja
+
+
+ Trening
+ Vježbanje nogu
+ Sastanak s Ivanom
+ U vrtu Rockstone
+ Knjižnica
+ Ručak s Marijom
+ U Plaza
+ Vrijeme za kavu
+
+
+ Kako mogu ukloniti praznike uvezene putem gumba \"Dodaj praznik\"?
+ Praznik koji je stvoren na taj način umetnut je u novu vrstu događaja pod nazivom \"Praznici\". Možete otići u Postavke -> Upravljanje vrstama događaja,
+ dugo pritisnite datu vrstu događaja i izbrišite ga odabirom koša za smeće.
+ Mogu li sinkronizirati događaje putem Google Kalendara ili druge usluge koje podržavaju CalDAV?
+ Da, samo uključite \"CalDAV sinkronizacija\" u postavkama aplikacije i odaberite kalendare koje želite sinkronizirati. Međutim, potrebna je aplikacija između Vašeg uređaja i poslužitelja.
+ U slučaju da želite sinkronizirati Google kalendar, njihova službena aplikacija Kalendar obavlja navedeni posao. Za ostale kalendare potreban Vam je aplikacija treće strane za upravljanje sinkronizacijom, na primjer DAVdroid.
+
+
+
+ Jednostavan kalendar s događajima, prilagodljivim widget i bez oglasa.
+
+ Jednostavan kalendar s dodatnom CalDAV sinkronizacijom. Možete jednostavno stvoriti ponavljajuće događaje i postaviti podsjetnike, također je moguće prikazati tjedne brojeve.
+
+ Sadrži mjesečni prikaz i widget s popisom događaja gdje možete prilagoditi boju teksta, kao i transparentnost te boju pozadine.
+
+ Ne sadrži oglase ili nepotrebne dozvole. Aplikacije je otvorenog koda, pruža prilagodljive boje.
+
+ Dopuštenje za pohranu podataka potrebna je samo za izvoz ili uvoz događaja iz .ics datoteka.
+
+ Dopuštenje za kontakte upotrebljava se samo pri uvozu rođendana i obljetnica kontakata.
+
+ Ova je aplikacija samo dio većeg broja aplikacija. Možete pronaći ostatak na https://www.simplemobiletools.com
+
+
+
+
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 9d64ddb5e..f85131d4d 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -26,6 +26,7 @@
Bejegyzés frissítve
Filter events by type
Please fill in a location to be shown on a map
+ An event is upcoming
Ismétlés
@@ -130,7 +131,7 @@
Add holidays
National holidays
Religious holidays
- Holidays have been successfully imported into a new event type
+ Holidays have been successfully imported into the \"Holidays\" event type
Importing some events failed
Importing holidays failed
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- Ez az alkalmazás egy nagyobb alkalmazás-sorozat része. A továbbiak itt találhatók: http://www.simplemobiletools.com
+ Ez az alkalmazás egy nagyobb alkalmazás-sorozat része. A továbbiak itt találhatók: https://www.simplemobiletools.com
Calendario mensile
- Calendar event list
+ Lista eventi calendario
Evento
@@ -26,6 +26,7 @@
Evento aggiornato correttamente
Filtra eventi per tipologia
Please fill in a location to be shown on a map
+ An event is upcoming
Ripeti
@@ -33,7 +34,7 @@
Giornalmente
Settimanalmente
Mensilmente
- Annulamente
+ Annualmente
Settimane
Mesi
Anni
@@ -45,10 +46,10 @@
Elimina tutte le occorrenze
Aggiorna solamente l\'occorenza selezionata
Aggiorna tutte le occorenze
- Repeat till a date
+ Ripeti fino a una data
Ripeti x volte
Ripeti per sempre
- times
+ volte
Ripeti
Repeat on
Ogni giorno
@@ -76,80 +77,81 @@
last
- Birthdays
- Add contact birthdays
- No birthdays have been found
- Birthdays added successfully
+ Compleanni
+ Aggiungi compleanni contatti
+ Nessun compleanno trovato
+ Compleanni aggiunti con successo
- Anniversaries
- Add contact anniversaries
- No anniversaries have been found
- Anniversaries added successfully
+ Anniversari
+ Aggiungi anniversari contatti
+ Nessun anniversario trovato
+ Anniversari aggiunti con successo
Promemoria
- before
- Add another reminder
- Event reminders
+ prima
+ Aggiungi un altro promemoria
+ Promemoria eventi
- Import events
- Export events
- Import events from an .ics file
- Export events to an .ics file
- Default event type
- Export past events too
- Include event types
- Filename (without .ics)
+ Importa eventi
+ Esporta eventi
+ Importa eventi da un file .ics
+ Esporta eventi in un file .ics
+ Tipo evento predefinito
+ Esporta anche eventi passati
+ Includi tipi evento
+ Nome file (senza .ics)
Titolo
- Location
+ Posizione
Descrizione
All-day
- Week
+ Settimana
- Event types
- Add a new type
- Edit type
- Type with this title already exists
- Color
- Regular event
- Default event type cannot be deleted
- Select an event type
+ Tipi evento
+ Aggiungi nuovo tipo
+ Modifica tipo
+ Un tipo con questo titolo esiste già
+ Colore
+ Evento regolare
+ Il tipo di evento predefinito non può essere cancellato
+ Seleziona un tipo di evento
Move affected events into the default event type
Permanently remove affected events
- To remove a CalDAV calendar you have to unsynchronize it
+ Per rimuovere un calendario CalDAV devi desincronizzarlo
- Holidays
- Add holidays
- National holidays
- Religious holidays
- Holidays have been successfully imported into a new event type
- Importing some events failed
- Importing holidays failed
+ Feste
+ Aggiungi feste
+ Feste nazionali
+ Feste religiose
+ Le feste sono state importate nel tipo evento \"Feste\" con successo
+ Importo di alcuni eventi fallito
+ Importo delle feste fallito
- Manage event types
+ Gestisci tipi evento
Start day at
End day at
- Show week numbers
+ Mostra numero settimane
Vibrate on reminder notification
- Reminder sound
+ Suoneria promemoria
No app capable of setting ringtone found
None
- The day cannot end earlier than it starts
+ Il giorno non può finire prima che cominci
CalDAV sync
Event lists
- Display events from the past
- Replace event description with location
- Delete all events
- Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Mostra eventi passati
+ Sostituisci la descrizione con la posizione
+ Cancella tutti gli eventi
+ Vuoi cancellare tutti gli eventi? Questo lascerà i tuoi tipi evento e le altre impostazioni invariate.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
+ This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
Repetition
@@ -131,7 +132,7 @@
Add holidays
National holidays
Religious holidays
- Holidays have been successfully imported into a new event type
+ Holidays have been successfully imported into the \"Holidays\" event type
Importing some events failed
Importing holidays failed
@@ -151,6 +152,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -195,7 +197,7 @@
לוח שנה פשוט עם אירועים, וויג\'ט בעיצוב אישי וללא פרסומות
- לוח שנה אוף-ליין ללא כל אינטגרציה עם לוח שנה אחר. אפשר בקלות ליצור אירועים מחזוריים ותזכורות אליהם. יש אפשרות להציג את מספרי השבועות. מכיל וויג\'ט 4×4 שניתן להתאים אישית את גודלו, צבע הטקסט והרקע שלו, ושקיפותו. אין פרסומות או דרישות להרשאות בלתי-נחוצות. קוד המקור לגמרי פתוח, וניתן לעצב את צבעי הממשק.\nאפליקציה זו היא רק פיסה אחת מתוך סדרה גדולה יותר של אפליקציות. ניתן למצוא את השאר בכתובת http://www.simplemobiletools.com
+ לוח שנה אוף-ליין ללא כל אינטגרציה עם לוח שנה אחר. אפשר בקלות ליצור אירועים מחזוריים ותזכורות אליהם. יש אפשרות להציג את מספרי השבועות. מכיל וויג\'ט 4×4 שניתן להתאים אישית את גודלו, צבע הטקסט והרקע שלו, ושקיפותו. אין פרסומות או דרישות להרשאות בלתי-נחוצות. קוד המקור לגמרי פתוח, וניתן לעצב את צבעי הממשק.\nאפליקציה זו היא רק פיסה אחת מתוך סדרה גדולה יותר של אפליקציות. ניתן למצוא את השאר בכתובת https://www.simplemobiletools.com
繰り返し
@@ -130,7 +131,7 @@
Add holidays
National holidays
Religious holidays
- Holidays have been successfully imported into a new event type
+ Holidays have been successfully imported into the \"Holidays\" event type
Importing some events failed
Importing holidays failed
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- このアプリは、大きな一連のアプリの一つです。 他のアプリは http://www.simplemobiletools.com で見つけることができます
+ このアプリは、大きな一連のアプリの一つです。 他のアプリは https://www.simplemobiletools.com で見つけることができます
반복
@@ -130,7 +131,7 @@
공휴일 추가
국경일
종교 휴일
- 공휴일을 새 이벤트 유형으로 가져왔습니다
+ Holidays have been successfully imported into the \"Holidays\" event type
일부 이벤트를 가져오지 못했습니다
공휴일을 가져오는데 실패했습니다
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- 이 앱은 더 큰 시리즈의 앱들 중 하나입니다. 나머지는 http://www.simplemobiletools.com 에서 찾을 수 있습니다.
+ 이 앱은 더 큰 시리즈의 앱들 중 하나입니다. 나머지는 https://www.simplemobiletools.com 에서 찾을 수 있습니다.
Pasikartojimas
@@ -130,7 +131,7 @@
Įtraukti atostogas
Nacionalinės atostogos
Religinės atostogos
- Atostogos sėkmingai importuotos į naujo įvykio tipą
+ Atostogos buvo sėkmingai importuotos į \"Atostogos\" įvykio tipą
Kai kurių įvykių importavimas nepavyko
Atostogų importavimas nepavyko
@@ -150,6 +151,7 @@
Pakeisti įvykio apibūdinimą į įvykio vietą
Ištrinti visus įvykius
Ar Jūs tikrai norite ištrinti visus įvykius? Tai neištrins įvykių tipų ir kitų nustatymų.
+ Show a grid
CalDAV
@@ -203,9 +205,9 @@
Saugyklos leidimas reikalingas tik eksportuoti ir importuoti įvykius iš .ics bylų.
- Contaktų leidimas naudojamas tik importuoti kontaktų gimtadienius ir sukaktis.
+ Kontaktų leidimas naudojamas tik importuoti kontaktų gimtadienius ir sukaktis.
- Ši programėle yra vienintelė iš keletos mūsų programėlių. Likusias Jūs galite rasti čia http://www.simplemobiletools.com
+ Ši programėle yra viena iš keletos mūsų programėlių. Likusias Jūs galite rasti čia https://www.simplemobiletools.com
Gjentagelse
@@ -130,7 +131,7 @@
Legg til off. fridager
Nasjonale off. fridager
Religiøse off. fridager
- Off. fridager er vellykket importert til en ny hendelsestype
+ Off. fridager er vellykket importert til hendelsestypen \"Off. fridager\"
Importering av noen hendelser feilet
Importering av off. fridager feilet
@@ -150,6 +151,7 @@
Erstatt hendelsesbeskrivelse med sted
Slett alle hendelser
Er du sikker på at du vil slette alle hendelser? Dine hendelsestyper og andre innstillinger blir beholdt.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
+ This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
Herhaling
@@ -130,7 +131,7 @@
Feestdagen toevoegen
Nationale feestdagen
Religieuze feestdagen
- Feestdagen geïmporteerd als nieuw afspraaktype
+ De feestdagen zijn geïmporteerd onder afspraaktype \"Feestdagen\"
Sommige feestdagen konden niet worden geïmporteerd
Fout bij importeren van feestdagen
@@ -150,6 +151,7 @@
Beschrijving vervangen door locatie van afspraken
Alle afspraken verwijderen
Alle afspraken verwijderen? Afspraaktypes en andere instellingen blijven behouden.
+ Rasterlijnen tonen
CalDAV
@@ -205,7 +207,7 @@
De machtiging voor contacten wordt alleen gebruikt voor het importeren van verjaardagen en feestdagen.
- Deze app is onderdeel van een grotere verzameling. Vind de andere apps op http://www.simplemobiletools.com
+ Deze app is onderdeel van een grotere verzameling. Vind de andere apps op https://www.simplemobiletools.com
Gjentagelse
@@ -130,7 +131,7 @@
Legg til off. fridager
Nasjonale off. fridager
Religiøse off. fridager
- Off. fridager er vellykket importert til en ny hendelsestype
+ Holidays have been successfully imported into the \"Holidays\" event type
Importering av noen hendelser feilet
Importering av off. fridager feilet
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
+ This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
Powtórzenie
@@ -130,7 +131,7 @@
Dodaj święto
Święta państwowe
Święta religijne
- Święta zostały pomyślnie zaimportowane do nowego typu wydarzeń
+ Holidays have been successfully imported into the \"Holidays\" event type
Importowanie niektórych świąt nie powiodło się
Importowanie świąt nie powiodło się
@@ -150,6 +151,7 @@
Zamieniaj opis wydarzenia na lokalizację
Usuń wszystkie wydarzenia
Czy na pewno mam usunąć wszystkie wydarzenia? Nie naruszy to typów wydarzeń i innych ustawień.
+ Show a grid
CalDAV
@@ -203,7 +205,7 @@
Uprawnienia kontaktów są używane tylko do importowania urodzin.
- Niniejsza aplikacja jest tylko częścią naszej kolekcji prostych narzędzi. Ta, jak i pozostałe, dostępne są na stronie http://www.simplemobiletools.com
+ Niniejsza aplikacja jest tylko częścią naszej kolekcji prostych narzędzi. Ta, jak i pozostałe, dostępne są na stronie https://www.simplemobiletools.com
Repetição
@@ -130,7 +131,7 @@
Add holidays
National holidays
Religious holidays
- Holidays have been successfully imported into a new event type
+ Holidays have been successfully imported into the \"Holidays\" event type
Importing some events failed
Importing holidays failed
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- Este aplicativo é apenas parte de um conjunto mais vasto de aplicações. Saiba mais em http://www.simplemobiletools.com
+ Este aplicativo é apenas parte de um conjunto mais vasto de aplicações. Saiba mais em https://www.simplemobiletools.com
Repetição
@@ -130,7 +131,7 @@
Adicionar feriados
Feriados nacionais
Feriados religiosos
- Os feriados foram importados para um novo tipo de evento
+ Os feriados foram adicionados com sucesso para o tipo de evento \"Feriados\"
Alguns eventos não foram importados
Falha ao importar os feriados
@@ -150,6 +151,7 @@
Substituir descrição pela localização do evento
Apagar todos os eventos
Tem a certeza de que deseja apagar todos os eventos? Esta ação não afeta os tipos de eventos nem as outras definições.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
A permissão aos contactos apenas é utilizada para importar os aniversários.
- Esta aplicação é apenas parte de um conjunto mais vasto de aplicações. Saiba mais em http://www.simplemobiletools.com
+ Esta aplicação é apenas parte de um conjunto mais vasto de aplicações. Saiba mais em https://www.simplemobiletools.com
Повторять
@@ -130,7 +131,7 @@
Добавить праздники
Национальные праздники
Религиозные праздники
- Праздники были успешно импортированы в новый тип событий
+ Holidays have been successfully imported into the \"Holidays\" event type
Не удалось импортировать некоторые события
Не удалось импортировать праздники
@@ -150,6 +151,7 @@
Заменить описание события местоположением
Удалить все события
Вы действительно хотите удалить все события? Это не затронет ваши типы событий и другие настройки.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
Разрешение на чтение контактов требуется только при импорте дней рождения.
- Это приложение является лишь частью крупной серии приложений. Вы можете найти остальные на http://www.simplemobiletools.com
+ Это приложение является лишь частью крупной серии приложений. Вы можете найти остальные на https://www.simplemobiletools.com
Opakovanie
@@ -121,9 +122,6 @@
Bežná udalosť
Predvolený typ nie je možné vymazať
Zvoľte typ udalosti
- Sviatky boli úspešne importované do nového typu udalostí
- Importovanie niektorých sviatkov zlyhalo
- Importovanie udalostí zlyhalo
Presunúť dotknuté udalosti do predvoleného typu udalostí
Natrvalo odstrániť dotknuté udalosti
Na odstránenie CalDAV kalendára musíte vypnúť jeho synchronizáciu
@@ -133,6 +131,9 @@
Pridať sviatky
Štátne sviatky
Náboženské sviatky
+ Sviatky boli úspešne importované do nového typu udalostí \"Sviatky\"
+ Importovanie niektorých sviatkov zlyhalo
+ Importovanie udalostí zlyhalo
Spravovať typy udalostí
@@ -150,6 +151,7 @@
Nahradiť popis udalosti miestom
Odstrániť všetky udalosti
Ste si istý, že chcete odstrániť všetky udalosti? Všetky typy udalostí a nastavenia ostanú nedotknuté.
+ Zobraziť mriežku
CalDAV
@@ -205,7 +207,7 @@
Oprávnenie ku kontaktom je používané iba pri pridávaní narodenín alebo výročí kontaktov.
- Táto aplikácia je iba jednou zo skupiny aplikácií. Ostatné viete nájsť na http://www.simplemobiletools.com
+ Táto aplikácia je iba jednou zo skupiny aplikácií. Ostatné viete nájsť na https://www.simplemobiletools.com
Upprepning
@@ -130,7 +131,7 @@
Lägg till helgdagar
Nationella helgdagar
Religiösa helgdagar
- Helgdagar har importerats till en ny händelsetyp
+ Holidays have been successfully imported into the \"Holidays\" event type
Vissa händelser kunde inte importeras
Helgdagar kunde inte importeras
@@ -150,6 +151,7 @@
Ersätt händelsebeskrivning med plats
Ta bort alla händelser
Är du säker på att du vill ta bort alla händelser? Dina händelsetyper och andra inställningar påverkas inte av borttagningen.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
Kontaktbehörigheten används bara för att importera kontakters födelsedagar och årsdagar.
- Denna app är bara en del av en större serie appar. Du hittar resten av dem på http://www.simplemobiletools.com
+ Denna app är bara en del av en större serie appar. Du hittar resten av dem på https://www.simplemobiletools.com
Tekrarla
@@ -130,7 +131,7 @@
Tatil ekle
National holidays
Religious holidays
- Holidays have been successfully imported into a new event type
+ Holidays have been successfully imported into the \"Holidays\" event type
Importing some events failed
Importing holidays failed
@@ -150,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- Bu uygulama, daha büyük bir uygulama serisinden sadece bir parça. Geri kalanını şu adresten bulabilirsiniz: http://www.simplemobiletools.com
+ Bu uygulama, daha büyük bir uygulama serisinden sadece bir parça. Geri kalanını şu adresten bulabilirsiniz: https://www.simplemobiletools.com
重複
@@ -130,7 +131,7 @@
添加節日
國定節日
宗教節日
- 節日成功匯入新活動類型
+ 節日已成功匯入"節日"活動類型
匯入一些活動失敗
匯入節日失敗
@@ -150,6 +151,7 @@
活動描述改成地點
刪除全部活動
你確定要刪除全部活動嗎?會完整留下你的活動類型和其他設定。
+ Show a grid
CalDAV
@@ -205,7 +207,7 @@
聯絡人權限只是用來匯入聯絡人生日和紀念日。
- 這程式只是一系列眾多應用程式的其中一項,你可以在這發現更多 http://www.simplemobiletools.com
+ 這程式只是一系列眾多應用程式的其中一項,你可以在這發現更多 https://www.simplemobiletools.com
+ Reworked custom notification sound picking, should be more reliable
Added a Location field\n
Allow adding Contact birthdays
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6b8e8cd71..ef70f77ce 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -26,6 +26,7 @@
Event updated successfully
Filter events by type
Please fill in a location to be shown on a map
+ An event is upcoming
Repetition
@@ -89,7 +90,6 @@
Reminder
- Tomorrow
before
Add another reminder
Event reminders
@@ -131,7 +131,7 @@
Add holidays
National holidays
Religious holidays
- Holidays have been successfully imported into a new event type
+ Holidays have been successfully imported into the \"Holidays\" event type
Importing some events failed
Importing holidays failed
@@ -151,6 +151,7 @@
Replace event description with location
Delete all events
Are you sure you want to delete all events? This will leave your event types and other settings intact.
+ Show a grid
CalDAV
@@ -206,7 +207,7 @@
The Contacts permission is used only at importing contact birthdays and anniversaries.
- This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
+ This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com