remove Google Sync as a standalone feature

This commit is contained in:
tibbi 2017-08-12 22:13:57 +02:00
parent 257144241a
commit 214a95eb5d
38 changed files with 10 additions and 985 deletions

View File

@ -42,20 +42,7 @@ dependencies {
compile 'com.facebook.stetho:stetho:1.4.1'
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2'
compile 'com.android.support:multidex:1.0.1'
compile 'com.google.code.gson:gson:2.8.0'
compile('com.google.http-client:google-http-client-gson:1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
compile 'com.google.android.gms:play-services-auth:10.0.1'
compile('com.google.api-client:google-api-client-android:1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
compile('com.google.apis:google-api-services-calendar:v3-rev249-1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

View File

@ -7,12 +7,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<application
android:name=".App"
@ -138,8 +134,6 @@
</intent-filter>
</receiver>
<receiver android:name=".receivers.GoogleSyncReceiver"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.simplemobiletools.calendar.fileprovider"

View File

@ -473,7 +473,6 @@ class EventActivity : SimpleActivity(), DBHelper.EventUpdateListener {
toast(R.string.event_added)
}
GoogleSyncHandler().tryInsertToGoogle(this, mEvent)
finish()
}
} else {
@ -502,7 +501,6 @@ class EventActivity : SimpleActivity(), DBHelper.EventUpdateListener {
}
private fun eventUpdated() {
GoogleSyncHandler().tryUpdateGoogleEvent(this, mEvent)
toast(R.string.event_updated)
finish()
}

View File

@ -18,7 +18,6 @@ import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.adapters.MyMonthPagerAdapter
import com.simplemobiletools.calendar.adapters.MyWeekPagerAdapter
import com.simplemobiletools.calendar.adapters.MyYearPagerAdapter
import com.simplemobiletools.calendar.asynctasks.FetchGoogleEventsTask
import com.simplemobiletools.calendar.dialogs.ExportEventsDialog
import com.simplemobiletools.calendar.dialogs.FilterEventTypesDialog
import com.simplemobiletools.calendar.dialogs.ImportEventsDialog
@ -27,7 +26,6 @@ import com.simplemobiletools.calendar.fragments.EventListFragment
import com.simplemobiletools.calendar.fragments.WeekFragment
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.interfaces.GoogleSyncListener
import com.simplemobiletools.calendar.interfaces.NavigationListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.models.EventType
@ -86,18 +84,9 @@ class MainActivity : SimpleActivity(), NavigationListener {
storeStateVariables()
updateViewPager()
if (!hasGetAccountsPermission()) {
config.googleSync = false
}
if (!hasCalendarPermission()) {
config.caldavSync = false
}
if (isGoogleSyncActive()) {
FetchGoogleEventsTask(applicationContext, googleSyncListener).execute()
}
scheduleGoogleSync(isGoogleSyncActive())
}
override fun onResume() {
@ -538,12 +527,6 @@ class MainActivity : SimpleActivity(), NavigationListener {
supportFragmentManager.beginTransaction().replace(R.id.calendar_event_list_holder, EventListFragment(), "").commit()
}
val googleSyncListener = object : GoogleSyncListener {
override fun syncCompleted() {
refreshViewPager()
}
}
override fun goLeft() {
main_view_pager.currentItem = main_view_pager.currentItem - 1
}

View File

@ -1,33 +1,21 @@
package com.simplemobiletools.calendar.activities
import android.Manifest
import android.accounts.AccountManager
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Resources
import android.graphics.Color
import android.media.RingtoneManager
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.support.v4.app.ActivityCompat
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException
import com.google.api.client.util.ExponentialBackOff
import com.google.api.services.calendar.CalendarScopes
import com.google.api.services.calendar.model.CalendarListEntry
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.asynctasks.FetchGoogleEventsTask
import com.simplemobiletools.calendar.dialogs.CustomEventReminderDialog
import com.simplemobiletools.calendar.dialogs.SnoozePickerDialog
import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.interfaces.GoogleSyncListener
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.calendar.helpers.FONT_SIZE_LARGE
import com.simplemobiletools.calendar.helpers.FONT_SIZE_MEDIUM
import com.simplemobiletools.calendar.helpers.FONT_SIZE_SMALL
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.updateTextColors
@ -36,9 +24,6 @@ import kotlinx.android.synthetic.main.activity_settings.*
class SettingsActivity : SimpleActivity() {
private val GET_RINGTONE_URI = 1
private val ACCOUNTS_PERMISSION = 2
private val REQUEST_ACCOUNT_NAME = 3
private val REQUEST_GOOGLE_PLAY_SERVICES = 4
private val CALENDAR_PERMISSION = 5
lateinit var res: Resources
@ -52,7 +37,6 @@ class SettingsActivity : SimpleActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
res = resources
setupGoogleSync()
setupCaldavSync()
}
@ -113,26 +97,6 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupGoogleSync() {
settings_google_sync.isChecked = isGoogleSyncActive()
settings_google_sync_holder.setOnClickListener {
if (config.googleSync) {
ConfirmationDialog(this, getString(R.string.google_sync_disabling), positive = R.string.ok, negative = R.string.cancel) {
dbHelper.deleteAllGoogleSyncEvents()
toggleGoogleSync()
}
} else {
if (isOnline()) {
ConfirmationDialog(this, getString(R.string.google_sync_testing), positive = R.string.ok, negative = 0) {
toggleGoogleSync()
}
} else {
toast(R.string.cannot_while_offline)
}
}
}
}
private fun setupCaldavSync() {
settings_caldav_sync.isChecked = config.caldavSync
settings_caldav_sync_holder.setOnClickListener {
@ -153,16 +117,6 @@ class SettingsActivity : SimpleActivity() {
config.caldavSync = settings_caldav_sync.isChecked
}
private fun toggleGoogleSync() {
settings_google_sync.toggle()
if (settings_google_sync.isChecked) {
tryEnablingSync()
} else {
disableGoogleSync()
}
}
private fun setupSundayFirst() {
settings_sunday_first.isChecked = config.isSundayFirst
settings_sunday_first_holder.setOnClickListener {
@ -333,136 +287,17 @@ class SettingsActivity : SimpleActivity() {
settings_reminder_sound.text = RingtoneManager.getRingtone(this, uri as Uri)?.getTitle(this)
config.reminderSound = uri.toString()
}
} else if (requestCode == REQUEST_ACCOUNT_NAME && data?.extras != null) {
val accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
config.syncAccountName = accountName
tryEnablingSync()
} else if (requestCode == REQUEST_AUTHORIZATION) {
tryEnablingSync()
}
} else if (resultCode == Activity.RESULT_CANCELED) {
if (requestCode == REQUEST_ACCOUNT_NAME || requestCode == REQUEST_AUTHORIZATION) {
disableGoogleSync()
}
}
}
private fun tryEnablingSync() {
if (!isGooglePlayServicesAvailable()) {
acquireGooglePlayServices()
} else if (!hasGetAccountsPermission()) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.GET_ACCOUNTS), ACCOUNTS_PERMISSION)
} else if (config.syncAccountName.isEmpty()) {
showAccountChooser()
} else {
Thread({
fetchEventsIfHasPermissions()
}).start()
}
}
private fun isGooglePlayServicesAvailable(): Boolean {
val apiAvailability = GoogleApiAvailability.getInstance()
val connectionStatusCode = apiAvailability.isGooglePlayServicesAvailable(this)
return connectionStatusCode == ConnectionResult.SUCCESS
}
private fun acquireGooglePlayServices() {
val apiAvailability = GoogleApiAvailability.getInstance()
val connectionStatusCode = apiAvailability.isGooglePlayServicesAvailable(this)
if (apiAvailability.isUserResolvableError(connectionStatusCode)) {
GoogleApiAvailability.getInstance().getErrorDialog(this, connectionStatusCode, REQUEST_GOOGLE_PLAY_SERVICES).show()
}
}
private fun fetchEventsIfHasPermissions() {
try {
getGoogleSyncService().colors().get().execute() // just checking if we have the permission for fetching user data
storeCalendarData()
config.googleSync = true
FetchGoogleEventsTask(applicationContext, googleSyncListener).execute()
runOnUiThread {
settings_google_sync.isChecked = true
val eventsToExport = dbHelper.getEventsToExport(true)
if (eventsToExport.isNotEmpty()) {
offerEventsUpload(eventsToExport)
}
}
} catch (e: Exception) {
if (e is UserRecoverableAuthIOException) {
startActivityForResult(e.intent, REQUEST_AUTHORIZATION)
} else {
toast(R.string.unknown_error_occurred)
}
}
}
private fun disableGoogleSync() {
settings_google_sync.isChecked = false
config.googleSync = false
config.syncAccountName = ""
config.googleDefaultEventColor = config.primaryColor
}
private fun storeCalendarData() {
Thread({
val calendar = getGoogleSyncService().calendarList().get(PRIMARY).execute()
config.googleDefaultEventColor = Color.parseColor(calendar.backgroundColor)
storeDefaultReminders(calendar)
}).start()
}
private fun storeDefaultReminders(calendar: CalendarListEntry) {
val reminderMinutes = ArrayList<Int>()
val reminders = calendar.defaultReminders
reminders.forEach {
if (it.method == POPUP) {
reminderMinutes.add(it.minutes)
}
}
config.googleDefaultReminders = reminderMinutes.joinToString(",")
}
private val googleSyncListener = object : GoogleSyncListener {
override fun syncCompleted() {
toast(R.string.events_imported_successfully)
}
}
private fun offerEventsUpload(eventsToExport: ArrayList<Event>) {
ConfirmationDialog(this, messageId = R.string.google_sync_existing) {
Thread({
eventsToExport.forEach {
try {
GoogleSyncHandler().tryInsertToGoogle(this, it)
} catch (e: Exception) {
}
}
}).start()
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == ACCOUNTS_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showAccountChooser()
} else {
disableGoogleSync()
}
} else if (requestCode == CALENDAR_PERMISSION) {
if (requestCode == CALENDAR_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
toggleCaldavSync()
}
}
}
private fun showAccountChooser() {
if (config.syncAccountName.isEmpty()) {
// more about oauth at https://developers.google.com/google-apps/calendar/auth
val credential = GoogleAccountCredential.usingOAuth2(this, arrayListOf(CalendarScopes.CALENDAR)).setBackOff(ExponentialBackOff())
startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_NAME)
}
}
}

