Skip to content

Commit

Permalink
wip: Talk Desktop Settings
Browse files Browse the repository at this point in the history
Signed-off-by: Grigorii K. Shartsev <[email protected]>
  • Loading branch information
ShGKme committed Sep 10, 2024
1 parent 5aa0d6f commit 9a6b3f6
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 0 deletions.
60 changes: 60 additions & 0 deletions src/talk/renderer/Settings/components/AccountsSettingsSection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<script setup lang="ts">
import { t } from '@nextcloud/l10n'
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js'
import IconAccountMultiplePlus from 'vue-material-design-icons/AccountMultiplePlus.vue'
import IconDelete from 'vue-material-design-icons/Delete.vue'
import SettingsSubsection from './SettingsSubsection.vue'
</script>

<template>
<SettingsSubsection>
<ul>
<NcListItem name="Grigorii K. Shartsev" details="nextcloud.local">
<template #icon>
<NcAvatar user="shgkme" />
</template>
<template #subname>
[email protected]
</template>
<template #actions>
<NcActionButton>
<template #icon>
<IconDelete :size="20" />
</template>
{{ t('talk_desktop', 'Remove') }}
</NcActionButton>
</template>
</NcListItem>
<NcListItem name="admin" details="stable30.local">
<template #icon>
<NcAvatar user="admin" />
</template>
<template #subname>
[email protected]
</template>
<template #actions>
<NcActionButton>
<template #icon>
<IconDelete :size="20" />
</template>
{{ t('talk_desktop', 'Remove') }}
</NcActionButton>
</template>
</NcListItem>
</ul>
<NcButton wide>
<template #icon>
<IconAccountMultiplePlus :size="20" />
</template>
{{ t('talk_desktop', 'Log into a new account') }}
</NcButton>
</SettingsSubsection>
</template>
107 changes: 107 additions & 0 deletions src/talk/renderer/Settings/components/DesktopSettingsSection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<script setup lang="ts">
import { t } from '@nextcloud/l10n'
import { computed, type ComputedRef, type Ref, ref, watch } from 'vue'
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
import SettingsSubsection from './SettingsSubsection.vue'
import IconThemeLightDark from 'vue-material-design-icons/ThemeLightDark.vue'
import IconWeatherSunny from 'vue-material-design-icons/WeatherSunny.vue'

Check failure on line 13 in src/talk/renderer/Settings/components/DesktopSettingsSection.vue

View workflow job for this annotation

GitHub Actions / NPM lint

'IconWeatherSunny' is defined but never used
import IconWeatherNight from 'vue-material-design-icons/WeatherNight.vue'

Check failure on line 14 in src/talk/renderer/Settings/components/DesktopSettingsSection.vue

View workflow job for this annotation

GitHub Actions / NPM lint

'IconWeatherNight' is defined but never used
import IconBellOutline from 'vue-material-design-icons/BellOutline.vue'
import { applyBodyThemeAttrs } from '../../../../shared/theme.utils.js'
type Theme = 'default' | 'light' | 'dark'
type SelectOption<T> = { label: string, value: T }
// Just an example
const theme: Ref<Theme> = ref('default')
watch(theme, () => {
applyBodyThemeAttrs(theme.value)
})
const themeOptions = [
{ label: t('talk_desktop', 'System default'), value: 'default' },
{ label: t('talk_desktop', 'Light'), value: 'light' },
{ label: t('talk_desktop', 'Dark'), value: 'dark' },
] as const
const themeOption: ComputedRef<SelectOption<Theme>> = computed({

Check failure on line 31 in src/talk/renderer/Settings/components/DesktopSettingsSection.vue

View workflow job for this annotation

GitHub Actions / NPM typecheck

No overload matches this call.
get: () => themeOptions.find(option => option.value === theme.value),
set: (valueOption: { label: string, value: Theme }) => {
theme.value = valueOption.value
},
})
const playSound = ref('no-dnd')
const playSoundOptions = [
{ label: t('talk_desktop', 'Always'), value: 'always' },
{ label: t('talk_desktop', 'When not in Do Not Disturb'), value: 'no-dnd' },
{ label: t('talk_desktop', 'Never'), value: 'never' },
] as const
const playSoundOption = computed({

Check failure on line 45 in src/talk/renderer/Settings/components/DesktopSettingsSection.vue

View workflow job for this annotation

GitHub Actions / NPM typecheck

No overload matches this call.
get: () => playSoundOptions.find(option => option.value === playSound.value),
set: (valueOption: { value: string }) => {
playSound.value = valueOption.value
},
})
const runMinimizedToTray = ref(false)
</script>

