Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MC Authentication + Account switching #78

Merged
merged 10 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion theseus_gui/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ theseus = { path = "../../theseus" }

serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.2", features = ["protocol-asset"] }
tauri = { version = "1.2", features = ["protocol-asset", "window-close", "window-create"] }
tokio = { version = "1", features = ["full"] }
thiserror = "1.0"
tokio-stream = { version = "0.1", features = ["fs"] }
Expand Down
4 changes: 4 additions & 0 deletions theseus_gui/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
"protocol": {
"asset": true,
"assetScope": ["$APPDATA/caches/icons/*"]
},
"window": {
"create": true,
"close": true
}
},
"bundle": {
Expand Down
6 changes: 4 additions & 2 deletions theseus_gui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {
ClientIcon,
PlusIcon,
SettingsIcon,
Avatar,
} from 'omorphia'
import { useTheming } from '@/store/state'
import AccountsCard from '@/components/ui/AccountsCard.vue'
import { toggleTheme } from '@/helpers/theme'
import { list } from '@/helpers/profile'

Expand All @@ -38,7 +38,9 @@ list().then(
<div class="container">
<div class="nav-container">
<div class="nav-section">
<Avatar size="sm" src="https://cdn.modrinth.com/data/AANobbMI/icon.png" />
<suspense>
<AccountsCard ref="accounts" />
</suspense>
<div class="pages-list">
<RouterLink to="/" class="button-base nav-button"><ClientIcon /></RouterLink>
<RouterLink to="/browse" class="button-base nav-button"> <SearchIcon /></RouterLink>
Expand Down
1 change: 1 addition & 0 deletions theseus_gui/src/assets/icons/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as PlayIcon } from './play.svg'
export { default as OpenFolderIcon } from './folder-open.svg'
export { default as BrowseIcon } from './folder-search.svg'
export { default as LoginIcon } from './log-in.svg'
1 change: 1 addition & 0 deletions theseus_gui/src/assets/icons/log-in.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions theseus_gui/src/assets/stylesheets/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
margin: var(--gap-sm) 0;
}

.small-card-divider {
background-color: var(--color-button-bg);
border: none;
color: var(--color-button-bg);
height: 1px;
}

CodexAdrian marked this conversation as resolved.
Show resolved Hide resolved
.no-wrap {
white-space: nowrap;
}
Expand Down
243 changes: 243 additions & 0 deletions theseus_gui/src/components/ui/AccountsCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<template>
<Avatar
ref="avatar"
CodexAdrian marked this conversation as resolved.
Show resolved Hide resolved
class="button-base"
size="sm"
:src="selectedAccount.profile_picture"
@click="toggle()"
/>
<transition name="fade">
<Card v-if="showCard" ref="card" class="account-card">
<div v-if="selectedAccount" class="selected account">
<Avatar size="xs" :src="selectedAccount.profile_picture" />
<div>
<h4>{{ selectedAccount.username }}</h4>
<p>Selected</p>
</div>
<Button icon-only color="raised" @click="logout(selectedAccount.id)">
<LogOutIcon />
</Button>
</div>
<div v-else class="logged-out account">
<h4>Not signed in</h4>
<Button icon-only color="primary" @click="login()">
<LoginIcon />
</Button>
</div>
<div v-if="displayAccounts.length > 0" class="account-group">
<div v-for="account in displayAccounts" :key="account.id" class="account-row">
<Button class="option account" @click="setAccount(account)">
<Avatar :src="account.profile_picture" class="icon" />
<p>{{ account.username }}</p>
</Button>
<Button icon-only @click="logout(account.id)">
<LogOutIcon />
</Button>
</div>
</div>
<Button v-if="accounts.length > 0" @click="login()">
<PlusIcon />
Add Account
</Button>
</Card>
</transition>
</template>

