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.facebook.stetho:stetho:1.4.1'
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2' compile 'com.bignerdranch.android:recyclerview-multiselect:0.2'
compile 'com.android.support:multidex:1.0.1' compile 'com.android.support:multidex:1.0.1'
compile 'com.google.code.gson:gson:2.8.0' 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" 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.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<application <application
android:name=".App" android:name=".App"
@ -138,8 +134,6 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".receivers.GoogleSyncReceiver"/>
<provider <provider
android:name="android.support.v4.content.FileProvider" android:name="android.support.v4.content.FileProvider"
android:authorities="com.simplemobiletools.calendar.fileprovider" android:authorities="com.simplemobiletools.calendar.fileprovider"

View File

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

View File

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

View File

@ -1,33 +1,21 @@
package com.simplemobiletools.calendar.activities package com.simplemobiletools.calendar.activities
import android.Manifest import android.Manifest
import android.accounts.AccountManager
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Color
import android.media.RingtoneManager import android.media.RingtoneManager
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.support.v4.app.ActivityCompat 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.R
import com.simplemobiletools.calendar.asynctasks.FetchGoogleEventsTask
import com.simplemobiletools.calendar.dialogs.CustomEventReminderDialog import com.simplemobiletools.calendar.dialogs.CustomEventReminderDialog
import com.simplemobiletools.calendar.dialogs.SnoozePickerDialog import com.simplemobiletools.calendar.dialogs.SnoozePickerDialog
import com.simplemobiletools.calendar.extensions.* import com.simplemobiletools.calendar.extensions.*
import com.simplemobiletools.calendar.helpers.* import com.simplemobiletools.calendar.helpers.FONT_SIZE_LARGE
import com.simplemobiletools.calendar.interfaces.GoogleSyncListener import com.simplemobiletools.calendar.helpers.FONT_SIZE_MEDIUM
import com.simplemobiletools.calendar.models.Event import com.simplemobiletools.calendar.helpers.FONT_SIZE_SMALL
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.updateTextColors import com.simplemobiletools.commons.extensions.updateTextColors
@ -36,9 +24,6 @@ import kotlinx.android.synthetic.main.activity_settings.*
class SettingsActivity : SimpleActivity() { class SettingsActivity : SimpleActivity() {
private val GET_RINGTONE_URI = 1 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 private val CALENDAR_PERMISSION = 5
lateinit var res: Resources lateinit var res: Resources
@ -52,7 +37,6 @@ class SettingsActivity : SimpleActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings) setContentView(R.layout.activity_settings)
res = resources res = resources
setupGoogleSync()
setupCaldavSync() 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() { private fun setupCaldavSync() {
settings_caldav_sync.isChecked = config.caldavSync settings_caldav_sync.isChecked = config.caldavSync
settings_caldav_sync_holder.setOnClickListener { settings_caldav_sync_holder.setOnClickListener {
@ -153,16 +117,6 @@ class SettingsActivity : SimpleActivity() {
config.caldavSync = settings_caldav_sync.isChecked config.caldavSync = settings_caldav_sync.isChecked
} }
private fun toggleGoogleSync() {
settings_google_sync.toggle()
if (settings_google_sync.isChecked) {
tryEnablingSync()
} else {
disableGoogleSync()
}
}
private fun setupSundayFirst() { private fun setupSundayFirst() {
settings_sunday_first.isChecked = config.isSundayFirst settings_sunday_first.isChecked = config.isSundayFirst
settings_sunday_first_holder.setOnClickListener { settings_sunday_first_holder.setOnClickListener {
@ -333,136 +287,17 @@ class SettingsActivity : SimpleActivity() {
settings_reminder_sound.text = RingtoneManager.getRingtone(this, uri as Uri)?.getTitle(this) settings_reminder_sound.text = RingtoneManager.getRingtone(this, uri as Uri)?.getTitle(this)
config.reminderSound = uri.toString() 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) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == ACCOUNTS_PERMISSION) { if (requestCode == CALENDAR_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showAccountChooser()
} else {
disableGoogleSync()
}
} else if (requestCode == CALENDAR_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
toggleCaldavSync() 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.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.net.ConnectivityManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v7.app.NotificationCompat 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.R
import com.simplemobiletools.calendar.activities.EventActivity import com.simplemobiletools.calendar.activities.EventActivity
import com.simplemobiletools.calendar.helpers.* import com.simplemobiletools.calendar.helpers.*
import com.simplemobiletools.calendar.helpers.Formatter import com.simplemobiletools.calendar.helpers.Formatter
import com.simplemobiletools.calendar.models.Event import com.simplemobiletools.calendar.models.Event
import com.simplemobiletools.calendar.receivers.GoogleSyncReceiver
import com.simplemobiletools.calendar.receivers.NotificationReceiver import com.simplemobiletools.calendar.receivers.NotificationReceiver
import com.simplemobiletools.calendar.services.SnoozeService import com.simplemobiletools.calendar.services.SnoozeService
import com.simplemobiletools.commons.extensions.getContrastColor 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.getNewEventTimestampFromCode(dayCode: String) = Formatter.getLocalDateTimeFromCode(dayCode).withTime(13, 0, 0, 0).seconds()
fun Context.getCurrentOffset() = SimpleDateFormat("Z", Locale.getDefault()).format(Date()) 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.config: Config get() = Config.newInstance(this)
val Context.dbHelper: DBHelper get() = DBHelper.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.media.RingtoneManager
import android.text.format.DateFormat import android.text.format.DateFormat
import com.simplemobiletools.calendar.R import com.simplemobiletools.calendar.R
import com.simplemobiletools.calendar.extensions.googleSyncQueue
import com.simplemobiletools.calendar.extensions.scheduleGoogleSync
import com.simplemobiletools.commons.helpers.BaseConfig import com.simplemobiletools.commons.helpers.BaseConfig
import java.util.* import java.util.*
@ -72,32 +70,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(FONT_SIZE, FONT_SIZE_MEDIUM) get() = prefs.getInt(FONT_SIZE, FONT_SIZE_MEDIUM)
set(size) = prefs.edit().putInt(FONT_SIZE, size).apply() 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 var caldavSync: Boolean
get() = prefs.getBoolean(CALDAV_SYNC, false) get() = prefs.getBoolean(CALDAV_SYNC, false)
set(caldavSync) = prefs.edit().putBoolean(CALDAV_SYNC, caldavSync).apply() 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) { fun addDisplayEventType(type: String) {
addDisplayEventTypes(HashSet<String>(Arrays.asList(type))) addDisplayEventTypes(HashSet<String>(Arrays.asList(type)))
} }

View File

@ -41,13 +41,10 @@ val VIEW = "view"
val REMINDER_MINUTES = "reminder_minutes" val REMINDER_MINUTES = "reminder_minutes"
val DISPLAY_EVENT_TYPES = "display_event_types" val DISPLAY_EVENT_TYPES = "display_event_types"
val FONT_SIZE = "font_size" val FONT_SIZE = "font_size"
val GOOGLE_SYNC = "google_sync"
val CALDAV_SYNC = "caldav_sync" val CALDAV_SYNC = "caldav_sync"
val SYNC_ACCOUNT_NAME = "sync_account_name" val SYNC_ACCOUNT_NAME = "sync_account_name"
val SNOOZE_DELAY = "snooze_delay" val SNOOZE_DELAY = "snooze_delay"
val DISPLAY_PAST_EVENTS = "display_past_events" 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, 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) 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 FONT_SIZE_LARGE = 2
val SOURCE_SIMPLE_CALENDAR = 0 val SOURCE_SIMPLE_CALENDAR = 0
val SOURCE_GOOGLE_SYNC = 1
val SOURCE_IMPORTED_ICS = 2 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 return null
} }
fun deleteEvents(ids: Array<String>, deleteFromGoogle: Boolean = true) { fun deleteEvents(ids: Array<String>) {
val args = TextUtils.join(", ", ids) val args = TextUtils.join(", ", ids)
val selection = "$MAIN_TABLE_NAME.$COL_ID IN ($args)" val selection = "$MAIN_TABLE_NAME.$COL_ID IN ($args)"
val cursor = getEventsCursor(selection) val cursor = getEventsCursor(selection)
@ -344,15 +344,10 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
context.cancelNotification(it.toInt()) context.cancelNotification(it.toInt())
} }
deleteChildEvents(args, deleteFromGoogle) deleteChildEvents(args)
if (deleteFromGoogle) {
events.forEach {
GoogleSyncHandler().tryDeleteFromGoogle(context, it)
}
}
} }
private fun deleteChildEvents(ids: String, deleteFromGoogle: Boolean) { private fun deleteChildEvents(ids: String) {
val projection = arrayOf(COL_ID) val projection = arrayOf(COL_ID)
val selection = "$COL_PARENT_EVENT_ID IN ($ids)" val selection = "$COL_PARENT_EVENT_ID IN ($ids)"
val childIds = ArrayList<String>() val childIds = ArrayList<String>()
@ -370,19 +365,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont
} }
if (childIds.isNotEmpty()) if (childIds.isNotEmpty())
deleteEvents(childIds.toTypedArray(), deleteFromGoogle) deleteEvents(childIds.toTypedArray())
}
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)
} }
fun addEventRepeatException(parentEventId: Int, occurrenceTS: Int) { 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.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.simplemobiletools.calendar.extensions.isGoogleSyncActive
import com.simplemobiletools.calendar.extensions.notifyRunningEvents import com.simplemobiletools.calendar.extensions.notifyRunningEvents
import com.simplemobiletools.calendar.extensions.scheduleAllEvents import com.simplemobiletools.calendar.extensions.scheduleAllEvents
import com.simplemobiletools.calendar.extensions.scheduleGoogleSync
class BootCompletedReceiver : BroadcastReceiver() { class BootCompletedReceiver : BroadcastReceiver() {
@ -14,7 +12,6 @@ class BootCompletedReceiver : BroadcastReceiver() {
context.apply { context.apply {
scheduleAllEvents() scheduleAllEvents()
notifyRunningEvents() 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>
<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 <RelativeLayout
android:id="@+id/settings_caldav_sync_holder" android:id="@+id/settings_caldav_sync_holder"
android:layout_width="match_parent" 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_picker">Keine App zum Setzen des Klingentons gefunden</string>
<string name="no_ringtone_selected">Kein Klingelton gewählt</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_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="no_ringtone_selected">Ninguno</string>
<string name="day_end_before_start">El día no puede terminar antes de que comience</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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">Aucune application capable de configurer la sonnerie trouvée</string>
<string name="no_ringtone_selected">Aucune</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item> <item quantity="other">%1$d minutes</item>

View File

@ -186,21 +186,12 @@
<string name="no_ringtone_picker">לא נמצאה אפליקציה להגדרת רינגטון</string> <string name="no_ringtone_picker">לא נמצאה אפליקציה להגדרת רינגטון</string>
<string name="no_ringtone_selected">ללא</string> <string name="no_ringtone_selected">ללא</string>
<string name="day_end_before_start">היום לא יכול להסתיים מוקדם משהוא מתחיל</string> <string name="day_end_before_start">היום לא יכול להסתיים מוקדם משהוא מתחיל</string>
<string name="google_sync">Google sync</string>
<string name="caldav_sync">CalDAV sync</string> <string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">Nie znalazłem aplikacji mogącej ustawiać dzwonki</string>
<string name="no_ringtone_selected">Żaden</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Pokazuj wydarzenia z przeszłości</string> <string name="display_past_events">Pokazuj wydarzenia z przeszłości</string>
<string name="snooze_delay">Opóźnij przypomnienie o</string> <string name="snooze_delay">Opóźnij przypomnienie o</string>
<string name="widgets">Widżety</string> <string name="widgets">Widżety</string>
<string name="cannot_while_offline">Nie możesz tego zrobić bez dostępu do internetu.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minutę</item> <item quantity="one">%1$d minutę</item>
<item quantity="few">%1$d minuty</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_picker">Não foi encontrado nenhum aplicativo capaz de definir o som</string>
<string name="no_ringtone_selected">Nenhum</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">Não foi encontrada uma aplicação capaz de definir o som</string>
<string name="no_ringtone_selected">Nenhum</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Mostrar eventos passados</string> <string name="display_past_events">Mostrar eventos passados</string>
<string name="snooze_delay">Adiar lembrete com a opção Snooze</string> <string name="snooze_delay">Adiar lembrete com a opção Snooze</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minuto</item> <item quantity="one">%1$d minuto</item>
<item quantity="other">%1$d minutos</item> <item quantity="other">%1$d minutos</item>

View File

@ -200,21 +200,12 @@
<string name="no_ringtone_picker">Не найдено приложение для выбора рингтона</string> <string name="no_ringtone_picker">Не найдено приложение для выбора рингтона</string>
<string name="no_ringtone_selected">Нет</string> <string name="no_ringtone_selected">Нет</string>
<string name="day_end_before_start">Конец дня не может быть раньше начала</string> <string name="day_end_before_start">Конец дня не может быть раньше начала</string>
<string name="google_sync">Синхронизация с Google</string>
<string name="caldav_sync">CalDAV sync</string> <string name="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Показывать прошедшие события</string> <string name="display_past_events">Показывать прошедшие события</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d минута</item> <item quantity="one">%1$d минута</item>
<item quantity="few">%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_picker">Nenašla sa žiadna aplikácia na zmenu zvučky</string>
<string name="no_ringtone_selected">Žiadna</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="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="caldav_sync">CalDAV synchronizácia</string>
<string name="display_past_events">Zobraziť minulé udalosti spred</string> <string name="display_past_events">Zobraziť minulé udalosti spred</string>
<string name="snooze_delay">Posunúť pripomienku s Odložiť o</string> <string name="snooze_delay">Posunúť pripomienku s Odložiť o</string>
<string name="widgets">Widgety</string> <string name="widgets">Widgety</string>
<string name="cannot_while_offline">Nemôžete to urobiť bez internetu.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minútu</item> <item quantity="one">%1$d minútu</item>
<item quantity="few">%1$d minúty</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_picker">Hittade ingen app som kan ställa in ljudet</string>
<string name="no_ringtone_selected">Ingen</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Visa tidigare händelser</string> <string name="display_past_events">Visa tidigare händelser</string>
<string name="snooze_delay">Skjut upp påminnelse med Snooza</string> <string name="snooze_delay">Skjut upp påminnelse med Snooza</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minut</item> <item quantity="one">%1$d minut</item>
<item quantity="other">%1$d minuter</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_picker">Zil sesi ayarlayabilen hiçbir uygulama bulunamadı</string>
<string name="no_ringtone_selected">Boş</string> <string name="no_ringtone_selected">Boş</string>
<string name="day_end_before_start">Gün başlamadan önce bitemez</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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</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_picker">No app capable of setting ringtone found</string>
<string name="no_ringtone_selected">None</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="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="caldav_sync">CalDAV sync</string>
<string name="display_past_events">Display events from the past</string> <string name="display_past_events">Display events from the past</string>
<string name="snooze_delay">Postpone reminder with Snooze by</string> <string name="snooze_delay">Postpone reminder with Snooze by</string>
<string name="widgets">Widgets</string> <string name="widgets">Widgets</string>
<string name="cannot_while_offline">You cannot do that while offline.</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"> <plurals name="by_minutes">
<item quantity="one">%1$d minute</item> <item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item> <item quantity="other">%1$d minutes</item>