mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-13 23:20:20 +00:00
feat: better android file picker, validate that selected directories have read/write permissions
This commit is contained in:
parent
6b37f517c9
commit
4bf572e71f
6 changed files with 55 additions and 21 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "6.4.71",
|
||||
"version": "6.4.72",
|
||||
"license": "BUSL-1.1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.15.5",
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
"gql.tada": "^1.8.10",
|
||||
"hayase-extensions": "github:hayase-app/extensions",
|
||||
"jassub": "^1.8.6",
|
||||
"native": "github:hayase-app/native",
|
||||
"rollup-plugin-license": "^3.6.0",
|
||||
"simple-copy": "^2.2.1",
|
||||
"svelte": "^4.2.19",
|
||||
|
|
@ -74,7 +75,6 @@
|
|||
"js-levenshtein": "^1.1.6",
|
||||
"lucide-svelte": "^0.511.0",
|
||||
"marked": "^15.0.11",
|
||||
"native": "github:hayase-app/native",
|
||||
"p2pt": "github:ThaUnknown/p2pt#modernise",
|
||||
"semver": "^7.7.2",
|
||||
"simple-store-svelte": "^1.0.6",
|
||||
|
|
|
|||
|
|
@ -89,9 +89,6 @@ importers:
|
|||
marked:
|
||||
specifier: ^15.0.11
|
||||
version: 15.0.11
|
||||
native:
|
||||
specifier: github:hayase-app/native
|
||||
version: https://codeload.github.com/hayase-app/native/tar.gz/31eb40c6c662dc58030bd70a279d9b8d38e3b904
|
||||
p2pt:
|
||||
specifier: github:ThaUnknown/p2pt#modernise
|
||||
version: https://codeload.github.com/ThaUnknown/p2pt/tar.gz/9ad7a56ed6ee43f5664ebad33b803702ee349316
|
||||
|
|
@ -183,6 +180,9 @@ importers:
|
|||
jassub:
|
||||
specifier: ^1.8.6
|
||||
version: 1.8.6
|
||||
native:
|
||||
specifier: github:hayase-app/native
|
||||
version: https://codeload.github.com/hayase-app/native/tar.gz/61d27bc30411840846e4e8ec5ea8ce875305e424
|
||||
rollup-plugin-license:
|
||||
specifier: ^3.6.0
|
||||
version: 3.6.0(picomatch@4.0.2)(rollup@4.40.2)
|
||||
|
|
@ -1900,8 +1900,8 @@ packages:
|
|||
engines: {node: ^18 || >=20}
|
||||
hasBin: true
|
||||
|
||||
native@https://codeload.github.com/hayase-app/native/tar.gz/31eb40c6c662dc58030bd70a279d9b8d38e3b904:
|
||||
resolution: {tarball: https://codeload.github.com/hayase-app/native/tar.gz/31eb40c6c662dc58030bd70a279d9b8d38e3b904}
|
||||
native@https://codeload.github.com/hayase-app/native/tar.gz/61d27bc30411840846e4e8ec5ea8ce875305e424:
|
||||
resolution: {tarball: https://codeload.github.com/hayase-app/native/tar.gz/61d27bc30411840846e4e8ec5ea8ce875305e424}
|
||||
version: 1.0.0
|
||||
|
||||
natural-compare@1.4.0:
|
||||
|
|
@ -4550,7 +4550,7 @@ snapshots:
|
|||
|
||||
nanoid@5.1.5: {}
|
||||
|
||||
native@https://codeload.github.com/hayase-app/native/tar.gz/31eb40c6c662dc58030bd70a279d9b8d38e3b904: {}
|
||||
native@https://codeload.github.com/hayase-app/native/tar.gz/61d27bc30411840846e4e8ec5ea8ce875305e424: {}
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ export function hover (node: HTMLElement, [cb = noop, hoverUpdate = noop]: [type
|
|||
const ctrl = new AbortController()
|
||||
node.addEventListener('wheel', e => {
|
||||
// cheap way to update hover state on scroll
|
||||
// TODO: this is bad on touch, but good on mouse, fix it
|
||||
if (document.elementsFromPoint(e.clientX, e.clientY).includes(node)) {
|
||||
if (lastHoverElement !== hoverUpdate) lastHoverElement?.(false)
|
||||
lastHoverElement = hoverUpdate
|
||||
|
|
|
|||
|
|
@ -41,5 +41,6 @@ export default {
|
|||
playerSeek: '2',
|
||||
playerSkip: false,
|
||||
playerSkipFiller: false,
|
||||
minimalPlayerUI: false
|
||||
minimalPlayerUI: false,
|
||||
androidStorageType: 'cache'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
<script lang='ts'>
|
||||
import { toast } from 'svelte-sonner'
|
||||
|
||||
import SettingCard from '$lib/components/SettingCard.svelte'
|
||||
import { Button } from '$lib/components/ui/button'
|
||||
import { SingleCombo } from '$lib/components/ui/combobox'
|
||||
import { Input } from '$lib/components/ui/input'
|
||||
import { Switch } from '$lib/components/ui/switch'
|
||||
import native from '$lib/modules/native'
|
||||
import { settings, SUPPORTS } from '$lib/modules/settings'
|
||||
|
||||
async function selectDownloadFolder () {
|
||||
$settings.torrentPath = await native.selectDownload()
|
||||
async function selectDownloadFolder (type?: string) {
|
||||
try {
|
||||
$settings.torrentPath = await native.selectDownload(type as 'cache' | 'internal' | 'sdcard' | undefined)
|
||||
} catch (error) {
|
||||
toast.error('Failed to select download folder. Please try again.', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error occurred.'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const androidDirectories = {
|
||||
cache: 'Cache',
|
||||
internal: 'Internal Storage',
|
||||
sdcard: 'SD Card'
|
||||
} as const
|
||||
</script>
|
||||
|
||||
<div class='space-y-3 pb-10 lg:max-w-4xl'>
|
||||
|
|
@ -27,14 +42,15 @@
|
|||
{/if}
|
||||
|
||||
<div class='font-weight-bold text-xl font-bold'>Client Settings</div>
|
||||
<SettingCard let:id title='Torrent Download Location' description='Path to the folder used to store torrents. By default this is the TMP folder, which might lose data when your OS tries to reclaim storage. {SUPPORTS.isAndroid ? 'RESTART IS REQUIRED. /sdcard/ is internal storage, not external SD Cards. /storage/AB12-34CD/ is external storage, not internal. Thank you Android!' : ''}'>
|
||||
<SettingCard let:id title='Torrent Download Location' description={`Path to the folder used to store torrents. By default this is the TEMP cache folder, which might lose data when your OS tries to reclaim storage.${SUPPORTS.isAndroid ? '\n\nSD Card saves to the Cards Download folder. If SD Card is not available torrents will automatically be saved to the Phone\'s Downloads folder' : ''}`}>
|
||||
<div class='flex'>
|
||||
{#if !SUPPORTS.isAndroid}
|
||||
<Input type='url' bind:value={$settings.torrentPath} readonly {id} placeholder='/tmp' class='sm:w-60 bg-background rounded-r-none pointer-events-none' />
|
||||
<Input type='url' bind:value={$settings.torrentPath} readonly {id} placeholder='/tmp/webtorrent' class='sm:w-60 bg-background rounded-r-none pointer-events-none' />
|
||||
<Button class='rounded-l-none font-bold' on:click={() => selectDownloadFolder()} variant='secondary'>Select Folder</Button>
|
||||
{:else}
|
||||
<Input type='text' bind:value={$settings.torrentPath} {id} placeholder='/tmp' class='sm:w-60 bg-background rounded-r-none' />
|
||||
<Input type='text' bind:value={$settings.torrentPath} {id} placeholder='/tmp/webtorrent' class='sm:w-60 bg-background rounded-r-none border-r-0' />
|
||||
<SingleCombo bind:value={$settings.androidStorageType} items={androidDirectories} class='w-32 shrink-0 border-input border rounded-l-none ' onSelected={selectDownloadFolder} />
|
||||
{/if}
|
||||
<Button class='rounded-l-none font-bold' on:click={selectDownloadFolder} variant='secondary'>Select Folder</Button>
|
||||
</div>
|
||||
</SettingCard>
|
||||
<SettingCard let:id title='Persist Files' description="Keeps torrents files instead of deleting them after a new torrent is played. This doesn't seed the files, only keeps them on your drive. This will quickly fill up your storage.">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
<script lang='ts'>
|
||||
import { toast } from 'svelte-sonner'
|
||||
|
||||
import Footer, { type Checks } from '../Footer.svelte'
|
||||
import Progress from '../Progress.svelte'
|
||||
|
||||
import SettingCard from '$lib/components/SettingCard.svelte'
|
||||
import { Button } from '$lib/components/ui/button'
|
||||
import { SingleCombo } from '$lib/components/ui/combobox'
|
||||
import { Input } from '$lib/components/ui/input'
|
||||
import { Switch } from '$lib/components/ui/switch'
|
||||
import native from '$lib/modules/native'
|
||||
|
|
@ -11,10 +14,22 @@
|
|||
import { SUPPORTS, settings } from '$lib/modules/settings'
|
||||
import { fastPrettyBytes } from '$lib/utils'
|
||||
|
||||
async function selectDownloadFolder () {
|
||||
$settings.torrentPath = await native.selectDownload()
|
||||
async function selectDownloadFolder (type?: string) {
|
||||
try {
|
||||
$settings.torrentPath = await native.selectDownload(type as 'cache' | 'internal' | 'sdcard' | undefined)
|
||||
} catch (error) {
|
||||
toast.error('Failed to select download folder. Please try again.', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error occurred.'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const androidDirectories = {
|
||||
cache: 'Cache',
|
||||
internal: 'Internal Storage',
|
||||
sdcard: 'SD Card'
|
||||
} as const
|
||||
|
||||
async function checkSpaceRequirements (_path: string): Checks['promise'] {
|
||||
const space = await native.checkAvailableSpace()
|
||||
if (space < 1e9) return { status: 'error', text: `${fastPrettyBytes(space)} available, 1GB is the recommended minimum.` }
|
||||
|
|
@ -28,14 +43,15 @@
|
|||
<Progress />
|
||||
|
||||
<div class='space-y-3 lg:max-w-4xl pt-5 h-full overflow-y-auto' use:dragScroll>
|
||||
<SettingCard class='bg-transparent' let:id title='Torrent Download Location' description='Path to the folder used to store torrents. By default this is the TMP folder, which might lose data when your OS tries to reclaim storage. {SUPPORTS.isAndroid ? 'RESTART IS REQUIRED. /sdcard/ is internal storage, not external SD Cards. /storage/AB12-34CD/ is external storage, not internal. Thank you Android!' : ''}'>
|
||||
<SettingCard let:id title='Torrent Download Location' description={`Path to the folder used to store torrents. By default this is the TEMP cache folder, which might lose data when your OS tries to reclaim storage.${SUPPORTS.isAndroid ? '\n\nSD Card saves to the Cards Download folder. If SD Card is not available torrents will automatically be saved to the Phone\'s Downloads folder' : ''}`}>
|
||||
<div class='flex'>
|
||||
{#if !SUPPORTS.isAndroid}
|
||||
<Input type='url' bind:value={$settings.torrentPath} readonly {id} placeholder='/tmp' class='sm:w-60 bg-background rounded-r-none pointer-events-none' />
|
||||
<Input type='url' bind:value={$settings.torrentPath} readonly {id} placeholder='/tmp/webtorrent' class='sm:w-60 bg-background rounded-r-none pointer-events-none' />
|
||||
<Button class='rounded-l-none font-bold' on:click={() => selectDownloadFolder()} variant='secondary'>Select Folder</Button>
|
||||
{:else}
|
||||
<Input type='text' bind:value={$settings.torrentPath} {id} placeholder='/tmp' class='sm:w-60 bg-background rounded-r-none' />
|
||||
<Input type='text' bind:value={$settings.torrentPath} {id} placeholder='/tmp/webtorrent' class='sm:w-60 bg-background rounded-r-none border-r-0' />
|
||||
<SingleCombo bind:value={$settings.androidStorageType} items={androidDirectories} class='w-32 shrink-0 border-input border rounded-l-none ' onSelected={selectDownloadFolder} />
|
||||
{/if}
|
||||
<Button class='rounded-l-none font-bold' on:click={selectDownloadFolder} variant='secondary'>Select Folder</Button>
|
||||
</div>
|
||||
</SettingCard>
|
||||
<SettingCard class='bg-transparent' let:id title='Persist Files' description="Keeps torrents files instead of deleting them after a new torrent is played. This doesn't seed the files, only keeps them on your drive. This will quickly fill up your storage.">
|
||||
|
|
|
|||
Loading…
Reference in a new issue