Przeglądaj źródła

Added experimental albumn in Camera module

TC pushbot 5 4 lat temu
rodzic
commit
1782302335

+ 48 - 3
mod/agi/agi.file.go

@@ -6,6 +6,8 @@ import (
 	"log"
 	"os"
 	"path/filepath"
+	"sort"
+	"strings"
 
 	"github.com/robertkrimen/otto"
 	fs "imuslab.com/arozos/mod/filesystem"
@@ -314,6 +316,8 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 			return reply
 		}
 
+		sortMode, _ := call.Argument(1).ToString()
+
 		if regex != "/" && !u.CanRead(regex) {
 			panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
 		}
@@ -336,11 +340,52 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 			return reply
 		}
 
-		results := []string{}
+		type SortingFileData struct {
+			Filename string
+			Filepath string
+			Filesize int64
+			ModTime  int64
+		}
+
+		parsedFilelist := []fs.FileData{}
 		for _, file := range suitableFiles {
-			thisRpath, _ := realpathToVirtualpath(filepath.ToSlash(file), u)
-			results = append(results, thisRpath)
+			vpath, _ := realpathToVirtualpath(filepath.ToSlash(file), u)
+			modtime, _ := fs.GetModTime(file)
+			parsedFilelist = append(parsedFilelist, fs.FileData{
+				Filename: filepath.Base(file),
+				Filepath: vpath,
+				Filesize: fs.GetFileSize(file),
+				ModTime:  modtime,
+			})
+		}
+
+		if sortMode != "" {
+			if sortMode == "reverse" {
+				//Sort by reverse name
+				sort.Slice(parsedFilelist, func(i, j int) bool {
+					return strings.ToLower(parsedFilelist[i].Filename) > strings.ToLower(parsedFilelist[j].Filename)
+				})
+			} else if sortMode == "smallToLarge" {
+				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize < parsedFilelist[j].Filesize })
+			} else if sortMode == "largeToSmall" {
+				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize > parsedFilelist[j].Filesize })
+			} else if sortMode == "mostRecent" {
+				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime > parsedFilelist[j].ModTime })
+			} else if sortMode == "leastRecent" {
+				sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime < parsedFilelist[j].ModTime })
+			} else {
+				sort.Slice(parsedFilelist, func(i, j int) bool {
+					return strings.ToLower(parsedFilelist[i].Filename) < strings.ToLower(parsedFilelist[j].Filename)
+				})
+			}
 		}
+
+		//Parse the results (Only extract the filepath)
+		results := []string{}
+		for _, fileData := range parsedFilelist {
+			results = append(results, fileData.Filepath)
+		}
+
 		reply, _ := vm.ToValue(results)
 		return reply
 	})

+ 52 - 0
web/Camera/backend/listPhoto.js

@@ -0,0 +1,52 @@
+/*
+    List Photos
+
+    This script list all the photos within the user selected save target folder
+    sorted by the time where the photo is taken (Latest first)
+*/
+
+requirelib("filelib");
+
+var savetarget = "user:/Photo/DCIM";
+
+function generatePhotoList(){
+    //Check if savetarget is empty
+    if (typeof savetarget == 'undefined' || savetarget == ""){
+        sendJSONResp(JSON.stringify({
+            error: "savetarget not defined"
+        }));
+        return
+    }
+
+    //Check if save target exists
+    if (!filelib.fileExists(savetarget)){
+        sendJSONResp(JSON.stringify({
+            error: "savetarget not exists"
+        }));
+        return
+    }
+
+    //Glob it
+    if (savetarget.substring(savetarget.length - 1,1) != "/"){
+        savetarget = savetarget + "/";
+    }
+
+    var files = filelib.aglob(savetarget + "*.*", "mostRecent");
+    var results = [];
+   
+    //Filter out only the png and jpg files
+    for (var i = 0; i < files.length; i++){
+        var thisFile = files[i];
+        if (!filelib.isDir(thisFile)){
+            var ext = thisFile.split(".").pop();
+            if (ext == "jpg" || ext == "png"){
+                results.push(thisFile);
+            }
+        }
+    }
+
+    //Send the results
+    sendJSONResp(JSON.stringify(results));
+}
+
+generatePhotoList();

