Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions lib/routes/transaction_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ class _TransactionPageState extends State<TransactionPage> {
Geo? _geo;
bool _geoHandpicked = false;

/// Device's current location, fetched independently of [_geo].
///
/// Used to surface nearby tag suggestions even when editing an existing
/// transaction whose saved location differs from where the user is now.
Geo? _deviceGeo;

bool locationFailed = false;

dynamic error;
Expand Down Expand Up @@ -242,9 +248,9 @@ class _TransactionPageState extends State<TransactionPage> {

_mapController = enableGeo ? MapController() : null;

if (widget.isNewTransaction) {
tryFetchLocation();
tryFetchLocation();

if (widget.isNewTransaction) {
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
_orchestrateFlow(transactionEntryFlow);
});
Expand Down Expand Up @@ -445,6 +451,7 @@ class _TransactionPageState extends State<TransactionPage> {
selectedTags: _selectedTags,
onTagsChanged: onTagsChanged,
location: _geo,
deviceLocation: _deviceGeo,
),
DescriptionSection(
value: _descriptionMarkdown,
Expand Down Expand Up @@ -654,20 +661,25 @@ class _TransactionPageState extends State<TransactionPage> {
void tryFetchLocation() {
if (Platform.isLinux) return;
if (LocalPreferences().enableGeo.get() != true) return;
if (LocalPreferences().autoAttachTransactionGeo.get() != true) return;

final bool autoAttach =
widget.isNewTransaction &&
LocalPreferences().autoAttachTransactionGeo.get() == true;

Geolocator.getLastKnownPosition()
.then((lastKnown) {
if (lastKnown == null) {
return;
}

if (_geo != null) {
// In case we already have a location, don't override with less accurate one
return;
}
final Geo geo = Geo.fromPosition(lastKnown);
_deviceGeo = geo;

_geo = Geo.fromPosition(lastKnown);
// Only seed the transaction's location from a less-accurate
// last-known fix when we'd otherwise have nothing.
if (autoAttach && _geo == null) {
_geo = geo;
}

if (mounted) setState(() => {});
})
Expand All @@ -677,7 +689,11 @@ class _TransactionPageState extends State<TransactionPage> {

Geolocator.getCurrentPosition()
.then((current) {
_geo = Geo.fromPosition(current);
final Geo geo = Geo.fromPosition(current);
_deviceGeo = geo;
if (autoAttach) {
_geo = geo;
}
})
.catchError((e, stackTrace) {
locationFailed = true;
Expand Down
36 changes: 26 additions & 10 deletions lib/routes/transaction_page/sections/tags_section.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,44 @@ class TagsSection extends StatelessWidget {
final VoidCallback selectTags;
final ValueChanged<List<TransactionTag>> onTagsChanged;

/// Used for suggesting nearby tags based on the transaction's location.
/// Transaction's saved location, used for suggesting nearby tags.
final Geo? location;

/// Device's current location, used in addition to [location] so that
/// suggestions reflect both where the transaction happened and where the
/// user is now (useful when editing an older transaction in a new place).
final Geo? deviceLocation;

const TagsSection({
super.key,
this.selectedTags,
required this.selectTags,
required this.onTagsChanged,
this.location,
this.deviceLocation,
});

@override
Widget build(BuildContext context) {
final List<TransactionTag>? suggestedGeoTags = switch (location
?.toLatLngPosition()) {
LatLng latLng => TransactionTagsProvider.of(
context,
).getCloseGeoTags(latLng, exclusionList: selectedTags),
_ => null,
};
final TransactionTagsProvider provider = TransactionTagsProvider.of(
context,
);

final List<LatLng> suggestionOrigins = [
?location?.toLatLngPosition(),
?deviceLocation?.toLatLngPosition(),
];

final Set<String> seen = {};
final List<TransactionTag> suggestedGeoTags = suggestionOrigins
.expand(
(origin) =>
provider.getCloseGeoTags(origin, exclusionList: selectedTags),
)
.where((tag) => seen.add(tag.uuid))
.toList();

final bool hasSuggestedGeoTags = suggestedGeoTags?.isNotEmpty == true;
final bool hasSuggestedGeoTags = suggestedGeoTags.isNotEmpty;

return Section(
title: "transaction.tags".t(context),
Expand All @@ -61,7 +77,7 @@ class TagsSection extends StatelessWidget {
onPressed: selectTags,
title: "transaction.tags.add".t(context),
),
...?suggestedGeoTags?.map(
...suggestedGeoTags.map(
(tag) => TransactionTagChip(
tag: tag,
selected: false,
Expand Down
Loading