import { useEffect, useState } from 'react'
import { useMemoizedFn } from 'ahooks'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { useNavigate } from '@tanstack/react-router'
import {
FolderOpenIcon,
HistoryIcon,
UploadIcon
} from 'lucide-react'
import { handleCloudImportAll } from '@/adapters/cloud-album'
import { AppMainCard } from '@/components/common/app-main-card'
import { FloatingPanelSheetContent } from '@/components/common/floating-panel-sheet-content'
import { Button } from '@/components/ui/button'
import { Sheet, SheetTrigger } from '@/components/ui/sheet'
import { useIPCOn } from '@/hooks/useIPC'
import { cn } from '@/lib/utils'
import { appActions, settingsStoreActions, useAppStore, useAlbumStore } from '@/store'
import { DESKTOP_HISTORY_PANEL_BREAKPOINT } from '@/utils/consts'
import { AlbumSource } from '#/types/cloudAlbum'
import { UploaderSwitcher } from './uploader-switcher'
import { buildUrlDialogInitialValue, buildVisibleProviderOptions, resolveCurrentSwitcherValue, resolveLinkFormat, resolvePasteStyle } from './utils'
import { HistoryPanel } from './history-panel'
import { DashboardActionBar } from './dashboard-action-bar'
import { UrlInputDialog } from './url-input-dialog'
import { useDashboardHistory } from './hooks/use-dashboard-history'
import { useDashboardCloudHistory } from './hooks/use-dashboard-cloud-history'
import { useDashboardUpload } from './hooks/use-dashboard-upload'
import { useDashboardDropHandler } from './hooks/use-dashboard-drop-handler'
import type { LinkFormat } from '@/types/dashboard'
function ProgressBar ({ value }: { value: number }) {
return (
)
}
function useDesktopHistoryVisible () {
const [visible, setVisible] = useState(() => {
return typeof window !== 'undefined' && window.innerWidth >= DESKTOP_HISTORY_PANEL_BREAKPOINT
})
useEffect(() => {
const mql = window.matchMedia(`(min-width: ${DESKTOP_HISTORY_PANEL_BREAKPOINT}px)`)
const sync = () => setVisible(mql.matches)
sync()
mql.addEventListener('change', sync)
return () => mql.removeEventListener('change', sync)
}, [])
return visible
}
export function PicGoDashboard () {
const navigate = useNavigate()
const { t } = useTranslation()
const [isHistoryOpen, setHistoryOpen] = useState(false)
const [isHistorySheetThumbnailReady, setHistorySheetThumbnailReady] = useState(false)
const isDesktopHistoryVisible = useDesktopHistoryVisible()
const [urlDialogOpen, setUrlDialogOpen] = useState(false)
const [urlDialogInitial, setUrlDialogInitial] = useState('')
const localHistoryItems = useDashboardHistory()
const cloudHistory = useDashboardCloudHistory()
const albumSource = useAlbumStore.use.albumSource()
const isCloudSource = albumSource === AlbumSource.CLOUD
const historyItems = isCloudSource ? cloudHistory.items : localHistoryItems
const historyLoading = isCloudSource ? cloudHistory.loading : false
const {
fileInputRef,
isUploading,
uploadProgress,
startUpload,
handleFileChange,
uploadClipboardFiles,
uploadFileList,
uploadUrls
} = useDashboardUpload()
const { handleDrop, dispatchUrls } = useDashboardDropHandler({ uploadFileList, uploadUrls })
const providers = useAppStore.use.providers()
const appConfig = useAppStore.use.appConfig()
const providerOptions = buildVisibleProviderOptions(providers, appConfig)
const currentSelection = resolveCurrentSwitcherValue(providerOptions, appConfig)
const hasVisibleProviders = providerOptions.length > 0
const linkFormat = resolveLinkFormat(appConfig?.settings.pasteStyle)
const handleSyncPicBed = useMemoizedFn(async () => {
try {
await Promise.all([appActions.refreshAppConfig(), appActions.refreshPicBeds()])
} catch (error) {
console.error(error)
}
})
useIPCOn('syncPicBed', handleSyncPicBed)
useEffect(() => {
const timer = window.setTimeout(() => {
setHistorySheetThumbnailReady(isHistoryOpen)
}, 100)
return () => window.clearTimeout(timer)
}, [isHistoryOpen])
const handleLinkFormatChange = useMemoizedFn(async (nextFormat: LinkFormat) => {
try {
await settingsStoreActions.saveSettingsConfig({ pasteStyle: resolvePasteStyle(nextFormat) })
} catch (error) {
toast.error(error instanceof Error ? error.message : t('OPERATION_FAILED'))
}
})
const handleUrlButtonClick = useMemoizedFn(async () => {
setUrlDialogInitial(await buildUrlDialogInitialValue())
setUrlDialogOpen(true)
})
return (
<>
event.preventDefault()}
onDrop={(event) => { handleDrop(event).catch(console.error) }}
>
{currentSelection
? (
)
: null}
{!hasVisibleProviders
? (
{t('DASHBOARD_NO_VISIBLE_PROVIDERS')}
{t('DASHBOARD_NO_VISIBLE_PROVIDERS_DESCRIPTION')}
)
: (
{t('DASHBOARD_DROP_IMAGES_HERE')}
)}
{isDesktopHistoryVisible
? (
)
: null}
>
)
}