Added new location row to edit screen

pull/757/head
Alex Baker 6 years ago
parent b9ea0bc72c
commit 1311db836f

@ -0,0 +1,952 @@
{
"formatVersion": 1,
"database": {
"version": 60,
"identityHash": "0b9d9a7ffbdad49c41ce8b4cf1720747",
"entities": [
{
"tableName": "notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `type` INTEGER NOT NULL, `location` INTEGER)",
"fields": [
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "taskId",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "location",
"columnName": "location",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"uid"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_notification_task",
"unique": true,
"columnNames": [
"task"
],
"createSql": "CREATE UNIQUE INDEX `index_notification_task` ON `${TABLE_NAME}` (`task`)"
}
],
"foreignKeys": []
},
{
"tableName": "tagdata",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `name` TEXT, `color` INTEGER, `tagOrdering` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "tagOrdering",
"columnName": "tagOrdering",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "userActivity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `message` TEXT, `picture` TEXT, `target_id` TEXT, `created_at` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "picture",
"columnName": "picture",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "targetId",
"columnName": "target_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created_at",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "task_attachments",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `task_id` TEXT, `name` TEXT, `path` TEXT, `content_type` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskId",
"columnName": "task_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "contentType",
"columnName": "content_type",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "task_list_metadata",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "tagUuid",
"columnName": "tag_uuid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "filter",
"columnName": "filter",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskIds",
"columnName": "task_ids",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `importance` INTEGER, `dueDate` INTEGER, `hideUntil` INTEGER, `created` INTEGER, `modified` INTEGER, `completed` INTEGER, `deleted` INTEGER, `notes` TEXT, `estimatedSeconds` INTEGER, `elapsedSeconds` INTEGER, `timerStart` INTEGER, `notificationFlags` INTEGER, `notifications` INTEGER, `lastNotified` INTEGER, `snoozeTime` INTEGER, `recurrence` TEXT, `repeatUntil` INTEGER, `calendarUri` TEXT, `remoteId` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "priority",
"columnName": "importance",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "dueDate",
"columnName": "dueDate",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "hideUntil",
"columnName": "hideUntil",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "modified",
"columnName": "modified",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "completed",
"columnName": "completed",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notes",
"columnName": "notes",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "estimatedSeconds",
"columnName": "estimatedSeconds",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "elapsedSeconds",
"columnName": "elapsedSeconds",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "timerStart",
"columnName": "timerStart",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notificationFlags",
"columnName": "notificationFlags",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notifications",
"columnName": "notifications",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastNotified",
"columnName": "lastNotified",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "snoozeTime",
"columnName": "snoozeTime",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "recurrence",
"columnName": "recurrence",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "repeatUntil",
"columnName": "repeatUntil",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "calendarUri",
"columnName": "calendarUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "t_rid",
"unique": true,
"columnNames": [
"remoteId"
],
"createSql": "CREATE UNIQUE INDEX `t_rid` ON `${TABLE_NAME}` (`remoteId`)"
}
],
"foreignKeys": []
},
{
"tableName": "alarms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `time` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `address` TEXT, `phone` TEXT, `url` TEXT, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `radius` INTEGER NOT NULL, `arrival` INTEGER NOT NULL, `departure` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "address",
"columnName": "address",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "phone",
"columnName": "phone",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "latitude",
"columnName": "latitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "longitude",
"columnName": "longitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "radius",
"columnName": "radius",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "arrival",
"columnName": "arrival",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "departure",
"columnName": "departure",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "tags",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `tag_uid` TEXT, `task_uid` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "tagUid",
"columnName": "tag_uid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskUid",
"columnName": "task_uid",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "google_tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `remote_id` TEXT, `list_id` TEXT, `parent` INTEGER NOT NULL, `indent` INTEGER NOT NULL, `order` INTEGER NOT NULL, `remote_order` INTEGER NOT NULL, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteId",
"columnName": "remote_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "listId",
"columnName": "list_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "parent",
"columnName": "parent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "indent",
"columnName": "indent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "order",
"columnName": "order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteOrder",
"columnName": "remote_order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastSync",
"columnName": "last_sync",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "filters",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `sql` TEXT, `values` TEXT, `criterion` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "sql",
"columnName": "sql",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "values",
"columnName": "values",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "criterion",
"columnName": "criterion",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "google_task_lists",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` TEXT, `remote_id` TEXT, `title` TEXT, `remote_order` INTEGER NOT NULL, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `color` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "account",
"columnName": "account",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remote_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "remoteOrder",
"columnName": "remote_order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastSync",
"columnName": "last_sync",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "caldav_calendar",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` TEXT, `uuid` TEXT, `name` TEXT, `color` INTEGER NOT NULL, `ctag` TEXT, `url` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "account",
"columnName": "account",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ctag",
"columnName": "ctag",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "caldav_tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `calendar` TEXT, `object` TEXT, `remote_id` TEXT, `etag` TEXT, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `vtodo` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "calendar",
"columnName": "calendar",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "object",
"columnName": "object",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remote_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "etag",
"columnName": "etag",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastSync",
"columnName": "last_sync",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "vtodo",
"columnName": "vtodo",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "caldav_account",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uuid` TEXT, `name` TEXT, `url` TEXT, `username` TEXT, `password` TEXT, `error` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "google_task_accounts",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` TEXT, `error` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "account",
"columnName": "account",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"0b9d9a7ffbdad49c41ce8b4cf1720747\")"
]
}
}

