Profile settings: add global Notification toggle
This commit is contained in:
parent
1ddedac0ef
commit
3ad766fe12
8 changed files with 128 additions and 79 deletions
|
|
@ -33,6 +33,7 @@
|
||||||
import stickers from "./plugins/stickers";
|
import stickers from "./plugins/stickers";
|
||||||
import { registerServiceWorker, notificationCount, windowNotificationPermission } from "./plugins/notificationAndServiceWorker.js"
|
import { registerServiceWorker, notificationCount, windowNotificationPermission } from "./plugins/notificationAndServiceWorker.js"
|
||||||
import logoMixin from "./components/logoMixin";
|
import logoMixin from "./components/logoMixin";
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
|
|
@ -175,13 +176,16 @@ export default {
|
||||||
}
|
}
|
||||||
return favicon;
|
return favicon;
|
||||||
},
|
},
|
||||||
|
...mapState([
|
||||||
|
'globalNotification'
|
||||||
|
])
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
notificationCount: {
|
notificationCount: {
|
||||||
handler(nCount) {
|
handler(nCount) {
|
||||||
// windowNotificationPermission
|
// windowNotificationPermission
|
||||||
// return value: 'granted', 'default', 'denied'
|
// return value: 'granted', 'default', 'denied'
|
||||||
if (nCount > 0 && this.windowNotificationPermission() === "granted") {
|
if (this.globalNotification && nCount > 0 && this.windowNotificationPermission() === "granted") {
|
||||||
this.showNotification()
|
this.showNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,8 @@
|
||||||
"password_new": "New password",
|
"password_new": "New password",
|
||||||
"password_repeat": "Repeat new password",
|
"password_repeat": "Repeat new password",
|
||||||
"display_name": "Display name",
|
"display_name": "Display name",
|
||||||
"display_name_required": "Display name is required"
|
"display_name_required": "Display name is required",
|
||||||
|
"notification_label": "Notification"
|
||||||
},
|
},
|
||||||
"profile_info_popup": {
|
"profile_info_popup": {
|
||||||
"you_are": "You are",
|
"you_are": "You are",
|
||||||
|
|
@ -382,7 +383,8 @@
|
||||||
"body": "Never miss a message or important conversation again! Be notified whenever someone sends you a message or replies to your chat.",
|
"body": "Never miss a message or important conversation again! Be notified whenever someone sends you a message or replies to your chat.",
|
||||||
"enable": "Enable"
|
"enable": "Enable"
|
||||||
},
|
},
|
||||||
"blocked_message": "Notifications blocked. Please reset the permissions"
|
"blocked_message": "Notification is blocked. Go to your device or browser settings to enable Notification",
|
||||||
|
"not_supported": "Notification is not yet supported in Mobile"
|
||||||
},
|
},
|
||||||
"emoji": {
|
"emoji": {
|
||||||
"search": "Search...",
|
"search": "Search...",
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,16 @@
|
||||||
no-gutters
|
no-gutters
|
||||||
align-content="center"
|
align-content="center"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
v-show="icon === 'notifications_active' ? this.windowNotificationPermission() !== 'granted' : true"
|
|
||||||
>
|
>
|
||||||
<v-col cols="auto" class="me-2">
|
<v-col cols="auto" class="me-2 align-self-center">
|
||||||
<v-icon :size="iconSize">{{ icon }}</v-icon>
|
<v-icon :size="iconSize">{{ icon }}</v-icon>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col>{{ text }}</v-col>
|
<v-col class="align-self-center">{{ text }}</v-col>
|
||||||
|
<v-col cols="auto" v-if="$slots.default"><slot/></v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { windowNotificationPermission } from "../plugins/notificationAndServiceWorker.js"
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ActionRow",
|
name: "ActionRow",
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -37,9 +35,6 @@ export default {
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
windowNotificationPermission
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,10 @@
|
||||||
<ChatHeaderPrivate class="chat-header flex-grow-0 flex-shrink-0"
|
<ChatHeaderPrivate class="chat-header flex-grow-0 flex-shrink-0"
|
||||||
v-on:header-click="onHeaderClick"
|
v-on:header-click="onHeaderClick"
|
||||||
v-on:view-room-details="viewRoomDetails"
|
v-on:view-room-details="viewRoomDetails"
|
||||||
v-on:notify="onNotificationDialog"
|
|
||||||
v-if="!useFileModeNonAdmin && $matrix.isDirectRoom(room)" />
|
v-if="!useFileModeNonAdmin && $matrix.isDirectRoom(room)" />
|
||||||
<ChatHeader class="chat-header flex-grow-0 flex-shrink-0"
|
<ChatHeader class="chat-header flex-grow-0 flex-shrink-0"
|
||||||
v-on:header-click="onHeaderClick"
|
v-on:header-click="onHeaderClick"
|
||||||
v-on:view-room-details="viewRoomDetails"
|
v-on:view-room-details="viewRoomDetails"
|
||||||
v-on:notify="onNotificationDialog"
|
|
||||||
v-else-if="!useFileModeNonAdmin" />
|
v-else-if="!useFileModeNonAdmin" />
|
||||||
<AudioLayout ref="chatContainer" class="auto-audio-player-root" v-if="useVoiceMode" :room="room"
|
<AudioLayout ref="chatContainer" class="auto-audio-player-root" v-if="useVoiceMode" :room="room"
|
||||||
:events="events" :autoplay="!showRecorder"
|
:events="events" :autoplay="!showRecorder"
|
||||||
|
|
@ -78,9 +76,9 @@
|
||||||
<component :is="componentForEvent(event)" :room="room" :originalEvent="event" :nextEvent="filteredEvents[index + 1]"
|
<component :is="componentForEvent(event)" :room="room" :originalEvent="event" :nextEvent="filteredEvents[index + 1]"
|
||||||
:timelineSet="timelineSet" v-on:send-quick-reaction.stop="sendQuickReaction"
|
:timelineSet="timelineSet" v-on:send-quick-reaction.stop="sendQuickReaction"
|
||||||
:componentFn="componentForEvent"
|
:componentFn="componentForEvent"
|
||||||
v-on:context-menu="showContextMenuForEvent({event: event, anchor: $event.anchor})"
|
v-on:context-menu="showContextMenuForEvent({event: event, anchor: $event.anchor})"
|
||||||
v-on:own-avatar-clicked="viewProfile"
|
v-on:own-avatar-clicked="viewProfile"
|
||||||
v-on:other-avatar-clicked="showAvatarMenuForEvent({event: event, anchor: $event.anchor})"
|
v-on:other-avatar-clicked="showAvatarMenuForEvent({event: event, anchor: $event.anchor})"
|
||||||
v-on:download="download(event)"
|
v-on:download="download(event)"
|
||||||
v-on:poll-closed="pollWasClosed(event)"
|
v-on:poll-closed="pollWasClosed(event)"
|
||||||
v-on:more="
|
v-on:more="
|
||||||
|
|
@ -324,45 +322,6 @@
|
||||||
|
|
||||||
<CreatePollDialog :show="showCreatePollDialog" @close="showCreatePollDialog = false" />
|
<CreatePollDialog :show="showCreatePollDialog" @close="showCreatePollDialog = false" />
|
||||||
|
|
||||||
<!-- Dialog for request Notification and register service worker-->
|
|
||||||
<v-dialog
|
|
||||||
v-model="notificationDialog"
|
|
||||||
persistent
|
|
||||||
class="ma-0 pa-0"
|
|
||||||
:width="$vuetify.breakpoint.smAndUp ? '688px' : '95%'"
|
|
||||||
>
|
|
||||||
<div class="dialog-content text-center">
|
|
||||||
<v-icon size="30">notifications_active</v-icon>
|
|
||||||
<h2 class="dialog-title">
|
|
||||||
{{ $t("notification.dialog.title") }}
|
|
||||||
</h2>
|
|
||||||
<div class="dialog-text">{{ $t("notification.dialog.body") }}</div>
|
|
||||||
<v-container fluid>
|
|
||||||
<v-row cols="12">
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-btn
|
|
||||||
depressed
|
|
||||||
text
|
|
||||||
block
|
|
||||||
class="text-button"
|
|
||||||
@click="notificationDialog = false"
|
|
||||||
>{{ $t("global.close") }}</v-btn
|
|
||||||
>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="6" align="center">
|
|
||||||
<v-btn
|
|
||||||
color="primary"
|
|
||||||
depressed
|
|
||||||
block
|
|
||||||
class="filled-button"
|
|
||||||
@click.stop="onNotifyRequest"
|
|
||||||
>{{ $t("notification.dialog.enable") }}</v-btn
|
|
||||||
>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</div>
|
|
||||||
</v-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -388,7 +347,6 @@ import chatMixin from "./chatMixin";
|
||||||
import sendAttachmentsMixin from "./sendAttachmentsMixin";
|
import sendAttachmentsMixin from "./sendAttachmentsMixin";
|
||||||
import AudioLayout from "./AudioLayout.vue";
|
import AudioLayout from "./AudioLayout.vue";
|
||||||
import FileDropLayout from "./file_mode/FileDropLayout";
|
import FileDropLayout from "./file_mode/FileDropLayout";
|
||||||
import { requestNotificationPermission, windowNotificationPermission } from "../plugins/notificationAndServiceWorker.js"
|
|
||||||
import roomTypeMixin from "./roomTypeMixin";
|
import roomTypeMixin from "./roomTypeMixin";
|
||||||
import roomMembersMixin from "./roomMembersMixin";
|
import roomMembersMixin from "./roomMembersMixin";
|
||||||
|
|
||||||
|
|
@ -525,7 +483,6 @@ export default {
|
||||||
Places: this.$t("emoji.categories.places")
|
Places: this.$t("emoji.categories.places")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
notificationDialog: false
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -914,18 +871,6 @@ export default {
|
||||||
this.initialLoadDone = true;
|
this.initialLoadDone = true;
|
||||||
console.log("Loading finished!");
|
console.log("Loading finished!");
|
||||||
},
|
},
|
||||||
windowNotificationPermission,
|
|
||||||
onNotificationDialog() {
|
|
||||||
if(this.windowNotificationPermission() === 'denied') {
|
|
||||||
alert(this.$t("notification.blocked_message"));
|
|
||||||
} else if(this.windowNotificationPermission() === 'default') {
|
|
||||||
this.notificationDialog = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onNotifyRequest() {
|
|
||||||
requestNotificationPermission()
|
|
||||||
this.notificationDialog = false;
|
|
||||||
},
|
|
||||||
onRoomJoined(initialEventId) {
|
onRoomJoined(initialEventId) {
|
||||||
// Listen to events
|
// Listen to events
|
||||||
this.$matrix.on("Room.timeline", this.onEvent);
|
this.$matrix.on("Room.timeline", this.onEvent);
|
||||||
|
|
@ -1157,7 +1102,7 @@ export default {
|
||||||
this.onLayoutChange(fn, element);
|
this.onLayoutChange(fn, element);
|
||||||
} else {
|
} else {
|
||||||
fn();
|
fn();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fn();
|
fn();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,11 +177,6 @@ export default {
|
||||||
this.$emit("view-room-details", { event: this.event });
|
this.$emit("view-room-details", { event: this.event });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
items.push({
|
|
||||||
icon: 'notifications_active', text: this.$t('global.notify'), handler: () => {
|
|
||||||
this.$emit("notify");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
items.push({
|
items.push({
|
||||||
icon: '$vuetify.icons.ic_member-leave', text: this.$t('leave.leave'), handler: () => {
|
icon: '$vuetify.icons.ic_member-leave', text: this.$t('leave.leave'), handler: () => {
|
||||||
this.leaveRoom();
|
this.leaveRoom();
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,16 @@
|
||||||
:icon="'$vuetify.icons.globe'"
|
:icon="'$vuetify.icons.globe'"
|
||||||
:text="$t('profile.select_language')"
|
:text="$t('profile.select_language')"
|
||||||
/>
|
/>
|
||||||
|
<ActionRow
|
||||||
|
@click="onUpdateGlobalNotification"
|
||||||
|
:icon="notificationIcon"
|
||||||
|
:text="$t('profile.notification_label')"
|
||||||
|
>
|
||||||
|
<v-switch
|
||||||
|
v-model="globalNotification"
|
||||||
|
readonly
|
||||||
|
></v-switch>
|
||||||
|
</ActionRow>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
<!-- edit password dialog -->
|
<!-- edit password dialog -->
|
||||||
|
|
@ -197,6 +207,45 @@
|
||||||
v-model="showSelectLanguageDialog"
|
v-model="showSelectLanguageDialog"
|
||||||
v-on:close="showSelectLanguageDialog = false"
|
v-on:close="showSelectLanguageDialog = false"
|
||||||
/>
|
/>
|
||||||
|
<!-- Dialog for request Notification -->
|
||||||
|
<v-dialog
|
||||||
|
v-model="notificationDialog"
|
||||||
|
persistent
|
||||||
|
class="ma-0 pa-0"
|
||||||
|
:width="$vuetify.breakpoint.smAndUp ? '688px' : '95%'"
|
||||||
|
>
|
||||||
|
<div class="dialog-content text-center">
|
||||||
|
<v-icon size="30">notifications_active</v-icon>
|
||||||
|
<h2 class="dialog-title">
|
||||||
|
{{ $t("notification.dialog.title") }}
|
||||||
|
</h2>
|
||||||
|
<div class="dialog-text">{{ $t("notification.dialog.body") }}</div>
|
||||||
|
<v-container fluid>
|
||||||
|
<v-row cols="12">
|
||||||
|
<v-col cols="6">
|
||||||
|
<v-btn
|
||||||
|
depressed
|
||||||
|
text
|
||||||
|
block
|
||||||
|
class="text-button"
|
||||||
|
@click="onNotifyDialogClosed"
|
||||||
|
>{{ $t("global.close") }}</v-btn
|
||||||
|
>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="6" align="center">
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
depressed
|
||||||
|
block
|
||||||
|
class="filled-button"
|
||||||
|
@click.stop="onNotifyDialog"
|
||||||
|
>{{ $t("notification.dialog.enable") }}</v-btn
|
||||||
|
>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</v-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -207,6 +256,8 @@ import util from "../plugins/utils";
|
||||||
import profileInfoMixin from "./profileInfoMixin";
|
import profileInfoMixin from "./profileInfoMixin";
|
||||||
import LogoutRoomDialog from './LogoutRoomDialog.vue';
|
import LogoutRoomDialog from './LogoutRoomDialog.vue';
|
||||||
import CopyLink from "./CopyLink.vue"
|
import CopyLink from "./CopyLink.vue"
|
||||||
|
import { requestNotificationPermission, windowNotificationPermission } from "../plugins/notificationAndServiceWorker.js"
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Profile",
|
name: "Profile",
|
||||||
|
|
@ -234,7 +285,8 @@ export default {
|
||||||
passwordErrorMessage: null,
|
passwordErrorMessage: null,
|
||||||
isAvatarLoaded: true,
|
isAvatarLoaded: true,
|
||||||
loadValue: 0,
|
loadValue: 0,
|
||||||
newPasswordHasError: false
|
newPasswordHasError: false,
|
||||||
|
notificationDialog: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -252,7 +304,13 @@ export default {
|
||||||
this.newPassword2 &&
|
this.newPassword2 &&
|
||||||
this.newPassword1 == this.newPassword2
|
this.newPassword1 == this.newPassword2
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
notificationIcon() {
|
||||||
|
return this.globalNotification ? 'notifications_active' : 'notifications_off';
|
||||||
|
},
|
||||||
|
...mapState([
|
||||||
|
'globalNotification'
|
||||||
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -306,7 +364,53 @@ export default {
|
||||||
console.log("Progress: " + JSON.stringify(progress));
|
console.log("Progress: " + JSON.stringify(progress));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
updateGlobalNotificationStore(flag) {
|
||||||
|
this.$store.commit('setGlobalNotification', flag);
|
||||||
|
},
|
||||||
|
windowNotificationPermission,
|
||||||
|
onUpdateGlobalNotification(showAlertOrDialog = true) {
|
||||||
|
const permission = this.windowNotificationPermission();
|
||||||
|
|
||||||
|
switch (permission) {
|
||||||
|
case 'denied':
|
||||||
|
this.updateGlobalNotificationStore(false);
|
||||||
|
if (showAlertOrDialog) {
|
||||||
|
alert(this.$t("notification.blocked_message"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'granted':
|
||||||
|
this.updateGlobalNotificationStore(!this.globalNotification);
|
||||||
|
break;
|
||||||
|
case 'default':
|
||||||
|
if (showAlertOrDialog) {
|
||||||
|
this.notificationDialog = true;
|
||||||
|
}
|
||||||
|
this.updateGlobalNotificationStore(!this.globalNotification);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
alert(this.$t("notification.not_supported"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async onNotifyDialog() {
|
||||||
|
const permission = await requestNotificationPermission()
|
||||||
|
if(permission === 'denied') {
|
||||||
|
this.updateGlobalNotificationStore(false);
|
||||||
|
alert(this.$t("notification.blocked_message"));
|
||||||
|
} else {
|
||||||
|
this.updateGlobalNotificationStore(true);
|
||||||
|
}
|
||||||
|
this.notificationDialog = false;
|
||||||
|
},
|
||||||
|
onNotifyDialogClosed() {
|
||||||
|
this.updateGlobalNotificationStore(false);
|
||||||
|
this.notificationDialog = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
if(this.globalNotification && this.windowNotificationPermission() !== 'granted') {
|
||||||
|
this.onUpdateGlobalNotification(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@ export function registerServiceWorker() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function requestNotificationPermission() {
|
export async function requestNotificationPermission() {
|
||||||
if("PushManager" in window) {
|
if("PushManager" in window) {
|
||||||
window.Notification.requestPermission();
|
return Notification?.requestPermission().then((permission) => permission);
|
||||||
} else {
|
} else {
|
||||||
console.log("No Push API Support!");
|
console.log("No Push API Support!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function windowNotificationPermission() {
|
export function windowNotificationPermission() {
|
||||||
return window.Notification.permission
|
return window?.Notification?.permission ?? 'Not_supported'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function notificationCount() {
|
export function notificationCount() {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ const vuexPersistLocalStorage = new VuexPersist({
|
||||||
language: state.language,
|
language: state.language,
|
||||||
currentRoomId: state.currentRoomId,
|
currentRoomId: state.currentRoomId,
|
||||||
hasShownMissedItemsHint: state.hasShownMissedItemsHint,
|
hasShownMissedItemsHint: state.hasShownMissedItemsHint,
|
||||||
|
globalNotification: state.globalNotification,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -98,6 +99,9 @@ export default new Vuex.Store({
|
||||||
},
|
},
|
||||||
setHasShownMissedItemsHint(state, flag) {
|
setHasShownMissedItemsHint(state, flag) {
|
||||||
state.hasShownMissedItemsHint = flag;
|
state.hasShownMissedItemsHint = flag;
|
||||||
|
},
|
||||||
|
setGlobalNotification(state, flag) {
|
||||||
|
state.globalNotification = flag;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue