Add LocationFilter

pull/996/head
Alex Baker 5 years ago
parent d6aa21c4f9
commit 0b95b11b68

@ -89,6 +89,7 @@ import org.tasks.data.TagDataDao;
import org.tasks.dialogs.DialogBuilder; import org.tasks.dialogs.DialogBuilder;
import org.tasks.dialogs.SortDialog; import org.tasks.dialogs.SortDialog;
import org.tasks.etesync.EteSyncCalendarSettingsActivity; import org.tasks.etesync.EteSyncCalendarSettingsActivity;
import org.tasks.filters.LocationFilter;
import org.tasks.injection.ForActivity; import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent; import org.tasks.injection.FragmentComponent;
import org.tasks.injection.InjectingFragment; import org.tasks.injection.InjectingFragment;
@ -331,6 +332,9 @@ public final class TaskListFragment extends InjectingFragment
private void setupMenu() { private void setupMenu() {
Menu menu = toolbar.getMenu(); Menu menu = toolbar.getMenu();
menu.clear(); menu.clear();
if (filter.hasBeginningMenu()) {
toolbar.inflateMenu(filter.getBeginningMenu());
}
toolbar.inflateMenu(R.menu.menu_task_list_fragment); toolbar.inflateMenu(R.menu.menu_task_list_fragment);
if (filter.hasMenu()) { if (filter.hasMenu()) {
toolbar.inflateMenu(filter.getMenu()); toolbar.inflateMenu(filter.getMenu());
@ -459,6 +463,9 @@ public final class TaskListFragment extends InjectingFragment
taskDao.setCollapsed(taskListViewModel.getValue(), true); taskDao.setCollapsed(taskListViewModel.getValue(), true);
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();
return true; return true;
case R.id.menu_open_map:
((LocationFilter) filter).openMap(context);
return true;
default: default:
return onOptionsItemSelected(item); return onOptionsItemSelected(item);
} }

@ -25,6 +25,7 @@ import com.todoroo.astrid.api.GtasksFilter;
import com.todoroo.astrid.api.TagFilter; import com.todoroo.astrid.api.TagFilter;
import org.tasks.R; import org.tasks.R;
import org.tasks.billing.Inventory; import org.tasks.billing.Inventory;
import org.tasks.filters.LocationFilter;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
import org.tasks.preferences.SyncPreferences; import org.tasks.preferences.SyncPreferences;
import org.tasks.themes.ColorProvider; import org.tasks.themes.ColorProvider;
@ -158,6 +159,8 @@ public class FilterViewHolder extends RecyclerView.ViewHolder {
return R.drawable.ic_outline_cloud_24px; return R.drawable.ic_outline_cloud_24px;
} else if (filter instanceof CustomFilter) { } else if (filter instanceof CustomFilter) {
return R.drawable.ic_outline_filter_list_24px; return R.drawable.ic_outline_filter_list_24px;
} else if (filter instanceof LocationFilter) {
return R.drawable.ic_outline_place_24px;
} else { } else {
return filter.icon; return filter.icon;
} }

@ -55,7 +55,7 @@ public class CaldavFilter extends Filter {
.where(getCriterion(caldavCalendar)); .where(getCriterion(caldavCalendar));
} }
public static Criterion getCriterion(CaldavCalendar caldavCalendar) { private static Criterion getCriterion(CaldavCalendar caldavCalendar) {
return Criterion.and( return Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(), TaskDao.TaskCriteria.activeAndVisible(),
CaldavTask.DELETED.eq(0), CaldavTask.DELETED.eq(0),

@ -197,6 +197,14 @@ public class Filter extends FilterListItem {
return true; return true;
} }
public boolean hasBeginningMenu() {
return getBeginningMenu() > 0;
}
public @MenuRes int getBeginningMenu() {
return 0;
}
public boolean hasMenu() { public boolean hasMenu() {
return getMenu() != 0; return getMenu() != 0;
} }

@ -22,8 +22,11 @@ import javax.inject.Inject;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.CaldavDao; import org.tasks.data.CaldavDao;
import org.tasks.data.CaldavTask; import org.tasks.data.CaldavTask;
import org.tasks.data.Geofence;
import org.tasks.data.GoogleTask; import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao; import org.tasks.data.GoogleTaskDao;
import org.tasks.data.LocationDao;
import org.tasks.data.Place;
import org.tasks.data.Tag; import org.tasks.data.Tag;
import org.tasks.data.TagDao; import org.tasks.data.TagDao;
import org.tasks.data.TagData; import org.tasks.data.TagData;
@ -40,6 +43,7 @@ public class TaskCreator {
private final GoogleTaskDao googleTaskDao; private final GoogleTaskDao googleTaskDao;
private final DefaultFilterProvider defaultFilterProvider; private final DefaultFilterProvider defaultFilterProvider;
private final CaldavDao caldavDao; private final CaldavDao caldavDao;
private final LocationDao locationDao;
private final TagDataDao tagDataDao; private final TagDataDao tagDataDao;
private final TaskDao taskDao; private final TaskDao taskDao;
@ -52,7 +56,8 @@ public class TaskCreator {
TagDao tagDao, TagDao tagDao,
GoogleTaskDao googleTaskDao, GoogleTaskDao googleTaskDao,
DefaultFilterProvider defaultFilterProvider, DefaultFilterProvider defaultFilterProvider,
CaldavDao caldavDao) { CaldavDao caldavDao,
LocationDao locationDao) {
this.gcalHelper = gcalHelper; this.gcalHelper = gcalHelper;
this.preferences = preferences; this.preferences = preferences;
this.tagDataDao = tagDataDao; this.tagDataDao = tagDataDao;
@ -61,6 +66,7 @@ public class TaskCreator {
this.googleTaskDao = googleTaskDao; this.googleTaskDao = googleTaskDao;
this.defaultFilterProvider = defaultFilterProvider; this.defaultFilterProvider = defaultFilterProvider;
this.caldavDao = caldavDao; this.caldavDao = caldavDao;
this.locationDao = locationDao;
} }
private static void setDefaultReminders(Preferences preferences, Task task) { private static void setDefaultReminders(Preferences preferences, Task task) {
@ -105,6 +111,13 @@ public class TaskCreator {
} }
} }
if (task.hasTransitory(Place.KEY)) {
Place place = locationDao.getPlace(task.getTransitory(Place.KEY));
if (place != null) {
locationDao.insert(new Geofence(place.getUid(), preferences));
}
}
taskDao.save(task, null); taskDao.save(task, null);
return task; return task;
} }
@ -152,6 +165,7 @@ public class TaskCreator {
break; break;
case GoogleTask.KEY: case GoogleTask.KEY:
case CaldavTask.KEY: case CaldavTask.KEY:
case Place.KEY:
task.putTransitory(key, value); task.putTransitory(key, value);
break; break;
default: default:

@ -1,19 +1,12 @@
package org.tasks.data; package org.tasks.data;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.room.Embedded; import androidx.room.Embedded;
import androidx.room.Ignore; import androidx.room.Ignore;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
import org.tasks.R;
public class Location implements Serializable, Parcelable { public class Location implements Serializable, Parcelable {
@ -140,18 +133,7 @@ public class Location implements Serializable, Parcelable {
} }
public void open(@Nullable Context context) { public void open(@Nullable Context context) {
if (context == null) { place.open(context);
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(place.getGeoUri()));
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
if (resolveInfos.isEmpty()) {
Toast.makeText(context, R.string.no_application_found_link, Toast.LENGTH_SHORT).show();
} else {
context.startActivity(intent);
}
} }
@Override @Override
@ -193,4 +175,8 @@ public class Location implements Serializable, Parcelable {
dest.writeParcelable(geofence, flags); dest.writeParcelable(geofence, flags);
dest.writeParcelable(place, flags); dest.writeParcelable(place, flags);
} }
public Place getPlace() {
return place;
}
} }

