Przeglądaj źródła

Added Music module experimental paging function

Toby Chui 3 lat temu
rodzic
commit
df21c58522

+ 8 - 1
web/Music/functions/listSong.js

@@ -55,7 +55,10 @@ function handleUserRequest(){
                 //Load from cache first. If cache list > 1000 then deliver the cache then update the cache file
                 newDBTableIfNotExists("AirMusic");
                 var cacheListRaw = readDBItem("AirMusic", "cache");
-
+                //var isRanged = false; //Check if this only need to return from a range
+                //if (typeof(start) != "undefined" && typeof(end) != "undefined"){
+                //    isRanged = true;
+                //}
                 if (cacheListRaw == ""){
                     //Cache list not generated yet. Continue
 
@@ -95,6 +98,10 @@ function handleUserRequest(){
                     var thisMusicFile = musicFiles[i];
                     var thisSongData = [];
                     
+                    /*
+                        Catch formats looks like this
+                        entry = [access_url, filename, ext, filesize]
+                    */
                     //Access Path 
                     thisSongData.push("/media?file=" + thisMusicFile);
                     //File Name only

BIN
web/Music/img/default.png


BIN
web/Music/img/default.psd


+ 153 - 26
web/Music/index.html

@@ -30,9 +30,9 @@
 	<button class="ui right item icon AMmenu noBorder button" onClick="enterSearchMode();"><i class="search icon"></i></button>
 	<!-- <button class="ui right item icon AMmenu noBorder button"><i class="ellipsis vertical icon"></i></button> -->
 </div>
-<div id="searchModeMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:85;position:fixed;top:0px;left:0px;width:100%;height:51px;display:none;">
+<div id="searchModeMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:85;position:fixed;top:0px;left:0px;width:100%;height:51px;display:none;margin-top: 0px;">
     <button class="ui item icon noBorder AMmenu button" onClick="exitSearchMode();"><i class="arrow left icon"></i></button>
-	<div class="ui fluid input" >
+	<div class="ui input" style="flex-grow: 1;">
 		<input id="searchInputBar" onkeypress="//handleSearchInputEnter(event);" type="text" style="background-color:rgb(48, 48, 48);border:0px !important;border-bottom:2px solid rgb(60, 60, 60) !important;margin-bottom:3px;color:white;" placeholder="Search Music">
 	</div>
 	<button class="ui right item icon AMmenu noBorder button" onClick="searchSong();"><i class="search icon"></i></button>
@@ -372,6 +372,9 @@
 	var playingFileDetail = []; //[id, filepath]
 	var displayList = []; //This is the list where the current UI is displaying.
 	var playingList = []; //This is the list where the player last clicked on an item to play
+	var pagingEnabled = false; //Enable this when there are too many songs in list
+	var pagingCutoffCount = 100; //No. of songs to start paging
+	var currentPage = 0;
 	var randomMode = false;
 	var repeatMode = 0; //Repeat mode 0 -> No repeat, 1 -> Repeat all 2 -> Repeat one
 	var updateSystemVolume = true;
@@ -469,6 +472,14 @@
 
 	function loadNetworkView(){
 		currentMode = "network";
+		togglePagingMode(false);
+	}
+
+	function togglePagingMode(enabled=false){
+		if (pagingEnabled != enabled){
+			currentPage = 0;
+		}
+		pagingEnabled = enabled;
 	}
 	
 	function initAudioListeners(){
@@ -609,7 +620,7 @@
 			listSong: "search:" + keyword
 		}, function(data){
 			currentPath = "";
-			var template = '<div class="mainList item" filepath={filepath} id={id} rawname={rawname}>\
+			var template = '<div class="mainList file item" filepath={filepath} id={id} rawname={rawname}>\
 			<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">\
 				<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>\
 				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
@@ -647,6 +658,7 @@
 			</div>');
 			return;
 		}
+		
 
         $("#interfaceTitle").text("Search");
         $("#AMmenuIcon").attr("class","search icon large whiteFont")
@@ -675,7 +687,9 @@
 		$("#mainList").append("<br><br><br><br><br><br><br>");
 		$("#interfaceDetails").text("[" + i + " songs]");
 		highLightPlayingMusic();
+		loadThumbnailToMusicList(".mainList.file.item");
 	});
+
 	}
 	
 	function enterRemotePlayID(object){
@@ -1146,6 +1160,12 @@
 
 	    updateMiniPlayerUI(displayName,info,id);
 
+		//Check if page mode is enabled. If yes, do auto tab switch
+		if (pagingEnabled){
+			var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
+			switchToPage(targetPageNumber);
+		}
+
 		//Seperate out the filepath without media server path
 		var fileVpath = filepath.split("=")[1];
 	    updateMainPlayerUI(displayName,info,id, fileVpath);
@@ -1195,6 +1215,12 @@
 
 				}else{
 					$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + data);