View File

@ -1,227 +0,0 @@
package com.simplemobiletools.calendar.asynctasks
import android.content.Context
import android.graphics.Color
import android.os.AsyncTask
import android.util.SparseIntArray
import android.widget.Toast
import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.reflect.TypeToken
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.interfaces.GoogleSyncListener
import com.simplemobiletools.calendar.models.*
import com.simplemobiletools.commons.extensions.isOnMainThread
import com.simplemobiletools.commons.extensions.toast
import org.joda.time.DateTime
import java.util.*
// more info about event fields at https://developers.google.com/google-apps/calendar/v3/reference/events/insert
class FetchGoogleEventsTask(val context: Context, val googleSyncListener: GoogleSyncListener? = null) : AsyncTask<Void, Void, String>() {
private val ITEMS = "items"
private val NEXT_PAGE_TOKEN = "nextPageToken"
private var dbHelper = context.dbHelper
private var eventTypes = ArrayList<EventType>()
private var eventColors = SparseIntArray()
private var service = context.getGoogleSyncService()
private var parseError: Exception? = null
private var noTitleText = context.getString(R.string.no_title)
override fun doInBackground(vararg params: Void): String {
if (!context.isGoogleSyncActive() || !context.isOnline())
return ""
// always handle queued operations before fetching new data
val queuedOperations = context.googleSyncQueue.getOperations()
queuedOperations.forEach {
when (it.operation) {
OPERATION_INSERT -> {
val event = dbHelper.getEventWithId(it.eventId)
if (event != null)
GoogleSyncHandler().insertToGoogle(context, event)
context.googleSyncQueue.clearOperationsOf(it.eventId)
}
OPERATION_UPDATE -> {
val event = dbHelper.getEventWithId(it.eventId)
if (event != null)
GoogleSyncHandler().updateGoogleEvent(context, event)
context.googleSyncQueue.clearOperationsOf(it.eventId)
}
OPERATION_DELETE -> {
GoogleSyncHandler().deleteFromGoogle(context, it.importId)
context.googleSyncQueue.clearOperationsOf(it.eventId)
}
}
}
try {
getColors()
getDataFromApi()
googleSyncListener?.syncCompleted()
} catch (e: Exception) {
parseError = e
}
return ""
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
if (context.isOnMainThread() && parseError != null && parseError is GoogleJsonResponseException) {
val msg = String.format(context.getString(R.string.google_sync_error_fetch), parseError!!.getGoogleMessageError())
context.toast(msg, Toast.LENGTH_LONG)
}
}
private fun getColors() {
val colors = service.colors().get().execute()
for ((id, color) in colors.event.entries) {
eventColors.put(id.toInt(), Color.parseColor(color.background))
}
}
private fun getDataFromApi() {
var currToken = ""
while (true) {
service.colors().get().execute()
val events = service.events().list(PRIMARY)
.setPageToken(currToken)
.execute()
for ((key, value) in events) {
if (key == ITEMS) {
eventTypes = dbHelper.fetchEventTypes()
val localGoogleEvents = dbHelper.getGoogleSyncEvents()
val remoteGoogleEvents = parseEvents(value.toString())
removeRedundantLocalEvents(localGoogleEvents, remoteGoogleEvents)
}
}
if (events.containsKey(NEXT_PAGE_TOKEN)) {
currToken = events[NEXT_PAGE_TOKEN] as String
} else {
break
}
}
}
private fun parseEvents(json: String): ArrayList<String> {
val remoteImportIds = ArrayList<String>()
var updateEvent = false
var eventId = 0
val importIDs = context.dbHelper.getImportIds()
val token = object : TypeToken<List<GoogleEvent>>() {}.type
val googleEvents = Gson().fromJson<ArrayList<GoogleEvent>>(json, token) ?: ArrayList<GoogleEvent>(8)
for (googleEvent in googleEvents) {
val importId = googleEvent.id
remoteImportIds.add(importId)
if (!googleEvent.status.equals(CONFIRMED, true))
continue
val lastUpdate = DateTime(googleEvent.updated).millis
if (importIDs.contains(importId)) {
val oldEvent = dbHelper.getEventWithImportId(importId)
if (oldEvent != null) {
if (oldEvent.lastUpdated >= lastUpdate) {
continue
} else {
updateEvent = true
eventId = oldEvent.id
}
}
}
val start = googleEvent.start
val end = googleEvent.end
var startTS: Int
var endTS: Int
var flags = 0
if (start.date != null) {
startTS = DateTime(start.date).withHourOfDay(1).seconds()
endTS = DateTime(end.date).withHourOfDay(1).seconds()
flags = flags or FLAG_ALL_DAY
} else {
startTS = DateTime(start.dateTime).seconds()
endTS = DateTime(end.dateTime).seconds()
}
val summary = googleEvent.summary ?: "($noTitleText)"
val description = googleEvent.description ?: ""
val reminders = getReminders(googleEvent.reminders)
val repeatRule = getRepeatRule(googleEvent, startTS)
val eventTypeId = getEventTypeId(googleEvent.colorId)
val event = Event(eventId, startTS, endTS, summary, description, reminders.getOrElse(0, { -1 }),
reminders.getOrElse(1, { -1 }), reminders.getOrElse(2, { -1 }), repeatRule.repeatInterval, importId, flags, repeatRule.repeatLimit,
repeatRule.repeatRule, eventTypeId, lastUpdated = lastUpdate, source = SOURCE_GOOGLE_SYNC)
if (event.getIsAllDay() && endTS > startTS) {
event.endTS -= DAY
}
if (updateEvent) {
dbHelper.update(event) {}
} else {
importIDs.add(importId)
dbHelper.insert(event) {}
}
}
return remoteImportIds
}
private fun removeRedundantLocalEvents(localGoogleEvents: List<Event>, remoteGoogleEvents: ArrayList<String>) {
val filtered = localGoogleEvents.filter { !remoteGoogleEvents.contains(it.importId) }
val filteredIds = Array(filtered.size, { i -> (filtered[i].id.toString()) })
dbHelper.deleteEvents(filteredIds, false)
}
private fun getEventTypeId(colorId: Int): Int {
var eventTypeId = -1
val eventType = "google_sync_$colorId"
eventTypes.forEach {
if (it.title.toLowerCase() == eventType)
eventTypeId = it.id
}
if (eventTypeId == -1) {
val newColor = if (eventColors[colorId] != 0) eventColors[colorId] else context.config.googleDefaultEventColor
val newEventType = EventType(0, eventType, newColor)
eventTypeId = dbHelper.insertEventType(newEventType)
eventTypes.add(newEventType)
}
return eventTypeId
}
private fun getRepeatRule(googleEvent: GoogleEvent, startTS: Int): RepeatRule {
val recurrence = googleEvent.recurrence?.firstOrNull()
return if (recurrence != null) {
Parser().parseRepeatInterval(recurrence.toString().trim('\"').substring(RRULE.length), startTS)
} else {
RepeatRule(0, 0, 0)
}
}
private fun getReminders(json: JsonObject?): List<Int> {
val reminderMinutes = ArrayList<Int>()
if (json?.has(OVERRIDES) == true) {
val array = json.getAsJsonArray(OVERRIDES)
val token = object : TypeToken<List<GoogleEventReminder>>() {}.type
val reminders = Gson().fromJson<ArrayList<GoogleEventReminder>>(array, token) ?: ArrayList<GoogleEventReminder>(2)
for ((method, minutes) in reminders) {
if (method == POPUP) {
reminderMinutes.add(minutes)
}
}
} else if (json?.has(USE_DEFAULT) == true) {
val minutes = context.config.googleDefaultReminders.splitToSequence(',')
minutes.forEach {
reminderMinutes.add(it.toInt())
}
}
return reminderMinutes
}
}

View File

@ -12,22 +12,15 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.net.ConnectivityManager
import android.net.Uri
import android.os.Build
import android.support.v4.content.ContextCompat
import android.support.v7.app.NotificationCompat
import com.google.api.client.extensions.android.http.AndroidHttp
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential
import com.google.api.client.json.gson.GsonFactory
import com.google.api.client.util.ExponentialBackOff
import com.google.api.services.calendar.CalendarScopes
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.receivers.GoogleSyncReceiver
import com.simplemobiletools.calendar.receivers.NotificationReceiver
import com.simplemobiletools.calendar.services.SnoozeService
import com.simplemobiletools.commons.extensions.getContrastColor
@ -237,41 +230,10 @@ fun Context.launchNewEventIntent(startNewTask: Boolean = false, today: Boolean =
}
}
fun Context.getGoogleSyncService(): com.google.api.services.calendar.Calendar {
val credential = GoogleAccountCredential.usingOAuth2(this, arrayListOf(CalendarScopes.CALENDAR)).setBackOff(ExponentialBackOff())
credential.selectedAccountName = config.syncAccountName
val transport = AndroidHttp.newCompatibleTransport()
return com.google.api.services.calendar.Calendar.Builder(transport, GsonFactory(), credential)
.setApplicationName(resources.getString(R.string.app_name))
.build()
}
fun Context.isOnline(): Boolean {
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return connectivityManager.activeNetworkInfo != null
}
fun Context.scheduleGoogleSync(activate: Boolean) {
val syncIntent = Intent(this, GoogleSyncReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, syncIntent, PendingIntent.FLAG_CANCEL_CURRENT)
val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager
if (activate) {
val syncCheckInterval = 4 * AlarmManager.INTERVAL_HOUR
alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + syncCheckInterval, syncCheckInterval, pendingIntent)
} else {
alarm.cancel(pendingIntent)
}
}
fun Context.getNewEventTimestampFromCode(dayCode: String) = Formatter.getLocalDateTimeFromCode(dayCode).withTime(13, 0, 0, 0).seconds()
fun Context.getCurrentOffset() = SimpleDateFormat("Z", Locale.getDefault()).format(Date())
fun Context.isGoogleSyncActive() = config.googleSync && config.syncAccountName.isNotEmpty()
val Context.config: Config get() = Config.newInstance(this)
val Context.dbHelper: DBHelper get() = DBHelper.newInstance(this)
val Context.googleSyncQueue: GoogleSyncQueueDB get() = GoogleSyncQueueDB.newInstance(this)

View File

@ -1,10 +0,0 @@
package com.simplemobiletools.calendar.extensions
import com.google.gson.Gson
import com.simplemobiletools.calendar.models.GoogleError
fun Exception.getGoogleMessageError(): String {
val json = message!!.substring(message!!.indexOf('{'))
val error = Gson().fromJson<GoogleError>(json, GoogleError::class.java)
return error.message
}

View File

@ -4,8 +4,6 @@ import android.content.Context
import android.media.RingtoneManager
import android.text.format.DateFormat
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.googleSyncQueue
import com.simplemobiletools.calendar.extensions.scheduleGoogleSync
import com.simplemobiletools.commons.helpers.BaseConfig
import java.util.*
@ -72,32 +70,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(FONT_SIZE, FONT_SIZE_MEDIUM)
set(size) = prefs.edit().putInt(FONT_SIZE, size).apply()
var googleSync: Boolean
get() = prefs.getBoolean(GOOGLE_SYNC, false)
set(googleSync) {
context.scheduleGoogleSync(googleSync)
if (!googleSync)
context.googleSyncQueue.clearQueue()
prefs.edit().putBoolean(GOOGLE_SYNC, googleSync).apply()
}
var caldavSync: Boolean
get() = prefs.getBoolean(CALDAV_SYNC, false)
set(caldavSync) = prefs.edit().putBoolean(CALDAV_SYNC, caldavSync).apply()
var syncAccountName: String
get() = prefs.getString(SYNC_ACCOUNT_NAME, "")
set(syncAccountName) = prefs.edit().putString(SYNC_ACCOUNT_NAME, syncAccountName).apply()
var googleDefaultEventColor: Int
get() = prefs.getInt(GOOGLE_DEFAULT_EVENT_COLOR, primaryColor)
set(color) = prefs.edit().putInt(GOOGLE_DEFAULT_EVENT_COLOR, color).apply()
var googleDefaultReminders: String
get() = prefs.getString(GOOGLE_DEFAULT_REMINDERS, "")
set(reminders) = prefs.edit().putString(GOOGLE_DEFAULT_REMINDERS, reminders).apply()
fun addDisplayEventType(type: String) {
addDisplayEventTypes(HashSet<String>(Arrays.asList(type)))
}

