Partially restore Astrid3ContentProvider

synthesis
Alex Baker 6 years ago
parent b72c187f43
commit 90ba23620c

@ -33,8 +33,8 @@ android {
defaultConfig {
testApplicationId "org.tasks.test"
applicationId "org.tasks"
versionCode 506
versionName "5.3.4"
versionCode 507
versionName "5.3.5"
targetSdkVersion 27
minSdkVersion 15
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

@ -59,12 +59,30 @@
<permission
android:name="org.tasks.permission.READ_TASKS"
android:permissionGroup="android.permission-group.MESSAGES"
android:protectionLevel="normal"
android:protectionLevel="dangerous"
android:label="@string/read_permission_label"
android:description="@string/read_permission_desc" />
<uses-permission android:name="org.tasks.permission.READ_TASKS" />
<!-- for reading data from add-ons or astrid via v3 content provider -->
<permission
android:name="org.tasks.READ"
android:description="@string/read_permission_desc"
android:protectionLevel="normal"
android:label="@string/read_permission_label" />
<uses-permission android:name="org.tasks.READ" />
<!-- for writing data to add-ons or astrid via v3 content provider -->
<permission
android:name="org.tasks.WRITE"
android:description="@string/write_permission_desc"
android:protectionLevel="normal"
android:label="@string/write_permission_label" />
<uses-permission android:name="org.tasks.WRITE" />
<!-- ========================================================== Metadata = -->
<supports-screens
@ -226,13 +244,22 @@
<provider
android:name="com.todoroo.astrid.provider.Astrid2TaskProvider"
android:authorities="org.tasks;org.tasks.tasksprovider"
android:authorities="org.tasks.tasksprovider"
android:exported="true"
android:multiprocess="true"
android:grantUriPermissions="true"
android:readPermission="org.tasks.permission.READ_TASKS" />
<provider
android:name="com.todoroo.astrid.provider.Astrid3ContentProvider"
android:authorities="org.tasks"
android:exported="true"
android:multiprocess="true"
android:grantUriPermissions="true"
android:readPermission="org.tasks.READ"
android:writePermission="org.tasks.WRITE" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"

@ -5,6 +5,8 @@
*/
package com.todoroo.astrid.api;
import org.tasks.BuildConfig;
/**
* Constants for interfacing with Astrid.
*
@ -12,11 +14,32 @@ package com.todoroo.astrid.api;
*/
public class AstridApiConstants {
// --- General Constants
/**
* Permission for reading tasks and receiving to GET_FILTERS intent
*/
public static final String PERMISSION_READ = BuildConfig.APPLICATION_ID + ".READ";
/**
* Permission for writing and creating tasks
*/
public static final String PERMISSION_WRITE = BuildConfig.APPLICATION_ID + ".WRITE";
/**
* Name of Astrid's publicly readable preference store
*/
public static final String PUBLIC_PREFS = "public";
// --- Content Provider
/**
* URI to append to base content URI for making group-by queries
*/
public static final String GROUP_BY_URI = "/groupby/";
// --- Broadcast Extras
/**
* Extras name for task id
*/

@ -0,0 +1,335 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.provider;
import android.annotation.SuppressLint;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskCreator;
import dagger.Lazy;
import java.util.Arrays;
import javax.inject.Inject;
import org.tasks.BuildConfig;
import org.tasks.LocalBroadcastManager;
import org.tasks.analytics.Tracker;
import org.tasks.analytics.Tracking.Events;
import org.tasks.injection.ContentProviderComponent;
import org.tasks.injection.InjectingContentProvider;
import timber.log.Timber;
/**
* Astrid 3 Content Provider. There are two ways to use this content provider:
* <ul>
* <li>access it directly just like any other content provider
* <li>use the DAO classes from the Astrid API library
* </ul>
* <p>
* The following base URI's are supported:
* <ul>
* <li>content://com.todoroo.astrid/tasks - task data ({@link Task})
* <li>content://com.todoroo.astrid/metadata - task metadata ({@link Metadata})
* </ul>
* <p>
* Each URI supports the following components:
* <ul>
* <li>/ - operate on all items (insert, delete, update, query)
* <li>/123 - operate on item id #123 (delete, update, query)
* <li>/groupby/title - query with SQL "group by" (query)
* </ul>
* <p>
* If you are writing a third-party application to access this data, you may
* also consider using one of the Api DAO objects like TaskApiDao.
*
* @author Tim Su <tim@todoroo.com>
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public class Astrid3ContentProvider extends InjectingContentProvider {
private static final Uri TASKS = Uri.parse("content://" + BuildConfig.APPLICATION_ID + "/tasks");
private static final Uri METADATA = Uri
.parse("content://" + BuildConfig.APPLICATION_ID + "/metadata");
/**
* URI for making a request over all items
*/
private static final int URI_DIR = 1;
/**
* URI for making a request over a single item by id
*/
private static final int URI_ITEM = 2;
/**
* URI for making a request over all items grouped by some field
*/
private static final int URI_GROUP = 3;
private static final UriMatcher uriMatcher;
@SuppressLint("StaticFieldLeak")
private static Database databaseOverride;
// --- instance variables
private boolean open;
@Inject Lazy<Database> database;
@Inject Lazy<Tracker> tracker;
@Inject Lazy<LocalBroadcastManager> localBroadcastManager;
@Inject Lazy<TaskCreator> taskCreator;
@Inject Lazy<TaskDao> taskDao;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
for (Uri uri : new Uri[]{TASKS, METADATA}) {
String authority = BuildConfig.APPLICATION_ID;
String table = uri.toString();
table = table.substring(table.indexOf('/', 11) + 1);
uriMatcher.addURI(authority, table, URI_DIR);
uriMatcher.addURI(authority, table + "/#", URI_ITEM);
uriMatcher.addURI(authority, table +
AstridApiConstants.GROUP_BY_URI + "*", URI_GROUP);
}
}
public Astrid3ContentProvider() {
setReadPermission(AstridApiConstants.PERMISSION_READ);
setWritePermission(AstridApiConstants.PERMISSION_WRITE);
}
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)) {
case URI_DIR:
case URI_GROUP:
return "vnd.android.cursor.dir/vnd.astrid";
case URI_ITEM:
return "vnd.android.cursor/vnd.astrid.item";
default:
throw new IllegalArgumentException(
"Unsupported URI " + uri + " (" + uriMatcher.match(uri) + ")");
}
}
@Override
protected void inject(ContentProviderComponent component) {
component.inject(this);
}
public static void setDatabaseOverride(Database override) {
databaseOverride = override;
}
private SupportSQLiteDatabase getDatabase() {
if (!open) {
database.get().openForWriting();
open = true;
}
Database database = databaseOverride == null ? this.database.get() : databaseOverride;
return database.getDatabase();
}
/* ======================================================================
* =========================================================== delete ===
* ====================================================================== */
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
Timber.d("DELETE %s\nselection=%s\nselectionArgs=%s", uri, selection,
Arrays.toString(selectionArgs));
String tableName = getTableName(uri);
if (!"tasks".equals(tableName)) {
return 0;
}
switch (uriMatcher.match(uri)) {
case URI_GROUP:
throw new IllegalArgumentException("Only the / or /# URI is valid for deletion.");
case URI_ITEM: {
String itemSelector = String.format("_id = '%s'", uri.getPathSegments().get(1));
if (TextUtils.isEmpty(selection)) {
selection = itemSelector;
} else {
selection = itemSelector + " AND " + selection;
}
}
case URI_DIR:
break;
default:
throw new IllegalArgumentException(
"Unknown URI " + uri + " (" + uriMatcher.match(uri) + ")");
}
int numDeleted = getDatabase().delete(tableName, selection, selectionArgs);
if (numDeleted > 0) {
localBroadcastManager.get().broadcastRefresh();
}
return numDeleted;
}
/* ======================================================================
* =========================================================== insert ===
* ====================================================================== */
/**
* Insert key/value pairs into given table
*/
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
Timber.d("INSERT %s\nvalues=%s", uri, values);
String tableName = getTableName(uri);
if (!"tasks".equals(tableName)) {
return null;
}
switch (uriMatcher.match(uri)) {
case URI_ITEM:
case URI_GROUP:
throw new IllegalArgumentException("Only the / URI is valid for insertion.");
case URI_DIR: {
Task task = taskCreator.get().createWithValues(null, "");
taskDao.get().createNew(task);
long id = task.getId();
if (id <= 0) {
throw new SQLException("Could not insert row into database (constraint failed?)");
}
getDatabase()
.update(tableName, SQLiteDatabase.CONFLICT_REPLACE, values, "_id = '" + id + "'",
null);
taskDao.get().save(taskDao.get().fetch(id), null);
Uri newUri = ContentUris.withAppendedId(uri, id);
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
/* ======================================================================
* =========================================================== update ===
* ====================================================================== */
@Override
public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
Timber.d("UPDATE %s\nvalues=%s\nselection=%s\nselectionArgs=%s", uri, values, selection,
Arrays.toString(selectionArgs));
String tableName = getTableName(uri);
if (!"tasks".equals(tableName)) {
return 0;
}
switch (uriMatcher.match(uri)) {
case URI_DIR:
case URI_GROUP:
throw new IllegalArgumentException("Only the /# URI is valid for update.");
case URI_ITEM:
Long id = Long.parseLong(uri.getPathSegments().get(1));
String byId = String.format("_id = '%s'", id);
selection = TextUtils.isEmpty(selection) ? byId : byId + " AND " + selection;
Task original = taskDao.get().fetch(id);
int updated = getDatabase()
.update(tableName, SQLiteDatabase.CONFLICT_ABORT, values, selection, selectionArgs);
if (updated == 1) {
taskDao.get().save(taskDao.get().fetch(id), original);
getContext().getContentResolver().notifyChange(uri, null);
}
return updated;
default:
throw new IllegalArgumentException(
"Unknown URI " + uri + " (" + uriMatcher.match(uri) + ")");
}
}
/* ======================================================================
* ============================================================ query ===
* ====================================================================== */
/**
* Query by task.
* <p>
* Note that the "sortOrder" field actually can be used to append any
* sort of clause to your SQL query as long as it is not also the
* name of a column
*/
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Timber.d("QUERY %s\ncolumns=%s\nselection=%s\nselectionArgs=%s\nsortOrder=%s", uri,
Arrays.toString(projection), selection, Arrays.toString(selectionArgs), sortOrder);
String tableName = getTableName(uri);
if (!"tasks".equals(tableName)) {
return null;
}
String groupBy = null;
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(getTableName(uri));
switch (uriMatcher.match(uri)) {
case URI_GROUP:
groupBy = uri.getPathSegments().get(2);
case URI_DIR:
break;
case URI_ITEM:
String itemSelector = String.format("_id = '%s'", uri.getPathSegments().get(1));
builder.appendWhere(itemSelector);
break;
default:
throw new IllegalArgumentException(
"Unknown URI " + uri + " (" + uriMatcher.match(uri) + ")");
}
String query = builder.buildQuery(projection, selection, groupBy, null, sortOrder, null);
Cursor cursor = getDatabase().query(query, selectionArgs);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// --- change listeners
public static void notifyDatabaseModification(Context context) {
ContentResolver cr = context.getContentResolver();
cr.notifyChange(TASKS, null, false);
}
private String getTableName(Uri uri) {
tracker.get().reportEvent(Events.ASTRID_3_CP);
String uriString = uri.toString();
if (uriString.startsWith(TASKS.toString())) {
return "tasks";
}
if (uriString.startsWith(METADATA.toString())) {
return "tags";
}
throw new IllegalArgumentException("Unsupported uri: " + uriString);
}
}

@ -38,7 +38,8 @@ public class Tracking {
TASKER_LIST_NOTIFICATION(R.string.tracking_category_tasker, R.string.tracking_action_list_notification),
IMPORT_XML(R.string.tracking_category_backup, R.string.tracking_action_import_xml),
IMPORT_JSON(R.string.tracking_category_backup, R.string.tracking_action_import_json),
EXPORT(R.string.tracking_category_backup, R.string.tracking_action_export);
EXPORT(R.string.tracking_category_backup, R.string.tracking_action_export),
ASTRID_3_CP(R.string.tracking_category_api, R.string.tracking_action_api_astrid3);
public final int category;
public final int action;

@ -7,6 +7,7 @@ import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.provider.Astrid2TaskProvider;
import com.todoroo.astrid.provider.Astrid3ContentProvider;
import org.tasks.ErrorReportingSingleThreadExecutor;
import org.tasks.analytics.Tracker;
import org.tasks.data.AlarmDao;
@ -64,7 +65,10 @@ public class ApplicationModule {
.allowMainThreadQueries() // TODO: remove me
.addMigrations(Migrations.MIGRATIONS)
.build()
.init(tracker, () -> Astrid2TaskProvider.notifyDatabaseModification(context));
.init(tracker, () -> {
Astrid2TaskProvider.notifyDatabaseModification(context);
Astrid3ContentProvider.notifyDatabaseModification(context);
});
}
@Provides

@ -1,6 +1,7 @@
package org.tasks.injection;
import com.todoroo.astrid.provider.Astrid2TaskProvider;
import com.todoroo.astrid.provider.Astrid3ContentProvider;
import dagger.Component;
@ -10,5 +11,7 @@ import dagger.Component;
ContentProviderModule.class
})
public interface ContentProviderComponent {
void inject(Astrid3ContentProvider astrid3ContentProvider);
void inject(Astrid2TaskProvider astrid2TaskProvider);
}