@ -1,6 +1,7 @@
package org.tasks.location;
import static com.google.android.gms.location.Geofence.NEVER_EXPIRE;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.singletonList;
@ -11,6 +12,7 @@ import android.content.Context;
import android.content.Intent;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.common.collect.Lists;
@ -47,27 +49,32 @@ public class GeofenceApi {
newClient(
client -> {
@SuppressWarnings("ResourceType")
@SuppressLint("MissingPermission")
PendingResult<Status> result =
LocationServices.GeofencingApi.addGeofences(
client,
getRequests(locations),
PendingIntent.getBroadcast(
context,
0,
new Intent(context, GeofenceTransitionsIntentService.Broadcast.class),
PendingIntent.FLAG_UPDATE_CURRENT));
result.setResultCallback(
status -> {
if (status.isSuccess()) {
Timber.i("Registered %s", locations);
} else {
Timber.e("Failed to register %s", locations);
}
client.disconnect();
});
List<Geofence> requests = getRequests(locations);
if (requests.isEmpty()) {
client.disconnect();
} else {
@SuppressWarnings("ResourceType")
@SuppressLint("MissingPermission")
PendingResult<Status> result =
LocationServices.GeofencingApi.addGeofences(
client,
requests,
PendingIntent.getBroadcast(
context,
0,
new Intent(context, GeofenceTransitionsIntentService.Broadcast.class),
PendingIntent.FLAG_UPDATE_CURRENT));
result.setResultCallback(
status -> {
if (status.isSuccess()) {
Timber.i("Registered %s", locations);
} else {
Timber.e("Failed to register %s", locations);
}
client.disconnect();
});
}
});
}
@ -102,7 +109,9 @@ public class GeofenceApi {
}
private List<com.google.android.gms.location.Geofence> getRequests(List<Location> locations) {
return newArrayList(transform(locations, this::toGoogleGeofence));
return newArrayList(
transform(
filter(locations, l -> l.isArrival() || l.isDeparture()), this::toGoogleGeofence));
}
private com.google.android.gms.location.Geofence toGoogleGeofence(Location location) {
@ -111,11 +120,18 @@ public class GeofenceApi {
(int)
TimeUnit.SECONDS.toMillis(
preferences.getIntegerFromString(R.string.p_geofence_responsiveness, 60));
int transitionTypes = 0;
if (location.isArrival()) {
transitionTypes |= GeofencingRequest.INITIAL_TRIGGER_ENTER;
}
if (location.isDeparture()) {
transitionTypes |= GeofencingRequest.INITIAL_TRIGGER_EXIT;
}
return new com.google.android.gms.location.Geofence.Builder()
.setCircularRegion(location.getLatitude(), location.getLongitude(), radius)
.setNotificationResponsiveness(responsiveness)
.setRequestId(Long.toString(location.getId()))
.setTransitionTypes(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.setTransitionTypes(transitionTypes)
.setExpirationDuration(NEVER_EXPIRE)
.build();
}

@ -1,11 +1,13 @@
package org.tasks.location;
import static com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER;
import static com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_EXIT;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import androidx.core.app.JobIntentService;
import com.google.android.gms.location.GeofencingEvent;
import com.todoroo.astrid.reminders.ReminderService;
import java.util.List;
import javax.inject.Inject;
import org.tasks.Notifier;
@ -33,9 +35,9 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
List<com.google.android.gms.location.Geofence> triggeringGeofences =
geofencingEvent.getTriggeringGeofences();
Timber.i("Received geofence transition: %s, %s", transitionType, triggeringGeofences);
if (transitionType == com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER) {
if (transitionType == GEOFENCE_TRANSITION_ENTER || transitionType == GEOFENCE_TRANSITION_EXIT) {
for (com.google.android.gms.location.Geofence triggerGeofence : triggeringGeofences) {
triggerNotification(triggerGeofence);
triggerNotification(triggerGeofence, transitionType == GEOFENCE_TRANSITION_ENTER);
}
} else {
Timber.w("invalid geofence transition type: %s", transitionType);
@ -47,11 +49,12 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
component.inject(this);
}
private void triggerNotification(com.google.android.gms.location.Geofence triggeringGeofence) {
private void triggerNotification(
com.google.android.gms.location.Geofence triggeringGeofence, boolean arrival) {
String requestId = triggeringGeofence.getRequestId();
try {
Location location = locationDao.getGeofence(Long.parseLong(requestId));
notifier.triggerTaskNotification(location.getTask(), ReminderService.TYPE_ALARM);
notifier.triggerTaskNotification(location, arrival);
} catch (Exception e) {
Timber.e(e, "Error triggering geofence %s: %s", requestId, e.getMessage());
}

@ -3,6 +3,7 @@ package org.tasks.location;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
@ -37,6 +38,18 @@ public class PlacePicker {
LatLng latLng = place.getLatLng();
Location location = new Location();
location.setName(place.getName().toString());
CharSequence address = place.getAddress();
if (address != null) {
location.setAddress(place.getAddress().toString());
}
CharSequence phoneNumber = place.getPhoneNumber();
if (phoneNumber != null) {
location.setPhone(phoneNumber.toString());
}
Uri uri = place.getWebsiteUri();
if (uri != null) {
location.setUrl(uri.toString());
}
location.setLatitude(latLng.latitude);
location.setLongitude(latLng.longitude);
location.setRadius(preferences.getIntegerFromString(R.string.p_geofence_radius, 250));

@ -31,7 +31,7 @@ import org.tasks.ui.MenuColorizer;
public class BeastModePreferences extends ThemedInjectingAppCompatActivity
implements Toolbar.OnMenuItemClickListener {
private static final String BEAST_MODE_ORDER_PREF = "beast_mode_order_v3"; // $NON-NLS-1$
private static final String BEAST_MODE_ORDER_PREF = "beast_mode_order_v4"; // $NON-NLS-1$
private static final String BEAST_MODE_PREF_ITEM_SEPARATOR = ";";
@BindView(R.id.toolbar)

@ -27,6 +27,7 @@ import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingPreferenceActivity;
import org.tasks.preferences.ActivityPermissionRequestor;
import org.tasks.preferences.DefaultFilterProvider;
import org.tasks.preferences.Device;
import org.tasks.preferences.PermissionRequestor;
import org.tasks.preferences.Preferences;
import org.tasks.sync.SyncAdapters;
@ -67,18 +68,17 @@ public class DefaultsPreferences extends InjectingPreferenceActivity
? getString(R.string.dont_add_to_calendar)
: defaultCalendarName);
if (syncAdapters.isSyncEnabled()) {
findPreference(R.string.p_default_remote_list)
.setOnPreferenceClickListener(
preference -> {
newRemoteListNativePicker(defaultFilterProvider.getDefaultRemoteList())
.show(getFragmentManager(), FRAG_TAG_REMOTE_LIST_SELECTION);
return false;
});
updateRemoteListSummary();
} else {
remove(R.string.p_default_remote_list);
}
findPreference(R.string.p_default_remote_list)
.setOnPreferenceClickListener(
preference -> {
newRemoteListNativePicker(defaultFilterProvider.getDefaultRemoteList())
.show(getFragmentManager(), FRAG_TAG_REMOTE_LIST_SELECTION);
return false;
});
updateRemoteListSummary();
requires(syncAdapters.isSyncEnabled(), R.string.p_default_remote_list);
requires(Device.SupportsLocationServices(this), R.string.p_default_location_reminder_key);
}
private void startCalendarSelectionActivity() {

@ -60,7 +60,7 @@ import timber.log.Timber;
CaldavAccount.class,
GoogleTaskAccount.class
},
version = 59)
version = 60)
public abstract class Database extends RoomDatabase {
public static final String NAME = "database";

@ -20,16 +20,13 @@ import org.tasks.time.DateTime;
@ApplicationScope
public final class ReminderService {
/** flag for due date reminder */
public static final int TYPE_DUE = 0;
/** flag for overdue reminder */
public static final int TYPE_OVERDUE = 1;
/** flag for random reminder */
public static final int TYPE_RANDOM = 2;
/** flag for a snoozed reminder */
public static final int TYPE_SNOOZE = 3;
/** flag for an alarm reminder */
public static final int TYPE_ALARM = 4;
public static final int TYPE_GEOFENCE_ENTER = 5;
public static final int TYPE_GEOFENCE_EXIT = 6;
private static final long NO_ALARM = Long.MAX_VALUE;

@ -5,22 +5,17 @@
*/
package com.todoroo.astrid.ui;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
import static com.google.common.collect.Sets.newHashSet;
import static com.todoroo.andlib.utility.DateUtilities.getLongDateStringWithTime;
import static com.todoroo.astrid.data.Task.NO_ID;
import static java.util.Collections.emptyList;
import static org.tasks.PermissionUtil.verifyPermissions;
import static org.tasks.date.DateTimeUtils.newDateTime;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@ -29,6 +24,7 @@ import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.Nullable;
import butterknife.BindView;
import butterknife.OnClick;
import butterknife.OnItemSelected;
@ -46,15 +42,8 @@ import org.tasks.R;
import org.tasks.activities.DateAndTimePickerActivity;
import org.tasks.activities.TimePickerActivity;
import org.tasks.data.Alarm;
import org.tasks.data.Location;
import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent;
import org.tasks.location.GeofenceService;
import org.tasks.location.PlacePicker;
import org.tasks.preferences.Device;
import org.tasks.preferences.FragmentPermissionRequestor;
import org.tasks.preferences.PermissionRequestor;
import org.tasks.preferences.Preferences;
import org.tasks.ui.HiddenTopArrayAdapter;
import org.tasks.ui.TaskEditControlFragment;
@ -68,20 +57,13 @@ public class ReminderControlSet extends TaskEditControlFragment {
public static final int TAG = R.string.TEA_ctrl_reminders_pref;
private static final int REQUEST_NEW_ALARM = 12152;
private static final int REQUEST_LOCATION_REMINDER = 12153;
private static final String EXTRA_FLAGS = "extra_flags";
private static final String EXTRA_RANDOM_REMINDER = "extra_random_reminder";
private static final String EXTRA_ALARMS = "extra_alarms";
private static final String EXTRA_GEOFENCES = "extra_geofences";
private final List<String> spinnerOptions = new ArrayList<>();
private final Set<Long> alarms = new LinkedHashSet<>();
private final Set<Location> locations = new LinkedHashSet<>();
@Inject AlarmService alarmService;
@Inject GeofenceService geofenceService;
@Inject FragmentPermissionRequestor permissionRequestor;
@Inject Device device;
@Inject Preferences preferences;
@Inject @ForActivity Context context;
@BindView(R.id.alert_container)
@ -125,16 +107,11 @@ public class ReminderControlSet extends TaskEditControlFragment {
if (savedInstanceState == null) {
flags = task.getReminderFlags();
randomReminder = task.getReminderPeriod();
setup(currentAlarms(), geofenceService.getGeofences(taskId));
setup(currentAlarms());
} else {
flags = savedInstanceState.getInt(EXTRA_FLAGS);
randomReminder = savedInstanceState.getLong(EXTRA_RANDOM_REMINDER);
List<Location> locations = new ArrayList<>();
List<Parcelable> geofenceArray = savedInstanceState.getParcelableArrayList(EXTRA_GEOFENCES);
for (Parcelable geofence : geofenceArray) {
locations.add((Location) geofence);
}
setup(Longs.asList(savedInstanceState.getLongArray(EXTRA_ALARMS)), locations);
setup(Longs.asList(savedInstanceState.getLongArray(EXTRA_ALARMS)));
}
addSpinner.setAdapter(remindAdapter);
@ -159,10 +136,6 @@ public class ReminderControlSet extends TaskEditControlFragment {
addRandomReminder(TimeUnit.DAYS.toMillis(14));
} else if (selected.equals(getString(R.string.pick_a_date_and_time))) {
addNewAlarm();
} else if (selected.equals(getString(R.string.pick_a_location))) {
if (permissionRequestor.requestFineLocation()) {
pickLocation();
}
}
if (position != 0) {
updateSpinner();
@ -193,7 +166,7 @@ public class ReminderControlSet extends TaskEditControlFragment {
return TAG;
}
private void setup(List<Long> alarms, List<Location> locations) {
private void setup(List<Long> alarms) {
setValue(flags);
alertContainer.removeAllViews();
@ -209,9 +182,6 @@ public class ReminderControlSet extends TaskEditControlFragment {
for (long timestamp : alarms) {
addAlarmRow(timestamp);
}
for (Location location : locations) {
addGeolocationReminder(location);
}
updateSpinner();
}
@ -219,8 +189,7 @@ public class ReminderControlSet extends TaskEditControlFragment {
public boolean hasChanges(Task original) {
return getFlags() != original.getReminderFlags()
|| getRandomReminderPeriod() != original.getReminderPeriod()
|| !newHashSet(currentAlarms()).equals(alarms)
|| !newHashSet(geofenceService.getGeofences(taskId)).equals(locations);
|| !newHashSet(currentAlarms()).equals(alarms);
}
@Override
@ -232,9 +201,6 @@ public class ReminderControlSet extends TaskEditControlFragment {
if (alarmService.synchronizeAlarms(task.getId(), alarms)) {
task.setModificationDate(DateUtilities.now());
}
if (geofenceService.synchronizeGeofences(task.getId(), locations)) {
task.setModificationDate(DateUtilities.now());
}
}
@Override
@ -244,7 +210,6 @@ public class ReminderControlSet extends TaskEditControlFragment {
outState.putInt(EXTRA_FLAGS, getFlags());
outState.putLong(EXTRA_RANDOM_REMINDER, getRandomReminderPeriod());
outState.putLongArray(EXTRA_ALARMS, Longs.toArray(alarms));
outState.putParcelableArrayList(EXTRA_GEOFENCES, newArrayList(locations));
}
@Override
@ -253,44 +218,16 @@ public class ReminderControlSet extends TaskEditControlFragment {
if (resultCode == Activity.RESULT_OK) {
addAlarmRow(data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L));
}
} else if (requestCode == REQUEST_LOCATION_REMINDER) {
if (resultCode == Activity.RESULT_OK) {
addGeolocationReminder(PlacePicker.getPlace(context, data, preferences));
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == PermissionRequestor.REQUEST_LOCATION) {
if (verifyPermissions(grantResults)) {
pickLocation();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void addAlarmRow(final Long timestamp) {
addAlarmRow(getLongDateStringWithTime(context, timestamp), v -> alarms.remove(timestamp));
alarms.add(timestamp);
}
private void pickLocation() {
Intent intent = PlacePicker.getIntent(getActivity());
if (intent != null) {
startActivityForResult(intent, REQUEST_LOCATION_REMINDER);
}
}
private void addGeolocationReminder(final Location location) {
addAlarmRow(location.getName(), v -> locations.remove(location));
locations.add(location);
}
private int getFlags() {
int value = 0;
if (whenDue) {
@ -357,9 +294,6 @@ public class ReminderControlSet extends TaskEditControlFragment {
if (randomControlSet == null) {
spinnerOptions.add(getString(R.string.randomly));
}
if (device.supportsLocationServices()) {
spinnerOptions.add(getString(R.string.pick_a_location));
}
spinnerOptions.add(getString(R.string.pick_a_date_and_time));
remindAdapter.notifyDataSetChanged();
}

@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import org.tasks.data.Location;
import org.tasks.injection.ForApplication;
import org.tasks.jobs.NotificationQueueEntry;
import org.tasks.notifications.AudioManager;
@ -103,11 +104,13 @@ public class Notifier {
notificationManager.notify(filter.listingTitle.hashCode(), builder, true, false, false);
}
public void triggerTaskNotification(long id, int type) {
public void triggerTaskNotification(Location location, boolean arrival) {
org.tasks.notifications.Notification notification = new org.tasks.notifications.Notification();
notification.taskId = id;
notification.type = type;
notification.taskId = location.getTask();
notification.type =
arrival ? ReminderService.TYPE_GEOFENCE_ENTER : ReminderService.TYPE_GEOFENCE_EXIT;
notification.timestamp = currentTimeMillis();
notification.location = location.getId();
triggerNotifications(Collections.singletonList(notification), true);
}

@ -1,17 +1,23 @@
package org.tasks.data;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.common.base.Strings;
import java.io.Serializable;
import java.util.regex.Pattern;
import org.tasks.backup.XmlReader;
@Entity(tableName = "locations")
public class Location implements Serializable, Parcelable {
private static final Pattern COORDS =
Pattern.compile("^\\d+°\\d+'\\d+\\.\\d+\"[NS] \\d+°\\d+'\\d+\\.\\d+\"[EW]$");
public static final Parcelable.Creator<Location> CREATOR =
new Parcelable.Creator<Location>() {
@Override
@ -35,6 +41,15 @@ public class Location implements Serializable, Parcelable {
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "address")
private String address;
@ColumnInfo(name = "phone")
private String phone;
@ColumnInfo(name = "url")
private String url;
@ColumnInfo(name = "latitude")
private double latitude;
@ -44,16 +59,42 @@ public class Location implements Serializable, Parcelable {
@ColumnInfo(name = "radius")
private int radius;
@ColumnInfo(name = "arrival")
private boolean arrival;
@ColumnInfo(name = "departure")
private boolean departure;
public Location() {}
@Ignore
public Location(Location o) {
id = o.id;
task = o.task;
name = o.name;
address = o.address;
phone = o.phone;
url = o.url;
latitude = o.latitude;
longitude = o.longitude;
radius = o.radius;
arrival = o.arrival;
departure = o.departure;
}
@Ignore
public Location(Parcel parcel) {
id = parcel.readLong();
task = parcel.readLong();
name = parcel.readString();
address = parcel.readString();
phone = parcel.readString();
url = parcel.readString();
latitude = parcel.readDouble();
longitude = parcel.readDouble();
radius = parcel.readInt();
arrival = parcel.readInt() == 1;
departure = parcel.readInt() == 1;
}
@Ignore
@ -112,12 +153,70 @@ public class Location implements Serializable, Parcelable {
this.radius = radius;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isArrival() {
return arrival;
}
public void setArrival(boolean arrival) {
this.arrival = arrival;
}
public boolean isDeparture() {
return departure;
}
public void setDeparture(boolean departure) {
this.departure = departure;
}
public String getDisplayName() {
if (Strings.isNullOrEmpty(address)) {
return name;
}
if (COORDS.matcher(name).matches()) {
return address;
}
if (address.startsWith(name)) {
return address;
}
return name;
}
public String getGeoUri() {
return String.format("geo:%s,%s?q=%s", latitude, longitude,
Uri.encode(Strings.isNullOrEmpty(address) ? name : address));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if (!(o instanceof Location)) {
return false;
}
@ -138,7 +237,22 @@ public class Location implements Serializable, Parcelable {
if (radius != location.radius) {
return false;
}
return name != null ? name.equals(location.name) : location.name == null;
if (arrival != location.arrival) {
return false;
}
if (departure != location.departure) {
return false;
}
if (name != null ? !name.equals(location.name) : location.name != null) {
return false;
}
if (address != null ? !address.equals(location.address) : location.address != null) {
return false;
}
if (phone != null ? !phone.equals(location.phone) : location.phone != null) {
return false;
}
return url != null ? url.equals(location.url) : location.url == null;
}
@Override
@ -148,11 +262,16 @@ public class Location implements Serializable, Parcelable {
result = (int) (id ^ (id >>> 32));
result = 31 * result + (int) (task ^ (task >>> 32));
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (address != null ? address.hashCode() : 0);
result = 31 * result + (phone != null ? phone.hashCode() : 0);
result = 31 * result + (url != null ? url.hashCode() : 0);
temp = Double.doubleToLongBits(latitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(longitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + radius;
result = 31 * result + (arrival ? 1 : 0);
result = 31 * result + (departure ? 1 : 0);
return result;
}
@ -166,12 +285,25 @@ public class Location implements Serializable, Parcelable {
+ ", name='"
+ name
+ '\''
+ ", address='"
+ address
+ '\''
+ ", phone='"
+ phone
+ '\''
+ ", url='"
+ url
+ '\''
+ ", latitude="
+ latitude
+ ", longitude="
+ longitude
+ ", radius="
+ radius
+ ", arrival="
+ arrival
+ ", departure="
+ departure
+ '}';
}
@ -185,8 +317,13 @@ public class Location implements Serializable, Parcelable {
out.writeLong(id);
out.writeLong(task);
out.writeString(name);
out.writeString(address);
out.writeString(phone);
out.writeString(url);
out.writeDouble(latitude);
out.writeDouble(longitude);
out.writeInt(radius);
out.writeInt(arrival ? 1 : 0);
out.writeInt(departure ? 1 : 0);
}
}

@ -1,9 +1,9 @@
package org.tasks.db;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.room.migration.Migration;
import android.database.sqlite.SQLiteException;
import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import timber.log.Timber;
public class Migrations {
@ -203,6 +203,19 @@ public class Migrations {
}
};
private static final Migration MIGRATION_59_60 =
new Migration(59, 60) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE `locations` ADD COLUMN `address` TEXT");
database.execSQL("ALTER TABLE `locations` ADD COLUMN `phone` TEXT");
database.execSQL("ALTER TABLE `locations` ADD COLUMN `url` TEXT");
database.execSQL("ALTER TABLE `locations` ADD COLUMN `arrival` INTEGER DEFAULT 1 NOT NULL");
database.execSQL("ALTER TABLE `locations` ADD COLUMN `departure` INTEGER DEFAULT 0 NOT NULL");
database.execSQL("ALTER TABLE `notification` ADD COLUMN `location` INTEGER");
}
};
public static final Migration[] MIGRATIONS =
new Migration[] {
MIGRATION_35_36,
@ -219,7 +232,8 @@ public class Migrations {
MIGRATION_52_53,
MIGRATION_53_54,
MIGRATION_54_58,
MIGRATION_58_59
MIGRATION_58_59,
MIGRATION_59_60
};
private static Migration NOOP(int from, int to) {

@ -145,4 +145,9 @@ public class AlertDialogBuilder {
locale.applyDirectionality(dialog);
return dialog;
}
public AlertDialogBuilder setCancelable(boolean cancelable) {
builder.setCancelable(cancelable);
return this;
}
}

@ -0,0 +1,147 @@
package org.tasks.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.google.common.base.Strings;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.data.Location;
import org.tasks.injection.DialogFragmentComponent;
import org.tasks.injection.ForActivity;
import org.tasks.injection.InjectingDialogFragment;
public class LocationDialog extends InjectingDialogFragment {
public static final String EXTRA_LOCATION = "extra_location";
public static final String EXTRA_ORIGINAL = "extra_original";
@Inject DialogBuilder dialogBuilder;
@Inject @ForActivity Context context;
@BindView(R.id.location_arrival)
Switch arrivalView;
@BindView(R.id.location_departure)
Switch departureView;
@BindView(R.id.location_call)
TextView callView;
@BindView(R.id.location_url)
TextView urlView;
public static LocationDialog newLocationDialog(Location location) {
LocationDialog dialog = new LocationDialog();
Bundle args = new Bundle();
args.putParcelable(EXTRA_ORIGINAL, location);
dialog.setArguments(args);
return dialog;
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
Location location =
savedInstanceState == null
? getOriginal()
: savedInstanceState.getParcelable(EXTRA_LOCATION);
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.location_details, null);
ButterKnife.bind(this, view);
arrivalView.setChecked(location.isArrival());
departureView.setChecked(location.isDeparture());
String phone = location.getPhone();
if (!Strings.isNullOrEmpty(phone)) {
callView.setVisibility(View.VISIBLE);
callView.setText(getString(R.string.call_number, phone));
}
String url = location.getUrl();
if (!Strings.isNullOrEmpty(url)) {
urlView.setVisibility(View.VISIBLE);
urlView.setText(getString(R.string.open_url, url));
}
return dialogBuilder
.newDialog()
.setTitle(location.getDisplayName())
.setView(view)
.setNegativeButton(android.R.string.cancel, null)
.setOnCancelListener(this::sendResult)
.setPositiveButton(android.R.string.ok, this::sendResult)
.setNeutralButton(R.string.delete, this::delete)
.create();
}
@Override
public void onCancel(DialogInterface dialog) {
sendResult(dialog);
}
private Location toLocation() {
Location result = getOriginal();
result.setArrival(arrivalView.isChecked());
result.setDeparture(departureView.isChecked());
return result;
}
private Location getOriginal() {
return new Location(getArguments().<Location>getParcelable(EXTRA_ORIGINAL));
}
private void sendResult(DialogInterface d, int... i) {
sendResult(toLocation());
}
private void delete(DialogInterface d, int i) {
sendResult(null);
}
private void sendResult(Location result) {
Intent data = new Intent();
data.putExtra(EXTRA_ORIGINAL, (Parcelable) getOriginal());
data.putExtra(EXTRA_LOCATION, (Parcelable) result);
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, data);
dismiss();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(EXTRA_LOCATION, toLocation());
}
@OnClick(R.id.location_url)
void openUrl() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(getOriginal().getUrl()));
startActivity(intent);
}
@OnClick(R.id.location_call)
void openDialer() {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + getOriginal().getPhone()));
startActivity(intent);
}
@Override
protected void inject(DialogFragmentComponent component) {
component.inject(this);
}
}

@ -1,6 +1,6 @@
package org.tasks.fragments;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import androidx.fragment.app.FragmentManager;
import com.todoroo.astrid.activity.BeastModePreferences;
@ -12,6 +12,7 @@ import com.todoroo.astrid.tags.TagsControlSet;
import com.todoroo.astrid.timers.TimerControlSet;
import com.todoroo.astrid.ui.EditTitleControlSet;
import com.todoroo.astrid.ui.HideUntilControlSet;
import org.tasks.ui.LocationControlSet;
import com.todoroo.astrid.ui.ReminderControlSet;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@ -19,6 +20,7 @@ import java.util.List;
import java.util.Map;
import org.tasks.BuildConfig;
import org.tasks.R;
import org.tasks.preferences.Device;
import org.tasks.preferences.Preferences;
import org.tasks.sync.SyncAdapters;
import org.tasks.ui.CalendarControlSet;
@ -44,7 +46,8 @@ public class TaskEditControlSetFragmentManager {
R.id.row_8,
R.id.row_9,
R.id.row_10,
R.id.row_11
R.id.row_11,
R.id.row_12
};
private static final int[] TASK_EDIT_CONTROL_SET_FRAGMENTS =
@ -57,6 +60,7 @@ public class TaskEditControlSetFragmentManager {
PriorityControlSet.TAG,
HideUntilControlSet.TAG,
ReminderControlSet.TAG,
LocationControlSet.TAG,
FilesControlSet.TAG,
TagsControlSet.TAG,
RepeatControlSet.TAG,
@ -73,17 +77,19 @@ public class TaskEditControlSetFragmentManager {
}
private final Map<String, Integer> controlSetFragments = new LinkedHashMap<>();
private final Context context;
private final List<String> displayOrder;
private final SyncAdapters syncAdapters;
private int numRows;
public TaskEditControlSetFragmentManager(
Activity activity, Preferences preferences, SyncAdapters syncAdapters) {
Context context, Preferences preferences, SyncAdapters syncAdapters) {
this.context = context;
this.syncAdapters = syncAdapters;
displayOrder = BeastModePreferences.constructOrderedControlList(preferences, activity);
displayOrder.add(0, activity.getString(EditTitleControlSet.TAG));
displayOrder.add(1, activity.getString(CommentBarFragment.TAG));
String hideAlwaysTrigger = activity.getString(R.string.TEA_ctrl_hide_section_pref);
displayOrder = BeastModePreferences.constructOrderedControlList(preferences, context);
displayOrder.add(0, context.getString(EditTitleControlSet.TAG));
displayOrder.add(1, context.getString(CommentBarFragment.TAG));
String hideAlwaysTrigger = context.getString(R.string.TEA_ctrl_hide_section_pref);
for (numRows = 0; numRows < displayOrder.size(); numRows++) {
if (displayOrder.get(numRows).equals(hideAlwaysTrigger)) {
break;
@ -91,7 +97,7 @@ public class TaskEditControlSetFragmentManager {
}
for (int resId : TASK_EDIT_CONTROL_SET_FRAGMENTS) {
controlSetFragments.put(activity.getString(resId), resId);
controlSetFragments.put(context.getString(resId), resId);
}
}
@ -147,6 +153,8 @@ public class TaskEditControlSetFragmentManager {
return new HideUntilControlSet();
case ReminderControlSet.TAG:
return new ReminderControlSet();
case LocationControlSet.TAG:
return Device.SupportsLocationServices(context) ? new LocationControlSet() : null;
case FilesControlSet.TAG:
return new FilesControlSet();
case TimerControlSet.TAG:

@ -5,6 +5,7 @@ import org.tasks.activities.CalendarSelectionDialog;
import org.tasks.activities.RemoteListSupportPicker;
import org.tasks.dialogs.AddAttachmentDialog;
import org.tasks.dialogs.ColorPickerDialog;
import org.tasks.dialogs.LocationDialog;
import org.tasks.dialogs.RecordAudioDialog;
import org.tasks.dialogs.SortDialog;
import org.tasks.gtasks.CreateListDialog;
@ -43,4 +44,6 @@ public interface DialogFragmentComponent {
void inject(CustomRecurrenceDialog customRecurrenceDialog);
void inject(BasicRecurrenceDialog basicRecurrenceDialog);
void inject(LocationDialog locationDialog);
}

@ -11,6 +11,7 @@ import com.todoroo.astrid.tags.TagsControlSet;
import com.todoroo.astrid.timers.TimerControlSet;
import com.todoroo.astrid.ui.EditTitleControlSet;
import com.todoroo.astrid.ui.HideUntilControlSet;
import org.tasks.ui.LocationControlSet;
import com.todoroo.astrid.ui.ReminderControlSet;
import dagger.Subcomponent;
import org.tasks.caldav.CaldavListFragment;
@ -70,4 +71,6 @@ public interface FragmentComponent {
void inject(GtasksListFragment gtasksListFragment);
void inject(CaldavListFragment caldavListFragment);
void inject(LocationControlSet locationControlSet);
}

@ -23,6 +23,9 @@ public class Notification {
@ColumnInfo(name = "type")
public int type;
@ColumnInfo(name = "location")
public Long location;
@Override
public String toString() {
return "Notification{"
@ -34,6 +37,8 @@ public class Notification {
+ timestamp
+ ", type="
+ type
+ ", location="
+ location
+ '}';
}
}

@ -8,6 +8,8 @@ import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastNougat;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastOreo;
import static com.todoroo.astrid.reminders.ReminderService.TYPE_GEOFENCE_ENTER;
import static com.todoroo.astrid.reminders.ReminderService.TYPE_GEOFENCE_EXIT;
import android.annotation.TargetApi;
import android.app.Notification;
@ -16,9 +18,9 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.text.TextUtils;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import android.text.TextUtils;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.todoroo.andlib.sql.QueryTemplate;
@ -35,6 +37,8 @@ import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication;
import org.tasks.intents.TaskIntents;
@ -58,6 +62,7 @@ public class NotificationManager {
private static final String GROUP_KEY = "tasks";
private static final int SUMMARY_NOTIFICATION_ID = 0;
private final NotificationManagerCompat notificationManagerCompat;
private final LocationDao locationDao;
private final NotificationDao notificationDao;
private final TaskDao taskDao;
private final Context context;
@ -70,12 +75,14 @@ public class NotificationManager {
Preferences preferences,
NotificationDao notificationDao,
TaskDao taskDao,
CheckBoxes checkBoxes) {
CheckBoxes checkBoxes,
LocationDao locationDao) {
this.context = context;
this.preferences = preferences;
this.notificationDao = notificationDao;
this.taskDao = taskDao;
this.checkBoxes = checkBoxes;
this.locationDao = locationDao;
notificationManagerCompat = NotificationManagerCompat.from(context);
if (atLeastOreo()) {
android.app.NotificationManager notificationManager =
@ -384,11 +391,22 @@ public class NotificationManager {
builder.setContentIntent(
PendingIntent.getActivity(context, (int) id, intent, PendingIntent.FLAG_UPDATE_CURRENT));
if (!Strings.isNullOrEmpty(taskDescription)) {
if (type == TYPE_GEOFENCE_ENTER || type == TYPE_GEOFENCE_EXIT) {
Location location = locationDao.getGeofence(notification.location);
if (location != null) {
builder.setContentText(
context.getString(
type == TYPE_GEOFENCE_ENTER
? R.string.location_arrived
: R.string.location_departed,
location.getDisplayName()));
}
} else if (!Strings.isNullOrEmpty(taskDescription)) {
builder
.setContentText(taskDescription)
.setStyle(new NotificationCompat.BigTextStyle().bigText(taskDescription));
}
Intent completeIntent = new Intent(context, CompleteTaskReceiver.class);
completeIntent.putExtra(CompleteTaskReceiver.TASK_ID, id);
PendingIntent completePendingIntent =

@ -23,6 +23,10 @@ public class Device {
private final Context context;
private final Locale locale;
public static boolean SupportsLocationServices(Context context) {
return context.getResources().getBoolean(R.bool.location_enabled);
}
@Inject
public Device(@ForApplication Context context, Locale locale) {
this.context = context;
@ -44,7 +48,7 @@ public class Device {
}
public boolean supportsLocationServices() {
return context.getResources().getBoolean(R.bool.location_enabled);
return SupportsLocationServices(context);
}
public boolean voiceInputAvailable() {

@ -0,0 +1,236 @@
package org.tasks.ui;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
import static org.tasks.PermissionUtil.verifyPermissions;
import static org.tasks.dialogs.LocationDialog.newLocationDialog;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import butterknife.BindView;
import butterknife.OnClick;
import com.google.common.base.Strings;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.data.Location;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.dialogs.LocationDialog;
import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent;
import org.tasks.location.GeofenceService;
import org.tasks.location.PlacePicker;
import org.tasks.preferences.FragmentPermissionRequestor;
import org.tasks.preferences.PermissionRequestor;
import org.tasks.preferences.Preferences;
import timber.log.Timber;
public class LocationControlSet extends TaskEditControlFragment {
public static final int TAG = R.string.TEA_ctrl_locations_pref;
private static final int REQUEST_LOCATION_REMINDER = 12153;
private static final int REQUEST_LOCATION_DETAILS = 12154;
private static final String FRAG_TAG_LOCATION_DIALOG = "location_dialog";
private static final String EXTRA_GEOFENCES = "extra_geofences";
private final Set<Location> locations = new LinkedHashSet<>();
@Inject GeofenceService geofenceService;
@Inject FragmentPermissionRequestor permissionRequestor;
@Inject Preferences preferences;
@Inject @ForActivity Context context;
@Inject DialogBuilder dialogBuilder;
@BindView(R.id.alert_container)
LinearLayout alertContainer;
private long taskId;
@Nullable
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
taskId = task.getId();
if (savedInstanceState == null) {
setup(geofenceService.getGeofences(taskId));
} else {
List<Location> locations = new ArrayList<>();
List<Parcelable> geofenceArray = savedInstanceState.getParcelableArrayList(EXTRA_GEOFENCES);
for (Parcelable geofence : geofenceArray) {
locations.add((Location) geofence);
}
setup(locations);
}
return view;
}
@OnClick(R.id.alarms_add)
void addAlarm(View view) {
if (permissionRequestor.requestFineLocation()) {
pickLocation();
}
}
@Override
protected int getLayout() {
return R.layout.control_set_locations;
}
@Override
public int getIcon() {
return R.drawable.ic_outline_place_24px;
}
@Override
public int controlId() {
return TAG;
}
private void setup(Iterable<Location> locations) {
alertContainer.removeAllViews();
for (Location location : locations) {
addGeolocationReminder(location);
}
}
@Override
public boolean hasChanges(Task original) {
return !newHashSet(geofenceService.getGeofences(taskId)).equals(locations);
}
@Override
public void apply(Task task) {
if (geofenceService.synchronizeGeofences(task.getId(), locations)) {
task.setModificationDate(DateUtilities.now());
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(EXTRA_GEOFENCES, newArrayList(locations));
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_LOCATION_REMINDER) {
if (resultCode == Activity.RESULT_OK) {
Location place = PlacePicker.getPlace(context, data, preferences);
int defaultReminders =
preferences.getIntegerFromString(R.string.p_default_location_reminder_key, 1);
place.setArrival(defaultReminders == 1 || defaultReminders == 3);
place.setDeparture(defaultReminders == 2 || defaultReminders == 3);
addGeolocationReminder(place);
}
} else if (requestCode == REQUEST_LOCATION_DETAILS) {
if (resultCode == Activity.RESULT_OK) {
Location original = data.getParcelableExtra(LocationDialog.EXTRA_ORIGINAL);
Location location = data.getParcelableExtra(LocationDialog.EXTRA_LOCATION);
Timber.d("original: %s, updated: %s", original, location);
locations.remove(original);
if (location != null) {
locations.add(location);
}
setup(locations);
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == PermissionRequestor.REQUEST_LOCATION) {
if (verifyPermissions(grantResults)) {
pickLocation();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void pickLocation() {
Intent intent = PlacePicker.getIntent(getActivity());
if (intent != null) {
startActivityForResult(intent, REQUEST_LOCATION_REMINDER);
}
}
private void addGeolocationReminder(final Location location) {
addAlarmRow(location);
locations.add(location);
}
private View addAlarmRow(Location location) {
final View alertItem = getActivity().getLayoutInflater().inflate(R.layout.location_row, null);
alertContainer.addView(alertItem);
addAlarmRow(alertItem, location);
return alertItem;
}
private void addAlarmRow(View alertItem, Location location) {
String name = location.getDisplayName();
String address = location.getAddress();
if (!Strings.isNullOrEmpty(address) && !address.equals(name)) {
TextView addressView = alertItem.findViewById(R.id.location_address);
addressView.setText(address);
addressView.setVisibility(View.VISIBLE);
}
SpannableString spannableString = new SpannableString(name);
spannableString.setSpan(
new ClickableSpan() {
@Override
public void onClick(@NonNull View view) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(location.getGeoUri()));
startActivity(intent);
}
},
0,
name.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView nameView = alertItem.findViewById(R.id.location_name);
nameView.setText(spannableString);
nameView.setMovementMethod(LinkMovementMethod.getInstance());
alertItem
.findViewById(R.id.location_more)
.setOnClickListener(
v -> {
LocationDialog dialog = newLocationDialog(location);
dialog.setTargetFragment(this, REQUEST_LOCATION_DETAILS);
dialog.show(getFragmentManager(), FRAG_TAG_LOCATION_DIALOG);
});
}
@Override
protected void inject(FragmentComponent component) {
component.inject(this);
}
}

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

@ -0,0 +1,6 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
<path android:fillColor="#FF000000" android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
</vector>

@ -6,7 +6,7 @@
android:layout_weight="1"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_gravity="center"
android:layout_gravity="top|center"
android:alpha="?attr/alpha_secondary"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?><!--
** Copyright (c) 2012 Todoroo Inc
**
** See the file "LICENSE" for the full license governing this code.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/alert_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<TextView
android:id="@+id/alarms_add"
style="@style/TaskEditTextPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/add_location"/>
</LinearLayout>

@ -86,6 +86,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="@+id/row_12"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/comments"
android:layout_width="match_parent"

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/location_call"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="@dimen/keyline_second"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_second"
android:paddingRight="@dimen/keyline_first"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:text="Call"
android:textAppearance="?attr/textAppearanceListItemSmall"
android:visibility="gone"
tools:ignore="HardcodedText"/>
<TextView
android:id="@+id/location_url"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="@dimen/keyline_second"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_second"
android:paddingRight="@dimen/keyline_first"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="2"
android:singleLine="false"
android:text="Open"
android:textAppearance="?attr/textAppearanceListItem"
android:visibility="gone"
tools:ignore="HardcodedText"/>
<Switch
android:id="@+id/location_arrival"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="@dimen/keyline_second"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_second"
android:paddingRight="@dimen/keyline_first"
android:gravity="center_vertical"
android:text="@string/location_remind_arrival"
android:textAppearance="?attr/textAppearanceListItemSmall"/>
<Switch
android:id="@+id/location_departure"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="@dimen/keyline_second"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_second"
android:paddingRight="@dimen/keyline_first"
android:gravity="center_vertical"
android:text="@string/location_remind_departure"
android:textAppearance="?attr/textAppearanceListItemSmall"/>
</LinearLayout>
</ScrollView>

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/task_edit_double_padding_top_bottom"
android:paddingBottom="@dimen/task_edit_double_padding_top_bottom"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="100"
android:orientation="vertical">
<TextView
android:id="@+id/location_name"
style="@style/TaskEditTextPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/asTextColor"/>
<TextView
android:id="@+id/location_address"
style="@style/TaskEditTextPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/asTextColorHint"
android:visibility="gone"
android:maxLines="1"
android:singleLine="true"
android:ellipsize="end"/>
</LinearLayout>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/location_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_gravity="top|center"
android:alpha="?attr/alpha_secondary"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:src="@drawable/ic_outline_more_vert_24px"
android:tint="?attr/icon_tint"/>
</LinearLayout>

@ -150,7 +150,6 @@
<string name="remove">حذف</string>
<string name="randomly">عشوائياً</string>
<string name="pick_a_date_and_time">اختر تاريخ و وقت</string>
<string name="pick_a_location">أختر الموقع</string>
<string name="filters">تصفيات</string>
<string name="filter_settings">إعدادات التصفية</string>
<string name="show_hidden">عرض المهام المخفية</string>

@ -124,7 +124,6 @@
<string name="day_after_tomorrow">Ден след утрешния</string>
<string name="next_week">Следваща седмица</string>
<string name="dont_hide">Не скривай</string>
<string name="no_deadline_reminder">Няма напомняния за краен срок</string>
<string name="at_deadline">При краен срок</string>
<string name="at_deadline_or_overdue">При крайния срок или просрочване</string>
<string name="BFE_Active">Моите задачи</string>
@ -329,7 +328,6 @@
<string name="pick_a_date">Избери дата</string>
<string name="pick_a_time">Избери време</string>
<string name="pick_a_date_and_time">Избери дата и време</string>
<string name="pick_a_location">Избери местоположение</string>
<string name="when_overdue">След крайния срок</string>
<string name="when_due">При краен срок</string>
<string name="geofence_radius_title">Радиус (метри)</string>

@ -110,7 +110,6 @@
<string name="day_after_tomorrow">Pozítří</string>
<string name="next_week">Příští týden</string>
<string name="dont_hide">Neskrývat</string>
<string name="no_deadline_reminder">Žádné upomínky v termínu</string>
<string name="at_deadline">V termínu</string>
<string name="at_deadline_or_overdue">V termínu nebo po něm</string>
<string name="BFE_Active">Aktivní úkoly</string>

@ -117,7 +117,6 @@
<string name="day_after_tomorrow">Übermorgen</string>
<string name="next_week">Nächste Woche</string>
<string name="dont_hide">Nicht verstecken</string>
<string name="no_deadline_reminder">Keine Fälligkeits-Erinnerungen</string>
<string name="at_deadline">Am Stichtag</string>
<string name="at_deadline_or_overdue">Zur Fälligkeit oder überfällig</string>
<string name="BFE_Active">Meine Aufgaben</string>
@ -321,7 +320,6 @@
<string name="pick_a_date">Datum auswählen</string>
<string name="pick_a_time">Uhrzeit auswählen</string>
<string name="pick_a_date_and_time">Tag und Uhrzeit auswählen</string>
<string name="pick_a_location">Ort auswählen</string>
<string name="when_overdue">Wenn überfällig</string>
<string name="when_due">Wenn fällig</string>
<string name="geofence_radius_title">Radius (Meter)</string>

@ -99,7 +99,6 @@
<string name="day_after_tomorrow">Μεθαύριο</string>
<string name="next_week">Επόμενη εβδομάδα</string>
<string name="dont_hide">Μη απόκρυψη</string>
<string name="no_deadline_reminder">Όχι υπενθυμίσεις προθεσμίας</string>
<string name="at_deadline">Στην προθεσμία</string>
<string name="at_deadline_or_overdue">Στην λήξη η και μετά</string>
<string name="CFA_type_add">ή</string>

@ -120,7 +120,6 @@
<string name="day_after_tomorrow">Pasado mañana</string>
<string name="next_week">Semana siguiente</string>
<string name="dont_hide">No ocultar</string>
<string name="no_deadline_reminder">Sin recordatorios del vencimiento</string>
<string name="at_deadline">En la fecha de vencimiento</string>
<string name="at_deadline_or_overdue">En la fecha de vencimiento o ya vencida</string>
<string name="BFE_Active">Mis Tareas</string>
@ -325,7 +324,6 @@
<string name="pick_a_date">Elegir fecha</string>
<string name="pick_a_time">Elegir hora</string>
<string name="pick_a_date_and_time">Elegir fecha y hora</string>
<string name="pick_a_location">Elegir ubicación</string>
<string name="when_overdue">Si está atrasada</string>
<string name="when_due">Al vencimiento</string>
<string name="geofence_radius_title">Radio (metros)</string>

@ -85,7 +85,6 @@
<string name="day_after_tomorrow">پس فردا</string>
<string name="next_week">هفته بعد</string>
<string name="dont_hide">مخفی نکن</string>
<string name="no_deadline_reminder">بدون یادآور موعود</string>
<string name="at_deadline">روز موعود</string>
<string name="at_deadline_or_overdue">در روز موعد یا پس از موعود</string>
<string name="BFE_Active">وظایف من</string>
@ -218,7 +217,6 @@
<string name="pick_a_date">یک تاریخ انتخاب کنید</string>
<string name="pick_a_time">یک زمان انتخاب کنید</string>
<string name="pick_a_date_and_time">انتخاب یک تاریخ و زمان</string>
<string name="pick_a_location">انتخاب یک موقعیت</string>
<string name="when_overdue">پس از موعود</string>
<string name="when_due">روز موعود</string>
<string name="geofence_radius_title">شعاع (متر)</string>

@ -118,7 +118,6 @@
<string name="day_after_tomorrow">Ylihuomenna</string>
<string name="next_week">Ensi viikko</string>
<string name="dont_hide">Älä piilota</string>
<string name="no_deadline_reminder">Ei määräpäivämuistutusta</string>
<string name="at_deadline">Määräaikana</string>
<string name="at_deadline_or_overdue">Määräpäivänä tai yliajalla</string>
<string name="BFE_Active">Omat tehtävät</string>
@ -322,7 +321,6 @@
<string name="pick_a_date">Valitse päivä</string>
<string name="pick_a_time">Valitse aika</string>
<string name="pick_a_date_and_time">Valitse päivä ja aika</string>
<string name="pick_a_location">Valitse sijainti</string>
<string name="when_overdue">Kunnes yliajalla</string>
<string name="when_due">Milloin määräaika</string>
<string name="geofence_radius_title">Säde (metriä)</string>

@ -119,7 +119,6 @@
<string name="day_after_tomorrow">Après-demain</string>
<string name="next_week">La semaine prochaine</string>
<string name="dont_hide">Ne pas masquer</string>
<string name="no_deadline_reminder">Pas de rappel de date limite</string>
<string name="at_deadline">À la date limite</string>
<string name="at_deadline_or_overdue">À la date limite ou après</string>
<string name="BFE_Active">Mes tâches</string>
@ -313,7 +312,6 @@
<string name="pick_a_date">Choisir une date</string>
<string name="pick_a_time">Choisir une heure</string>
<string name="pick_a_date_and_time">Choisir date et heure</string>
<string name="pick_a_location">Choisir une localisation</string>
<string name="when_overdue">En cas de retard</string>
<string name="when_due">A l\'échéance</string>
<string name="geofence_radius_title">Rayon (mètres)</string>

@ -114,7 +114,6 @@
<string name="day_after_tomorrow">Pasado mañana</string>
<string name="next_week">Semana siguiente</string>
<string name="dont_hide">No ocultar</string>
<string name="no_deadline_reminder">Sin recordatorios del vencimiento</string>
<string name="at_deadline">En la fecha de vencimiento</string>
<string name="at_deadline_or_overdue">En la fecha de vencimiento o ya vencida</string>
<string name="BFE_Active">Mis Tareas</string>
@ -244,7 +243,6 @@
<string name="pick_a_date">Elegir fecha</string>
<string name="pick_a_time">Elegir hora</string>
<string name="pick_a_date_and_time">Elegir fecha y hora</string>
<string name="pick_a_location">Elegir ubicación</string>
<string name="when_overdue">Si está atrasada</string>
<string name="when_due">Al vencimiento</string>
<string name="geofence_radius_title">Radio (metros)</string>

@ -124,7 +124,6 @@
<string name="day_after_tomorrow">Holnapután</string>
<string name="next_week">Következő hét</string>
<string name="dont_hide">Nem rejtett</string>
<string name="no_deadline_reminder">Határidő emlékeztetők nélkül</string>
<string name="at_deadline">Határidő bekövetkeztekor</string>
<string name="at_deadline_or_overdue">Határidő bekövetkeztekor vagy túllépésekor</string>
<string name="BFE_Active">Saját Feladatok</string>
@ -329,7 +328,6 @@
<string name="pick_a_date">Dátum kiválasztása</string>
<string name="pick_a_time">Időpont kiválasztása</string>
<string name="pick_a_date_and_time">Válasszon dátumot és időpontot</string>
<string name="pick_a_location">Válassza ki a helyet</string>
<string name="when_overdue">Határidő lejárta után</string>
<string name="when_due">Határidő elérésekor</string>
<string name="geofence_radius_title">Távolság (méterben)</string>

@ -121,7 +121,6 @@
<string name="day_after_tomorrow">Dopodomani</string>
<string name="next_week">Settimana successiva</string>
<string name="dont_hide">Non nascondere</string>
<string name="no_deadline_reminder">Nessun promemoria scadenza</string>
<string name="at_deadline">Alla scadenza</string>
<string name="at_deadline_or_overdue">Alla scadenza o già scaduta</string>
<string name="BFE_Active">Le mie attività</string>
@ -326,7 +325,6 @@
<string name="pick_a_date">Scegli una data</string>
<string name="pick_a_time">Scegli un\'ora</string>
<string name="pick_a_date_and_time">Scegli data e ora</string>
<string name="pick_a_location">Seleziona una posizione</string>
<string name="when_overdue">Quando scaduta</string>
<string name="when_due">Alla scadenza</string>
<string name="geofence_radius_title">Raggio (metri)</string>

@ -121,7 +121,6 @@
<string name="day_after_tomorrow">מחרתיים</string>
<string name="next_week">בשבוע הבא</string>
<string name="dont_hide">אל תסתיר</string>
<string name="no_deadline_reminder">ללא תזכורות במועד הסף</string>
<string name="at_deadline">במועד הסף</string>
<string name="at_deadline_or_overdue">במועד היעד או לאחריו</string>
<string name="BFE_Active">המשימות שלי</string>
@ -327,7 +326,6 @@
<string name="pick_a_date">בחר/י בתאריך</string>
<string name="pick_a_time">בחר שעה</string>
<string name="pick_a_date_and_time">בחר תאריך ושעה</string>
<string name="pick_a_location">בחר מיקום</string>
<string name="when_overdue">לאחר מועד היעד</string>
<string name="when_due">במועד היעד</string>
<string name="geofence_radius_title">רדיוס (במטרים)</string>

@ -115,7 +115,6 @@
<string name="day_after_tomorrow">明後日</string>
<string name="next_week">来週</string>
<string name="dont_hide">常に表示する</string>
<string name="no_deadline_reminder">期限を通知しない</string>
<string name="at_deadline">期限に</string>
<string name="at_deadline_or_overdue">期限または期限を過ぎて</string>
<string name="BFE_Active">マイ タスク</string>
@ -319,7 +318,6 @@
<string name="pick_a_date">日付を選択</string>
<string name="pick_a_time">時間を選択</string>
<string name="pick_a_date_and_time">日付と時間を選択</string>
<string name="pick_a_location">場所を選択</string>
<string name="when_overdue">期限を過ぎたとき</string>
<string name="when_due">期限に</string>
<string name="geofence_radius_title">半径 (メートル)</string>

@ -123,7 +123,6 @@
<string name="day_after_tomorrow">모레</string>
<string name="next_week">다음 주</string>
<string name="dont_hide">숨기지 않기</string>
<string name="no_deadline_reminder">기한 알림 없음</string>
<string name="at_deadline">완료일에</string>
<string name="at_deadline_or_overdue">마감일이나 그 이후</string>
<string name="BFE_Active">나의 할일</string>
@ -329,7 +328,6 @@
<string name="pick_a_date">날짜 선택</string>
<string name="pick_a_time">시간 선택</string>
<string name="pick_a_date_and_time">날짜와 시간 선택</string>
<string name="pick_a_location">위치 선택</string>
<string name="when_overdue">일정 마감일이 지났을 때</string>
<string name="when_due">일정 마감일에</string>
<string name="geofence_radius_title">반경 (미터 단위)</string>

@ -121,7 +121,6 @@
<string name="day_after_tomorrow">Poryt</string>
<string name="next_week">Kitą savaitę</string>
<string name="dont_hide">Neslėpti</string>
<string name="no_deadline_reminder">Be termino pabaigos priminimų</string>
<string name="at_deadline">Atėjus terminui</string>
<string name="at_deadline_or_overdue">Atėjus terminui arba po jo</string>
<string name="BFE_Active">Mano užduotys</string>
@ -326,7 +325,6 @@
<string name="pick_a_date">Pasirinkti datą</string>
<string name="pick_a_time">Pasirinkti laiką</string>
<string name="pick_a_date_and_time">Pasirinkti datą ir laiką</string>
<string name="pick_a_location">Parinkti vietą</string>
<string name="when_overdue">Terminui pasibaigus</string>
<string name="when_due">Atėjus terminui</string>
<string name="geofence_radius_title">Spindulys (metrais)</string>

@ -120,7 +120,6 @@
<string name="day_after_tomorrow">Overmorgen</string>
<string name="next_week">Volgende week</string>
<string name="dont_hide">Niet verbergen</string>
<string name="no_deadline_reminder">Herinneringen zonder einddatum</string>
<string name="at_deadline">Op de einddatum</string>
<string name="at_deadline_or_overdue">Op of na de einddatum</string>
<string name="BFE_Active">Mijn taken</string>
@ -324,7 +323,6 @@
<string name="pick_a_date">Kies een datum</string>
<string name="pick_a_time">Kies een tijd</string>
<string name="pick_a_date_and_time">Kies een datum en tijd</string>
<string name="pick_a_location">Kies een locatie</string>
<string name="when_overdue">Na de einddatum</string>
<string name="when_due">Op de eindtijd</string>
<string name="geofence_responsiveness_title">Antwoord tijd (hogere waarde verbruikt meer batterij)</string>

@ -115,7 +115,6 @@
<string name="day_after_tomorrow">Pojutrze</string>
<string name="next_week">Przyszły tydzień</string>
<string name="dont_hide">Nie ukrywaj</string>
<string name="no_deadline_reminder">Brak przypomnień dla terminu nieprzekraczalnego</string>
<string name="at_deadline">W dniu terminu nieprzekraczalnego</string>
<string name="at_deadline_or_overdue">W nieprzekraczalnym terminie lub gdy zaległe</string>
<string name="BFE_Active">Moje zadania</string>
@ -310,7 +309,6 @@
<string name="pick_a_date">Wybierz datę</string>
<string name="pick_a_time">Wybierz czas</string>
<string name="pick_a_date_and_time">Wybierz datę i czas</string>
<string name="pick_a_location">Wybierz lokalizację</string>
<string name="when_overdue">Gdy zaległe</string>
<string name="when_due">Gdy w terminie</string>
<string name="geofence_radius_title">Zasięg (metrów)</string>

@ -119,7 +119,6 @@
<string name="day_after_tomorrow">Depois de amanhã</string>
<string name="next_week">Próxima semana</string>
<string name="dont_hide">Não ocultar</string>
<string name="no_deadline_reminder">Sem lembretes no vencimento</string>
<string name="at_deadline">No vencimento</string>
<string name="at_deadline_or_overdue">No prazo ou vencidas</string>
<string name="BFE_Active">Minhas Tarefas</string>
@ -324,7 +323,6 @@
<string name="pick_a_date">Escolha uma data</string>
<string name="pick_a_time">Escolha uma hora</string>
<string name="pick_a_date_and_time">Escolha data e horário</string>
<string name="pick_a_location">Escolher lugar</string>
<string name="when_overdue">Quando vencida</string>
<string name="when_due">Quando vencer</string>
<string name="geofence_radius_title">Raio (metros)</string>

@ -116,7 +116,6 @@
<string name="day_after_tomorrow">Depois de amanhã</string>
<string name="next_week">Próxima semana</string>
<string name="dont_hide">Não ocultar</string>
<string name="no_deadline_reminder">Sem lembrete de data limite</string>
<string name="at_deadline">Na data limite</string>
<string name="at_deadline_or_overdue">Na data limite ou ultrapassada</string>
<string name="BFE_Active">Minhas tarefas</string>
@ -319,7 +318,6 @@
<string name="pick_a_date">Escolha a data</string>
<string name="pick_a_time">Escolha a hora</string>
<string name="pick_a_date_and_time">Escolha a data e a hora</string>
<string name="pick_a_location">Escolha o local</string>
<string name="when_overdue">Se data limite ultrapassada</string>
<string name="when_due">Na data limite</string>
<string name="geofence_radius_title">Raio (metros)</string>

@ -120,7 +120,6 @@
<string name="day_after_tomorrow">Послезавтра</string>
<string name="next_week">Следующая неделя</string>
<string name="dont_hide">Не скрывать</string>
<string name="no_deadline_reminder">Нет напоминаний</string>
<string name="at_deadline">В срок</string>
<string name="at_deadline_or_overdue">Вовремя или просрочена</string>
<string name="BFE_Active">Мои задачи</string>
@ -325,7 +324,6 @@
<string name="pick_a_date">Дата</string>
<string name="pick_a_time">Время</string>
<string name="pick_a_date_and_time">Дата и время</string>
<string name="pick_a_location">По местонахождению</string>
<string name="when_overdue">Когда просрочено</string>
<string name="when_due">В срок</string>
<string name="geofence_radius_title">Радиус (в метрах)</string>

@ -115,7 +115,6 @@
<string name="day_after_tomorrow">Pozajtra</string>
<string name="next_week">Nasledujúci týždeň</string>
<string name="dont_hide">Neskrývať</string>
<string name="no_deadline_reminder">Žiadne pripomienky v termíne</string>
<string name="at_deadline">V termíne</string>
<string name="at_deadline_or_overdue">V termíne alebo po termíne</string>
<string name="BFE_Active">Moje Úlohy</string>
@ -319,7 +318,6 @@
<string name="pick_a_date">Vybrať dátum</string>
<string name="pick_a_time">Vybrať čas</string>
<string name="pick_a_date_and_time">Vybrať dátum a čas</string>
<string name="pick_a_location">Vybrať miesto</string>
<string name="when_overdue">Keď po termíne</string>
<string name="when_due">Keď v termíne</string>
<string name="geofence_radius_title">Okruh (v metroch)</string>

@ -99,7 +99,6 @@
<string name="day_after_tomorrow">Pojutrišnjem</string>
<string name="next_week">Naslednji teden</string>
<string name="dont_hide">Ne skrij</string>
<string name="no_deadline_reminder">Brez opomnikov o dospelosti</string>
<string name="at_deadline">Ob dospelosti</string>
<string name="at_deadline_or_overdue">Ob dospelosti ali potem</string>
<string name="BFE_Active">Moji Opravki</string>

@ -115,7 +115,6 @@
<string name="day_after_tomorrow">I övermorgon</string>
<string name="next_week">Nästa vecka</string>
<string name="dont_hide">Dölj inte</string>
<string name="no_deadline_reminder">Inga varsel om förfall</string>
<string name="at_deadline">Vid förfallodagen</string>
<string name="at_deadline_or_overdue">Vid eller efter förfallodagen</string>
<string name="BFE_Active">Mina Uppgifter</string>
@ -243,7 +242,6 @@
<string name="pick_a_date">Ställ in datum</string>
<string name="pick_a_time">Ställ in tid</string>
<string name="pick_a_date_and_time">Ställ in datum och tid</string>
<string name="pick_a_location">Välj en plats</string>
<string name="when_overdue">Efter förfallotid</string>
<string name="when_due">Vid förfallotid</string>
<string name="geofence_radius_title">Radie (meter)</string>

@ -125,7 +125,6 @@
<string name="day_after_tomorrow">Yarından Sonra</string>
<string name="next_week">Gelecek Hafta</string>
<string name="dont_hide">Gizleme</string>
<string name="no_deadline_reminder">Son gün hatırlatması yok</string>
<string name="at_deadline">Son tarihte</string>
<string name="at_deadline_or_overdue">Son tarihte ya da aşıldığında</string>
<string name="BFE_Active">Görevlerim</string>
@ -331,7 +330,6 @@
<string name="pick_a_date">Bir tarih seç</string>
<string name="pick_a_time">Bir zaman seç</string>
<string name="pick_a_date_and_time">Bir tarih ve zaman seç</string>
<string name="pick_a_location">Bir konum seç</string>
<string name="when_overdue">Geciktiğinde</string>
<string name="when_due">Zamanı geldiğinde</string>
<string name="geofence_radius_title">Yarıçap (metre)</string>

@ -118,7 +118,6 @@
<string name="day_after_tomorrow">Післязавтра</string>
<string name="next_week">Наступного тижня</string>
<string name="dont_hide">Не приховувати</string>
<string name="no_deadline_reminder">Нема нагадувань</string>
<string name="at_deadline">Під час дедлайну</string>
<string name="at_deadline_or_overdue">Вчасно або прострочено</string>
<string name="BFE_Active">Мої завдання</string>
@ -246,7 +245,6 @@
<string name="pick_a_date">Обрати дату</string>
<string name="pick_a_time">Обрати час</string>
<string name="pick_a_date_and_time">Обрати дату та час</string>
<string name="pick_a_location">Обрати місцезнаходження</string>
<string name="when_overdue">Коли прострочено</string>
<string name="when_due">Коли заплановано час</string>
<string name="geofence_radius_title">Радіус (метри)</string>

@ -121,7 +121,6 @@
<string name="day_after_tomorrow">后天</string>
<string name="next_week">下周</string>
<string name="dont_hide">不隐藏</string>
<string name="no_deadline_reminder">无截止期限提醒</string>
<string name="at_deadline">截止期限时</string>
<string name="at_deadline_or_overdue">截止期限或过期时</string>
<string name="BFE_Active">我的任务</string>
@ -326,7 +325,6 @@
<string name="pick_a_date">选个日期</string>
<string name="pick_a_time">选个时间</string>
<string name="pick_a_date_and_time">选个日期和时间</string>
<string name="pick_a_location">选个地址</string>
<string name="when_overdue">过期时</string>
<string name="when_due">到期时</string>
<string name="geofence_radius_title">半径(米)</string>

@ -94,7 +94,6 @@
<string name="day_after_tomorrow">後天</string>
<string name="next_week">下週</string>
<string name="dont_hide">不隱藏</string>
<string name="no_deadline_reminder">無截止期限提醒</string>
<string name="at_deadline">在截止期限時</string>
<string name="at_deadline_or_overdue">在截止期限或過期時</string>
<string name="BFE_Active">我的工作</string>

@ -169,7 +169,7 @@
</string-array>
<string-array name="EPr_default_reminders">
<item>@string/no_deadline_reminder</item>
<item>@string/no_reminders</item>
<item>@string/at_deadline</item>
<item>@string/when_overdue</item>
<item>@string/at_deadline_or_overdue</item>
@ -240,4 +240,18 @@
<item>@string/pro_tasker_plugins</item>
<item>@string/pro_dashclock_extension</item>
</string-array>
<string-array name="EPr_default_location_reminder">
<item>@string/no_reminders</item>
<item>@string/default_location_reminder_on_arrival</item>
<item>@string/default_location_reminder_on_departure</item>
<item>@string/default_location_reminder_on_arrival_or_departure</item>
</string-array>
<string-array name="EPR_default_location_reminder_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>

@ -139,6 +139,7 @@
<!-- default reminders setting (corresponds to reminder flags) -->
<string name="p_default_reminders_key">p_def_reminders</string>
<string name="p_default_location_reminder_key">p_def_location_reminders</string>
<!-- default reminder mode setting (corresponds to entry in TEA_reminder_mode_once, TEA_reminder_mode_five, TEA_reminder_mode_nonstop) -->
<string name="p_default_reminders_mode_key">rmd_default_reminder_mode</string>
@ -175,6 +176,7 @@
<string name="TEA_ctrl_files_pref">TEA_ctrl_files_pref</string>
<string name="TEA_ctrl_hide_until_pref">TEA_ctrl_hide_until_pref</string>
<string name="TEA_ctrl_hide_section_pref">TEA_ctrl_hide_section_pref</string>
<string name="TEA_ctrl_locations_pref">TEA_ctrl_locations_pref</string>
<string name="TEA_ctrl_reminders_pref">TEA_ctrl_reminders_pref</string>
<string name="TEA_ctrl_timer_pref">TEA_ctrl_timer_pref</string>
<string name="TEA_ctrl_comments">TEA_ctrl_comments</string>
@ -191,6 +193,7 @@
<item>@string/TEA_ctrl_when_pref</item>
<item>@string/TEA_ctrl_repeat_pref</item>
<item>@string/TEA_ctrl_importance_pref</item>
<item>@string/TEA_ctrl_locations_pref</item>
<item>@string/TEA_ctrl_lists_pref</item>
<item>@string/TEA_ctrl_google_task_list</item>
<item>@string/TEA_ctrl_reminders_pref</item>

@ -284,6 +284,7 @@ File %1$s contained %2$s.\n\n
<!-- slide 43e: Preference: Default Reminders Title -->
<string name="EPr_default_reminders_title">Default reminders</string>
<string name="EPr_default_location_reminder_title">Default location reminders</string>
<!-- slide 45d: Reminder Mode Preference: Default Reminders Duration -->
<string name="EPr_default_reminders_mode_title">Default ring/vibrate type</string>
@ -298,9 +299,12 @@ File %1$s contained %2$s.\n\n
<string name="dont_hide">Don\'t hide</string>
<string name="no_deadline_reminder">No deadline reminders</string>
<string name="at_deadline">At deadline</string>
<string name="at_deadline_or_overdue">At deadline or overdue</string>
<string name="no_reminders">No reminders</string>
<string name="default_location_reminder_on_arrival">On arrival</string>
<string name="default_location_reminder_on_departure">On departure</string>
<string name="default_location_reminder_on_arrival_or_departure">On arrival and departure</string>
<!-- ================================================= Filter Exposer == -->
@ -674,13 +678,13 @@ File %1$s contained %2$s.\n\n
<string name="quiet_hours_summary">No reminders during quiet hours</string>
<string name="TLA_menu_donate">Donate</string>
<string name="add_reminder">Add reminder</string>
<string name="add_location">Add location</string>
<string name="remove">Remove</string>
<string name="randomly_once">Randomly once</string>
<string name="randomly">Randomly</string>
<string name="pick_a_date">Pick a date</string>
<string name="pick_a_time">Pick a time</string>
<string name="pick_a_date_and_time">Pick a date and time</string>
<string name="pick_a_location">Pick a location</string>
<string name="when_overdue">When overdue</string>
<string name="when_due">When due</string>
<string name="geofence_radius_title">Radius (meters)</string>
@ -875,4 +879,10 @@ File %1$s contained %2$s.\n\n
<string name="linkify">Show links</string>
<string name="linkify_description">Add links to websites, addresses, and phone numbers</string>
<string name="show_list_indicators">Show list chips</string>
<string name="location_remind_arrival">Remind on arrival</string>
<string name="location_remind_departure">Remind on departure</string>
<string name="call_number">Call %s</string>
<string name="open_url">Open %s</string>
<string name="location_arrived">Arrived at %s</string>
<string name="location_departed">Departed %s</string>
</resources>

@ -32,6 +32,12 @@
android:entryValues="@array/EPr_default_reminders_values"
android:key="@string/p_default_reminders_key"
android:title="@string/EPr_default_reminders_title"/>
<com.todoroo.astrid.ui.MultilineListPreference
android:defaultValue="1"
android:entries="@array/EPr_default_location_reminder"
android:entryValues="@array/EPR_default_location_reminder_values"
android:key="@string/p_default_location_reminder_key"
android:title="@string/EPr_default_location_reminder_title" />
<com.todoroo.astrid.ui.MultilineListPreference
android:defaultValue="0"
android:entries="@array/EPr_reminder_random"

Loading…
Cancel
Save