View File

@ -41,13 +41,10 @@ val VIEW = "view"
val REMINDER_MINUTES = "reminder_minutes"
val DISPLAY_EVENT_TYPES = "display_event_types"
val FONT_SIZE = "font_size"
val GOOGLE_SYNC = "google_sync"
val CALDAV_SYNC = "caldav_sync"
val SYNC_ACCOUNT_NAME = "sync_account_name"
val SNOOZE_DELAY = "snooze_delay"
val DISPLAY_PAST_EVENTS = "display_past_events"
val GOOGLE_DEFAULT_EVENT_COLOR = "google_default_event_color"
val GOOGLE_DEFAULT_REMINDERS = "google_default_reminders"
val letterIDs = intArrayOf(R.string.sunday_letter, R.string.monday_letter, R.string.tuesday_letter, R.string.wednesday_letter,
R.string.thursday_letter, R.string.friday_letter, R.string.saturday_letter)
@ -121,15 +118,4 @@ val FONT_SIZE_MEDIUM = 1
val FONT_SIZE_LARGE = 2
val SOURCE_SIMPLE_CALENDAR = 0
val SOURCE_GOOGLE_SYNC = 1
val SOURCE_IMPORTED_ICS = 2
// Google Sync
val PRIMARY = "primary"
val POPUP = "popup"
val OPERATION_INSERT = 1
val OPERATION_UPDATE = 2
val OPERATION_DELETE = 3
val OVERRIDES = "overrides"
val DEFAULT_REMINDERS = "defaultReminders"
val USE_DEFAULT = "useDefault"

View File

