diff --git a/src-tauri/src/database.rs b/src-tauri/src/database.rs index 9852b323..b49ffb6b 100644 --- a/src-tauri/src/database.rs +++ b/src-tauri/src/database.rs @@ -28,8 +28,40 @@ pub(crate) async fn migrate_database(pool: &SqlitePool) -> DBResult<()> { Ok(()) } -pub(crate) async fn list_servers(pool: &SqlitePool) -> DBResult> { - let servers = query_as::<_, entities::Server>("select * from servers") +pub(crate) async fn list_servers( + pool: &SqlitePool, +) -> DBResult)>> { + let servers = sqlx::query( + r#" +SELECT servers.id, servers.domain, servers.base_url, servers.sns, servers.favicon, servers.account_id, + accounts.id, accounts.username, accounts.account_id, accounts.avatar, accounts.client_id, accounts.client_secret, + accounts.access_token, accounts.refresh_token, accounts.usual +FROM servers LEFT JOIN accounts ON servers.account_id = accounts.id"#, + ).map(|row: SqliteRow| { + let server = entities::Server { + id: row.get(0), + domain: row.get(1), + base_url: row.get(2), + sns: row.get(3), + favicon: row.get(4), + account_id: row.get(5), + }; + if row.get(6) { + (server, Some(entities::Account { + id: row.get(6), + username: row.get(7), + account_id: row.get(8), + avatar: row.get(9), + client_id: row.get(10), + client_secret: row.get(11), + access_token: row.get(12), + refresh_token: row.get(13), + usual: row.get(14), + })) + } else { + (server, None) + } + }) .fetch_all(pool) .await?; diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0e04a05c..e3d4fd1a 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -20,7 +20,7 @@ rust_i18n::i18n!("locales"); #[tauri::command] async fn list_servers( sqlite_pool: State<'_, sqlx::SqlitePool>, -) -> Result, String> { +) -> Result)>, String> { let servers = database::list_servers(&sqlite_pool) .await .map_err(|e| e.to_string())?; diff --git a/src/components/Navigator.tsx b/src/components/Navigator.tsx index 857836a3..8d48d349 100644 --- a/src/components/Navigator.tsx +++ b/src/components/Navigator.tsx @@ -3,7 +3,7 @@ import { ReactElement, useEffect, useState } from 'react' import { Icon } from '@rsuite/icons' import { Popover, Dropdown, Sidebar, Sidenav, Whisper, Button, Avatar, Badge, FlexboxGrid } from 'rsuite' import { BsPlus, BsGear, BsPencilSquare } from 'react-icons/bs' -import { Server } from 'src/entities/server' +import { Server, ServerSet } from 'src/entities/server' import FailoverImg from 'src/utils/failoverImg' import { Unread } from 'src/entities/unread' import { Instruction } from 'src/entities/instruction' @@ -11,7 +11,7 @@ import { listen } from '@tauri-apps/api/event' import { useTranslation } from 'react-i18next' type NavigatorProps = { - servers: Array + servers: Array unreads: Array addNewServer: () => void openAuthorize: (server: Server) => void @@ -87,19 +87,30 @@ const Navigator: React.FC = (props): ReactElement => { )} {servers.map(server => ( -
+
- serverMenu({ className, left, top, onClose, server, openAuthorize }, ref) + serverMenu({ className, left, top, onClose, server: server.server, openAuthorize }, ref) } > - diff --git a/src/components/compose/Compose.tsx b/src/components/compose/Compose.tsx index 9aafe943..640cd9af 100644 --- a/src/components/compose/Compose.tsx +++ b/src/components/compose/Compose.tsx @@ -6,7 +6,7 @@ import { invoke } from '@tauri-apps/api/tauri' import generator, { MegalodonInterface } from 'megalodon' import { USER_AGENT } from 'src/defaults' -import { Server } from 'src/entities/server' +import { Server, ServerSet } from 'src/entities/server' import { Account } from 'src/entities/account' import failoverImg from 'src/utils/failoverImg' import Status from './Status' @@ -38,7 +38,7 @@ const renderAccountIcon = (props: any, ref: any, account: [Account, Server] | un type Props = { setOpened: (value: boolean) => void - servers: Array + servers: Array } const Compose: React.FC = props => { diff --git a/src/components/timelines/New.tsx b/src/components/timelines/New.tsx index d16f0f1f..c7ef807d 100644 --- a/src/components/timelines/New.tsx +++ b/src/components/timelines/New.tsx @@ -14,7 +14,7 @@ import { } from 'rsuite' import { Icon } from '@rsuite/icons' import { BsPlus, BsHouseDoor, BsBell, BsPeople, BsGlobe2, BsStar, BsListUl, BsChevronLeft, BsBookmark, BsEnvelope } from 'react-icons/bs' -import { Server } from '../../entities/server' +import { Server, ServerSet } from '../../entities/server' import { useEffect, useState } from 'react' import { invoke } from '@tauri-apps/api/tauri' import generator, { Entity } from 'megalodon' @@ -125,7 +125,7 @@ const AuthorizedTimelines: React.FC = props => { } type Props = { - servers: Array + servers: Array } const New: React.FC = props => { @@ -160,15 +160,15 @@ const New: React.FC = props => { const addTimelineMenu = ({ onClose, left, top, className }, ref: any) => { const handleSelect = (eventKey: string) => { onClose() - const target = props.servers.find(s => s.id === parseInt(eventKey)) - setServer(target) + const target = props.servers.find(s => s.server.id === parseInt(eventKey)) + setServer(target.server) } return ( {props.servers.map(server => ( - - {server.domain} + + {server.account ? server.account.username + '@' + server.server.domain : server.server.domain} ))} diff --git a/src/entities/server.ts b/src/entities/server.ts index 019c016f..4b381f49 100644 --- a/src/entities/server.ts +++ b/src/entities/server.ts @@ -1,3 +1,5 @@ +import { Account } from './account' + export type Server = { id: number domain: string @@ -6,3 +8,8 @@ export type Server = { favicon: string | null account_id: number | null } + +export type ServerSet = { + server: Server + account: Account | null +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index e8ebb9fd..dc28235c 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -5,7 +5,7 @@ import { Container, Content, useToaster, Animation } from 'rsuite' import { isPermissionGranted, requestPermission, sendNotification } from '@tauri-apps/api/notification' import dayjs from 'dayjs' -import { Server } from 'src/entities/server' +import { Server, ServerSet } from 'src/entities/server' import { Timeline } from 'src/entities/timeline' import { Unread } from 'src/entities/unread' import alert from 'src/components/utils/alert' @@ -23,11 +23,12 @@ import { Settings } from 'src/entities/settings' import SettingsPage from 'src/components/settings/Settings' import Detail from 'src/components/detail/Detail' import { useTranslation } from 'react-i18next' +import { Account } from 'src/entities/account' function App() { const { t, i18n } = useTranslation() - const [servers, setServers] = useState>([]) + const [servers, setServers] = useState>([]) const [timelines, setTimelines] = useState>([]) const [unreads, setUnreads] = useState>([]) const [composeOpened, setComposeOpened] = useState(false) @@ -44,13 +45,19 @@ function App() { useEffect(() => { loadAppearance() - invoke>('list_servers').then(res => { + invoke>('list_servers').then(res => { if (res.length === 0) { console.debug('There is no server') dispatch({ target: 'newServer', value: true }) toaster.push(alert('info', t('alert.no_server')), { placement: 'topCenter' }) } else { - setServers(res) + console.debug('list_servers: ', res) + setServers( + res.map(r => ({ + server: r[0], + account: r[1] + })) + ) } }) @@ -60,8 +67,13 @@ function App() { loadTimelines() }) listen('updated-servers', async () => { - const res = await invoke>('list_servers') - setServers(res) + const res = await invoke>('list_servers') + setServers( + res.map(r => ({ + server: r[0], + account: r[1] + })) + ) }) listen('receive-notification', async ev => { @@ -105,7 +117,7 @@ function App() { } const toggleCompose = () => { - if (servers.find(s => s.account_id !== null)) { + if (servers.find(s => s.account !== null)) { setComposeOpened(previous => !previous) } else { toaster.push(alert('info', t('alert.need_auth')), { placement: 'topStart' })