+					$(".dropdownList.file.item").each(function(){
+						var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
+						if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
+							$(this).find("img").attr("src","data:image/jpg;base64," + data);
+						}
+					})
 				}
 			});
 		})
@@ -1273,7 +1299,17 @@
     	    }
     	    playingFileDetail = [id,filepath];
     	    //Need not to update the playlist because it is the same
-    	    highLightPlayingMusic();
+			if (pagingEnabled){
+				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
+				switchToPage(targetPageNumber, function(){
+					highLightPlayingMusic();
+					parsePlayingSongList();
+				});
+			}else{
+				highLightPlayingMusic();
+			}
+			
+			
 	    }else{
 	        //This is the only song in playlist. Play again from start
 	        audioElement[0].pause();
@@ -1313,7 +1349,15 @@
     	    }
     	    playingFileDetail = [id,filepath];
     	    //Need not to update the playlist because it is the same
-    	    highLightPlayingMusic();
+    	    if (pagingEnabled){
+				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
+				switchToPage(targetPageNumber, function(){
+					highLightPlayingMusic();
+					parsePlayingSongList();
+				});
+			}else{
+				highLightPlayingMusic();
+			}
 	    }else{
 	        //This is the only song in playlist. Play again from start
 	        audioElement[0].pause();
@@ -1483,7 +1527,7 @@
 							${i + 1}
 						</div>
 						<div class="mainList rightFunctionBar" type="file" align="center" onclick="showMore(this);">
-							<i class="ellipsis vertical icon" style="top: 2em;"></i>
+							<i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>
 						</div>
 					</div>`);
 
@@ -1581,6 +1625,7 @@
 		currentMode = "playlist";
 		//Clear the main list
 		$("#mainList").html("");
+		togglePagingMode(false);
 		ao_module_agirun("Music/functions/playlist.js", {
 			opr: "root",
 		},function(data){
@@ -1628,6 +1673,7 @@
         </div>\
     </div>';
         $("#interfaceTitle").text("Storage");
+		togglePagingMode(false);
 		$("#AMmenuIcon").attr("class","folder open icon large whiteFont");
 		ao_module_agirun("Music/functions/listSong.js", {
 			listdir: "root",
@@ -1894,15 +1940,7 @@
 				//Use back the previous method of filepath storage for compatibility
 				var filepath = $(this).attr("filepath");
 			}
-	        
-			/*
-	        if (id == playingFileDetail[0] && filepath == playingFileDetail[1]){
-	            //This piece of music is playing in the current list
-	            $(this).addClass("playingTrack");
-	        }else if (playingFileDetail[0] == -1 && filepath == playingFileDetail[1]){
-				//This is for external accessed music playback. Music file might or might not exists in the current playlist. Try to highlight anyway
-				$(this).addClass("playingTrack");
-			}*/
+			
 			//Id is ignored in the 9/9/2019 updates and only check if the path matches.
 			if (filepath == playingFileDetail[1]){
 				$(this).addClass("playingTrack");
@@ -2057,8 +2095,14 @@
 
 			//Get thumbnail from the current list to prevent re-loading form remote
 			let targetThumbnail = $("#" + (i + 1)).find("img").attr("src");
+			let opacityShowing = "";
+			if ($("#" + (i + 1)).length == 0){
+				//Item not exists
+				targetThumbnail = "img/eq.svg";
+				opacityShowing = "opacity: 0.6;"
+			}
 
-			$("#currentPlayingMainList").append(`<div class="dropdownList file item" filepath="${ao_module_utils.objectToAttr(playingList[i][0])}" listid="${i + 1}" rawname="${ao_module_utils.objectToAttr(playingList[i][1])}">
+			$("#currentPlayingMainList").append(`<div class="dropdownList file item" style="${opacityShowing}" filepath="${ao_module_utils.objectToAttr(playingList[i][0])}" listid="${i + 1}" rawname="${ao_module_utils.objectToAttr(playingList[i][1])}">
 				<div class="ui header selectable" style="margin:0px !important;" onClick="playSongFromDropdownList(this);">
 					<img class="ui small image" src="${targetThumbnail}" style="margin-right: 0.2em;"></img>
 					<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
@@ -2104,13 +2148,32 @@
 					});
 				}
 			}
-			console.log(displayList);
-	        
-	        if (playingList == []){
+
+			//Updates 2022-07-12: Check if the list is too long. If yes, use paging
+			let renderRange = [0,displayList.length];
+
+			if (displayList.length > pagingCutoffCount){
+				togglePagingMode(true);
+				renderRange = [0, pagingCutoffCount];
+			}else{
+				togglePagingMode(false);
+			}
+
+			if (playingList == []){
 	            playingList = Array.from(displayList);
 	        }
-	        $("#mainList").html("");
-	        for ( var i =0; i < displayList.length; i++){
+
+			renderDisplayList(displayList,renderRange[0], renderRange[1] );
+
+	    }, function(){
+			alert("Failed to access listSong API with type: " + type)
+		});
+	    hideLeftMenu();
+	}
+
+	function renderDisplayList(displayList, start, end, callback=undefined){
+		$("#mainList").html("");
+		for ( var i =start; i < end; i++){
 	            var songInfo = displayList[i];
 	            var path = songInfo[0];
 	            var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
@@ -2132,18 +2195,82 @@
 					</div>
 				</div>`);
 	        }