@ -323,7 +323,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
return null
}
fun deleteEvents(ids: Array<String>, deleteFromGoogle: Boolean = true) {
fun deleteEvents(ids: Array<String>) {
val args = TextUtils.join(", ", ids)
val selection = "$MAIN_TABLE_NAME.$COL_ID IN ($args)"
val cursor = getEventsCursor(selection)
@ -344,15 +344,10 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
context.cancelNotification(it.toInt())
}
deleteChildEvents(args, deleteFromGoogle)
if (deleteFromGoogle) {
events.forEach {
GoogleSyncHandler().tryDeleteFromGoogle(context, it)
}
}
deleteChildEvents(args)
}
private fun deleteChildEvents(ids: String, deleteFromGoogle: Boolean) {
private fun deleteChildEvents(ids: String) {
val projection = arrayOf(COL_ID)
val selection = "$COL_PARENT_EVENT_ID IN ($ids)"
val childIds = ArrayList<String>()
@ -370,19 +365,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
}
if (childIds.isNotEmpty())
deleteEvents(childIds.toTypedArray(), deleteFromGoogle)
}
fun getGoogleSyncEvents(): List<Event> {
val selection = "$COL_SOURCE = $SOURCE_GOOGLE_SYNC"
val cursor = getEventsCursor(selection)
return fillEvents(cursor)
}
fun deleteAllGoogleSyncEvents() {
val events = getGoogleSyncEvents()
val eventIDs = Array(events.size, { i -> (events[i].id.toString()) })
deleteEvents(eventIDs, false)
deleteEvents(childIds.toTypedArray())
}
fun addEventRepeatException(parentEventId: Int, occurrenceTS: Int) {

View File

@ -1,126 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.Context
import android.widget.Toast
import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.api.services.calendar.model.EventDateTime
import com.google.api.services.calendar.model.EventReminder
import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.activities.SimpleActivity
import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.commons.extensions.toast
import java.util.*
class GoogleSyncHandler {
fun tryInsertToGoogle(activity: SimpleActivity, event: Event) {
if (activity.isGoogleSyncActive()) {
if (activity.isOnline()) {
Thread({
val errorMsg = insertToGoogle(activity, event)
if (errorMsg.isNotEmpty()) {
val msg = String.format(activity.getString(R.string.google_sync_error_insert), errorMsg)
activity.toast(msg, Toast.LENGTH_LONG)
}
}).start()
} else {
activity.googleSyncQueue.addOperation(event.id, OPERATION_INSERT, event.importId)
}
}
}
fun insertToGoogle(context: Context, event: Event): String {
val googleEvent = mergeMyEventToGoogleEvent(com.google.api.services.calendar.model.Event(), event)
try {
context.getGoogleSyncService().events().insert(PRIMARY, googleEvent).execute()
} catch (e: GoogleJsonResponseException) {
return e.getGoogleMessageError()
}
return ""
}
fun tryUpdateGoogleEvent(activity: SimpleActivity, event: Event) {
if (activity.isGoogleSyncActive()) {
if (activity.isOnline()) {
Thread({
val errorMsg = updateGoogleEvent(activity.applicationContext, event)
if (errorMsg.isNotEmpty()) {
val msg = String.format(activity.getString(R.string.google_sync_error_update), errorMsg)
activity.toast(msg, Toast.LENGTH_LONG)
}
}).start()
} else {
activity.googleSyncQueue.addOperation(event.id, OPERATION_UPDATE, event.importId)
}
}
}
fun updateGoogleEvent(context: Context, event: Event): String {
try {
val googleEvent = context.getGoogleSyncService().events().get(PRIMARY, event.importId).execute()
val newGoogleEvent = mergeMyEventToGoogleEvent(googleEvent, event)
context.getGoogleSyncService().events().update(PRIMARY, newGoogleEvent.id, newGoogleEvent).execute()
} catch (e: GoogleJsonResponseException) {
return e.getGoogleMessageError()
}
return ""
}
fun tryDeleteFromGoogle(context: Context, event: Event) {
Thread({
if (context.isOnline()) {
deleteFromGoogle(context, event.importId)
} else {
context.googleSyncQueue.addOperation(event.id, OPERATION_DELETE, event.importId)
}
}).start()
}
fun deleteFromGoogle(context: Context, importId: String) {
try {
context.getGoogleSyncService().events().delete(PRIMARY, importId).execute()
} catch (ignored: Exception) {
}
}
private fun mergeMyEventToGoogleEvent(googleEvent: com.google.api.services.calendar.model.Event, event: Event): com.google.api.services.calendar.model.Event {
googleEvent.apply {
summary = event.title
description = event.description
if (event.getIsAllDay()) {
start = EventDateTime().setDate(com.google.api.client.util.DateTime(true, event.startTS * 1000L, null))
end = EventDateTime().setDate(com.google.api.client.util.DateTime(true, (event.endTS + DAY) * 1000L, null))
} else {
start = EventDateTime().setDateTime(com.google.api.client.util.DateTime(event.startTS * 1000L)).setTimeZone(TimeZone.getDefault().id)
end = EventDateTime().setDateTime(com.google.api.client.util.DateTime(event.endTS * 1000L)).setTimeZone(TimeZone.getDefault().id)
}
id = event.importId
status = CONFIRMED.toLowerCase()
Parser().getShortRepeatInterval(event).let {
if (it.isNotEmpty()) {
recurrence = listOf(it)
} else {
recurrence = null
}
}
if (event.getReminders().isNotEmpty()) {
reminders = getEventReminders(event).setUseDefault(false)
} else {
reminders = com.google.api.services.calendar.model.Event.Reminders().setUseDefault(false)
}
}
return googleEvent
}
private fun getEventReminders(event: Event): com.google.api.services.calendar.model.Event.Reminders {
val reminders = ArrayList<EventReminder>()
event.getReminders().forEach {
val reminder = EventReminder().setMinutes(it).setMethod(POPUP)
reminders.add(reminder)
}
return com.google.api.services.calendar.model.Event.Reminders().setOverrides(reminders)
}
}

View File

@ -1,112 +0,0 @@
package com.simplemobiletools.calendar.helpers
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import com.simplemobiletools.calendar.models.GoogleOperation
import com.simplemobiletools.commons.extensions.getIntValue
import com.simplemobiletools.commons.extensions.getStringValue
// database for storing operations performed on google events locally, while the user was offline
class GoogleSyncQueueDB private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
private val OPERATIONS_TABLE_NAME = "operations"
private val COL_ID = "id"
private val COL_EVENT_ID = "event_id"
private val COL_OPERATION = "operation"
private val COL_IMPORT_ID = "import_id"
private val mDb: SQLiteDatabase = writableDatabase
companion object {
private val DB_VERSION = 1
private val DB_NAME = "googlesyncqueue.db"
var dbInstance: GoogleSyncQueueDB? = null
fun newInstance(context: Context): GoogleSyncQueueDB {
if (dbInstance == null)
dbInstance = GoogleSyncQueueDB(context)
return dbInstance!!
}
}
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $OPERATIONS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_EVENT_ID INTEGER, $COL_OPERATION INTEGER, " +
"$COL_IMPORT_ID TEXT)")
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
}
fun addOperation(eventId: Int, operation: Int, importId: String) {
val hadInsertOperation = getOperationOf(eventId)?.operation?.equals(OPERATION_INSERT) == true
if (operation == OPERATION_DELETE) {
clearOperationsOf(eventId)
if (hadInsertOperation) {
return
}
}
if (operation == OPERATION_UPDATE) {
if (hadInsertOperation) {
return
}
}
val contentValues = ContentValues().apply {
put(COL_EVENT_ID, eventId)
put(COL_OPERATION, operation)
put(COL_IMPORT_ID, importId)
}
mDb.insert(OPERATIONS_TABLE_NAME, null, contentValues)
}
fun getOperationOf(eventId: Int): GoogleOperation? {
val selection = "$COL_EVENT_ID = $eventId"
val projection = arrayOf(COL_OPERATION, COL_IMPORT_ID)
var cursor: Cursor? = null
try {
cursor = mDb.query(OPERATIONS_TABLE_NAME, projection, selection, null, null, null, null)
if (cursor?.moveToFirst() == true) {
val operation = cursor.getIntValue(COL_OPERATION)
val importId = cursor.getStringValue(COL_IMPORT_ID)
return GoogleOperation(eventId, operation, importId)
}
} finally {
cursor?.close()
}
return null
}
fun getOperations(): ArrayList<GoogleOperation> {
val operations = ArrayList<GoogleOperation>()
val projection = arrayOf(COL_EVENT_ID, COL_OPERATION, COL_IMPORT_ID)
var cursor: Cursor? = null
try {
cursor = mDb.query(OPERATIONS_TABLE_NAME, projection, null, null, null, null, null)
if (cursor?.moveToFirst() == true) {
do {
val eventId = cursor.getIntValue(COL_EVENT_ID)
val operation = cursor.getIntValue(COL_OPERATION)
val importId = cursor.getStringValue(COL_IMPORT_ID)
operations.add(GoogleOperation(eventId, operation, importId))
} while (cursor.moveToNext())
}
} finally {
cursor?.close()
}
return operations
}
fun clearOperationsOf(eventId: Int) {
val selection = "$COL_EVENT_ID = $eventId"
mDb.delete(OPERATIONS_TABLE_NAME, selection, null)
}
fun clearQueue() {
mDb.delete(OPERATIONS_TABLE_NAME, null, null)
}
}