@ -13,6 +13,7 @@
<string name="export_toast_no_tasks">لا يوجد مهام للتصدير.</string>
<string name="import_summary_title"> إستعادة المُلخَّص</string>
<string name="read_permission_label">إذن المهام</string>
<string name="write_permission_label">أخذ التصاريح</string>
<string name="DLG_delete_this_task_question">حذف هذه المهمه؟</string>
<string name="DLG_hour_minutes">الوقت (ساعة : دقيقة)</string>
<string name="DLG_undo">تراجع</string>

@ -24,6 +24,7 @@
<string name="DLG_error_sdcard">Нямате достъп до папка: %s</string>
<string name="DLG_error_sdcard_general">SD картата не може да бъде достъпена!</string>
<string name="read_permission_label">Tasks Разрешение</string>
<string name="write_permission_label">Tasks Разрешение</string>
<string name="discard_confirmation">Сигурни ли сте че искате да отхвърлите промените си?</string>
<string name="keep_editing">Продължаване на редактиране</string>
<string name="DLG_delete_this_task_question">Изтриване на тази задача?</string>

@ -17,6 +17,7 @@
<string name="DLG_error_sdcard">No es pot accedir a la carpeta: %s</string>
<string name="DLG_error_sdcard_general">No s\'ha pogut accedir a la targeta SD.</string>
<string name="read_permission_label">Permís de l\'Tasks</string>
<string name="write_permission_label">Permís de l\'Tasks</string>
<string name="DLG_delete_this_task_question">Voleu suprimir aquesta tasca?</string>
<string name="DLG_hour_minutes">Temps (hores : minuts)</string>
<string name="DLG_undo">Desfés</string>

