mirror of
https://github.com/NoCrypt/migu.git
synced 2026-04-20 08:02:12 +00:00
feat: swipe gesture in android
This commit is contained in:
parent
a2739ca114
commit
7ac6fd678e
6 changed files with 212 additions and 3 deletions
|
|
@ -10,6 +10,7 @@ android {
|
|||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-community-file-opener')
|
||||
implementation project(':capacitor-community-screen-brightness')
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-browser')
|
||||
implementation project(':capacitor-filesystem')
|
||||
|
|
@ -17,6 +18,7 @@ dependencies {
|
|||
implementation project(':capacitor-status-bar')
|
||||
implementation project(':capacitor-nodejs')
|
||||
implementation project(':capacitor-plugin-safe-area')
|
||||
implementation project(':capacitor-volume-control')
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ project(':capacitor-android').projectDir = new File('../../node_modules/@capacit
|
|||
include ':capacitor-community-file-opener'
|
||||
project(':capacitor-community-file-opener').projectDir = new File('../../node_modules/@capacitor-community/file-opener/android')
|
||||
|
||||
include ':capacitor-community-screen-brightness'
|
||||
project(':capacitor-community-screen-brightness').projectDir = new File('../../node_modules/@capacitor-community/screen-brightness/android')
|
||||
|
||||
include ':capacitor-app'
|
||||
project(':capacitor-app').projectDir = new File('../../node_modules/@capacitor/app/android')
|
||||
|
||||
|
|
@ -25,3 +28,6 @@ project(':capacitor-nodejs').projectDir = new File('../../node_modules/capacitor
|
|||
|
||||
include ':capacitor-plugin-safe-area'
|
||||
project(':capacitor-plugin-safe-area').projectDir = new File('../../node_modules/capacitor-plugin-safe-area/android')
|
||||
|
||||
include ':capacitor-volume-control'
|
||||
project(':capacitor-volume-control').projectDir = new File('../../../volume-control/capacitor-volume-control/android')
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@capacitor-community/file-opener": "^6.0.0",
|
||||
"@capacitor-community/screen-brightness": "^6.0.0",
|
||||
"@capacitor/android": "^6.1.1",
|
||||
"@capacitor/app": "^6.0.0",
|
||||
"@capacitor/cli": "^6.1.1",
|
||||
"@capacitor/browser": "^6.0.1",
|
||||
"@capacitor/cli": "^6.1.1",
|
||||
"@capacitor/core": "^6.1.1",
|
||||
"@capacitor/filesystem": "^6.0.0",
|
||||
"@capacitor/ios": "^6.1.1",
|
||||
|
|
@ -38,6 +39,7 @@
|
|||
"@capacitor/status-bar": "^6.0.0",
|
||||
"capacitor-nodejs": "https://github.com/hampoelz/Capacitor-NodeJS/releases/download/v1.0.0-beta.7/capacitor-nodejs.tgz",
|
||||
"capacitor-plugin-safe-area": "^3.0.3",
|
||||
"capacitor-volume-control": "^0.0.1",
|
||||
"common": "workspace:*",
|
||||
"cordova-plugin-navigationbar-color": "^0.1.0",
|
||||
"cordova-plugin-pip": "^0.0.2",
|
||||
|
|
|
|||
173
common/modules/swipecontrol.js
Normal file
173
common/modules/swipecontrol.js
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
import { Capacitor } from '@capacitor/core';
|
||||
import { ScreenBrightness } from '@capacitor-community/screen-brightness';
|
||||
import { VolumeControl } from 'capacitor-volume-control';
|
||||
|
||||
export function swipeControls(node, props = { enabled: true, immersePlayer: () => {} }) {
|
||||
if (!props.enabled) return;
|
||||
|
||||
const isNative = Capacitor.isNativePlatform();
|
||||
let brightness = 50;
|
||||
let volume = 50; // Start at middle volume (range 0-100)
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let isDragging = false;
|
||||
let activeControl = null;
|
||||
let timeoutId;
|
||||
let updateTimeoutId;
|
||||
|
||||
const indicators = document.createElement('div');
|
||||
indicators.className = 'swipe-control-indicators';
|
||||
indicators.style.cssText = `
|
||||
position: absolute;
|
||||
top: 75%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
pointer-events: none;
|
||||
color: white;
|
||||
text-shadow: 1px 1px 2px black;
|
||||
`;
|
||||
|
||||
indicators.innerHTML = `
|
||||
<div class="indicator brightness">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="5"/>
|
||||
<line x1="12" y1="1" x2="12" y2="3"/>
|
||||
<line x1="12" y1="21" x2="12" y2="23"/>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
||||
<line x1="1" y1="12" x2="3" y2="12"/>
|
||||
<line x1="21" y1="12" x2="23" y2="12"/>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
||||
</svg>
|
||||
<span class="brightness-value">100%</span>
|
||||
</div>
|
||||
<div class="indicator volume">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
|
||||
<path d="M15.54 8.46a5 5 0 0 1 0 7.07"/>
|
||||
<path d="M19.07 4.93a10 10 0 0 1 0 14.14"/>
|
||||
</svg>
|
||||
<span class="volume-value">50%</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
node.style.position = 'relative';
|
||||
node.appendChild(indicators);
|
||||
|
||||
const brightnessValue = indicators.querySelector('.brightness-value');
|
||||
const volumeValue = indicators.querySelector('.volume-value');
|
||||
|
||||
function handleTouchStart(event) {
|
||||
if (!props.enabled) return;
|
||||
props.immersePlayer();
|
||||
if (!isNative) return;
|
||||
isDragging = true;
|
||||
startX = event.touches[0].clientX;
|
||||
startY = event.touches[0].clientY;
|
||||
const rect = node.getBoundingClientRect();
|
||||
activeControl = (event.touches[0].clientX - rect.left) < rect.width / 2 ? 'brightness' : 'volume';
|
||||
}
|
||||
|
||||
function handleTouchMove(event) {
|
||||
if (!props.enabled) return;
|
||||
if (!isNative || !isDragging) return;
|
||||
|
||||
const currentY = event.touches[0].clientY;
|
||||
const deltaY = startY - currentY;
|
||||
const rect = node.getBoundingClientRect();
|
||||
const sensitivity = 0.5 * (200 / rect.height);
|
||||
|
||||
if (activeControl === 'brightness') {
|
||||
brightness = Math.max(0, Math.min(100, brightness + deltaY * sensitivity));
|
||||
updateBrightness();
|
||||
} else if (activeControl === 'volume') {
|
||||
volume = Math.max(0, Math.min(100, volume + deltaY * sensitivity));
|
||||
debouncedUpdateVolume();
|
||||
}
|
||||
|
||||
showControlsIndicator();
|
||||
startY = currentY;
|
||||
}
|
||||
|
||||
function handleTouchEnd() {
|
||||
if (!props.enabled) return;
|
||||
isDragging = false;
|
||||
activeControl = null;
|
||||
}
|
||||
|
||||
async function updateBrightness() {
|
||||
try {
|
||||
await ScreenBrightness.setBrightness({ brightness: brightness / 100 });
|
||||
brightnessValue.textContent = `${Math.round(brightness)}%`;
|
||||
} catch (error) {
|
||||
console.error('Error updating brightness:', error);
|
||||
}
|
||||
}
|
||||
|
||||
let lastVolume = 50;
|
||||
const VOLUME_CHANGE_THRESHOLD = 1;
|
||||
|
||||
function debouncedUpdateVolume() {
|
||||
clearTimeout(updateTimeoutId);
|
||||
|
||||
// Update UI immediately
|
||||
volumeValue.textContent = `${Math.round(volume)}%`;
|
||||
|
||||
updateTimeoutId = setTimeout(async () => {
|
||||
if (Math.abs(volume - lastVolume) >= VOLUME_CHANGE_THRESHOLD) {
|
||||
try {
|
||||
await VolumeControl.setVolume({ volume: Math.round(volume), showUI: false });
|
||||
lastVolume = volume;
|
||||
} catch (error) {
|
||||
console.error('Error updating volume:', error);
|
||||
// Retry logic
|
||||
setTimeout(() => debouncedUpdateVolume(), 50);
|
||||
}
|
||||
}
|
||||
}, 33);
|
||||
}
|
||||
function showControlsIndicator() {
|
||||
indicators.style.opacity = '1';
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
indicators.style.opacity = '0';
|
||||
props.immersePlayer();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
node.addEventListener('touchstart', handleTouchStart);
|
||||
node.addEventListener('touchmove', handleTouchMove, { passive: false });
|
||||
node.addEventListener('touchend', handleTouchEnd);
|
||||
|
||||
async function init() {
|
||||
if (isNative) {
|
||||
try {
|
||||
const { brightness: currentBrightness } = await ScreenBrightness.getBrightness();
|
||||
const { volume: currentVolume } = await VolumeControl.getCurrentVolume();
|
||||
brightness = currentBrightness * 100;
|
||||
volume = currentVolume;
|
||||
updateBrightness();
|
||||
debouncedUpdateVolume();
|
||||
} catch (error) {
|
||||
console.error('Error initializing brightness and volume:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
node.removeEventListener('touchstart', handleTouchStart);
|
||||
node.removeEventListener('touchmove', handleTouchMove);
|
||||
node.removeEventListener('touchend', handleTouchEnd);
|
||||
clearTimeout(timeoutId);
|
||||
node.removeChild(indicators);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
import { SUPPORTS } from '@/modules/support.js'
|
||||
import 'rvfc-polyfill'
|
||||
import IPC from '@/modules/ipc.js'
|
||||
import { swipeControls } from '@/modules/swipecontrol';
|
||||
|
||||
const emit = createEventDispatcher()
|
||||
|
||||
|
|
@ -1027,6 +1028,7 @@
|
|||
class:fitWidth
|
||||
bind:this={container}
|
||||
role='none'
|
||||
use:swipeControls={{enabled: SUPPORTS.isAndroid, immersePlayer}}
|
||||
on:pointermove={resetImmerse}
|
||||
on:keypress={resetImmerse}
|
||||
on:keydown={resetImmerse}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ importers:
|
|||
'@capacitor-community/file-opener':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(@capacitor/core@6.1.1)
|
||||
'@capacitor-community/screen-brightness':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(@capacitor/core@6.1.1)
|
||||
'@capacitor/android':
|
||||
specifier: ^6.1.1
|
||||
version: 6.1.1(@capacitor/core@6.1.1)
|
||||
|
|
@ -99,6 +102,9 @@ importers:
|
|||
capacitor-plugin-safe-area:
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3(@capacitor/core@6.1.1)
|
||||
capacitor-volume-control:
|
||||
specifier: ^0.0.1
|
||||
version: 0.0.1(@capacitor/core@6.1.1)
|
||||
common:
|
||||
specifier: workspace:*
|
||||
version: link:../common
|
||||
|
|
@ -311,6 +317,11 @@ packages:
|
|||
peerDependencies:
|
||||
'@capacitor/core': ^6.0.0
|
||||
|
||||
'@capacitor-community/screen-brightness@6.0.0':
|
||||
resolution: {integrity: sha512-8yU2Epwym7IKJ3Ae8LDlo6RDbZuo4x2B2M1oKT04kaVjWRxHzx6wETpzLJqrwix1NyqbXIx5TPPBpk0Kxmv45w==}
|
||||
peerDependencies:
|
||||
'@capacitor/core': ^6.0.0
|
||||
|
||||
'@capacitor/android@6.1.1':
|
||||
resolution: {integrity: sha512-rhO/nH6NJizGV5KizoIoGxCmkos3HnyUzI9TNv8IVy/C8h6lPM5Gt9cxGclb6k0OBTtgv6iJVo654+m4kzv0Qg==}
|
||||
peerDependencies:
|
||||
|
|
@ -1633,6 +1644,11 @@ packages:
|
|||
peerDependencies:
|
||||
'@capacitor/core': ^6.0.0
|
||||
|
||||
capacitor-volume-control@0.0.1:
|
||||
resolution: {integrity: sha512-AuD38P2my58LsYfsJMF7KmCrLfe9mRwo30KDSq1lUVGaWyCw5byJwQCywwsC/fijrd8q6dMZ+7c3krPqwnBLLA==}
|
||||
peerDependencies:
|
||||
'@capacitor/core': ^6.0.0
|
||||
|
||||
caseless@0.12.0:
|
||||
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
|
||||
|
||||
|
|
@ -5694,6 +5710,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@capacitor/core': 6.1.1
|
||||
|
||||
'@capacitor-community/screen-brightness@6.0.0(@capacitor/core@6.1.1)':
|
||||
dependencies:
|
||||
'@capacitor/core': 6.1.1
|
||||
|
||||
'@capacitor/android@6.1.1(@capacitor/core@6.1.1)':
|
||||
dependencies:
|
||||
'@capacitor/core': 6.1.1
|
||||
|
|
@ -7394,6 +7414,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@capacitor/core': 6.1.1
|
||||
|
||||
capacitor-volume-control@0.0.1(@capacitor/core@6.1.1):
|
||||
dependencies:
|
||||
'@capacitor/core': 6.1.1
|
||||
|
||||
caseless@0.12.0: {}
|
||||
|
||||
chalk@2.4.2:
|
||||
|
|
@ -7500,7 +7524,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
'@types/estree': 1.0.5
|
||||
acorn: 8.11.3
|
||||
acorn: 8.12.0
|
||||
estree-walker: 3.0.3
|
||||
periscopic: 3.1.0
|
||||
|
||||
|
|
@ -11104,7 +11128,7 @@ snapshots:
|
|||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
'@types/estree': 1.0.5
|
||||
acorn: 8.11.3
|
||||
acorn: 8.12.0
|
||||
aria-query: 5.3.0
|
||||
axobject-query: 4.0.0
|
||||
code-red: 1.0.4
|
||||
|
|
|
|||
Loading…
Reference in a new issue