<template>
<div>
<SettingsSubsection :name="t('talk_desktop', 'General')">
<NcCheckboxRadioSwitch :checked.sync="runMinimizedToTray" type="switch">
{{ t('talk_desktop', 'Launch at startup') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :checked.sync="runMinimizedToTray" type="switch">
{{ t('talk_desktop', 'Launch minimized to the system tray') }}
</NcCheckboxRadioSwitch>
</SettingsSubsection>

<SettingsSubsection :name="t('talk_desktop', 'Appearance')">
<label style="display: flex; gap: 8px; padding: 0 8px;">
<span style="display: flex; align-items: center">
<IconThemeLightDark :size="20" style="width: 36px" />
<span>{{ t('talk_desktop', 'Theme') }}</span>
</span>
<NcSelect v-model="themeOption"
:clearable="false"
:searchable="false"
label-outside
style="margin: 0 !important; flex: 1 0 auto;"
:options="themeOptions" />
</label>

<NcCheckboxRadioSwitch :checked.sync="runMinimizedToTray" type="switch">
{{ t('talk_desktop', 'Use monochrome tray icon') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :checked.sync="runMinimizedToTray" type="switch">
{{ t('talk_desktop', 'Use system title bar') }}
</NcCheckboxRadioSwitch>
</SettingsSubsection>

<SettingsSubsection :name="t('talk_desktop', 'Notifications')">
<label style="display: flex; gap: 8px; padding: 0 8px;">
<span style="display: flex; align-items: center">
<IconBellOutline :size="20" style="width: 36px" />
<span>{{ t('talk_desktop', 'Notification sound') }}</span>
</span>
<NcSelect v-model="playSoundOption"
:clearable="false"
:searchable="false"
label-outside
style="margin: 0 !important"
:options="playSoundOptions" />
</label>
<NcCheckboxRadioSwitch :checked.sync="runMinimizedToTray" type="switch">
{{ t('talk_desktop', 'Show message text in the notification') }}
</NcCheckboxRadioSwitch>
</SettingsSubsection>
</div>
</template>
35 changes: 35 additions & 0 deletions src/talk/renderer/Settings/components/SettingsSubsection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<script setup lang="ts">
defineProps<{
name?: string
}>()
</script>

<template>
<div class="settings-subsection">
<h3 v-if="name" class="settings-subsection__title">
{{ name }}
</h3>
<div class="setting-subsection__content">
<slot />
</div>
</div>
</template>

<style scoped>
.settings-subsection__title {
/* Override the default margin */
margin-block-start: 0 !important;
}
.setting-subsection__content {
display: flex;
flex-direction: column;
gap: var(--default-grid-baseline);
align-items: stretch;
}
</style>
43 changes: 43 additions & 0 deletions src/talk/renderer/Settings/createSettingsSectionElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import Vue from 'vue'
import type { DefineComponent, Component, ComponentInstance } from 'vue'

/**
* Create a custom element for a settings section from a Vue component
* @param component - Vue component to use as a settings section
*/
export function createSettingsSectionElement(component: Component): CustomElementConstructor & { tagName: string } {
class SettingsSectionElement extends HTMLElement {

static tagName = 'talk-desktop-settings-section-' + Math.random().toString(36).substring(6)

vm: ComponentInstance
rootElement: HTMLElement
isMounted: boolean = false

constructor() {
super()
this.rootElement = document.createElement('div')
const ComponentConstructor = Vue.extend(component as DefineComponent)
this.vm = new ComponentConstructor()
}

connectedCallback() {
if (this.isMounted) {
return
}
this.isMounted = true
this.appendChild(this.rootElement)
this.vm.$mount(this.rootElement)
}

}

window.customElements.define(SettingsSectionElement.tagName, SettingsSectionElement)

return SettingsSectionElement
}
26 changes: 26 additions & 0 deletions src/talk/renderer/Settings/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { t } from '@nextcloud/l10n'
import { createSettingsSectionElement } from './createSettingsSectionElement.ts'
import DesktopSettingsSection from './components/DesktopSettingsSection.vue'
import AccountsSettingsSection from './components/AccountsSettingsSection.vue'

/**
* Register Talk Desktop settings sections
*/
export function registerTalkDesktopSettingsSection() {
window.OCA.Talk.Settings.registerSection({
id: 'talk-desktop-settings',
name: t('talk_desktop', 'Application'),
element: createSettingsSectionElement(DesktopSettingsSection).tagName,
})

window.OCA.Talk.Settings.registerSection({
id: 'talk-desktop-accounts',
name: t('talk_desktop', 'Accounts'),
element: createSettingsSectionElement(AccountsSettingsSection).tagName,
})
}
8 changes: 8 additions & 0 deletions src/talk/renderer/components/MainMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<script setup>
import { computed } from 'vue'
import IconCog from 'vue-material-design-icons/Cog.vue'
import IconReload from 'vue-material-design-icons/Reload.vue'
import IconWeb from 'vue-material-design-icons/Web.vue'
import IconBug from 'vue-material-design-icons/Bug.vue'
Expand All @@ -25,6 +26,7 @@ const talkRouter = window.OCA.Talk.Desktop.talkRouter
const talkWebLink = computed(() => generateUrl(talkRouter.value?.currentRoute?.fullPath ?? ''))
const showHelp = () => window.TALK_DESKTOP.showHelp()
const reload = () => window.location.reload()
const openSettings = () => window.OCA.Talk.Settings.open()
</script>
<template>
Expand Down Expand Up @@ -59,6 +61,12 @@ const reload = () => window.location.reload()
<NcActionSeparator />
<NcActionButton close-after-click @click="openSettings">
<template #icon>
<IconCog :size="20" />
</template>
{{ t('talk_desktop', 'Settings') }}
</NcActionButton>
<NcActionButton @click="showHelp">
<template #icon>
<IconInformationOutline :size="20" />
Expand Down
3 changes: 3 additions & 0 deletions src/talk/renderer/talk.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { setupWebPage } from '../../shared/setupWebPage.js'
import { createViewer } from './Viewer/Viewer.js'
import { createDesktopApp } from './desktop.app.js'
import { registerTalkDesktopSettingsSection } from './Settings/index.ts'

// Initially open the welcome page, if not specified
if (!window.location.hash) {
Expand All @@ -36,4 +37,6 @@ initTalkHashIntegration(window.OCA.Talk.instance)

window.OCA.Talk.Desktop.talkRouter.value = window.OCA.Talk.instance.$router

registerTalkDesktopSettingsSection()

await import('./notifications/notifications.store.js')

0 comments on commit 9a6b3f6

Please sign in to comment.