@ -20,6 +20,7 @@
<string name="DLG_error_sdcard">Chyba v přístupu k adresáři: %s</string>
<string name="DLG_error_sdcard_general">Chyba v přístupu k SD kartě!</string>
<string name="read_permission_label">Tasks Práva</string>
<string name="write_permission_label">Tasks Práva</string>
<string name="DLG_delete_this_task_question">Smazat tento úkol?</string>
<string name="DLG_hour_minutes">Čas (hodin : minut)</string>
<string name="DLG_undo">Vrátit změny</string>

@ -19,6 +19,7 @@
<string name="DLG_error_sdcard">Kan ikke få adgang til mappen: %s</string>
<string name="DLG_error_sdcard_general">Kan ikke få adgang til dig SD-kort!</string>
<string name="read_permission_label">Tasks Tilladelser</string>
<string name="write_permission_label">Tasks Tilladelser</string>
<string name="DLG_delete_this_task_question">Slet denne opgave?</string>
<string name="DLG_hour_minutes">Tid (timer : minutter)</string>
<string name="WID_dateButtonUnset">Tryk for at indstille</string>

@ -19,6 +19,7 @@
<string name="DLG_error_sdcard">Ordner konnte nicht geöffnet werden: %s</string>
<string name="DLG_error_sdcard_general">Auf die SD-Karte konnte nicht zugegriffen werden!</string>
<string name="read_permission_label">Tasks Zugriffsrechte</string>
<string name="write_permission_label">Tasks Zugriffsrechte</string>
<string name="discard_confirmation">Änderungen wirklich verwerfen?</string>
<string name="keep_editing">Weiter bearbeiten</string>
<string name="DLG_delete_this_task_question">Diese Aufgabe löschen?</string>

