Skip to content

Commit

Permalink
Merge pull request #12940 from nextcloud/feat/dark-theme-change
Browse files Browse the repository at this point in the history
fix(frontend): handle dark theme change without reload
  • Loading branch information
ShGKme authored Sep 2, 2024
2 parents 9288857 + d0659e1 commit df11b3f
Show file tree
Hide file tree
Showing 14 changed files with 425 additions and 319 deletions.
335 changes: 188 additions & 147 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@nextcloud/upload": "^1.5.0",
"@nextcloud/vue": "^8.17.1",
"@vueuse/components": "^11.0.3",
"@vueuse/core": "^11.0.1",
"blurhash": "^2.0.5",
"crypto-js": "^4.2.0",
"debounce": "^2.1.0",
Expand Down
16 changes: 12 additions & 4 deletions src/components/AvatarWrapper/AvatarWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
:alt="name"
class="avatar icon">
<NcAvatar v-else
:key="id"
:key="id + (isDarkTheme ? '-dark' : '-light')"
:user="id"
:display-name="name"
:menu-container="menuContainerWithFallback"
Expand Down Expand Up @@ -52,9 +52,9 @@ import { t } from '@nextcloud/l10n'
import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'

import { useIsDarkTheme } from '../../composables/useIsDarkTheme.ts'
import { ATTENDEE, AVATAR } from '../../constants.js'
import { getUserProxyAvatarOcsUrl } from '../../services/avatarService.ts'
import { isDarkTheme } from '../../utils/isDarkTheme.js'

export default {

Expand Down Expand Up @@ -133,6 +133,14 @@ export default {
default: false,
},
},

setup() {
const isDarkTheme = useIsDarkTheme()
return {
isDarkTheme,
}
},

