diff --git a/module/webui/index.html b/module/webui/index.html
index 307a6ac..2ae3529 100644
--- a/module/webui/index.html
+++ b/module/webui/index.html
@@ -32,7 +32,7 @@
-
+
+
+
diff --git a/module/webui/scripts/about.js b/module/webui/scripts/about.js
index 2aee469..3bc013e 100644
--- a/module/webui/scripts/about.js
+++ b/module/webui/scripts/about.js
@@ -1,4 +1,4 @@
-import { execCommand } from './main.js';
+import { execCommand, linkRedirect } from './main.js';
const telegramLink = document.getElementById('telegram');
const githubLink = document.getElementById('github');
@@ -38,17 +38,9 @@ document.getElementById("about").addEventListener("click", () => {
});
// Event listener for link redirect
-telegramLink.addEventListener('click', async () => {
- try {
- await execCommand('am start -a android.intent.action.VIEW -d https://t.me/kowchannel');
- } catch (error) {
- console.error('Error opening Telegram link:', error);
- }
+telegramLink.addEventListener('click', function() {
+ linkRedirect('https://t.me/kowchannel');
});
-githubLink.addEventListener('click', async () => {
- try {
- await execCommand('am start -a android.intent.action.VIEW -d https://github.com/KOWX712/Tricky-Addon-Update-Target-List');
- } catch (error) {
- console.error('Error opening GitHub link:', error);
- }
+githubLink.addEventListener('click', function() {
+ linkRedirect('https://github.com/KOWX712/Tricky-Addon-Update-Target-List');
});
\ No newline at end of file
diff --git a/module/webui/scripts/applist.js b/module/webui/scripts/applist.js
index 5bd76c7..141ba55 100644
--- a/module/webui/scripts/applist.js
+++ b/module/webui/scripts/applist.js
@@ -86,7 +86,7 @@ export async function fetchAppList() {
} catch (error) {
console.error("Failed to fetch or render app list with names:", error);
}
- floatingBtn.style.transform = "translateY(-120px)";
+ floatingBtn.style.transform = 'translateY(0)';
toggleableCheckbox();
if (appListContainer.firstChild !== updateCard) {
appListContainer.insertBefore(updateCard, appListContainer.firstChild);
@@ -119,9 +119,7 @@ function toggleableCheckbox() {
const content = card.querySelector(".content");
const checkbox = content.querySelector(".checkbox");
content.addEventListener("click", (event) => {
- if (event.target !== checkbox) {
- checkbox.checked = !checkbox.checked;
- }
+ checkbox.checked = !checkbox.checked;
});
});
}
\ No newline at end of file
diff --git a/module/webui/scripts/main.js b/module/webui/scripts/main.js
index d93a91b..7ec252c 100644
--- a/module/webui/scripts/main.js
+++ b/module/webui/scripts/main.js
@@ -12,13 +12,14 @@ export const noConnection = document.querySelector('.no-connection');
// Loading, Save and Prompt Elements
const loadingIndicator = document.querySelector('.loading');
const prompt = document.getElementById('prompt');
+const floatingCard = document.querySelector('.floating-card');
export const floatingBtn = document.querySelector('.floating-btn');
export const basePath = "set-path";
export const appsWithExclamation = [];
export const appsWithQuestion = [];
const ADDITIONAL_APPS = [ "com.google.android.gms", "io.github.vvb2060.keyattestation", "io.github.vvb2060.mahoshojo", "icu.nullptr.nativetest" ];
-const rippleClasses = ['.language-option', '.menu-button', '.menu-options li', '.search-card', '.card', '.update-card', '.link-icon', '.floating-btn', '.uninstall-container'];
+const rippleClasses = ['.language-option', '.menu-button', '.menu-options li', '.search-card', '.card', '.update-card', '.link-icon', '.floating-btn', '.uninstall-container', '.boot-hash-save-button', '.boot-hash-value'];
// Variables
let e = 0;
@@ -41,7 +42,7 @@ async function refreshAppList() {
isRefreshing = true;
title.style.transform = 'translateY(0)';
searchMenuContainer.style.transform = 'translateY(0)';
- floatingBtn.style.transform = 'translateY(0)';
+ hideFloatingBtn();
searchInput.value = '';
clearBtn.style.display = "none";
appListContainer.innerHTML = '';
@@ -89,15 +90,27 @@ export function showPrompt(key, isSuccess = true) {
clearTimeout(window.promptTimeout);
}
setTimeout(() => {
- prompt.classList.add('visible');
- prompt.classList.remove('hidden');
+ if (typeof ksu !== 'undefined' && ksu.mmrl) {
+ prompt.style.transform = 'translateY(calc((var(--window-inset-bottom) + 60%) * -1))';
+ } else {
+ prompt.style.transform = 'translateY(-60%)';
+ }
window.promptTimeout = setTimeout(() => {
- prompt.classList.remove('visible');
- prompt.classList.add('hidden');
+ prompt.style.transform = 'translateY(100%)';
}, 3000);
}, 200);
}
+// Function to redirect link on external browser
+export async function linkRedirect(link) {
+ try {
+ await execCommand(`am start -a android.intent.action.VIEW -d ${link}`);
+ } catch (error) {
+ toast('error!');
+ console.error('Error redirect link:', error);
+ }
+}
+
// Save configure and preserve ! and ? in target.txt
document.getElementById("save").addEventListener("click", async () => {
const selectedApps = Array.from(appListContainer.querySelectorAll(".checkbox:checked"))
@@ -155,6 +168,16 @@ function adjustHeaderForMMRL() {
const insetTopValue = parseInt(insetTop, 10);
searchMenuContainer.style.top = `${insetTopValue + 40}px`;
headerBlock.style.display = 'block';
+ floatingCard.style.bottom = 'calc(var(--window-inset-bottom) + 50px)';
+ }
+}
+
+// Funtion to adapt floating button hide in MMRL
+function hideFloatingBtn() {
+ if (typeof ksu !== 'undefined' && ksu.mmrl) {
+ floatingBtn.style.transform = 'translateY(calc(var(--window-inset-bottom) + 120px))';
+ } else {
+ floatingBtn.style.transform = 'translateY(120px)';
}
}
@@ -162,26 +185,55 @@ function adjustHeaderForMMRL() {
function applyRippleEffect() {
rippleClasses.forEach(selector => {
document.querySelectorAll(selector).forEach(element => {
- element.addEventListener("click", function(event) {
+ element.addEventListener("pointerdown", function (event) {
+ if (isScrolling) return;
+
const ripple = document.createElement("span");
ripple.classList.add("ripple");
+ // Calculate ripple size and position
const rect = element.getBoundingClientRect();
const width = rect.width;
const size = Math.max(rect.width, rect.height);
const x = event.clientX - rect.left - size / 2;
const y = event.clientY - rect.top - size / 2;
- let duration = 0.3 + (width / 800) * 0.5;
+ // Determine animation duration
+ let duration = 0.2 + (width / 800) * 0.5;
duration = Math.min(0.8, Math.max(0.2, duration));
+
+ // Set ripple styles
ripple.style.width = ripple.style.height = `${size}px`;
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
ripple.style.animationDuration = `${duration}s`;
+ ripple.style.transition = `opacity ${duration}s ease`;
+
+ // Adaptive color
+ const computedStyle = window.getComputedStyle(element);
+ const bgColor = computedStyle.backgroundColor || "rgba(0, 0, 0, 0)";
+ const textColor = computedStyle.color;
+ const isDarkColor = (color) => {
+ const rgb = color.match(/\d+/g);
+ if (!rgb) return false;
+ const [r, g, b] = rgb.map(Number);
+ return (r * 0.299 + g * 0.587 + b * 0.114) < 128; // Luma formula
+ };
+ ripple.style.backgroundColor = isDarkColor(bgColor) ? "rgba(255, 255, 255, 0.2)" : "";
+
+ // Append ripple and handle cleanup
element.appendChild(ripple);
- ripple.addEventListener("animationend", () => {
- ripple.remove();
- });
+ const handlePointerUp = () => {
+ ripple.classList.add("end");
+ setTimeout(() => {
+ ripple.classList.remove("end");
+ ripple.remove();
+ }, duration * 1000);
+ element.removeEventListener("pointerup", handlePointerUp);
+ element.removeEventListener("pointercancel", handlePointerUp);
+ };
+ element.addEventListener("pointerup", handlePointerUp);
+ element.addEventListener("pointercancel", handlePointerUp);
});
});
});
@@ -189,19 +241,26 @@ function applyRippleEffect() {
// Scroll event
let lastScrollY = window.scrollY;
+let isScrolling = false;
+let scrollTimeout;
const scrollThreshold = 40;
window.addEventListener('scroll', () => {
+ isScrolling = true;
+ clearTimeout(scrollTimeout);
+ scrollTimeout = setTimeout(() => {
+ isScrolling = false;
+ }, 200);
if (isRefreshing) return;
if (window.scrollY > lastScrollY && window.scrollY > scrollThreshold) {
title.style.transform = 'translateY(-80px)';
headerBlock.style.transform = 'translateY(-80px)';
searchMenuContainer.style.transform = 'translateY(-40px)';
- floatingBtn.style.transform = 'translateY(0)';
+ hideFloatingBtn();
} else if (window.scrollY < lastScrollY) {
headerBlock.style.transform = 'translateY(0)';
title.style.transform = 'translateY(0)';
searchMenuContainer.style.transform = 'translateY(0)';
- floatingBtn.style.transform = 'translateY(-120px)';
+ floatingBtn.style.transform = 'translateY(0)';
}
lastScrollY = window.scrollY;
});
@@ -254,4 +313,9 @@ export async function execCommand(command) {
reject(error);
}
});
+}
+
+// Function to toast message
+export function toast(message) {
+ ksu.toast(message);
}
\ No newline at end of file
diff --git a/module/webui/styles/about.css b/module/webui/styles/about.css
index 676f3fa..a6b95df 100644
--- a/module/webui/styles/about.css
+++ b/module/webui/styles/about.css
@@ -53,14 +53,17 @@
#module_name_line1 {
font-size: 26px;
+ user-select: none;
}
#module_name_line2 {
font-size: 22px;
+ user-select: none;
}
#authored {
font-size: 14px;
+ user-select: none;
}
#disclaimer {
@@ -70,6 +73,7 @@
#acknowledgment {
font-weight: bold;
font-size: 18px;
+ user-select: none;
}
.link-icon {
@@ -95,6 +99,7 @@
background-color: #38A7ED;
color: #fff;
fill: #fff;
+ user-select: none;
}
#github {
@@ -103,6 +108,7 @@
background-color: #606060;
color: #fff;
fill: #fff;
+ user-select: none;
}
#link-text {
diff --git a/module/webui/styles/applist.css b/module/webui/styles/applist.css
index f6eb4cc..65c742c 100644
--- a/module/webui/styles/applist.css
+++ b/module/webui/styles/applist.css
@@ -67,11 +67,66 @@
max-width: calc(100% - 30px);
overflow-wrap: break-word;
word-break: break-word;
+ user-select: none;
+}
+
+.checkbox-wrapper {
+ position: relative;
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ margin-left: auto;
}
.checkbox {
- margin-left: auto;
- transform: scale(1.15);
+ opacity: 0;
+ position: absolute;
+ width: 0;
+ height: 0;
+}
+
+.custom-checkbox {
+ position: relative;
+ display: inline-block;
+ width: 100%;
+ height: 100%;
+ border: 2px solid #ccc;
+ border-radius: 4px;
+ transition: border-color 1s ease, transform 0.3s ease, background-color 0.4s cubic-bezier(0.22, 1, 0.36, 1);
+ box-sizing: border-box;
+}
+
+.tick-symbol {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%) scale(0);
+ opacity: 0;
+ transition: transform 0.2s ease-out, opacity 0.3s ease;
+}
+
+.checkbox:checked + .custom-checkbox {
+ border-color: #007bff;
+ background-color: #007bff;
+ transition: border-color 0.1s ease;
+ animation: border-bounce 0.3s ease-out;
+}
+
+.checkbox:checked + .custom-checkbox .tick-symbol {
+ transform: translate(-50%, -50%) scale(1);
+ opacity: 1;
+}
+
+@keyframes border-bounce {
+ 0% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(0.8);
+ }
+ 100% {
+ transform: scale(1);
+ }
}
@media (prefers-color-scheme: dark) {
diff --git a/module/webui/styles/boot-hash.css b/module/webui/styles/boot-hash.css
index 3cbaac9..d8bb635 100644
--- a/module/webui/styles/boot-hash.css
+++ b/module/webui/styles/boot-hash.css
@@ -42,15 +42,30 @@
opacity: 1;
}
-.input-box {
- width: calc(100% - 20px);
+.boot-hash-value {
+ width: 100%;
height: 100px;
- resize: none;
- padding: 9px;
font-size: 16px;
background-color: #FFF;
border: 1px solid #ccc;
border-radius: 10px;
+ box-sizing: border-box;
+ position: relative;
+ overflow: hidden;
+}
+
+.input-box {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ padding: 10px;
+ font-size: 16px;
+ border-radius: 9px;
+ box-sizing: border-box;
+ background-color: transparent;
+ outline-color: #007bff;
}
.button-container {
@@ -67,11 +82,9 @@
background-color: #007bff;
color: white;
margin-left: auto;
- transition: background-color 0.2s ease;
-}
-
-.boot-hash-save-button:active {
- background-color: #003d80;
+ position: relative;
+ overflow: hidden;
+ user-select: none;
}
@media (prefers-color-scheme: dark) {
@@ -81,6 +94,9 @@
.input-box {
color: #fff;
+ }
+
+ .boot-hash-value {
background-color: #343434;
border: 1px solid #6E6E6E;
}
diff --git a/module/webui/styles/global.css b/module/webui/styles/global.css
index 57355f4..cb2b333 100644
--- a/module/webui/styles/global.css
+++ b/module/webui/styles/global.css
@@ -12,7 +12,7 @@ body {
display: flex;
justify-content: center;
position: fixed;
- bottom: -70px;
+ bottom: 50px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
@@ -30,9 +30,10 @@ body {
padding: 10px 20px;
font-size: 20px;
font-weight: bold;
- transition: transform 0.3s ease-in-out, background-color 0.2s ease;
+ transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
border-radius: 50px 50px;
overflow: hidden;
+ user-select: none;
}
.prompt {
@@ -49,49 +50,13 @@ body {
width: auto;
max-width: calc(100% - 40px);
transform: translateY(100%);
- transition: transform 0.5s ease;
-}
-
-.prompt.visible {
- animation: YbounceIn 0.4s forwards;
-}
-
-.prompt.hidden {
- animation: YbounceOut 0.4s forwards;
+ transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.prompt.error {
background-color: #f44336;
}
-@keyframes YbounceIn {
- 0% {
- transform: translateY(100%);
- }
-
- 50% {
- transform: translateY(-80%);
- }
-
- 100% {
- transform: translateY(-60%);
- }
-}
-
-@keyframes YbounceOut {
- 0% {
- transform: translateY(-60%);
- }
-
- 50% {
- transform: translateY(-80%);
- }
-
- 100% {
- transform: translateY(100%);
- }
-}
-
.loading {
position: fixed;
top: 0;
@@ -130,6 +95,7 @@ body {
background-color: #CE0000;
white-space: nowrap;
overflow: hidden;
+ user-select: none;
}
.uninstall-container i {
@@ -150,15 +116,19 @@ body {
position: absolute;
border-radius: 50%;
transform: scale(0);
- animation: ripple-animation ease-out;
+ opacity: 1;
+ animation: ripple-animation ease-out forwards;
pointer-events: none;
background: rgba(0, 0, 0, 0.2);
}
+.ripple.end {
+ opacity: 0;
+}
+
@keyframes ripple-animation {
to {
- transform: scale(4);
- opacity: 0;
+ transform: scale(3);
}
}
@@ -167,9 +137,4 @@ body {
background-color: #121212;
color: #fff;
}
-
- .ripple {
- background: rgba(255, 255, 255, 0.2);
- }
-
}
\ No newline at end of file
diff --git a/module/webui/styles/header.css b/module/webui/styles/header.css
index 97264b7..f4c86c9 100644
--- a/module/webui/styles/header.css
+++ b/module/webui/styles/header.css
@@ -8,12 +8,13 @@
width: calc(100% - 10px);
max-width: 1100px;
background-color: #F5F5F5;
- transition: transform 0.3s ease;
+ transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
z-index: 1100;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
+ user-select: none;
}
.header-block {
@@ -24,7 +25,7 @@
left: 0;
width: 100%;
z-index: 1100;
- transition: transform 0.3s ease;
+ transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
height: var(--window-inset-top);
}
@@ -74,7 +75,7 @@
max-height: calc(100vh - 50px);
overflow-y: auto;
transform: translateY(-10px);
- transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
+ transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.language-menu.show {
@@ -97,6 +98,7 @@
transition: background-color 0.2s ease;
position: relative;
overflow: hidden;
+ user-select: none;
}
.language-option:last-child {
@@ -133,7 +135,7 @@
justify-content: center;
align-items: center;
opacity: 0;
- transition: opacity 0.2s ease;
+ transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.help-overlay.show {
@@ -174,6 +176,7 @@
.help-content p {
font-size: 26px;
+ user-select: none;
}
.help-content ul {
diff --git a/module/webui/styles/search_menu.css b/module/webui/styles/search_menu.css
index 982387b..7c9fff5 100644
--- a/module/webui/styles/search_menu.css
+++ b/module/webui/styles/search_menu.css
@@ -6,7 +6,7 @@
width: calc(100% - 20px);
max-width: 1100px;
z-index: 1000;
- transition: transform 0.3s ease;
+ transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
margin-left: auto;
margin-right: auto;
left: 0;
@@ -86,7 +86,7 @@
display: inline-block;
fill: #000;
transform: rotate(0deg);
- transition: transform 0.2s ease;
+ transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.menu-icon.menu-open {
@@ -108,10 +108,10 @@
max-height: calc(100vh - 120px);
overflow-y: auto;
white-space: nowrap;
- opacity: 0;
visibility: hidden;
transform: translateX(120%);
- transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s ease;
+ transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
+ user-select: none;
}
#select-denylist {
@@ -120,7 +120,6 @@
.menu-options.visible {
display: block;
- opacity: 1;
visibility: visible;
transform: translateX(0);
}