@ -22,6 +22,7 @@
<string name="DLG_error_sdcard">Δεν υπάρχει πρόσβαση στον φάκελο: %s</string>
<string name="DLG_error_sdcard_general">Δεν υπάρχει πρόσβαση στην SD κάρτα!</string>
<string name="read_permission_label">Άδεια εργασιών</string>
<string name="write_permission_label">Άδεια Εργασιών</string>
<string name="DLG_delete_this_task_question">Διαγραφή εργασίας;</string>
<string name="DLG_hour_minutes">Ώρα (ώρες : λεπτά)</string>
<string name="DLG_undo">Αναίρεση</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">No se puede acceder a la carpeta: %s</string>
<string name="DLG_error_sdcard_general">¡No se pudo acceder a su tarjeta de memoria SD!</string>
<string name="read_permission_label">Permisos de Tasks</string>
<string name="write_permission_label">Permisos de Tasks</string>
<string name="discard_confirmation">¿Quieres descartar los cambios?</string>
<string name="keep_editing">Seguir editando</string>
<string name="DLG_delete_this_task_question">¿Borrar esta tarea?</string>

@ -24,6 +24,7 @@
<string name="DLG_error_sdcard">Ei pääsyä kansioon: %s</string>
<string name="DLG_error_sdcard_general">Ei pääsyä SD kortillesi!</string>
<string name="read_permission_label">Tasks käyttöoikeus</string>
<string name="write_permission_label">Tasks käyttöoikeus</string>
<string name="discard_confirmation">Oletko varma että haluat hylätä muutokset?</string>
<string name="keep_editing">Jatka muokkausta</string>
<string name="DLG_delete_this_task_question">Poista tämä tehtävä?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Impossible d\'accéder au dossier : %s</string>
<string name="DLG_error_sdcard_general">Impossible d\'accéder à la carte SD !</string>
<string name="read_permission_label">Permissions de Tasks</string>
<string name="write_permission_label">Permissions de Tasks</string>
<string name="discard_confirmation">Êtes-vous sûr de vouloir annuler vos modifications ?</string>
<string name="keep_editing">Continuer l\'édition</string>
<string name="DLG_delete_this_task_question">Supprimer cette tâche ?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">No se puede acceder a la carpeta: %s</string>
<string name="DLG_error_sdcard_general">¡No se pudo acceder a su tarjeta de memoria SD!</string>
<string name="read_permission_label">Permisos de Tasks</string>
<string name="write_permission_label">Permisos de Tasks</string>
<string name="discard_confirmation">¿Quieres descartar los cambios?</string>
<string name="keep_editing">Seguir editando</string>
<string name="DLG_delete_this_task_question">¿Borrar esta tarea?</string>