+ 12 - 1
web/Camera/backend/loadLatestPhoto.js

@@ -28,7 +28,18 @@ function getLatestPhotoFilename(){
     }
 
     //Save target exists. Glob it
-    var files = filelib.aglob(savetarget + "*.jpg");
+    var jpgFiles = filelib.aglob(savetarget + "*.jpg");
+    var pngFiles = filelib.aglob(savetarget + "*.png");
+    var files = [];
+
+    for (var i = 0; i < jpgFiles.length; i++){
+        files.push(jpgFiles[i]);
+    }
+
+    for (var i = 0; i < pngFiles.length; i++){
+        files.push(pngFiles[i]);
+    }
+
     var latestFileMtime = 0;
     var latestFilename = "";
     for (var i = 0; i < files.length; i++){

+ 1 - 0
web/Camera/img/icons/back-arrow.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>

+ 1 - 0
web/Camera/img/icons/delete.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M14.12 10.47L12 12.59l-2.13-2.12-1.41 1.41L10.59 14l-2.12 2.12 1.41 1.41L12 15.41l2.12 2.12 1.41-1.41L13.41 14l2.12-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4zM6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM8 9h8v10H8V9z"/></svg>

+ 1 - 0
web/Camera/img/icons/folder.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z"/></svg>

BIN
web/Camera/img/no-photo.png


BIN
web/Camera/img/no-photo.psd


BIN
web/Camera/img/place-holder.png


BIN
web/Camera/img/place-holder.psd


+ 10 - 6
web/Camera/index.html

@@ -124,6 +124,7 @@
 
 			.ablumnpreview{
 				width: 3em;
+				cursor: pointer;
 			}
 
 			.latestPreview{
@@ -156,11 +157,6 @@
 		<video id="camera" class="previewer" autoplay></video>
 		<div id="shutterCover"></div>
 		<canvas id="canvas" style="display:none;"></canvas>
-		<div id="albumn">
-			<div class="ablumnpreview">
-				<img class="ui fluid image latestPreview" src="img/module_icon.png"> 
-			</div>
-		</div>
 		<div id="controls">
 			<div class="zoombarcontainer">
 				<input id="zoombar" type="range" min="1" max="100" value="50">
@@ -200,7 +196,11 @@
 					</div>
 				</div>
 			</div>
-
+			<div id="albumn">
+				<div class="ablumnpreview" onclick="openImageView();">
+					<img class="ui fluid image latestPreview" src="img/module_icon.png"> 
+				</div>
+			</div>
 		</div>
 		<script>
 			let isMobile = false;
@@ -221,6 +221,10 @@
 				initVideoDeviceConstraints();
 			});
 
+			function openImageView(){
+				window.location.href = "preview.html";
+			}
+
 			$(window).on("resize", function(){
 				handleWindowResize();
 			});	

+ 198 - 0
web/Camera/preview.html

