diff --git a/packages/gallery/src/data/album.js b/packages/gallery/src/data/album.js index 872427b..e17f346 100644 --- a/packages/gallery/src/data/album.js +++ b/packages/gallery/src/data/album.js @@ -1,5 +1,6 @@ import { PouchDB, TypeSpec } from '../services/db.js'; -import { log } from '../services/console.js'; +import { ImageType } from '../data/image.js'; +import { extractID } from '../utils/conversion.js'; class AlbumSpec extends TypeSpec { static getUniqueID(doc) { @@ -9,23 +10,48 @@ class AlbumSpec extends TypeSpec { .toLowerCase(); } - async addMember(member, position) { - const currentPosition = this.members.indexOf(member); - const newPosition = position ? position : this.members.length; - if (currentPosition !== -1) { - this.members.splice(currentPosition, 1); - } - this.members.splice(newPosition, 0, member); - await this.save(); + async findImages(live = false) { + return await ImageType.find( + Object.assign({ [`$links.${this._id}`]: { $exists: true } }, ImageType.selector), + live + ); } - async removeMember(member) { - const currentPosition = this.members.indexOf(member); - - if (currentPosition !== -1) { - this.members.splice(currentPosition, 1); + async addImage(image) { + if (!image.$links[this._id]) { + await image.update({ + $links: { + [this._id]: { + sequence: this.count + } + } + }); + this.count += 1; await this.save(); } + return image; + } + + async removeImage(image) { + if (image.$links[this._id]) { + delete image.$links[this._id]; + this.count -= 1; + await image.save(); + await this.save(); + } + return image; + } + + async addImageBlob(blob) { + return await this.addImage(await ImageType.upload(blob)); + } + + async delete(cascade = true) { + if (cascade) { + const images = await this.findImages(); + images.map(async i => await this.removeImage(i)); + } + return await this.update({ _deleted: true }); } // @@ -34,10 +60,8 @@ class AlbumSpec extends TypeSpec { // // const schema = { // title: t.REQUIRED_STRING, - // members: { - // type: "array", - // items: t.STRING - // } + // createdDate: t.REQUIRED_DATE, + // count: t.REQUIRED_INTEGER // }; // } } diff --git a/packages/gallery/src/data/image.js b/packages/gallery/src/data/image.js index 3943474..7b60ba1 100644 --- a/packages/gallery/src/data/image.js +++ b/packages/gallery/src/data/image.js @@ -91,29 +91,25 @@ const processImportables = backgroundTask(async function _processImportables(ima tags.DateTimeOriginal ? new Date(tags.DateTimeOriginal * 1000).toISOString() : image.originalDate ).toISOString(); - await image.update( - { - originalDate, - width, - height, - orientation: tags.Orientation, - digest, - make: tags.Make, - model: tags.Model, - flash: !!tags.Flash, - iso: tags.ISO, - sizes, - gps: { - latitude: tags.GPSLatitude, - longitude: tags.GPSLongitude, - altitude: tags.GPSAltitude, - heading: tags.GPSImgDirection - } - }, - false - ); delete image.importing; - await image.save(); + await image.update({ + originalDate, + width, + height, + orientation: tags.Orientation, + digest, + make: tags.Make, + model: tags.Model, + flash: !!tags.Flash, + iso: tags.ISO, + sizes, + gps: { + latitude: tags.GPSLatitude, + longitude: tags.GPSLongitude, + altitude: tags.GPSAltitude, + heading: tags.GPSImgDirection + } + }); const module = await import('../context/generateThumbnails'); module.generateThumbnailForImage(image); diff --git a/packages/gallery/src/interface/album.js b/packages/gallery/src/interface/album.js index 75119de..ea05f6b 100644 --- a/packages/gallery/src/interface/album.js +++ b/packages/gallery/src/interface/album.js @@ -6,7 +6,7 @@ import { pouchDocArrayHash, pouchDocHash } from '../utils/conversion.js'; import { ThumbnailView } from './thumbnail.js'; import { prop, computed, bundle } from 'frptools'; -export function AlbumView(vm, params) { +export function AlbumView(vm, doc) { const model = prop({}, pouchDocHash); const images = prop([], pouchDocArrayHash); @@ -16,53 +16,49 @@ export function AlbumView(vm, params) { let laCleanup = null; - id.subscribe(async () => { - const la = await ImageType.find( - { - _id: { $in: members() } - }, - true - ); - - function refresh() { - images(la()); - vm.redraw(); + model.subscribe(async album => { + if (!album.findImages) { + return; } + const imagesLiveArray = await album.findImages(true); if (laCleanup) { laCleanup(); } - laCleanup = la.subscribe(refresh); - la.ready.subscribe(refresh); + function refresh() { + images(imagesLiveArray()); + vm.redraw(); + } + + laCleanup = imagesLiveArray.subscribe(refresh); + imagesLiveArray.ready.subscribe(refresh); }); function removeImageFromAlbum(image) { - model().removeMember(image._id); + model().removeImage(image); } - function removeAlbum() { - model().delete(); + function removeAlbum(album) { + album.delete(); } function uploadImages(album, evt) { - Promise.all(Array.from(evt.currentTarget.files).map(ImageType.upload)).then(images => { - images.forEach(i => album.addMember(i._id)); - }); + Array.from(evt.currentTarget.files).forEach(f => album.addImageBlob(f)); } - model(params.doc); + model(doc); - return function(vm, params, key, opts) { - model(params.doc); + return function(vm, album, key, opts) { + model(album); return el('.album', [ - el('h2', [title(), el('button', { onclick: removeAlbum }, 'X')]), + el('h2', [title(), el('button', { onclick: [removeAlbum, album] }, 'X')]), el('input#fInput', { type: 'file', multiple: true, accept: 'image/jpeg', - onchange: [uploadImages, model()] + onchange: [uploadImages, album] }), ...images().map(i => { return defineView( diff --git a/packages/gallery/src/interface/gallery.js b/packages/gallery/src/interface/gallery.js index 4d138fb..ee64367 100644 --- a/packages/gallery/src/interface/gallery.js +++ b/packages/gallery/src/interface/gallery.js @@ -89,23 +89,13 @@ export function GalleryView(vm, model) { { doc: i, showTags: true, - // addTag: imageTag.add, remove: deleteImage - // removeTag: imageTag.remove }, i._id + i._rev ); }) : data().map(a => { - return vw( - AlbumView, - { - doc: a - // addTag: imageTag.add, - // remove: imageTag.remove - }, - a._id + a._rev - ); + return vw(AlbumView, a, a._id + a._rev); })) ]) ]); diff --git a/packages/gallery/src/services/db.js b/packages/gallery/src/services/db.js index 94a749a..b4ba77f 100644 --- a/packages/gallery/src/services/db.js +++ b/packages/gallery/src/services/db.js @@ -19,7 +19,7 @@ export const PouchDB = core export class TypeSpec { constructor(props) { this._populateId(props); - Object.assign(this, props, { type: this._prefix }); + Object.assign(this, { $links: {} }, props, { type: this._prefix }); } static getSequence(doc) { diff --git a/packages/gallery/src/utils/comparators.js b/packages/gallery/src/utils/comparators.js index 9b14c2b..29956b3 100644 --- a/packages/gallery/src/utils/comparators.js +++ b/packages/gallery/src/utils/comparators.js @@ -1,7 +1,4 @@ -import { pick } from './conversion.js'; - -const extractID = pick('_id'); -const extractREV = pick('_rev'); +import { extractID, extractREV } from './conversion.js'; export function pouchDocComparator(a, b) { return extractID(a) === extractID(b) && extractREV(a) === extractREV(b); diff --git a/packages/gallery/src/utils/conversion.js b/packages/gallery/src/utils/conversion.js index 3c8808d..4eee9f6 100644 --- a/packages/gallery/src/utils/conversion.js +++ b/packages/gallery/src/utils/conversion.js @@ -46,3 +46,6 @@ export function deepAssign(to, ...rest) { } export const pick = id => doc => doc[id]; + +export const extractID = pick('_id'); +export const extractREV = pick('_rev');