View File

@ -1,5 +0,0 @@
package com.simplemobiletools.calendar.interfaces
interface GoogleSyncListener {
fun syncCompleted()
}

View File

@ -1,3 +0,0 @@
package com.simplemobiletools.calendar.models
data class GoogleError(val message: String)

View File

@ -1,7 +0,0 @@
package com.simplemobiletools.calendar.models
import com.google.gson.JsonArray
import com.google.gson.JsonObject
data class GoogleEvent(val summary: String?, val description: String?, val status: String, val start: GoogleEventDateTime, val end: GoogleEventDateTime,
val reminders: JsonObject, val recurrence: JsonArray?, val id: String, val colorId: Int, val updated: String)

View File

@ -1,3 +0,0 @@
package com.simplemobiletools.calendar.models
data class GoogleEventDateTime(val date: String?, val dateTime: String?, val timeZone: String?)

View File

@ -1,3 +0,0 @@
package com.simplemobiletools.calendar.models
data class GoogleEventReminder(val method: String, val minutes: Int)

View File

@ -1,3 +0,0 @@
package com.simplemobiletools.calendar.models
data class GoogleOperation(val eventId: Int, val operation: Int, val importId: String)

View File

@ -3,10 +3,8 @@ package com.simplemobiletools.calendar.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.simplemobiletools.calendar.extensions.isGoogleSyncActive
import com.simplemobiletools.calendar.extensions.notifyRunningEvents
import com.simplemobiletools.calendar.extensions.scheduleAllEvents
import com.simplemobiletools.calendar.extensions.scheduleGoogleSync
class BootCompletedReceiver : BroadcastReceiver() {
@ -14,7 +12,6 @@ class BootCompletedReceiver : BroadcastReceiver() {
context.apply {
scheduleAllEvents()
notifyRunningEvents()
scheduleGoogleSync(isGoogleSyncActive())
}
}
}

View File

@ -1,13 +0,0 @@
package com.simplemobiletools.calendar.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.simplemobiletools.calendar.asynctasks.FetchGoogleEventsTask
class GoogleSyncReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, arg1: Intent) {
FetchGoogleEventsTask(context).execute()
}
}

View File

@ -109,26 +109,6 @@
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_google_sync_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:padding="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_google_sync"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/google_sync"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_caldav_sync_holder"
android:layout_width="match_parent"

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">Keine App zum Setzen des Klingentons gefunden</string>
<string name="no_ringtone_selected">Kein Klingelton gewählt</string>
<string name="day_end_before_start">Terminbeginn kann nicht vor Terminende liegen</string>
<string name="google_sync">Google Sync</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">No se ha encontrado ninguna aplicación capaz de establecer el tono de llamada</string>
<string name="no_ringtone_selected">Ninguno</string>
<string name="day_end_before_start">El día no puede terminar antes de que comience</string>
<string name="google_sync">Sincronización de Google</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">Aucune application capable de configurer la sonnerie trouvée</string>
<string name="no_ringtone_selected">Aucune</string>
<string name="day_end_before_start">Le jour ne peut pas se terminer plus tôt qu\'il ne débute</string>
<string name="google_sync">Synchronisation Google</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</string>
<string name="day_end_before_start">The day cannot end earlier than it starts</string>
<string name="google_sync">Google sync</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</string>
<string name="day_end_before_start">The day cannot end earlier than it starts</string>
<string name="google_sync">Google sync</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</string>
<string name="day_end_before_start">The day cannot end earlier than it starts</string>
<string name="google_sync">Google sync</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">לא נמצאה אפליקציה להגדרת רינגטון</string>
<string name="no_ringtone_selected">ללא</string>
<string name="day_end_before_start">היום לא יכול להסתיים מוקדם משהוא מתחיל</string>
<string name="google_sync">Google sync</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</string>
<string name="day_end_before_start">The day cannot end earlier than it starts</string>
<string name="google_sync">Google sync</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -191,21 +191,12 @@
<string name="no_ringtone_picker">Nie znalazłem aplikacji mogącej ustawiać dzwonki</string>
<string name="no_ringtone_selected">Żaden</string>
<string name="day_end_before_start">Dzień nie może zakończyć się wcześniej niż się zaczyna</string>
<string name="google_sync">Synchronizacja z Google</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Pokazuj wydarzenia z przeszłości</string>
<string name="snooze_delay">Opóźnij przypomnienie o</string>
<string name="widgets">Widżety</string>
<string name="cannot_while_offline">Nie możesz tego zrobić bez dostępu do internetu.</string>
<!-- Google sync -->
<string name="google_sync_testing">Synchronizacja z Google jest w fazie testów, sync is in a testing mode. Polegasz na niej na własną odpowiedzialność. Wszelkie raporty odnośnie tej funkcji pisane na adres hello@simplemobiletools.com są mile widziane.</string>
<string name="google_sync_existing">Wysłać istniejące wydarzenia na Dysk Google?</string>
<string name="google_sync_disabling">Wyłączenie synchronizacji z Google usunie wszelkie zsynchronizowane z Twoim urządzeniem wydarzenia, pozostwiając je nienaruszone w chmurze.</string>
<string name="google_sync_error_insert">Wystąił błąd podczas wysyłania wydarzeń na Dysk Google: %1$s</string>
<string name="google_sync_error_update">Wystąił błąd podczas aktualizacji wydarzeń na Dysku Google: %1$s</string>
<string name="google_sync_error_fetch">Wystąił błąd podczas pobierania wydarzeń z Dysku Google: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minutę</item>
<item quantity="few">%1$d minuty</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">Não foi encontrado nenhum aplicativo capaz de definir o som</string>
<string name="no_ringtone_selected">Nenhum</string>
<string name="day_end_before_start">O dia final não pode ser antes do início</string>
<string name="google_sync">Sincronização Google</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">Não foi encontrada uma aplicação capaz de definir o som</string>
<string name="no_ringtone_selected">Nenhum</string>
<string name="day_end_before_start">O dia final não pode ser antes do inicial</string>
<string name="google_sync">Sincronização Google</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Mostrar eventos passados</string>
<string name="snooze_delay">Adiar lembrete com a opção Snooze</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">A sincronização Google ainda não está terminada. Reporte os erros encontrados para hello@simplemobiletools.com. Obrigado!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minuto</item>
<item quantity="other">%1$d minutos</item>