@ -24,6 +24,7 @@
<string name="DLG_error_sdcard">Könyvtár nem elérhető: %s</string>
<string name="DLG_error_sdcard_general">SD kártya nem elérhető</string>
<string name="read_permission_label">Tasks Engedélyek</string>
<string name="write_permission_label">Tasks Engedélyek</string>
<string name="discard_confirmation">Biztosan el akarja vetni a változtatásokat?</string>
<string name="keep_editing">Vissza a szerkesztéshez</string>
<string name="DLG_delete_this_task_question">Feladat törlése?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Impossibile accedere alla cartella: %s</string>
<string name="DLG_error_sdcard_general">Impossibile accedere alla scheda SD!</string>
<string name="read_permission_label">Permessi attività</string>
<string name="write_permission_label">Permessi attività</string>
<string name="discard_confirmation">Sicuro di voler annullare tutte le modifiche?</string>
<string name="keep_editing">Continua modifica</string>
<string name="DLG_delete_this_task_question">Elimino l\'attività?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">לא ניתן לגשת לתיקיה: %s</string>
<string name="DLG_error_sdcard_general">לא ניתן לגשת לכרטיס ה־SD שלך!</string>
<string name="read_permission_label">הרשאות אסטריד</string>
<string name="write_permission_label">הרשאות אסטריד</string>
<string name="discard_confirmation">להתעלם מהשינויים ?</string>
<string name="keep_editing">המשך לערוך</string>
<string name="DLG_delete_this_task_question">למחוק משימה זו?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">フォルダ %s を開けません</string>
<string name="DLG_error_sdcard_general">SDカードにアクセスできません</string>
<string name="read_permission_label">タスクの読み込み</string>
<string name="write_permission_label">タスクの読み込み</string>
<string name="discard_confirmation">変更を破棄してもよろしいですか?</string>
<string name="keep_editing">編集を続ける</string>
<string name="DLG_delete_this_task_question">このタスクを削除しますか?</string>

@ -24,6 +24,7 @@
<string name="DLG_error_sdcard">폴더에 접근 불가: %s</string>
<string name="DLG_error_sdcard_general">SD 카드에 접근할 수 없습니다!</string>
<string name="read_permission_label">Tasks 권한</string>
<string name="write_permission_label">Tasks 권한</string>
<string name="discard_confirmation">변경 사항을 버리시겠습니까?</string>
<string name="keep_editing">계속 편집</string>
<string name="DLG_delete_this_task_question">이 할일을 삭제할까요?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Nėra prieigos prie aplanko: %s</string>
<string name="DLG_error_sdcard_general">Nėra prieigos prie SD kortelės!</string>
<string name="read_permission_label">Tasks leidimas</string>
<string name="write_permission_label">Tasks leidimas</string>
<string name="discard_confirmation">Ar tikrai norite atmesti pakeitimus?</string>
<string name="keep_editing">Tęsti redagavimą</string>
<string name="DLG_delete_this_task_question">Ištrinti šią užduotį?</string>