+
+			if (pagingEnabled){
+				//Append the page switch buttons
+				let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
+				let pageSelector  = "";
+				for (var i = 0; i < numberOfPages; i++){
+					pageSelector = pageSelector + `<button onclick="switchToPage(${i});" class="inverted ui icon button" style="border: 0px solid transparent; box-shadow: none !important; -webkit-box-shadow: none !important;">
+										${i + 1}
+									</button>`;
+				}
+				$("#mainList").append(`<div class="mainList item" style="cursor: unset;">
+					<div>${pageSelector}</div>	
+				</div>`);
+			}
+
+
 	        totalMusicCount = displayList.length;
 	        $("#mainList").append("<br><br><br><br><br><br><br>");
-	        $("#interfaceDetails").text("[" + i + " songs]");
+	        $("#interfaceDetails").text("[" + totalMusicCount + " songs]");
 	        highLightPlayingMusic();
 
+			
 			//Load thumbnail for song in list
 			loadThumbnailToMusicList();
 
-	    }, function(){
-			alert("Failed to access listSong API with type: " + type)
-		});
-	    hideLeftMenu();
+			if (callback != undefined){
+				callback();
+			}
+	}
+
+	function switchToPage(pageNumber, callback=undefined){
+		if (!pagingEnabled){
+			return;
+		}
+		let thisCallback = callback;
+		if (pageNumber == currentPage){
+			//Already in that page
+			if (thisCallback != undefined){
+				callback();
+			}
+			return;
+		}
+
+		currentPage = pageNumber;
+
+		let startPage = pageNumber * pagingCutoffCount;
+		let endPage = startPage + pagingCutoffCount;
+		if (endPage > displayList.length){
+			endPage = displayList.length;
+		}
+
+		
+		if (thisCallback == undefined){
+			renderDisplayList(displayList, startPage, endPage, function(){
+				window.scrollTo(0, document.body.scrollHeight);
+			});
+		}else{
+			renderDisplayList(displayList, startPage, endPage,thisCallback);
+		}
+		
+	}
+
+	function getPageNumberByPlaybackId(id){
+		let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
+		let targetPageNo = Math.ceil(id / pagingCutoffCount) - 1;
+		return targetPageNo;
+	}
+
+	function getPageStartAndEndByPageNumber(pageNumber){
+		let startPage = pageNumber * pagingCutoffCount;
+		let endPage = startPage + pagingCutoffCount;
+		if (endPage > displayList.length){
+			endPage = displayList.length;
+		}
+
+		return [startPage, endPage];
 	}
 	
 	

+ 10 - 3
web/Music/main.css

@@ -97,8 +97,15 @@ p,span,h1,h2,h3,h4,h5,h6,div,a,button{
     height:100%;
     width:100%;
     background:rgba(20,20,20,0.8);
-    backdrop-filter: blur(3px);
 }
+
+@supports ((-webkit-backdrop-filter: blur(2px)) or (backdrop-filter: blur(2px))) {
+    #playerInterface{
+        backdrop-filter: blur(2px);
+        background:rgba(20,20,20,0.5);
+    }
+}
+
 #miniPlayer{
     z-index:45;
     position:fixed;
@@ -209,8 +216,8 @@ p,span,h1,h2,h3,h4,h5,h6,div,a,button{
     padding-right:6em;
     padding-top:5px;
     padding-bottom:5px;
-    background-color:rgba(12, 12, 12, 0.8);
-    backdrop-filter: saturate(180%) blur(5px);
+    background-color:rgba(12, 12, 12, 0.6);
+    backdrop-filter: saturate(180%) blur(3px);
     display:none;
     z-index:95;
 }