@ -9,6 +9,7 @@ import androidx.room.Query;
import androidx.room.Update; import androidx.room.Update;
import io.reactivex.Single; import io.reactivex.Single;
import java.util.List; import java.util.List;
import org.tasks.filters.LocationFilters;
@Dao @Dao
public interface LocationDao { public interface LocationDao {
@ -62,10 +63,22 @@ public interface LocationDao {
@Query("SELECT * FROM places WHERE place_id = :id") @Query("SELECT * FROM places WHERE place_id = :id")
Place getPlace(long id); Place getPlace(long id);
@Query("SELECT * FROM places WHERE uid = :uid")
Place getPlace(String uid);
@Query( @Query(
"SELECT places.*, IFNULL(COUNT(geofence_id),0) AS count FROM places LEFT OUTER JOIN geofences ON geofences.place = places.uid GROUP BY uid ORDER BY COUNT(geofence_id) DESC") "SELECT places.*, IFNULL(COUNT(geofence_id),0) AS count FROM places LEFT OUTER JOIN geofences ON geofences.place = places.uid GROUP BY uid ORDER BY COUNT(geofence_id) DESC")
LiveData<List<PlaceUsage>> getPlaceUsage(); LiveData<List<PlaceUsage>> getPlaceUsage();
@Query("SELECT * FROM places WHERE latitude LIKE :latitude AND longitude LIKE :longitude") @Query("SELECT * FROM places WHERE latitude LIKE :latitude AND longitude LIKE :longitude")
Place findPlace(String latitude, String longitude); Place findPlace(String latitude, String longitude);
@Query("SELECT places.*, COUNT(tasks._id) AS count FROM places "
+ " INNER JOIN geofences ON geofences.place = places.uid "
+ " INNER JOIN tasks ON geofences.task = tasks._id"
+ " WHERE tasks.completed = 0 AND tasks.deleted = 0"
+ " AND tasks.hideUntil < :now"
+ " GROUP BY places.uid"
+ " ORDER BY count DESC")
List<LocationFilters> getPlaceFilters(long now);
} }

@ -3,10 +3,15 @@ package org.tasks.data;
import static com.mapbox.api.geocoding.v5.GeocodingCriteria.TYPE_ADDRESS; import static com.mapbox.api.geocoding.v5.GeocodingCriteria.TYPE_ADDRESS;
import static org.tasks.data.Place.TABLE_NAME; import static org.tasks.data.Place.TABLE_NAME;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.location.Location; import android.location.Location;
import android.net.Uri; import android.net.Uri;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.room.ColumnInfo; import androidx.room.ColumnInfo;
import androidx.room.Entity; import androidx.room.Entity;
@ -23,11 +28,13 @@ import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.fortuna.ical4j.model.property.Geo; import net.fortuna.ical4j.model.property.Geo;
import org.tasks.R;
import org.tasks.location.MapPosition; import org.tasks.location.MapPosition;
@Entity(tableName = TABLE_NAME, indices = @Index(name = "place_uid", value = "uid", unique = true)) @Entity(tableName = TABLE_NAME, indices = @Index(name = "place_uid", value = "uid", unique = true))
public class Place implements Serializable, Parcelable { public class Place implements Serializable, Parcelable {
public static final String KEY = "place";
public static final String TABLE_NAME = "places"; public static final String TABLE_NAME = "places";
public static final Table TABLE = new Table(TABLE_NAME); public static final Table TABLE = new Table(TABLE_NAME);
@ -233,7 +240,22 @@ public class Place implements Serializable, Parcelable {
return Strings.isNullOrEmpty(address) ? null : address.replace(String.format("%s, ", name), ""); return Strings.isNullOrEmpty(address) ? null : address.replace(String.format("%s, ", name), "");
} }
String getGeoUri() { public void open(Context context) {
if (context == null) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(getGeoUri()));
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
if (resolveInfos.isEmpty()) {
Toast.makeText(context, R.string.no_application_found_link, Toast.LENGTH_SHORT).show();
} else {
context.startActivity(intent);
}
}
private String getGeoUri() {
return String.format( return String.format(
"geo:%s,%s?q=%s", "geo:%s,%s?q=%s",
latitude, longitude, Uri.encode(getDisplayName())); latitude, longitude, Uri.encode(getDisplayName()));

@ -2,6 +2,7 @@ package org.tasks.filters;
import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform; import static com.google.common.collect.Lists.transform;
import static com.todoroo.andlib.utility.AndroidUtilities.assertNotMainThread; import static com.todoroo.andlib.utility.AndroidUtilities.assertNotMainThread;
@ -14,6 +15,7 @@ import static org.tasks.ui.NavigationDrawerFragment.REQUEST_SETTINGS;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListItem; import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.core.BuiltInFilterExposer; import com.todoroo.astrid.core.BuiltInFilterExposer;
@ -40,6 +42,7 @@ import org.tasks.data.CaldavAccount;
import org.tasks.data.CaldavDao; import org.tasks.data.CaldavDao;
import org.tasks.data.GoogleTaskAccount; import org.tasks.data.GoogleTaskAccount;
import org.tasks.data.GoogleTaskListDao; import org.tasks.data.GoogleTaskListDao;
import org.tasks.data.LocationDao;
import org.tasks.etesync.EteSyncCalendarSettingsActivity; import org.tasks.etesync.EteSyncCalendarSettingsActivity;
import org.tasks.filters.NavigationDrawerSubheader.SubheaderType; import org.tasks.filters.NavigationDrawerSubheader.SubheaderType;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
@ -59,6 +62,7 @@ public class FilterProvider {
private final GoogleTaskListDao googleTaskListDao; private final GoogleTaskListDao googleTaskListDao;
private final CaldavDao caldavDao; private final CaldavDao caldavDao;
private final Preferences preferences; private final Preferences preferences;
private final LocationDao locationDao;
@Inject @Inject
public FilterProvider( public FilterProvider(
@ -70,7 +74,8 @@ public class FilterProvider {
TagFilterExposer tagFilterExposer, TagFilterExposer tagFilterExposer,
GoogleTaskListDao googleTaskListDao, GoogleTaskListDao googleTaskListDao,
CaldavDao caldavDao, CaldavDao caldavDao,
Preferences preferences) { Preferences preferences,
LocationDao locationDao) {
this.context = context; this.context = context;
this.inventory = inventory; this.inventory = inventory;
this.builtInFilterExposer = builtInFilterExposer; this.builtInFilterExposer = builtInFilterExposer;
@ -80,6 +85,7 @@ public class FilterProvider {
this.googleTaskListDao = googleTaskListDao; this.googleTaskListDao = googleTaskListDao;
this.caldavDao = caldavDao; this.caldavDao = caldavDao;
this.preferences = preferences; this.preferences = preferences;
this.locationDao = locationDao;
} }
public List<FilterListItem> getRemoteListPickerItems() { public List<FilterListItem> getRemoteListPickerItems() {
@ -97,7 +103,7 @@ public class FilterProvider {
getSubmenu( getSubmenu(
account.getAccount(), account.getAccount(),
!isNullOrEmpty(account.getError()), !isNullOrEmpty(account.getError()),
account.isCollapsed() ? Collections.emptyList() : filters.getValue(), filters.getValue(),
true, true,
account.isCollapsed(), account.isCollapsed(),
SubheaderType.GOOGLE_TASKS, SubheaderType.GOOGLE_TASKS,
@ -110,7 +116,7 @@ public class FilterProvider {
getSubmenu( getSubmenu(
account.getName(), account.getName(),
!isNullOrEmpty(account.getError()), !isNullOrEmpty(account.getError()),
account.isCollapsed() ? Collections.emptyList() : filters.getValue(), filters.getValue(),
true, true,
account.isCollapsed(), account.isCollapsed(),
SubheaderType.CALDAV, SubheaderType.CALDAV,
@ -141,6 +147,19 @@ public class FilterProvider {
items.addAll( items.addAll(
getSubmenu(R.string.tags, R.string.p_collapse_tags, tagFilterExposer::getFilters)); getSubmenu(R.string.tags, R.string.p_collapse_tags, tagFilterExposer::getFilters));
if (navigationDrawer) {
boolean collapsed = preferences.getBoolean(R.string.p_collapse_locations, false);
items.addAll(
getSubmenu(
context.getString(R.string.locations),
false,
collapsed ? Collections.emptyList() : getLocationFilters(),
true,
collapsed,
SubheaderType.PREFERENCE,
R.string.p_collapse_locations));
}
if (navigationDrawer && !preferences.getBoolean(R.string.p_collapse_tags, false)) { if (navigationDrawer && !preferences.getBoolean(R.string.p_collapse_tags, false)) {
items.add( items.add(
new NavigationDrawerAction( new NavigationDrawerAction(
@ -156,7 +175,7 @@ public class FilterProvider {
getSubmenu( getSubmenu(
account.getAccount(), account.getAccount(),
!isNullOrEmpty(account.getError()), !isNullOrEmpty(account.getError()),
account.isCollapsed() ? Collections.emptyList() : filters.getValue(), filters.getValue(),
!navigationDrawer, !navigationDrawer,
account.isCollapsed(), account.isCollapsed(),
SubheaderType.GOOGLE_TASKS, SubheaderType.GOOGLE_TASKS,
@ -179,7 +198,7 @@ public class FilterProvider {
getSubmenu( getSubmenu(
account.getName(), account.getName(),
!isNullOrEmpty(account.getError()), !isNullOrEmpty(account.getError()),
account.isCollapsed() ? Collections.emptyList() : filters.getValue(), filters.getValue(),
!navigationDrawer, !navigationDrawer,
account.isCollapsed(), account.isCollapsed(),
SubheaderType.CALDAV, SubheaderType.CALDAV,
@ -236,6 +255,12 @@ public class FilterProvider {
return items; return items;
} }
private List<Filter> getLocationFilters() {
List<LocationFilters> filters = locationDao.getPlaceFilters(now());
return newArrayList(
Iterables.transform(filter(filters, f -> f.count > 0), LocationFilters::toLocationFilter));
}
private List<Filter> getFilters() { private List<Filter> getFilters() {
ArrayList<Filter> filters = new ArrayList<>(); ArrayList<Filter> filters = new ArrayList<>();
filters.addAll(builtInFilterExposer.getFilters()); filters.addAll(builtInFilterExposer.getFilters());

@ -0,0 +1,96 @@
package org.tasks.filters;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import java.util.HashMap;
import java.util.Map;
import org.tasks.R;
import org.tasks.data.Geofence;
import org.tasks.data.Place;
public class LocationFilter extends Filter {
public static final Parcelable.Creator<LocationFilter> CREATOR =
new Parcelable.Creator<LocationFilter>() {
@Override
public LocationFilter createFromParcel(Parcel source) {
return new LocationFilter(source);
}
/** {@inheritDoc} */
@Override
public LocationFilter[] newArray(int size) {
return new LocationFilter[size];
}
};
private Place place;
private LocationFilter(Parcel source) {
super();
readFromParcel(source);
place = source.readParcelable(getClass().getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(place, 0);
}
public LocationFilter(Place place) {
super(place.getDisplayName(), queryTemplate(place), getValuesForNewTask(place));
this.place = place;
}
public Place getPlace() {
return place;
}
private static QueryTemplate queryTemplate(Place place) {
return new QueryTemplate()
.join(Join.inner(Geofence.TABLE, Task.ID.eq(Geofence.TASK)))
.join(Join.inner(Place.TABLE, Place.UID.eq(Geofence.PLACE)))
.where(getCriterion(place));
}
private static Criterion getCriterion(Place place) {
return Criterion.and(TaskDao.TaskCriteria.activeAndVisible(), Place.UID.eq(place.getUid()));
}
private static Map<String, Object> getValuesForNewTask(Place place) {
Map<String, Object> result = new HashMap<>();
result.put(Place.KEY, place.getUid());
return result;
}
@Override
public int getBeginningMenu() {
return R.menu.menu_location_list_settings;
}
@Override
public boolean areItemsTheSame(@NonNull FilterListItem other) {
return other instanceof LocationFilter
&& place.getUid().equals(((LocationFilter) other).getPlace().getUid());
}
@Override
public boolean areContentsTheSame(@NonNull FilterListItem other) {
return place.equals(((LocationFilter) other).getPlace()) && count == other.count;
}
public void openMap(Context context) {
place.open(context);
}
}

@ -0,0 +1,44 @@
package org.tasks.filters;
import androidx.room.Embedded;
import org.tasks.data.Place;
public class LocationFilters {
@Embedded public Place place;
public int count;
public LocationFilter toLocationFilter() {
LocationFilter filter = new LocationFilter(place);
filter.count = count;
return filter;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof LocationFilters)) {
return false;
}
LocationFilters that = (LocationFilters) o;
if (count != that.count) {
return false;
}
return place != null ? place.equals(that.place) : that.place == null;
}
@Override
public int hashCode() {
int result = place != null ? place.hashCode() : 0;
result = 31 * result + count;
return result;
}
@Override
public String toString() {
return "LocationFilters{" + "place=" + place + ", count=" + count + '}';
}
}

@ -25,7 +25,6 @@ import com.todoroo.astrid.service.TaskCompleter;
import com.todoroo.astrid.ui.CheckableImageView; import com.todoroo.astrid.ui.CheckableImageView;
import java.util.List; import java.util.List;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.Location;
import org.tasks.data.TaskContainer; import org.tasks.data.TaskContainer;
import org.tasks.dialogs.Linkify; import org.tasks.dialogs.Linkify;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
@ -280,8 +279,6 @@ public class ViewHolder extends RecyclerView.ViewHolder {
Object tag = v.getTag(); Object tag = v.getTag();
if (tag instanceof Filter) { if (tag instanceof Filter) {
callback.onClick((Filter) tag); callback.onClick((Filter) tag);
} else if (tag instanceof Location) {
((Location) tag).open(context);
} else if (tag instanceof TaskContainer) { } else if (tag instanceof TaskContainer) {
TaskContainer task = (TaskContainer) tag; TaskContainer task = (TaskContainer) tag;
callback.toggleSubtasks(task, !task.isCollapsed()); callback.toggleSubtasks(task, !task.isCollapsed());

@ -162,7 +162,8 @@ object CustomIcons {
1125 to R.drawable.ic_outline_info_24px, 1125 to R.drawable.ic_outline_info_24px,
1126 to R.drawable.ic_outline_palette_24px, 1126 to R.drawable.ic_outline_palette_24px,
1127 to R.drawable.ic_outline_sd_storage_24px, 1127 to R.drawable.ic_outline_sd_storage_24px,
1128 to R.drawable.ic_baseline_lens_24px 1128 to R.drawable.ic_baseline_lens_24px,
1129 to R.drawable.ic_map_24px
) )
@kotlin.jvm.JvmStatic @kotlin.jvm.JvmStatic

@ -26,8 +26,10 @@ import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import org.tasks.R; import org.tasks.R;
import org.tasks.billing.Inventory; import org.tasks.billing.Inventory;
import org.tasks.data.Location;
import org.tasks.data.TagData; import org.tasks.data.TagData;
import org.tasks.data.TaskContainer; import org.tasks.data.TaskContainer;
import org.tasks.filters.LocationFilter;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.themes.ColorProvider; import org.tasks.themes.ColorProvider;
@ -111,9 +113,11 @@ public class ChipProvider {
if (!hideSubtaskChip && task.hasChildren()) { if (!hideSubtaskChip && task.hasChildren()) {
chips.add(newSubtaskChip(task, !showText)); chips.add(newSubtaskChip(task, !showText));
} }
if (task.hasLocation()) { if (task.hasLocation() && !(filter instanceof LocationFilter)) {
Chip chip = newChip(task.getLocation()); Location location = task.getLocation();
apply(chip, R.drawable.ic_outline_place_24px, task.getLocation().getDisplayName(), 0, showText, showIcon); Chip chip = newChip(new LocationFilter(location.getPlace()));
apply(
chip, R.drawable.ic_outline_place_24px, location.getDisplayName(), 0, showText, showIcon);
chips.add(chip); chips.add(chip);
} }
if (!isSubtask) { if (!isSubtask) {

@ -83,12 +83,19 @@ public class LocationControlSet extends TaskEditControlFragment {
View view = super.onCreateView(inflater, container, savedInstanceState); View view = super.onCreateView(inflater, container, savedInstanceState);
if (savedInstanceState == null) { if (savedInstanceState == null) {
if (!task.isNew()) { if (task.isNew()) {
if (task.hasTransitory(Place.KEY)) {
Place place = locationDao.getPlace(task.getTransitory(Place.KEY));
if (place != null) {
original = new Location(new Geofence(place.getUid(), preferences), place);
}
}
} else {
original = locationDao.getGeofences(task.getId()); original = locationDao.getGeofences(task.getId());
}
if (original != null) { if (original != null) {
location = new Location(original.geofence, original.place); location = new Location(original.geofence, original.place);
} }
}
} else { } else {
original = savedInstanceState.getParcelable(EXTRA_ORIGINAL); original = savedInstanceState.getParcelable(EXTRA_ORIGINAL);
location = savedInstanceState.getParcelable(EXTRA_LOCATION); location = savedInstanceState.getParcelable(EXTRA_LOCATION);

@ -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="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48L3,20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48L21,3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM10,5.47l4,1.4v11.66l-4,-1.4L10,5.47zM5,6.46l3,-1.01v11.7l-3,1.16L5,6.46zM19,17.54l-3,1.01L16,6.86l3,-1.16v11.84z"/>
</vector>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_open_map"
android:title="@string/open_map"
android:icon="@drawable/ic_map_24px"
app:showAsAction="ifRoom" />
</menu>

@ -7,13 +7,13 @@
android:id="@+id/menu_voice_add" android:id="@+id/menu_voice_add"
android:icon="@drawable/ic_outline_mic_none_24px" android:icon="@drawable/ic_outline_mic_none_24px"
android:title="@string/EPr_voiceInputEnabled_title" android:title="@string/EPr_voiceInputEnabled_title"
app:showAsAction="always"/> app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/menu_search" android:id="@+id/menu_search"
android:icon="@drawable/ic_outline_search_24px" android:icon="@drawable/ic_outline_search_24px"
android:title="@string/TLA_menu_search" android:title="@string/TLA_menu_search"
app:actionViewClass="androidx.appcompat.widget.SearchView" app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always|collapseActionView"/> app:showAsAction="ifRoom|collapseActionView"/>
<item <item
android:id="@+id/menu_sort" android:id="@+id/menu_sort"
android:icon="@drawable/ic_outline_sort_24px" android:icon="@drawable/ic_outline_sort_24px"

@ -293,4 +293,5 @@
<string name="p_desaturate_colors">desaturate_colors</string> <string name="p_desaturate_colors">desaturate_colors</string>
<string name="p_collapse_filters">collapse_filters</string> <string name="p_collapse_filters">collapse_filters</string>
<string name="p_collapse_tags">collapse_tags</string> <string name="p_collapse_tags">collapse_tags</string>
<string name="p_collapse_locations">collapse_locations</string>
</resources> </resources>

@ -566,4 +566,5 @@ File %1$s contained %2$s.\n\n
<string name="desaturate_colors">Desaturate colors</string> <string name="desaturate_colors">Desaturate colors</string>
<string name="desaturate_colors_summary_on">Colors will be desaturated in dark themes</string> <string name="desaturate_colors_summary_on">Colors will be desaturated in dark themes</string>
<string name="desaturate_colors_summary_off">Colors will not be desaturated in dark themes</string> <string name="desaturate_colors_summary_off">Colors will not be desaturated in dark themes</string>
<string name="locations">Locations</string>
</resources> </resources>

Loading…
Cancel
Save