@ -17,6 +17,7 @@
<string name="DLG_error_sdcard">Får ikke tilgang til mappen: %s</string>
<string name="DLG_error_sdcard_general">Ditt SD-kort er ikke tilgjengelig!</string>
<string name="read_permission_label">Tasks Tillatelse</string>
<string name="write_permission_label">Tasks Tillatelse</string>
<string name="DLG_delete_this_task_question">Slett denne oppgaven?</string>
<string name="DLG_hour_minutes">Tid (timer : minutter)</string>
<string name="WID_dateButtonUnset">Klikk for å sette</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Toegang geweigerd tot map: %s</string>
<string name="DLG_error_sdcard_general">Toegang tot SD-kaart geweigerd!</string>
<string name="read_permission_label">Taak toestemmingen</string>
<string name="write_permission_label">Taak toestemmingen</string>
<string name="discard_confirmation">Weet u zeker dat u de wijzigingen niet wilt opslaan?</string>
<string name="keep_editing">Blijf editen</string>
<string name="DLG_delete_this_task_question">Taak verwijderen?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Brak dostępu do folderu: %s</string>
<string name="DLG_error_sdcard_general">Brak dostępu do Twojej karty SD!</string>
<string name="read_permission_label">Uprawnienia Tasks</string>
<string name="write_permission_label">Zezwolenia Tasks</string>
<string name="discard_confirmation">Czy jesteś pewien, że chcesz porzucić zmiany?</string>
<string name="keep_editing">Kontynuuj edycję</string>
<string name="DLG_delete_this_task_question">Usunąć to zadanie?</string>

@ -20,6 +20,7 @@
<string name="DLG_error_sdcard">Não foi possível acessar a pasta: %s</string>
<string name="DLG_error_sdcard_general">Não foi possível acessar seu cartão SD!</string>
<string name="read_permission_label">Permissões do Tasks</string>
<string name="write_permission_label">Permissões do Tasks</string>
<string name="discard_confirmation">Você tem certeza que deseja descartar suas mudanças?</string>
<string name="keep_editing">Continuar editando</string>
<string name="DLG_delete_this_task_question">Excluir esta tarefa?</string>

@ -23,6 +23,7 @@
<string name="DLG_error_sdcard">Não é possível aceder à pasta: %s</string>
<string name="DLG_error_sdcard_general">Não é possível aceder ao seu cartão SD!</string>
<string name="read_permission_label">Permissões do Tasks</string>
<string name="write_permission_label">Permissões do Tasks</string>
<string name="discard_confirmation">Tem a certeza que deseja descartar as alterações?</string>
<string name="keep_editing">Continuar a editar</string>
<string name="DLG_delete_this_task_question">Remover esta tarefa?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Нет доступа к папке:%s</string>
<string name="DLG_error_sdcard_general">Нет доступа к карте памяти!</string>
<string name="read_permission_label">Разрешения Tasks</string>
<string name="write_permission_label">Разрешения Tasks</string>
<string name="discard_confirmation">Вы действительно хотите отказаться от сделанных изменений?</string>
<string name="keep_editing">Продолжить редактировать</string>
<string name="DLG_delete_this_task_question">Удалить эту задачу?</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Chyba v prístupe do priečinka. %s</string>
<string name="DLG_error_sdcard_general">Chyba v prístupe k SD karte!</string>
<string name="read_permission_label">Povolenia Úloh</string>
<string name="write_permission_label">Tasks povolenia</string>
<string name="discard_confirmation">Naozaj nechceš uložiť zmeny?</string>
<string name="keep_editing">Pokračuj v úpravách</string>
<string name="DLG_delete_this_task_question">Vymazať túto úlohu?</string>

@ -22,6 +22,7 @@
<string name="DLG_error_sdcard">Datoteka:%s ni dostopna</string>
<string name="DLG_error_sdcard_general">Tvoja SD kartica ni dostopna.</string>
<string name="read_permission_label">Dovoljenje Opravkom</string>
<string name="write_permission_label">Dovoljenje Opravkom</string>
<string name="DLG_delete_this_task_question">Zbrišem ta opravek?</string>
<string name="DLG_hour_minutes">Čas (ure : minute)</string>
<string name="DLG_undo">Razveljavi</string>

@ -21,6 +21,7 @@
<string name="DLG_error_sdcard">Mappåtkomst nekad: %s</string>
<string name="DLG_error_sdcard_general">SD-kort ej tillgängligt!</string>
<string name="read_permission_label">Tasks Tillstånd</string>
<string name="write_permission_label">Tasks Tillstånd</string>
<string name="discard_confirmation">Är du säker på att du inte vill spara dina ändringar?</string>
<string name="keep_editing">Fortsätt redigera</string>
<string name="DLG_delete_this_task_question">Radera denna uppgift?</string>