computed: {
// Determines which icon is displayed
iconClass() {
Expand All @@ -159,7 +167,7 @@ export default {
},
avatarClass() {
return {
'avatar-wrapper--dark': isDarkTheme,
'avatar-wrapper--dark': this.isDarkTheme,
'avatar-wrapper--offline': this.offline,
'avatar-wrapper--condensed': this.condensed,
'avatar-wrapper--highlighted': this.highlighted,
Expand Down Expand Up @@ -197,7 +205,7 @@ export default {
return this.menuContainer ?? this.$store.getters.getMainContainerSelector()
},
avatarUrl() {
return getUserProxyAvatarOcsUrl(this.token, this.id, isDarkTheme, this.size > AVATAR.SIZE.MEDIUM ? 512 : 64)
return getUserProxyAvatarOcsUrl(this.token, this.id, this.isDarkTheme, this.size > AVATAR.SIZE.MEDIUM ? 512 : 64)
},
},

Expand Down
20 changes: 14 additions & 6 deletions src/components/ConversationIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<!-- Using key on NcAvatar forces NcAvatar re-mount and solve the problem, could not really optimal -->
<!-- TODO: Check if props update support in NcAvatar is more performant -->
<NcAvatar v-else
:key="item.token"
:key="item.token + (isDarkTheme ? '-dark' : '-light')"
:size="size"
:user="item.name"
:disable-menu="disableMenu"
Expand Down Expand Up @@ -62,10 +62,10 @@ import { t } from '@nextcloud/l10n'

import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js'

import { useIsDarkTheme } from '../composables/useIsDarkTheme.ts'
import { AVATAR, CONVERSATION } from '../constants.js'
import { getConversationAvatarOcsUrl } from '../services/avatarService.ts'
import { hasTalkFeature } from '../services/CapabilitiesManager.ts'
import { isDarkTheme } from '../utils/isDarkTheme.js'

const supportsAvatar = hasTalkFeature('local', 'avatar')

Expand Down Expand Up @@ -133,6 +133,14 @@ export default {
},
},

setup() {
const isDarkTheme = useIsDarkTheme()

return {
isDarkTheme,
}
},

computed: {
showCall() {
return !this.hideCall && this.item.hasCall
Expand Down Expand Up @@ -209,7 +217,7 @@ export default {
},

themeClass() {
return `conversation-icon--${isDarkTheme ? 'dark' : 'bright'}`
return `conversation-icon--${this.isDarkTheme ? 'dark' : 'bright'}`
},

isOneToOne() {
Expand All @@ -218,9 +226,9 @@ export default {

conversationType() {
if (this.item.remoteServer) {
return { icon: WebIcon, label: t('spreed', 'Federated conversation') }
return { key: 'federated', icon: WebIcon, label: t('spreed', 'Federated conversation') }
} else if (this.item.type === CONVERSATION.TYPE.PUBLIC) {
return { icon: LinkVariantIcon, label: t('spreed', 'Public conversation') }
return { key: 'public', icon: LinkVariantIcon, label: t('spreed', 'Public conversation') }
}
return null
},
Expand All @@ -230,7 +238,7 @@ export default {
return undefined
}

return getConversationAvatarOcsUrl(this.item.token, isDarkTheme, this.item.avatarVersion)
return getConversationAvatarOcsUrl(this.item.token, this.isDarkTheme, this.item.avatarVersion)
},
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ import NcEmojiPicker from '@nextcloud/vue/dist/Components/NcEmojiPicker.js'

import ConversationIcon from '../ConversationIcon.vue'

import { useIsDarkTheme } from '../../composables/useIsDarkTheme.ts'
import { AVATAR } from '../../constants.js'
import { isDarkTheme } from '../../utils/isDarkTheme.js'

// eslint-disable-next-line n/no-extraneous-import
import 'cropperjs/dist/cropper.css'
Expand Down Expand Up @@ -173,7 +173,9 @@ export default {
emits: ['avatar-edited'],

setup() {
const isDarkTheme = useIsDarkTheme()
return {
isDarkTheme,
AVATAR,
validMimeTypes,
}
Expand Down Expand Up @@ -209,7 +211,7 @@ export default {
},

themeClass() {
return `avatar__preview-emoji--${isDarkTheme ? 'dark' : 'bright'}`
return `avatar__preview-emoji--${this.isDarkTheme ? 'dark' : 'bright'}`
},

showControls() {
Expand All @@ -220,7 +222,7 @@ export default {
return [{
label: t('spreed', 'Choose'),
callback: (nodes) => this.handleFileChoose(nodes),
type: 'primary'
type: 'primary',
}]
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<template>
<span ref="mention" class="mention">
<NcUserBubble v-if="size"
:key="isDarkTheme ? 'dark' : 'light'"
:display-name="name"
:avatar-image="avatarUrl"
:user="id"
Expand All @@ -19,8 +20,8 @@ import { loadState } from '@nextcloud/initial-state'

import NcUserBubble from '@nextcloud/vue/dist/Components/NcUserBubble.js'

import { useIsDarkTheme } from '../../../../../composables/useIsDarkTheme.ts'
import { getConversationAvatarOcsUrl, getUserProxyAvatarOcsUrl } from '../../../../../services/avatarService.ts'
import { isDarkTheme } from '../../../../../utils/isDarkTheme.js'

export default {
name: 'Mention',
Expand Down Expand Up @@ -52,6 +53,14 @@ export default {
},
},

setup() {
const isDarkTheme = useIsDarkTheme()

return {
isDarkTheme,
}
},

data() {
return {
size: null,
Expand Down Expand Up @@ -101,7 +110,7 @@ export default {
avatarUrl() {
if (this.isRemoteUser) {
return this.token
? getUserProxyAvatarOcsUrl(this.token, this.id + '@' + this.server, isDarkTheme, 64)
? getUserProxyAvatarOcsUrl(this.token, this.id + '@' + this.server, this.isDarkTheme, 64)
: 'icon-user-forced-white'
} else if (this.isGroupMention) {
return 'icon-group-forced-white'
Expand All @@ -111,7 +120,7 @@ export default {
return undefined
}

return getConversationAvatarOcsUrl(this.id, isDarkTheme)
return getConversationAvatarOcsUrl(this.id, this.isDarkTheme)
},
},

Expand Down
11 changes: 6 additions & 5 deletions src/components/NewMessage/NewMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ import NewMessagePollEditor from './NewMessagePollEditor.vue'
import NewMessageTypingIndicator from './NewMessageTypingIndicator.vue'
import Quote from '../Quote.vue'

import { useIsDarkTheme } from '../../composables/useIsDarkTheme.ts'
import { ATTENDEE, CONVERSATION, PARTICIPANT, PRIVACY } from '../../constants.js'
import { getConversationAvatarOcsUrl, getUserProxyAvatarOcsUrl } from '../../services/avatarService.ts'
import BrowserStorage from '../../services/BrowserStorage.js'
Expand All @@ -211,7 +212,6 @@ import { useBreakoutRoomsStore } from '../../stores/breakoutRooms.ts'
import { useChatExtrasStore } from '../../stores/chatExtras.js'
import { useSettingsStore } from '../../stores/settings.js'
import { fetchClipboardContent } from '../../utils/clipboard.js'
import { isDarkTheme } from '../../utils/isDarkTheme.js'
import { parseSpecialSymbols } from '../../utils/textParse.ts'

export default {
Expand Down Expand Up @@ -289,8 +289,9 @@ export default {

setup(props) {
const supportTypingStatus = getTalkConfig(props.token, 'chat', 'typing-privacy') !== undefined

const isDarkTheme = useIsDarkTheme()
return {
isDarkTheme,
breakoutRoomsStore: useBreakoutRoomsStore(),
chatExtrasStore: useChatExtrasStore(),
settingsStore: useSettingsStore(),
Expand Down Expand Up @@ -909,7 +910,7 @@ export default {
// Set icon for candidate mentions that are not for users.
if (possibleMention.source === 'calls') {
possibleMention.icon = 'icon-user-forced-white'
possibleMention.iconUrl = getConversationAvatarOcsUrl(this.token, isDarkTheme)
possibleMention.iconUrl = getConversationAvatarOcsUrl(this.token, this.isDarkTheme)
possibleMention.subline = possibleMention?.details ? possibleMention.details : t('spreed', 'Everyone')
} else if (possibleMention.source === ATTENDEE.ACTOR_TYPE.GROUPS) {
possibleMention.icon = 'icon-group-forced-white'
Expand All @@ -919,14 +920,14 @@ export default {
possibleMention.subline = t('spreed', 'Guest')
} else if (possibleMention.source === ATTENDEE.ACTOR_TYPE.FEDERATED_USERS) {
possibleMention.icon = 'icon-user-forced-white'
possibleMention.iconUrl = getUserProxyAvatarOcsUrl(this.token, possibleMention.id, isDarkTheme, 64)
possibleMention.iconUrl = getUserProxyAvatarOcsUrl(this.token, possibleMention.id, this.isDarkTheme, 64)
} else {
// The avatar is automatically shown for users, but an icon
// is nevertheless required as fallback.
possibleMention.icon = 'icon-user-forced-white'
if (possibleMention.source === ATTENDEE.ACTOR_TYPE.USERS && possibleMention.id !== possibleMention.mentionId) {
// Prevent local users avatars in federated room to be overwritten
possibleMention.iconUrl = generateUrl('avatar/{userId}/64' + (isDarkTheme ? '/dark' : '') + '?v=0', { userId: possibleMention.id })
possibleMention.iconUrl = generateUrl('avatar/{userId}/64' + (this.isDarkTheme ? '/dark' : '') + '?v=0', { userId: possibleMention.id })
}
// Convert status properties to an object.
if (possibleMention.status) {
Expand Down
10 changes: 8 additions & 2 deletions src/components/NewMessage/NewMessageAbsenceInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
<div v-if="userAbsence.replacementUserId" class="absence-reminder__replacement">
<!-- TRANSLATORS An acting person during the period of absence of the main contact -->
<p>{{ t('spreed','Replacement: ') }}</p>
<NcUserBubble class="absence-reminder__replacement__bubble"
<NcUserBubble :key="isDarkTheme ? 'dark' : 'light'"
class="absence-reminder__replacement__bubble"
:title="t('spreed','Open conversation')"
:display-name="userAbsence.replacementUserDisplayName"
:user="userAbsence.replacementUserId"
Expand Down Expand Up @@ -48,6 +49,7 @@ import NcUserBubble from '@nextcloud/vue/dist/Components/NcUserBubble.js'

import AvatarWrapper from '../AvatarWrapper/AvatarWrapper.vue'

import { useIsDarkTheme } from '../../composables/useIsDarkTheme.ts'
import { AVATAR } from '../../constants.js'

export default {
Expand All @@ -74,7 +76,11 @@ export default {
},

setup() {
return { AVATAR }
const isDarkTheme = useIsDarkTheme()
return {
AVATAR,
isDarkTheme,
}
},

data() {
Expand Down
Loading

0 comments on commit df11b3f

Please sign in to comment.