View File

@ -200,21 +200,12 @@
<string name="no_ringtone_picker">Не найдено приложение для выбора рингтона</string>
<string name="no_ringtone_selected">Нет</string>
<string name="day_end_before_start">Конец дня не может быть раньше начала</string>
<string name="google_sync">Синхронизация с Google</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Показывать прошедшие события</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d минута</item>
<item quantity="few">%1$d минуты</item>

View File

@ -193,21 +193,12 @@
<string name="no_ringtone_picker">Nenašla sa žiadna aplikácia na zmenu zvučky</string>
<string name="no_ringtone_selected">Žiadna</string>
<string name="day_end_before_start">Deň nemôže skončiť skôr než začne</string>
<string name="google_sync">Google synchronizácia</string>
<string name="caldav_sync">CalDAV synchronizácia</string>
<string name="display_past_events">Zobraziť minulé udalosti spred</string>
<string name="snooze_delay">Posunúť pripomienku s Odložiť o</string>
<string name="widgets">Widgety</string>
<string name="cannot_while_offline">Nemôžete to urobiť bez internetu.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google synchronizácia je v testovacej prevádzke, buďte opatrní pri spoliehaní sa na ňu. Nahlásenie akýchkoľvek ohlasov na hello@simplemobiletools.com je vítané. Vďaka!</string>
<string name="google_sync_existing">Nahrať momentálne existujúce udalosti Googlu?</string>
<string name="google_sync_disabling">Vypnutie Google synchonizácie odstráni všetky synchronizované udalosti zo zariadenia, no v oblakoch ostanú nedotknuté.</string>
<string name="google_sync_error_insert">Chyba pri nahrávaní udalosti na Google: %1$s</string>
<string name="google_sync_error_update">Chyba pri úprave udalosti na Googli: %1$s</string>
<string name="google_sync_error_fetch">Chyba pri čítaní Google udalostí: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minútu</item>
<item quantity="few">%1$d minúty</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">Hittade ingen app som kan ställa in ljudet</string>
<string name="no_ringtone_selected">Ingen</string>
<string name="day_end_before_start">Dagen kan inte börja innan den tar slut</string>
<string name="google_sync">Google Synk</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Visa tidigare händelser</string>
<string name="snooze_delay">Skjut upp påminnelse med Snooza</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minut</item>
<item quantity="other">%1$d minuter</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">Zil sesi ayarlayabilen hiçbir uygulama bulunamadı</string>
<string name="no_ringtone_selected">Boş</string>
<string name="day_end_before_start">Gün başlamadan önce bitemez</string>
<string name="google_sync">Google senkronizasyonu</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</string>
<string name="day_end_before_start">The day cannot end earlier than it starts</string>
<string name="google_sync">Google sync</string>
<string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</string>
<!-- Google sync -->
<string name="google_sync_testing">Google sync is in a testing mode, please be cautions when relying on it. Reporting any feedback at hello@simplemobiletools.com would be appreciated. Thanks!</string>
<string name="google_sync_existing">Upload currently existing events to Google?</string>
<string name="google_sync_disabling">Disabling Google sync will delete all synced events from your device, while leaving them intact in the cloud.</string>
<string name="google_sync_error_insert">Error uploading event to Google: %1$s</string>
<string name="google_sync_error_update">Error updating event at Google: %1$s</string>
<string name="google_sync_error_fetch">Error fetching Google events: %1$s</string>
<plurals name="by_minutes">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>