view libervia/pages/photos/album/_browser/__init__.py @ 1308:7a4a92cf5b2b

browser (album): start slideshow on photo click
author Goffi <goffi@goffi.org>
date Thu, 16 Jul 2020 09:08:50 +0200
parents 6e110baa707f
children 39a87d9099c4
line wrap: on
line source

from browser import document, window, bind, html, DOMNode
from browser import aio
from browser import timer
from javascript import JSON
from interpreter import Inspector
from bridge import Bridge
from template import Template
import dialog
from slideshow import SlideShow

files_service = window.files_service
files_path = window.files_path
bridge = Bridge()


def on_progress(ev, photo_elt):
    if ev.lengthComputable:
        percent = int(ev.loaded/ev.total*100)
        update_progress(photo_elt, percent)


def on_load(file_, photo_elt):
    update_progress(photo_elt, 100)
    photo_elt.classList.add("progress_finished")
    photo_elt.classList.remove("progress_started")
    photo_elt.select_one('.action_delete').bind("click", on_delete)
    print(f"file {file_.name} uploaded correctly")


def on_error(failure, file_, photo_elt):
    # TODO: cleaner error notification
    window.alert(f"can't upload {file_.name}: failure")


def update_progress(photo_elt, new_value):
    progress_elt = photo_elt.select_one("progress")
    progress_elt.value = new_value
    progress_elt.text = f"{new_value}%"


def on_slot_cb(file_, upload_slot, photo_elt):
    put_url, get_url, headers = upload_slot
    xhr = window.XMLHttpRequest.new()
    xhr.open("PUT", put_url, True)
    xhr.upload.bind('progress', lambda ev: on_progress(ev, photo_elt))
    xhr.upload.bind('load', lambda ev: on_load(file_, photo_elt))
    xhr.upload.bind('error', lambda ev: on_error(xhr.response, file_, photo_elt))
    xhr.setRequestHeader('Xmpp-File-Path', window.encodeURIComponent(files_path))
    xhr.setRequestHeader('Xmpp-File-No-Http', "true")
    xhr.send(file_)


def on_slot_eb(file_, failure, photo_elt):
    breakpoint()


def upload_files(files):
    print(f"uploading {len(files)} files")
    photo_tpl = Template('photo/item.html')
    album_items = document['album_items']
    for file_ in files:
        url = window.URL.createObjectURL(file_)
        photo_elt = photo_tpl.get_elt({
            "file": {
                "name": file_.name,
                # we don't want to open the file on click, it's not yet the
                # uploaded URL
                "url": url,
                # we have no thumb yet, so we use the whole image
                # TODO: reduce image for preview
                "thumb_url": url,
            },
            "uploading": True,
        })
        photo_elt.classList.add("progress_started")
        print(photo_elt.outerHTML)
        album_items <= photo_elt
        # timer.set_timeout(lambda photo_elt=photo_elt: fake_finish(photo_elt), 5000)

        bridge.fileHTTPUploadGetSlot(
            file_.name,
            file_.size,
            file_.type or '',
            files_service,
            callback=lambda upload_slot, file_=file_, photo_elt=photo_elt:
                on_slot_cb(file_, upload_slot, photo_elt),
            errback=lambda failure, file_=file_, photo_elt=photo_elt:
                on_slot_eb(file_, failure, photo_elt),
        )


@bind("#file_drop", "drop")
def on_file_select(evt):
    evt.stopPropagation()
    evt.preventDefault()
    files = evt.dataTransfer.files
    upload_files(files)


@bind("#file_drop", "dragover")
def on_drag_over(evt):
    evt.stopPropagation()
    evt.preventDefault()
    evt.dataTransfer.dropEffect = 'copy'


@bind("#file_input", "change")
def on_file_input_change(evt):
    files = evt.currentTarget.files
    upload_files(files)


def file_delete_cb(item_elt, item):
    item_elt.classList.add("state_deleted")
    item_elt.bind("transitionend", lambda evt: item_elt.remove())
    print(f"deleted {item['name']}")


def file_delete_eb(failure, item_elt, item):
    # TODO: cleaner error notification
    window.alert(f"error while deleting {item['name']}: failure")


def delete_ok(evt, notif_elt, item_elt, item):
    file_path = f"{files_path.rstrip('/')}/{item['name']}"
    bridge.fileSharingDelete(
        files_service,
        file_path,
        "",
        callback=lambda : file_delete_cb(item_elt, item),
        errback=lambda failure: file_delete_eb(failure, item_elt, item),
    )


def delete_cancel(evt, notif_elt, item_elt, item):
    notif_elt.remove()
    item_elt.classList.remove("selected_for_deletion")


def on_delete(evt):
    evt.stopPropagation()
    target = evt.currentTarget
    item_elt = DOMNode(target.elt.closest('.item'))
    item_elt.classList.add("selected_for_deletion")
    item = JSON.parse(item_elt.dataset.item)
    dialog.Confirm(
        f"{item['name']!r} will be deleted, are you sure?",
        ok_label="delete",
    ).show(
        ok_cb=lambda evt, notif_elt: delete_ok(evt, notif_elt, item_elt, item),
        cancel_cb=lambda evt, notif_elt: delete_cancel(evt, notif_elt, item_elt, item),
    )


@bind(".photo_thumb_click", "click")
def photo_click(evt):
    evt.stopPropagation()
    evt.preventDefault()
    slideshow = SlideShow()
    target = evt.currentTarget
    clicked_item_elt = DOMNode(target.elt.closest('.item'))

    select_idx = 0
    slideshow.attach()
    for idx, item_elt in enumerate(document.select('.item')):
        item = JSON.parse(item_elt.dataset.item)
        slide = html.DIV(Class="swiper-slide")
        img = html.IMG(src=item['url'], Class="slide_img")
        slide <= img
        slide._item = item
        slideshow.add_slide(slide)
        if item_elt == clicked_item_elt:
            slideshow.index = idx


for elt in document.select('.action_delete'):
    elt.bind("click", on_delete)