<script setup>
import { Avatar, Button, Card, PlusIcon, LogOutIcon } from 'omorphia'
import { LoginIcon } from '@/assets/icons'
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import {
users,
remove_user,
authenticate_begin_flow,
authenticate_await_completion,
} from '@/helpers/auth'
import { get, set } from '@/helpers/settings'
import { WebviewWindow } from '@tauri-apps/api/window'

const settings = ref(await get())

const appendProfiles = (accounts) => {
return accounts.map((account) => {
return {
...account,
profile_picture: `https://crafthead.net/helm/${account.username}/128`,
}
})
}

const accounts = ref(await users().then(appendProfiles))

const displayAccounts = computed(() =>
accounts.value.filter((account) => settings.value.default_user !== account.id)
)

const selectedAccount = ref(
await users().then((accounts) =>
accounts.find((account) => account.id === settings.value.default_user)
)
)

const refreshValues = async () => {
accounts.value = await users().then(appendProfiles)
selectedAccount.value = accounts.value.find(
(account) => account.id === settings.value.default_user
)
}

let showCard = ref(false)
let card = ref(null)
let avatar = ref(null)

const setAccount = async (account) => {
settings.value.default_user = account.id
selectedAccount.value = account
await set(settings.value)
}

const login = async () => {
console.log('login process')
const url = await authenticate_begin_flow()
console.log(url)

const window = new WebviewWindow('loginWindow', {
url: url,
})

window.once('tauri://created', function () {
console.log('webview created')
})

window.once('tauri://error', function (e) {
console.log('webview error', e)
})

const loggedIn = await authenticate_await_completion()
await setAccount(loggedIn)
await refreshValues()
await window.close()
}

const logout = async (id) => {
await remove_user(id)
await refreshValues()
if (!selectedAccount.value && accounts.value.length > 0) {
await setAccount(accounts.value[0])
await refreshValues()
}
}

const toggle = () => {
showCard.value = !showCard.value
console.log('toggled')
}

const handleClickOutside = (event) => {
if (
card.value &&
avatar.value.$el !== event.target &&
card.value.$el !== event.target &&
!document.elementsFromPoint(event.clientX, event.clientY).includes(card.value.$el)
) {
showCard.value = false
}
}

onMounted(() => {
window.addEventListener('click', handleClickOutside)
})

onBeforeUnmount(() => {
window.removeEventListener('click', handleClickOutside)
})
</script>

<style scoped lang="scss">
.selected {
background: var(--color-brand-highlight);
border-radius: var(--radius-lg);
color: var(--color-contrast);
gap: 1rem;
}

.logged-out {
background: var(--color-bg);
border-radius: var(--radius-lg);
gap: 1rem;
}

.account {
width: max-content;
display: flex;
align-items: center;
text-align: left;
padding: 0.5rem 1rem;
}

.account-card {
position: absolute;
display: flex;
flex-direction: column;
top: 0;
left: 5rem;
z-index: 100;
gap: 0.5rem;
padding: 1rem;
border: 1px solid var(--color-button-bg);
width: max-content;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;

&.hidden {
display: none;
}
}

.accounts-title {
font-size: 1.2rem;
font-weight: bolder;
}

.account-group {
width: 100%;
display: flex;
flex-direction: column;
gap: 0.5rem;
}

.option {
width: calc(100% - 2.25rem);
background: var(--color-raised-bg);
color: var(--color-base);
box-shadow: none;

img {
margin-right: 0.5rem;
}
}

.icon {
--size: 1.5rem !important;
}

.account-row {
display: flex;
flex-direction: row;
gap: 0.5rem;
vertical-align: center;
justify-content: space-between;
padding-right: 1rem;
}

.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
1 change: 1 addition & 0 deletions theseus_gui/src/components/ui/Instance.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const props = defineProps({
width: 100%;
border-radius: var(--radius-sm);
filter: none !important;
aspect-ratio: 1;
}
.project-info {
margin-top: 1rem;
Expand Down