@@ -0,0 +1,198 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<meta name="apple-mobile-web-app-capable" content="yes" />
+		<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
+		<meta name="theme-color" content="#4b75ff">
+		<link rel="stylesheet" href="../script/semantic/semantic.min.css">
+		<script src="../script/jquery.min.js"></script>
+		<script src="../script/semantic/semantic.min.js"></script>
+		<script src="../script/ao_module.js"></script>
+        <title>Camera</title>
+        <style>
+            body{
+                background-color: black;
+            }
+
+            .topcontrol{
+                position: fixed;
+                top: 0px;
+                left: 0px;
+                width: 100%;
+                padding: 8px;
+                z-index: 1000;
+            }
+
+            .clickable{
+                width: 3em;
+                cursor: pointer;
+            }
+
+            .right-floated{
+                position: absolute;
+                right: 8px;
+                top: 8px;
+                display: inline-block;
+            }
+
+            .imgwrapper{
+                position: fixed;
+                top: 0px;
+                left: 0px;
+                width: 100%;
+                height: 100%;
+                z-index: 10;
+            }
+            .imgbox {
+                display: grid;
+                height: 100%;
+                z-index: 10 !important;
+            }
+            .center-fit {
+                max-width: 100%;
+                max-height: 100vh;
+                margin: auto;
+                z-index: 10;
+            }
+        </style>
+    </head>
+    <body>
+        <div class="topcontrol">
+            <div class="clickable" onclick="backToCamera();">
+                <img class="ui mini image" src="img/icons/back-arrow.svg"/>
+            </div>
+            <div class="right-floated">
+                <div class="clickable" onclick="openInFolder();" style="display: inline-block;">
+                    <img class="ui mini image" src="img/icons/folder.svg"/>
+                </div>
+                <div class="clickable" onclick="deleteThis();" style="display: inline-block;">
+                    <img class="ui mini image" src="img/icons/delete.svg"/>
+                </div>
+            </div>
+        </div>
+        <div class="imgwrapper">
+            <div class="imgbox">
+                <img id="viewpoint" class="center-fit" src='img/place-holder.png'>
+            </div>
+        </div>
+        <script>
+            let photoList = [];
+            let currentViewingPhoto = 0; //The index of current viewing photo
+            let saveTarget = "user:/Photo/DCIM/";
+            
+            function backToCamera(){
+                window.location.href = "index.html";
+            }
+
+            $(document).ready(function(){
+                //Load the latest image
+                ao_module_agirun("Camera/backend/listPhoto.js",{
+                    savetarget: saveTarget,
+                }, function(data){
+                    if (data.error !== undefined || data == ""){
+                        //No photo
+                    }else{
+                        //Load it
+                        currentViewingPhoto = 0;
+                        photoList = data;
+                        $("#viewpoint").attr('src', '../media/?file=' + data[0]);
+                    }
+                });
+            });
+
+            function openInFolder(){
+                if (currentViewingPhoto == ""){
+                    //Unknown error. open the DCIM folder
+                    ao_module_openPath(saveTarget);
+                }else{
+                    //Open the folder and highlight the picture
+                    var filedata = currentViewingPhoto.split("/");
+                    var filename = filedata.pop();
+                    var fileRoot = filedata.join("/");
+                    ao_module_openPath(fileRoot, filename);
+                }
+                
+            }
+
+
+            function nextPhoto(){
+                if (currentViewingPhoto == currentViewingPhoto.length - 1){
+                    //Already the last photo
+                }else{
+                    renderPhotoByPath(currentViewingPhoto + 1);
+                }
+            }
+
+            function previousPhoto(){
+                if (currentViewingPhoto == 0){
+                    //Already the firs photo
+                }else{
+                    renderPhotoByPath(currentViewingPhoto - 1);
+                }
+                
+            }
+
+            function renderPhotoByPath(index){
+                if (photoList[index] != undefined){
+                    currentViewingPhoto = index;
+                    $("#viewpoint").attr('src', '../media/?file=' + photoList[index]);
+                }
+                
+            }
+
+            /*
+                Special code to handle swipe left and right
+                
+            */
+
+            document.addEventListener('touchstart', handleTouchStart, false);        
+            document.addEventListener('touchmove', handleTouchMove, false);
+
+            var xDown = null;                                                        
+            var yDown = null;
+
+            function getTouches(evt) {
+            return evt.touches ||             // browser API
+                    evt.originalEvent.touches; // jQuery
+            }                                                     
+
+            function handleTouchStart(evt) {
+                const firstTouch = getTouches(evt)[0];                                      
+                xDown = firstTouch.clientX;                                      
+                yDown = firstTouch.clientY;                                      
+            };                                                
+
+            function handleTouchMove(evt) {
+                if ( ! xDown || ! yDown ) {
+                    return;
+                }
+
+                var xUp = evt.touches[0].clientX;                                    
+                var yUp = evt.touches[0].clientY;
+
+                var xDiff = xDown - xUp;
+                var yDiff = yDown - yUp;
+
+                if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
+                    if ( xDiff > 0 ) {
+                        /* left swipe */ 
+                        nextPhoto();
+                    } else {
+                        /* right swipe */
+                        previousPhoto();
+                    }                       
+                } else {
+                    if ( yDiff > 0 ) {
+                        /* up swipe */ 
+                    } else { 
+                        /* down swipe */
+                    }                                                                 
+                }
+                /* reset values */
+                xDown = null;
+                yDown = null;                                             
+            };
+        </script>
+    </body>
+</html>