UX: Refactor photo viewer API and frontend components #1307 #1438

This commit is contained in:
Michael Mayer 2022-03-31 17:09:08 +02:00
parent 83d9f7af32
commit 16f3c004c9
14 changed files with 298 additions and 377 deletions

View file

@ -63,8 +63,11 @@ const Scrollbar = {
this.update(preserveOverflow);
},
disabled: function () {
return hidePending > 0;
},
hidden: function () {
return hidePending > 0 || hideDefault;
return this.disabled() || hideDefault;
},
};

View file

@ -27,6 +27,8 @@ import PhotoSwipe from "photoswipe";
import PhotoSwipeUI_Default from "photoswipe/dist/photoswipe-ui-default.js";
import Event from "pubsub-js";
import Util from "util.js";
import Api from "./api";
import Thumb from "model/thumb";
const thumbs = window.__CONFIG__.thumbs;
@ -119,24 +121,26 @@ class Viewer {
// isFake - true when content is added to fake caption container
// (used to get size of next or previous caption)
if (!item.title) {
item.title = item.Title;
if (!item.Title) {
captionEl.children[0].innerHTML = "";
return false;
}
captionEl.children[0].innerHTML = Util.encodeHTML(item.title);
captionEl.children[0].innerHTML = Util.encodeHTML(item.Title);
if (item.playable) {
if (item.Playable) {
captionEl.children[0].innerHTML +=
' <i aria-hidden="true" class="v-icon material-icons theme--dark" title="Play">play_circle_fill</i>';
}
if (item.description) {
if (item.Description) {
captionEl.children[0].innerHTML +=
'<br><span class="description">' + Util.encodeHTML(item.description) + "</span>";
'<br><span class="description">' + Util.encodeHTML(item.Description) + "</span>";
}
if (item.playable) {
if (item.Playable) {
captionEl.children[0].innerHTML =
"<button>" + captionEl.children[0].innerHTML + "</button>";
}
@ -195,9 +199,9 @@ class Viewer {
});
gallery.listen("gettingData", function (index, item) {
item.src = item[nextSize].src;
item.w = item[nextSize].w;
item.h = item[nextSize].h;
item.src = item.Thumbs[nextSize].src;
item.w = item.Thumbs[nextSize].w;
item.h = item.Thumbs[nextSize].h;
previousSize = nextSize;
});
@ -215,6 +219,85 @@ class Viewer {
return "fit_7680";
}
static show(ctx, index) {
if (ctx.loading || !ctx.listen || ctx.viewer.loading || !ctx.results[index]) {
return false;
}
const selected = ctx.results[index];
if (!ctx.viewer.dirty && ctx.viewer.results && ctx.viewer.results.length > index) {
// Reuse existing viewer result if possible.
let i = -1;
if (ctx.viewer.results[index] && ctx.viewer.results[index].UID === selected.UID) {
i = index;
} else {
i = ctx.viewer.results.findIndex((p) => p.UID === selected.UID);
}
if (
i > -1 &&
(((ctx.viewer.complete || ctx.complete) &&
ctx.viewer.results.length >= ctx.results.length) ||
i + ctx.viewer.batchSize <= ctx.viewer.results.length)
) {
ctx.$viewer.show(ctx.viewer.results, i);
return;
}
}
// Fetch photos from server API.
ctx.viewer.loading = true;
const params = ctx.searchParams();
params.count = params.offset + ctx.viewer.batchSize;
params.offset = 0;
// Fetch viewer results from API.
return Api.get("photos/view", { params })
.then((response) => {
const count = response && response.data ? response.data.length : 0;
if (count === 0) {
ctx.$notify.warn(ctx.$gettext("No pictures found"));
ctx.viewer.dirty = true;
ctx.viewer.complete = false;
return;
}
// Process response.
if (response.headers && response.headers["x-count"]) {
const c = parseInt(response.headers["x-count"]);
const l = parseInt(response.headers["x-limit"]);
ctx.viewer.complete = c < l;
} else {
ctx.viewer.complete = ctx.complete;
}
let i;
if (response.data[index] && response.data[index].UID === selected.UID) {
i = index;
} else {
i = response.data.findIndex((p) => p.UID === selected.UID);
}
ctx.viewer.results = Thumb.wrap(response.data);
// Show photos.
ctx.$viewer.show(ctx.viewer.results, i);
ctx.viewer.dirty = false;
})
.catch(() => {
ctx.viewer.dirty = true;
ctx.viewer.complete = false;
})
.finally(() => {
// Unblock.
ctx.viewer.loading = false;
});
}
}
export default Viewer;

View file

@ -27,8 +27,8 @@ import PNotify from "component/notify.vue";
import PNavigation from "component/navigation.vue";
import PScrollTop from "component/scroll-top.vue";
import PLoadingBar from "component/loading-bar.vue";
import PPhotoViewer from "component/photo-viewer.vue";
import PVideoPlayer from "component/video/player.vue";
import PPhotoViewer from "component/photo/viewer.vue";
import PPhotoToolbar from "component/photo/toolbar.vue";
import PPhotoCards from "component/photo/cards.vue";
import PPhotoMosaic from "component/photo/mosaic.vue";

View file

@ -11,7 +11,7 @@
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<div class="pswp__taken hidden-xs-only">{{ formatDate(item.taken) }}</div>
<div class="pswp__taken hidden-xs-only">{{ formatDate(item.TakenAtLocal) }}</div>
<div class="pswp__counter"></div>
@ -35,7 +35,7 @@
<button class="pswp__button action-like hidden-shared-only" style="background: none;"
:title="$gettext('Like')" @click.exact="onLike">
<v-icon v-if="item.favorite" size="16" color="white">favorite</v-icon>
<v-icon v-if="item.Favorite" size="16" color="white">favorite</v-icon>
<v-icon v-else size="16" color="white">favorite_border</v-icon>
</button>
@ -158,7 +158,7 @@ export default {
this.onPause();
}
if (data.item && this.item && this.item.uid !== data.item.uid) {
if (data.item && this.item && this.item.UID !== data.item.UID) {
this.closePlayer();
}
@ -171,8 +171,8 @@ export default {
this.$clipboard.toggle(this.item);
},
onPlay() {
if (this.item && this.item.playable) {
new Photo().find(this.item.uid).then((video) => this.openPlayer(video));
if (this.item && this.item.Playable) {
new Photo().find(this.item.UID).then((video) => this.openPlayer(video));
}
},
openPlayer(video) {
@ -236,14 +236,14 @@ export default {
onDownload() {
this.onPause();
if (!this.item || !this.item.download_url) {
if (!this.item || !this.item.DownloadUrl) {
console.warn("photo viewer: no download url");
return;
}
Notify.success(this.$gettext("Downloading…"));
new Photo().find(this.item.uid).then(p => p.downloadAll());
new Photo().find(this.item.UID).then(p => p.downloadAll());
},
onEdit() {
this.onPause();
@ -253,15 +253,15 @@ export default {
// remove duplicates
let filtered = g.items.filter(function (p, i, s) {
return !(i > 0 && p.uid === s[i - 1].uid);
return !(i > 0 && p.UID === s[i - 1].UID);
});
let selection = filtered.map((p, i) => {
if (g.currItem.uid === p.uid) {
if (g.currItem.UID === p.UID) {
index = i;
}
return p.uid;
return p.UID;
});
let album = null;

View file

@ -10,7 +10,7 @@
<script>
export default {
name: "PPhotoPlayer",
name: "PVideoPlayer",
props: {
show: {
type: Boolean,

View file

@ -33,20 +33,21 @@ const thumbs = window.__CONFIG__.thumbs;
export class Thumb extends Model {
getDefaults() {
return {
uid: "",
title: "",
taken: "",
description: "",
favorite: false,
playable: false,
original_w: 0,
original_h: 0,
download_url: "",
UID: "",
Title: "",
TakenAtLocal: "",
Description: "",
Favorite: false,
Playable: false,
DownloadUrl: "",
Width: 0,
Height: 0,
Thumbs: {},
};
}
getId() {
return this.uid;
return this.UID;
}
hasId() {
@ -54,26 +55,27 @@ export class Thumb extends Model {
}
toggleLike() {
this.favorite = !this.favorite;
this.Favorite = !this.Favorite;
if (this.favorite) {
return Api.post("photos/" + this.uid + "/like");
if (this.Favorite) {
return Api.post("photos/" + this.UID + "/like");
} else {
return Api.delete("photos/" + this.uid + "/like");
return Api.delete("photos/" + this.UID + "/like");
}
}
static thumbNotFound() {
const result = {
uid: "",
title: $gettext("Not Found"),
taken: "",
description: "",
favorite: false,
playable: false,
original_w: 0,
original_h: 0,
download_url: "",
UID: "",
Title: $gettext("Not Found"),
TakenAtLocal: "",
Description: "",
Favorite: false,
Playable: false,
DownloadUrl: "",
Width: 0,
Height: 0,
Thumbs: {},
};
for (let i = 0; i < thumbs.length; i++) {
@ -110,22 +112,23 @@ export class Thumb extends Model {
}
const result = {
uid: photo.UID,
title: photo.Title,
taken: photo.getDateString(),
description: photo.Description,
favorite: photo.Favorite,
playable: photo.isPlayable(),
download_url: this.downloadUrl(photo),
original_w: photo.Width,
original_h: photo.Height,
UID: photo.UID,
Title: photo.Title,
TakenAtLocal: photo.getDateString(),
Description: photo.Description,
Favorite: photo.Favorite,
Playable: photo.isPlayable(),
DownloadUrl: this.downloadUrl(photo),
Width: photo.Width,
Height: photo.Height,
Thumbs: {},
};
for (let i = 0; i < thumbs.length; i++) {
let t = thumbs[i];
let size = photo.calculateSize(t.w, t.h);
result[t.size] = {
result.Thumbs[t.size] = {
src: photo.thumbnailUrl(t.size),
w: size.width,
h: size.height,
@ -141,22 +144,23 @@ export class Thumb extends Model {
}
const result = {
uid: photo.UID,
title: photo.Title,
taken: photo.getDateString(),
description: photo.Description,
favorite: photo.Favorite,
playable: photo.isPlayable(),
download_url: this.downloadUrl(file),
original_w: file.Width,
original_h: file.Height,
UID: photo.UID,
Title: photo.Title,
TakenAtLocal: photo.getDateString(),
Description: photo.Description,
Favorite: photo.Favorite,
Playable: photo.isPlayable(),
DownloadUrl: this.downloadUrl(file),
Width: file.Width,
Height: file.Height,
Thumbs: {},
};
for (let i = 0; i < thumbs.length; i++) {
let t = thumbs[i];
let size = this.calculateSize(file, t.w, t.h);
result[t.size] = {
result.Thumbs[t.size] = {
src: this.thumbnailUrl(file, t.size),
w: size.width,
h: size.height,

View file

@ -48,9 +48,9 @@
<script>
import {Photo, TypeLive, TypeRaw, TypeVideo} from "model/photo";
import Album from "model/album";
import Event from "pubsub-js";
import Thumb from "model/thumb";
import Api from "common/api";
import Event from "pubsub-js";
import Viewer from "common/viewer";
export default {
name: 'PPageAlbumPhotos',
@ -92,7 +92,8 @@ export default {
viewer: {
results: [],
loading: false,
complete: true,
complete: false,
dirty: false,
batchSize: batchSize > 160 ? 480 : batchSize * 3
},
};
@ -174,7 +175,7 @@ export default {
Event.publish("dialog.edit", {selection: selection, album: this.album, index: index});
},
openPhoto(index, showMerged) {
if (this.loading || this.viewer.loading || !this.results[index]) {
if (this.loading || !this.listen || this.viewer.loading || !this.results[index]) {
return false;
}
@ -194,78 +195,21 @@ export default {
} else if (showMerged) {
this.$viewer.show(Thumb.fromFiles([selected]), 0);
} else {
if (this.viewer.results && this.viewer.results.length > index) {
// Reuse existing viewer result if possible.
let i = -1;
if (this.viewer.results[index] && this.viewer.results[index].uid === selected.UID) {
i = index;
} else {
i = this.viewer.results.findIndex(p => p.uid === selected.UID);
}
if (i > -1 && (((this.viewer.complete || this.complete) && this.viewer.results.length >= this.results.length)
|| ((i + this.viewer.batchSize) <= this.viewer.results.length))
) {
this.$viewer.show(this.viewer.results, i);
return;
}
}
// Fetch photos from server API.
this.viewer.loading = true;
const params = this.searchParams();
params.count = this.complete ? params.offset : params.offset + this.viewer.batchSize;
params.offset = 0;
// Fetch viewer results from API.
return Api.get("photos/view", {params}).then((response) => {
let count = response && response.data ? response.data.length : 0;
if (count > 0) {
// Process response.
if (response.headers && response.headers["x-count"]) {
const c = parseInt(response.headers["x-count"]);
const l = parseInt(response.headers["x-limit"]);
this.viewer.complete = c < l;
}
let i;
if (response.data[index] && response.data[index].uid === selected.UID) {
i = index;
} else {
i = response.data.findIndex(p => p.uid === selected.UID);
}
this.viewer.results = Thumb.wrap(response.data);
// Show photos.
this.$viewer.show(this.viewer.results, i);
} else {
// Don't open viewer if nothing was found.
this.viewer.results = [];
this.viewer.complete = false;
this.$notify.warn(this.$gettext("No pictures found"));
}
}).catch(() => {
// Reset results in case of an error.
this.viewer.results = [];
this.viewer.complete = false;
}).finally(() => {
// Unblock.
this.viewer.loading = false;
});
Viewer.show(this, index);
}
return true;
},
loadMore() {
if (this.scrollDisabled) return;
if (this.scrollDisabled || this.$scrollbar.disabled()) return;
this.scrollDisabled = true;
this.listen = false;
if (this.dirty) {
this.viewer.dirty = true;
}
const count = this.dirty ? (this.page + 2) * this.batchSize : this.batchSize;
const offset = this.dirty ? 0 : this.offset;

View file

@ -224,14 +224,12 @@ export default {
this.busy = true;
this.completed = 0;
this.fileName = data.filePath;
break;
case "indexing":
this.action = this.$gettext("Indexing");
this.busy = true;
this.completed = 0;
this.fileName = data.fileName;
break;
case "updating":
if (data.step === "stacks") {
@ -249,28 +247,24 @@ export default {
this.busy = true;
this.completed = 0;
this.fileName = "";
break;
case "converting":
this.action = this.$gettext("Converting");
this.busy = true;
this.completed = 0;
this.fileName = data.fileName;
break;
case "thumbnails":
this.action = this.$gettext("Creating thumbnails for");
this.busy = true;
this.completed = 0;
this.fileName = data.fileName;
break;
case 'completed':
this.action = "";
this.busy = false;
this.completed = 100;
this.fileName = '';
break;
default:
console.log(data);

View file

@ -44,8 +44,8 @@
<script>
import {Photo, TypeLive, TypeRaw, TypeVideo} from "model/photo";
import Thumb from "model/thumb";
import Viewer from "common/viewer";
import Event from "pubsub-js";
import Api from "common/api";
export default {
name: 'PPagePhotos',
@ -113,7 +113,8 @@ export default {
viewer: {
results: [],
loading: false,
complete: true,
complete: false,
dirty: false,
batchSize: batchSize > 160 ? 480 : batchSize * 3
},
};
@ -220,7 +221,7 @@ export default {
Event.publish("dialog.edit", {selection: selection, album: null, index: index});
},
openPhoto(index, showMerged) {
if (this.loading || this.viewer.loading || !this.results[index]) {
if (this.loading || !this.listen || this.viewer.loading || !this.results[index]) {
return false;
}
@ -240,76 +241,19 @@ export default {
} else if (showMerged) {
this.$viewer.show(Thumb.fromFiles([selected]), 0);
} else {
if (this.viewer.results && this.viewer.results.length > index) {
// Reuse existing viewer result if possible.
let i = -1;
if (this.viewer.results[index] && this.viewer.results[index].uid === selected.UID) {
i = index;
} else {
i = this.viewer.results.findIndex(p => p.uid === selected.UID);
}
if (i > -1 && (((this.viewer.complete || this.complete) && this.viewer.results.length >= this.results.length)
|| ((i + this.viewer.batchSize) <= this.viewer.results.length))
) {
this.$viewer.show(this.viewer.results, i);
return;
}
}
// Fetch photos from server API.
this.viewer.loading = true;
const params = this.searchParams();
params.count = this.complete ? params.offset : params.offset + this.viewer.batchSize;
params.offset = 0;
// Fetch viewer results from API.
return Api.get("photos/view", {params}).then((response) => {
let count = response && response.data ? response.data.length : 0;
if (count > 0) {
// Process response.
if (response.headers && response.headers["x-count"]) {
const c = parseInt(response.headers["x-count"]);
const l = parseInt(response.headers["x-limit"]);
this.viewer.complete = c < l;
}
let i;
if (response.data[index] && response.data[index].uid === selected.UID) {
i = index;
} else {
i = response.data.findIndex(p => p.uid === selected.UID);
}
this.viewer.results = Thumb.wrap(response.data);
// Show photos.
this.$viewer.show(this.viewer.results, i);
} else {
// Don't open viewer if nothing was found.
this.viewer.results = [];
this.viewer.complete = false;
this.$notify.warn(this.$gettext("No pictures found"));
}
}).catch(() => {
// Reset results in case of an error.
this.viewer.results = [];
this.viewer.complete = false;
}).finally(() => {
// Unblock.
this.viewer.loading = false;
});
Viewer.show(this, index);
}
},
loadMore() {
if (this.scrollDisabled) return;
if (this.scrollDisabled || this.$scrollbar.disabled()) return;
this.scrollDisabled = true;
this.listen = false;
if (this.dirty) {
this.viewer.dirty = true;
}
const count = this.dirty ? (this.page + 2) * this.batchSize : this.batchSize;
const offset = this.dirty ? 0 : this.offset;

View file

@ -24,13 +24,11 @@ Additional information can be found in our Developer Guide:
*/
import PNavigation from "navigation.vue";
import PNotify from "component/notify.vue";
import PScrollTop from "component/scroll-top.vue";
import PLoadingBar from "component/loading-bar.vue";
import PPhotoViewer from "component/photo-viewer.vue";
import PVideoPlayer from "component/video/player.vue";
import PPhotoViewer from "component/photo/viewer.vue";
import PPhotoCards from "photo/cards.vue";
import PPhotoMosaic from "photo/mosaic.vue";
import PPhotoList from "photo/list.vue";
@ -41,13 +39,11 @@ const components = {};
components.install = (Vue) => {
Vue.component("PNavigation", PNavigation);
Vue.component("PNotify", PNotify);
Vue.component("PScrollTop", PScrollTop);
Vue.component("PLoadingBar", PLoadingBar);
Vue.component("PVideoPlayer", PVideoPlayer);
Vue.component("PPhotoViewer", PPhotoViewer);
Vue.component("PVideoPlayer", PVideoPlayer);
Vue.component("PPhotoCards", PPhotoCards);
Vue.component("PPhotoMosaic", PPhotoMosaic);
Vue.component("PPhotoList", PPhotoList);

View file

@ -89,11 +89,11 @@
<script>
import {Photo, TypeLive, TypeRaw, TypeVideo} from "model/photo";
import Album from "model/album";
import Event from "pubsub-js";
import Thumb from "model/thumb";
import Event from "pubsub-js";
import Notify from "common/notify";
import download from "common/download";
import Api from "common/api";
import Viewer from "common/viewer";
export default {
name: 'PPageAlbumPhotos',
@ -136,7 +136,8 @@ export default {
viewer: {
results: [],
loading: false,
complete: true,
complete: false,
dirty: false,
batchSize: batchSize > 160 ? 480 : batchSize * 3
},
};
@ -230,7 +231,7 @@ export default {
Event.publish("dialog.edit", {selection: selection, album: this.album, index: index});
},
openPhoto(index, showMerged) {
if (this.loading || this.viewer.loading || !this.results[index]) {
if (this.loading || !this.listen || this.viewer.loading || !this.results[index]) {
return false;
}
@ -250,78 +251,21 @@ export default {
} else if (showMerged) {
this.$viewer.show(Thumb.fromFiles([selected]), 0);
} else {
if (this.viewer.results && this.viewer.results.length > index) {
// Reuse existing viewer result if possible.
let i = -1;
if (this.viewer.results[index] && this.viewer.results[index].uid === selected.UID) {
i = index;
} else {
i = this.viewer.results.findIndex(p => p.uid === selected.UID);
}
if (i > -1 && (((this.viewer.complete || this.complete) && this.viewer.results.length >= this.results.length)
|| ((i + this.viewer.batchSize) <= this.viewer.results.length))
) {
this.$viewer.show(this.viewer.results, i);
return;
}
}
// Fetch photos from server API.
this.viewer.loading = true;
const params = this.searchParams();
params.count = this.complete ? params.offset : params.offset + this.viewer.batchSize;
params.offset = 0;
// Fetch viewer results from API.
return Api.get("photos/view", {params}).then((response) => {
let count = response && response.data ? response.data.length : 0;
if (count > 0) {
// Process response.
if (response.headers && response.headers["x-count"]) {
const c = parseInt(response.headers["x-count"]);
const l = parseInt(response.headers["x-limit"]);
this.viewer.complete = c < l;
}
let i;
if (response.data[index] && response.data[index].uid === selected.UID) {
i = index;
} else {
i = response.data.findIndex(p => p.uid === selected.UID);
}
this.viewer.results = Thumb.wrap(response.data);
// Show photos.
this.$viewer.show(this.viewer.results, i);
} else {
// Don't open viewer if nothing was found.
this.viewer.results = [];
this.viewer.complete = false;
this.$notify.warn(this.$gettext("No pictures found"));
}
}).catch(() => {
// Reset results in case of an error.
this.viewer.results = [];
this.viewer.complete = false;
}).finally(() => {
// Unblock.
this.viewer.loading = false;
});
Viewer.show(this, index);
}
return true;
},
loadMore() {
if (this.scrollDisabled) return;
if (this.scrollDisabled || this.$scrollbar.disabled()) return;
this.scrollDisabled = true;
this.listen = false;
if (this.dirty) {
this.viewer.dirty = true;
}
const count = this.dirty ? (this.page + 2) * this.batchSize : this.batchSize;
const offset = this.dirty ? 0 : this.offset;

View file

@ -9,24 +9,24 @@ let assert = chai.assert;
describe("model/thumb", () => {
it("should get thumb defaults", () => {
const values = {
uid: "55",
title: "",
taken: "",
description: "",
favorite: false,
playable: false,
original_w: 0,
original_h: 0,
download_url: "",
UID: "55",
Title: "",
TakenAtLocal: "",
Description: "",
Favorite: false,
Playable: false,
Width: 0,
Height: 0,
DownloadUrl: "",
};
const thumb = new Thumb(values);
const result = thumb.getDefaults();
assert.equal(result.uid, "");
assert.equal(result.UID, "");
});
it("should get id", () => {
const values = {
uid: "55",
UID: "55",
};
const thumb = new Thumb(values);
assert.equal(thumb.getId(), "55");
@ -34,13 +34,13 @@ describe("model/thumb", () => {
it("should return hasId", () => {
const values = {
uid: "55",
UID: "55",
};
const thumb = new Thumb(values);
assert.equal(thumb.hasId(), true);
const values2 = {
title: "",
Title: "",
};
const thumb2 = new Thumb(values2);
assert.equal(thumb2.hasId(), false);
@ -48,28 +48,28 @@ describe("model/thumb", () => {
it("should toggle like", () => {
const values = {
uid: "55",
title: "",
taken: "",
description: "",
favorite: true,
playable: false,
original_w: 0,
original_h: 0,
download_url: "",
UID: "55",
Title: "",
TakenAtLocal: "",
Description: "",
Favorite: true,
Playable: false,
Width: 0,
Height: 0,
DownloadUrl: "",
};
const thumb = new Thumb(values);
assert.equal(thumb.favorite, true);
assert.equal(thumb.Favorite, true);
thumb.toggleLike();
assert.equal(thumb.favorite, false);
assert.equal(thumb.Favorite, false);
thumb.toggleLike();
assert.equal(thumb.favorite, true);
assert.equal(thumb.Favorite, true);
});
it("should return thumb not found", () => {
const result = Thumb.thumbNotFound();
assert.equal(result.uid, "");
assert.equal(result.favorite, false);
assert.equal(result.UID, "");
assert.equal(result.Favorite, false);
});
it("should test from file", () => {
@ -93,11 +93,11 @@ describe("model/thumb", () => {
};
const photo = new Photo(values2);
const result = Thumb.fromFile(photo, file);
assert.equal(result.uid, "5");
assert.equal(result.description, "Nice description");
assert.equal(result.original_w, 500);
assert.equal(result.UID, "5");
assert.equal(result.Description, "Nice description");
assert.equal(result.Width, 500);
const result2 = Thumb.fromFile();
assert.equal(result2.uid, "");
assert.equal(result2.UID, "");
});
it("should test from files", () => {
@ -143,9 +143,9 @@ describe("model/thumb", () => {
const photo3 = new Photo(values4);
const Photos2 = [photo, photo2, photo3];
const result2 = Thumb.fromFiles(Photos2);
assert.equal(result2[0].uid, "ABC123");
assert.equal(result2[0].description, "Nice description 2");
assert.equal(result2[0].original_w, 500);
assert.equal(result2[0].UID, "ABC123");
assert.equal(result2[0].Description, "Nice description 2");
assert.equal(result2[0].Width, 500);
assert.equal(result2.length, 1);
const values5 = {
ID: 8,
@ -168,9 +168,9 @@ describe("model/thumb", () => {
const Photos3 = [photo3, photo2, photo4];
const result3 = Thumb.fromFiles(Photos3);
assert.equal(result3.length, 1);
assert.equal(result3[0].uid, "ABC123");
assert.equal(result3[0].description, "Nice description 2");
assert.equal(result3[0].original_w, 500);
assert.equal(result3[0].UID, "ABC123");
assert.equal(result3[0].Description, "Nice description 2");
assert.equal(result3[0].Width, 500);
});
it("should test from files", () => {
@ -199,9 +199,9 @@ describe("model/thumb", () => {
};
const photo = new Photo(values);
const result = Thumb.fromPhoto(photo);
assert.equal(result.uid, "ABC123");
assert.equal(result.description, "Nice description 3");
assert.equal(result.original_w, 500);
assert.equal(result.UID, "ABC123");
assert.equal(result.Description, "Nice description 3");
assert.equal(result.Width, 500);
const values3 = {
ID: 8,
UID: "ABC124",
@ -209,7 +209,7 @@ describe("model/thumb", () => {
};
const photo3 = new Photo(values3);
const result2 = Thumb.fromPhoto(photo3);
assert.equal(result2.uid, "");
assert.equal(result2.UID, "");
const values2 = {
ID: 8,
UID: "ABC123",
@ -222,9 +222,9 @@ describe("model/thumb", () => {
};
const photo2 = new Photo(values2);
const result3 = Thumb.fromPhoto(photo2);
assert.equal(result3.uid, "ABC123");
assert.equal(result3.title, "Crazy Cat");
assert.equal(result3.description, "Nice description");
assert.equal(result3.UID, "ABC123");
assert.equal(result3.Title, "Crazy Cat");
assert.equal(result3.Description, "Nice description");
});
it("should test from photos", () => {
@ -248,9 +248,9 @@ describe("model/thumb", () => {
const photo = new Photo(values);
const Photos = [photo];
const result = Thumb.fromPhotos(Photos);
assert.equal(result[0].uid, "ABC123");
assert.equal(result[0].description, "Nice description 3");
assert.equal(result[0].original_w, 500);
assert.equal(result[0].UID, "ABC123");
assert.equal(result[0].Description, "Nice description 3");
assert.equal(result[0].Width, 500);
});
it("should return download url", () => {

View file

@ -11,23 +11,25 @@ import (
// ViewerResult returns a new photo viewer result.
func (photo Photo) ViewerResult(contentUri, apiUri, previewToken, downloadToken string) viewer.Result {
return viewer.Result{
UID: photo.PhotoUID,
Title: photo.PhotoTitle,
Taken: photo.TakenAtLocal,
Description: photo.PhotoDescription,
Favorite: photo.PhotoFavorite,
Playable: photo.PhotoType == entity.TypeVideo || photo.PhotoType == entity.TypeLive,
DownloadUrl: viewer.DownloadUrl(photo.FileHash, apiUri, downloadToken),
OriginalW: photo.FileWidth,
OriginalH: photo.FileHeight,
Fit720: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit720], contentUri, previewToken),
Fit1280: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1280], contentUri, previewToken),
Fit1920: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1920], contentUri, previewToken),
Fit2048: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2048], contentUri, previewToken),
Fit2560: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2560], contentUri, previewToken),
Fit3840: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit3840], contentUri, previewToken),
Fit4096: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit4096], contentUri, previewToken),
Fit7680: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit7680], contentUri, previewToken),
UID: photo.PhotoUID,
Title: photo.PhotoTitle,
TakenAtLocal: photo.TakenAtLocal,
Description: photo.PhotoDescription,
Favorite: photo.PhotoFavorite,
Playable: photo.PhotoType == entity.TypeVideo || photo.PhotoType == entity.TypeLive,
DownloadUrl: viewer.DownloadUrl(photo.FileHash, apiUri, downloadToken),
Width: photo.FileWidth,
Height: photo.FileHeight,
Thumbs: viewer.Thumbs{
Fit720: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit720], contentUri, previewToken),
Fit1280: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1280], contentUri, previewToken),
Fit1920: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1920], contentUri, previewToken),
Fit2048: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2048], contentUri, previewToken),
Fit2560: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2560], contentUri, previewToken),
Fit3840: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit3840], contentUri, previewToken),
Fit4096: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit4096], contentUri, previewToken),
Fit7680: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit7680], contentUri, previewToken),
},
}
}
@ -50,23 +52,25 @@ func (photos PhotoResults) ViewerResults(contentUri, apiUri, previewToken, downl
// ViewerResult creates a new photo viewer result.
func (photo GeoResult) ViewerResult(contentUri, apiUri, previewToken, downloadToken string) viewer.Result {
return viewer.Result{
UID: photo.PhotoUID,
Title: photo.PhotoTitle,
Taken: photo.TakenAtLocal,
Description: photo.PhotoDescription,
Favorite: photo.PhotoFavorite,
Playable: photo.PhotoType == entity.TypeVideo || photo.PhotoType == entity.TypeLive,
DownloadUrl: viewer.DownloadUrl(photo.FileHash, apiUri, downloadToken),
OriginalW: photo.FileWidth,
OriginalH: photo.FileHeight,
Fit720: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit720], contentUri, previewToken),
Fit1280: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1280], contentUri, previewToken),
Fit1920: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1920], contentUri, previewToken),
Fit2048: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2048], contentUri, previewToken),
Fit2560: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2560], contentUri, previewToken),
Fit3840: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit3840], contentUri, previewToken),
Fit4096: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit4096], contentUri, previewToken),
Fit7680: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit7680], contentUri, previewToken),
UID: photo.PhotoUID,
Title: photo.PhotoTitle,
TakenAtLocal: photo.TakenAtLocal,
Description: photo.PhotoDescription,
Favorite: photo.PhotoFavorite,
Playable: photo.PhotoType == entity.TypeVideo || photo.PhotoType == entity.TypeLive,
DownloadUrl: viewer.DownloadUrl(photo.FileHash, apiUri, downloadToken),
Width: photo.FileWidth,
Height: photo.FileHeight,
Thumbs: viewer.Thumbs{
Fit720: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit720], contentUri, previewToken),
Fit1280: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1280], contentUri, previewToken),
Fit1920: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit1920], contentUri, previewToken),
Fit2048: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2048], contentUri, previewToken),
Fit2560: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit2560], contentUri, previewToken),
Fit3840: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit3840], contentUri, previewToken),
Fit4096: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit4096], contentUri, previewToken),
Fit7680: viewer.NewThumb(photo.FileWidth, photo.FileHeight, photo.FileHash, thumb.Sizes[thumb.Fit7680], contentUri, previewToken),
},
}
}

View file

@ -4,26 +4,31 @@ import (
"time"
)
// Results represents a list of viewer search results.
type Results []Result
// Thumbs represents photo viewer thumbs in different sizes.
type Thumbs struct {
Fit720 Thumb `json:"fit_720"`
Fit1280 Thumb `json:"fit_1280"`
Fit1920 Thumb `json:"fit_1920"`
Fit2048 Thumb `json:"fit_2048"`
Fit2560 Thumb `json:"fit_2560"`
Fit3840 Thumb `json:"fit_3840"`
Fit4096 Thumb `json:"fit_4096"`
Fit7680 Thumb `json:"fit_7680"`
}
// Result represents a photo viewer result.
type Result struct {
UID string `json:"uid"`
Title string `json:"title"`
Taken time.Time `json:"taken"`
Description string `json:"description"`
Favorite bool `json:"favorite"`
Playable bool `json:"playable"`
DownloadUrl string `json:"download_url""`
OriginalW int `json:"original_w"`
OriginalH int `json:"original_h"`
Fit720 Thumb `json:"fit_720"`
Fit1280 Thumb `json:"fit_1280"`
Fit1920 Thumb `json:"fit_1920"`
Fit2048 Thumb `json:"fit_2048"`
Fit2560 Thumb `json:"fit_2560"`
Fit3840 Thumb `json:"fit_3840"`
Fit4096 Thumb `json:"fit_4096"`
Fit7680 Thumb `json:"fit_7680"`
UID string `json:"UID"`
Title string `json:"Title"`
TakenAtLocal time.Time `json:"TakenAtLocal"`
Description string `json:"Description"`
Favorite bool `json:"Favorite"`
Playable bool `json:"Playable"`
DownloadUrl string `json:"DownloadUrl"`
Width int `json:"Width"`
Height int `json:"Height"`
Thumbs Thumbs `json:"Thumbs"`
}
// Results represents a list of viewer search results.
type Results []Result