Skip to content

Commit dab365f

Browse files
committed
feat: Global Account Controller implented with Context's
1 parent 6d9f145 commit dab365f

File tree

11 files changed

+275
-197
lines changed

11 files changed

+275
-197
lines changed

apps/desktop/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ fn main() {
1010
"get_users",
1111
"get_user",
1212
"remove_user",
13+
"get_default_user",
14+
"set_default_user",
1315
// Cluster
1416
"create_cluster",
1517
"remove_cluster",

apps/desktop/permissions/onelauncher/default.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ permissions = [
66
"allow-get-users",
77
"allow-get-user",
88
"allow-remove-user",
9+
"allow-get-default-user",
10+
"allow-set-default-user",
911

1012
# Cluster
1113
"allow-create-cluster",

apps/desktop/src/api/commands.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ macro_rules! collect_commands {
2525
auth_login,
2626
get_users,
2727
get_user,
28+
get_default_user,
29+
set_default_user,
2830
remove_user,
2931
// Cluster
3032
create_cluster,
@@ -212,6 +214,24 @@ pub async fn get_user(uuid: Uuid) -> Result<MinecraftCredentials, String> {
212214
Ok(minecraft::get_user(uuid).await?)
213215
}
214216

217+
#[specta::specta]
218+
#[tauri::command]
219+
pub async fn get_default_user() -> Result<Option<MinecraftCredentials>, String> {
220+
let uuid = minecraft::get_default_user().await?;
221+
222+
match uuid {
223+
Some(uuid) => Ok(Some(minecraft::get_user(uuid).await?)),
224+
None => Ok(None),
225+
}
226+
}
227+
228+
#[specta::specta]
229+
#[tauri::command]
230+
pub async fn set_default_user(uuid: Uuid) -> Result<(), String> {
231+
minecraft::set_default_user(uuid).await?;
232+
Ok(())
233+
}
234+
215235
#[specta::specta]
216236
#[tauri::command]
217237
pub async fn auth_login(handle: AppHandle) -> Result<Option<MinecraftCredentials>, String> {

apps/frontend/src/ui/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import NotificationOverlay from './components/overlay/notifications/Notification
88
import { SettingsProvider } from './hooks/useSettings';
99
import { ClusterModalController } from './components/overlay/cluster/ClusterCreationModal';
1010
import { MultiProvider } from './components/MultiProvider';
11+
import { AccountControllerProvider } from './components/overlay/account/AddAccountModal';
1112
import { AppInfo } from '~utils/program-info';
1213

1314
function App(props: ParentProps) {
@@ -50,6 +51,7 @@ function GlobalContexts(props: ParentProps) {
5051
values={[
5152
SettingsProvider,
5253
ClusterModalController,
54+
AccountControllerProvider,
5355
]}
5456
>
5557
{props.children}

apps/frontend/src/ui/components/Navbar.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import { createSignal } from 'solid-js';
33
import { Bell01Icon, Cloud01Icon, Settings01Icon, TerminalBrowserIcon } from '@untitled-theme/icons-solid';
44
import { open } from '@tauri-apps/plugin-shell';
55
import { WEBSITE } from '@onelauncher/client';
6-
import useAccount from '../hooks/useAccount';
76
import PolyfrostFull from './logos/PolyfrostFull';
8-
import AccountPopup from './overlay/AccountPopup';
7+
import AccountPopup from './overlay/account/AccountsPopup';
98
import PlayerHead from './game/PlayerHead';
109
import Button from './base/Button';
1110
import NotificationPopup from './overlay/notifications/NotificationPopup';
1211
import Popup from './overlay/Popup';
12+
import useAccountController from './overlay/account/AddAccountModal';
1313

1414
interface NavbarLinkProps {
1515
path: string;
@@ -33,9 +33,9 @@ function NavbarLink(props: NavbarLinkProps) {
3333
function Navbar() {
3434
const [profileMenuOpen, setProfileMenuOpen] = createSignal(false);
3535
const [notificationMenuOpen, setNotificationMenuOpen] = createSignal(false);
36-
const navigate = useNavigate();
36+
const controller = useAccountController();
3737

38-
const account = useAccount();
38+
const navigate = useNavigate();
3939

4040
let profileButton!: HTMLButtonElement;
4141
let notificationButton!: HTMLButtonElement;
@@ -81,7 +81,7 @@ function Navbar() {
8181
ref={profileButton}
8282
onClick={() => setProfileMenuOpen(!profileMenuOpen())}
8383
>
84-
<PlayerHead class="w-[30px] h-[30px] rounded-md hover:opacity-70" uuid={account.uuid} />
84+
<PlayerHead class="w-[30px] h-[30px] rounded-md hover:opacity-70" uuid={controller.defaultAccount()?.id} />
8585
</button>
8686
</div>
8787

apps/frontend/src/ui/components/game/PlayerHead.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { JSX } from 'solid-js';
33
import steveSrc from '../../../assets/images/steve.png';
44

55
type PlayerHeadProps = JSX.IntrinsicElements['img'] & {
6-
uuid: string;
6+
uuid: string | null | undefined;
77
onError?: () => any;
88
};
99

@@ -24,13 +24,15 @@ function PlayerHead(props: PlayerHeadProps) {
2424
{...rest}
2525
/>
2626
</Show>
27-
<img
28-
src={headSrc(split.uuid)}
29-
onLoad={() => setLoading(false)}
30-
onError={() => props.onError && props.onError()}
31-
class={`image-render-pixel ${isLoading() ? 'hidden' : ''} ${split.class}`}
32-
{...rest}
33-
/>
27+
<Show when={props.uuid !== null && props.uuid !== undefined}>
28+
<img
29+
src={headSrc(split.uuid!)}
30+
onLoad={() => setLoading(false)}
31+
onError={() => props.onError && props.onError()}
32+
class={`image-render-pixel ${isLoading() ? 'hidden' : ''} ${split.class}`}
33+
{...rest}
34+
/>
35+
</Show>
3436
</>
3537
);
3638
}

apps/frontend/src/ui/components/overlay/AccountPopup.tsx

Lines changed: 0 additions & 75 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { For, Show } from 'solid-js';
2+
import { LogOut01Icon, PlusIcon, Settings01Icon } from '@untitled-theme/icons-solid';
3+
import { useNavigate } from '@solidjs/router';
4+
import Button from '../../base/Button';
5+
import PlayerHead from '../../game/PlayerHead';
6+
import Popup from '../Popup';
7+
import useAccountController from './AddAccountModal';
8+
import type { MinecraftCredentials } from '~bindings';
9+
10+
interface AccountComponentProps {
11+
account: MinecraftCredentials | null | undefined;
12+
loggedIn?: boolean;
13+
}
14+
15+
function AccountComponent(props: AccountComponentProps) {
16+
return (
17+
<Show when={props.account}>
18+
<div class={`flex flex-row justify-between p-2 rounded-lg ${!props.loggedIn && 'hover:bg-gray-05 active:bg-gray-10 hover:text-fg-primary-hover'}`}>
19+
<div class="flex flex-row justify-start flex-1 gap-x-3">
20+
<PlayerHead class="w-8 h-8 rounded-md" uuid={props.account!.id} />
21+
<div class="flex flex-col items-center justify-center">
22+
<div class="flex flex-col items-start justify-between">
23+
<p class="font-semibold h-[18px]">{props.account!.username}</p>
24+
{props.loggedIn && <p class="text-xs">Logged in</p>}
25+
</div>
26+
</div>
27+
</div>
28+
{props.loggedIn && (
29+
<Button buttonStyle="icon">
30+
<LogOut01Icon class=" stroke-danger" />
31+
</Button>
32+
)}
33+
</div>
34+
</Show>
35+
);
36+
}
37+
38+
function AccountPopup(props: Popup.PopupProps) {
39+
const controller = useAccountController();
40+
41+
const filteredAccounts = () => controller.accounts()?.filter(account => account.id !== controller.defaultAccount()?.id) ?? [];
42+
43+
const navigate = useNavigate();
44+
45+
return (
46+
<Popup {...props}>
47+
<div class="bg-secondary rounded-xl border border-gray-10 w-72 p-2 shadow-md shadow-black/30">
48+
<div class="flex flex-col gap-y-2 text-fg-primary">
49+
<AccountComponent account={controller.defaultAccount()} loggedIn />
50+
51+
<Show when={filteredAccounts().length !== 0}>
52+
<div class="w-full h-px bg-gray-05 rounded-md" />
53+
<For each={filteredAccounts()}>
54+
{account => (
55+
<AccountComponent account={account} />
56+
)}
57+
</For>
58+
<div class="w-full h-px bg-gray-05 rounded-md" />
59+
</Show>
60+
61+
<div class="flex flex-row justify-between">
62+
<div>
63+
<Button
64+
buttonStyle="ghost"
65+
iconLeft={<PlusIcon />}
66+
onClick={() => {
67+
props.setVisible(false);
68+
controller.displayAddAccount();
69+
}}
70+
>
71+
Add Account
72+
</Button>
73+
</div>
74+
<div class="flex flex-row">
75+
<Button
76+
buttonStyle="icon"
77+
large
78+
onClick={() => {
79+
props.setVisible(false);
80+
navigate('/settings/accounts');
81+
}}
82+
>
83+
<Settings01Icon class="stroke-fg-primary" />
84+
</Button>
85+
</div>
86+
</div>
87+
88+
</div>
89+
</div>
90+
</Popup>
91+
);
92+
}
93+
94+
export default AccountPopup;

0 commit comments

Comments
 (0)