@ -25,6 +25,7 @@
<string name="DLG_error_sdcard">%s dizinine erişilemedi.</string>
<string name="DLG_error_sdcard_general">Bellek kartınıza erişilemiyor!</string>
<string name="read_permission_label">Tasks İzni</string>
<string name="write_permission_label">Tasks İzni</string>
<string name="discard_confirmation">Değişikliklerinizi gözden çıkarmak istediğinize emin misiniz?</string>
<string name="keep_editing">Düzenlemeyi sürdür</string>
<string name="DLG_delete_this_task_question">Bu görev silinsin mi?</string>

@ -24,6 +24,7 @@
<string name="DLG_error_sdcard">Немає доступу до папки: %s</string>
<string name="DLG_error_sdcard_general">Немає доступу до карти SD!</string>
<string name="read_permission_label">Дозволи Tasks</string>
<string name="write_permission_label">Дозволи Tasks</string>
<string name="discard_confirmation">Дійсно хочете скасувати ваші зміни?</string>
<string name="keep_editing">Продовжити редагування</string>
<string name="DLG_delete_this_task_question">Видалити цю задачу?</string>

@ -22,6 +22,7 @@
<string name="DLG_error_sdcard_general">无法访问您的 SD 卡!</string>
<string name="read_permission_label">清单小助理权限</string>
<string name="discard_confirmation">确定放弃你的改变吗?</string>
<string name="write_permission_label">清单小助理权限</string>
<string name="keep_editing">继续编辑</string>
<string name="DLG_delete_this_task_question">确认删除?</string>
<string name="DLG_hour_minutes">时间(小时:分钟)</string>

@ -19,6 +19,7 @@
<string name="DLG_error_sdcard">無法開啟資料夾: %s</string>
<string name="DLG_error_sdcard_general">無法存取您的SD卡!</string>
<string name="read_permission_label">Tasks 權限</string>
<string name="write_permission_label">Tasks 權限</string>
<string name="DLG_delete_this_task_question">確認刪除?</string>
<string name="DLG_hour_minutes">時間 (小時:分鐘)</string>
<string name="DLG_undo">撤消</string>

@ -13,6 +13,7 @@
<string name="p_date_shortcut_evening">date_shortcut_evening</string>
<string name="p_date_shortcut_night">date_shortcut_night</string>
<string name="write_permission_desc">create new tasks, edit existing tasks</string>
<string name="read_permission_desc">read tasks, display task filters</string>
<!-- ======================================================== REMINDERS == -->
@ -232,6 +233,7 @@
<string name="tracking_category_error">Error</string>
<string name="tracking_category_tasker">Tasker</string>
<string name="tracking_category_backup">Backup</string>
<string name="tracking_category_api">API</string>
<string name="tracking_action_add">Add</string>
<string name="tracking_action_start">Start</string>
<string name="tracking_action_move">Move</string>
@ -249,6 +251,7 @@
<string name="tracking_action_import_xml">Import XML</string>
<string name="tracking_action_import_json">Import JSON</string>
<string name="tracking_action_export">Export</string>
<string name="tracking_action_api_astrid3">3</string>
<string name="tracking_event_night_mode_mismatch">Night Mismatch</string>
<string name="tracking_event_play_services_error">Play Services Error</string>

@ -57,6 +57,9 @@ File %1$s contained %2$s.\n\n
<!-- permission title for READ_TASKS -->
<string name="read_permission_label">Tasks Permission</string>
<!-- permission title for READ_TASKS -->
<string name="write_permission_label">Tasks Permission</string>
<!-- ================================================== Generic Dialogs == -->
<string name="discard_confirmation">Are you sure you want to discard your changes?</string>

Loading…
Cancel
Save