Skip to content

Commit

Permalink
feat: filter to view all files without location data in places (fix #…
Browse files Browse the repository at this point in the history
…1124)

Signed-off-by: Varun Patil <radialapps@gmail.com>
  • Loading branch information
pulsejet committed Jun 24, 2024
1 parent b39f529 commit c25a659
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

- **Feature**: Add filter to view all files without location data in places ([#1124](https://github.com/pulsejet/memories/issues/1124))
- **Fix**: Broken indexing of large video files. If you have improperly indexed large files, run `occ memories:index -f` ([#1195](https://github.com/pulsejet/memories/issues/1195))

## [v7.3.1] - 2024-05-03
Expand Down
14 changes: 12 additions & 2 deletions lib/ClustersBackend/PlacesBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,21 @@ public function isEnabled(): bool

public function transformDayQuery(IQueryBuilder &$query, bool $aggregate): void
{
$locationId = (int) $this->request->getParam('places');
$locId = $this->request->getParam('places');

// Files that have no GPS coordinates set
if ('NULL' === $locId) {
$query->andWhere($query->expr()->orX(
$query->expr()->isNull('m.lat'),
$query->expr()->isNull('m.lon'),
));

return;
}

$query->innerJoin('m', 'memories_places', 'mp', $query->expr()->andX(
$query->expr()->eq('mp.fileid', 'm.fileid'),
$query->expr()->eq('mp.osm_id', $query->createNamedParameter($locationId)),
$query->expr()->eq('mp.osm_id', $query->createNamedParameter((int) $locId)),
));
}

Expand Down
10 changes: 6 additions & 4 deletions src/components/Timeline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -661,12 +661,14 @@ export default defineComponent({
// Places
if (this.routeIsPlaces) {
if (!name || !name.includes('-')) {
if (name?.includes('-')) {
const id = name.split('-', 1)[0];
set(DaysFilterType.PLACE, id);
} else if (name === this.c.PLACES_NULL) {
set(DaysFilterType.PLACE, this.c.PLACES_NULL);
} else {
throw new Error('Invalid place route');
}
const id = name.split('-', 1)[0];
set(DaysFilterType.PLACE, id);
}
// Tags
Expand Down
4 changes: 1 addition & 3 deletions src/components/top-matter/ClusterTopMatter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import * as strings from '@services/strings';
import BackIcon from 'vue-material-design-icons/ArrowLeft.vue';
export default defineComponent({
name: 'TagTopMatter',
name: 'ClusterTopMatter',
components: {
NcActions,
NcActionButton,
Expand All @@ -37,8 +37,6 @@ export default defineComponent({
switch (this.$route.name) {
case _m.routes.Tags.name:
return this.t('recognize', this.$route.params.name);
case _m.routes.Places.name:
return this.$route.params.name?.split('-').slice(1).join('-');
default:
return null;
}
Expand Down
9 changes: 6 additions & 3 deletions src/components/top-matter/PlacesDynamicTopMatter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ export default defineComponent({
methods: {
async refresh(): Promise<boolean> {
// Clear folders
// Clear subplaces
this.places = [];
// Skip if unidentified location view
if (this.routeIsPlacesUnassigned) return false;
// Get ID of place from URL
const placeId = Number(this.$route.params.name?.split('-')[0]) || -1;
const url = API.Q(API.PLACE_LIST(), { inside: placeId });
// Make API call to get subfolders
// Make API call to get subplaces
try {
this.places = (await axios.get<ICluster[]>(url)).data;
} catch (e) {
Expand All @@ -49,7 +52,7 @@ export default defineComponent({
route(place: ICluster) {
return {
name: 'places',
name: _m.routes.Places.name,
params: {
name: place.cluster_id + '-' + place.name,
},
Expand Down
79 changes: 79 additions & 0 deletions src/components/top-matter/PlacesTopMatter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<div class="places-top-matter">
<NcActions v-if="name">
<NcActionButton :aria-label="t('memories', 'Back')" @click="back()">
{{ t('memories', 'Back') }}
<template #icon> <BackIcon :size="20" /> </template>
</NcActionButton>
</NcActions>

<div class="name">{{ name || viewname }}</div>

<div class="right-actions">
<NcActions :inline="0">
<!-- root view (not cluster or unassigned) -->
<template v-if="!name && !routeIsPlacesUnassigned">
<NcActionButton
:aria-label="t('memories', 'Files without location')"
@click="openUnassigned"
close-after-click
>
{{ t('memories', 'Files without location') }}
<template #icon> <UnassignedIcon :size="20" /> </template>
</NcActionButton>
</template>
</NcActions>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js';
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js';
import * as strings from '@services/strings';
import BackIcon from 'vue-material-design-icons/ArrowLeft.vue';
import UnassignedIcon from 'vue-material-design-icons/MapMarkerOff.vue';
export default defineComponent({
name: 'PlacesTopMatter',
components: {
NcActions,
NcActionButton,
BackIcon,
UnassignedIcon,
},
computed: {
viewname(): string {
return strings.viewName(this.$route.name!);
},
name(): string | null {
if (this.routeIsPlacesUnassigned) {
return this.t('memories', 'Unidentified location');
}
return this.$route.params.name?.split('-').slice(1).join('-');
},
},
methods: {
back() {
this.$router.go(-1);
},
openUnassigned() {
this.$router.push({
name: _m.routes.Places.name,
params: {
name: this.c.PLACES_NULL,
},
});
},
},
});
</script>
4 changes: 3 additions & 1 deletion src/components/top-matter/TopMatter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import FolderTopMatter from './FolderTopMatter.vue';
import ClusterTopMatter from './ClusterTopMatter.vue';
import FaceTopMatter from './FaceTopMatter.vue';
import AlbumTopMatter from './AlbumTopMatter.vue';
import PlacesTopMatter from './PlacesTopMatter.vue';
import * as utils from '@services/utils';
Expand Down Expand Up @@ -50,8 +51,9 @@ export default defineComponent({
return this.initstate.shareType === 'folder' ? FolderTopMatter : null;
case _m.routes.Albums.name:
return AlbumTopMatter;
case _m.routes.Tags.name:
case _m.routes.Places.name:
return PlacesTopMatter;
case _m.routes.Tags.name:
return ClusterTopMatter;
case _m.routes.Recognize.name:
case _m.routes.FaceRecognition.name:
Expand Down
5 changes: 5 additions & 0 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export type GlobalRouteCheckers = {
routeIsPublic: boolean;
routeIsPeople: boolean;
routeIsRecognizeUnassigned: boolean;
routeIsPlacesUnassigned: boolean;
routeIsCluster: boolean;
};

Expand All @@ -191,6 +192,10 @@ defineRouteChecker(
'routeIsRecognizeUnassigned',
(route) => route?.name === routes.Recognize.name && route!.params.name === c.FACE_NULL,
);
defineRouteChecker(
'routeIsPlacesUnassigned',
(route) => route?.name === routes.Places.name && route!.params.name === c.PLACES_NULL,
);
defineRouteChecker('routeIsCluster', (route) =>
[
routes.Albums.name,
Expand Down
1 change: 1 addition & 0 deletions src/services/utils/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const constants = Object.freeze({
FLAG_IS_LOCAL: 1 << 6,

FACE_NULL: 'NULL',
PLACES_NULL: 'NULL',

MIME_RAW: 'image/x-dcraw',
FORBIDDEN_EDIT_MIMES: ['image/bmp', 'image/x-dcraw', 'video/MP2T'], // Exif.php
Expand Down

0 comments on commit c25a659

Please sign in to comment.