Skip to content
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
10 changes: 5 additions & 5 deletions src/script/main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ import {MediaDevicesHandler} from 'Repositories/media/MediaDevicesHandler';
import {MediaStreamHandler} from 'Repositories/media/MediaStreamHandler';
import {NotificationRepository} from 'Repositories/notification/NotificationRepository';
import {PreferenceNotificationRepository} from 'Repositories/notification/PreferenceNotificationRepository';
import {PermissionRepository} from 'Repositories/permission/PermissionRepository';
import {initializePermissions} from 'Repositories/permission/permissionHandlers';
import {PropertiesRepository} from 'Repositories/properties/PropertiesRepository';
import {PropertiesService} from 'Repositories/properties/PropertiesService';
import {SearchRepository} from 'Repositories/search/SearchRepository';
Expand Down Expand Up @@ -191,10 +191,12 @@ export class App {
const repositories: ViewModelRepositories = {} as ViewModelRepositories;
const selfService = new SelfService();
const teamService = new TeamService();
const permissionRepository = new PermissionRepository();
// Initialize permissions
void initializePermissions();

const mediaConstraintsHandler = new MediaConstraintsHandler();

const mediaStreamHandler = new MediaStreamHandler(mediaConstraintsHandler, permissionRepository);
const mediaStreamHandler = new MediaStreamHandler(mediaConstraintsHandler);
const mediaDevicesHandler = new MediaDevicesHandler();

container.registerInstance(MediaDevicesHandler, mediaDevicesHandler);
Expand Down Expand Up @@ -284,10 +286,8 @@ export class App {
repositories.conversation,
repositories.team,
);
repositories.permission = permissionRepository;
repositories.notification = new NotificationRepository(
repositories.conversation,
repositories.permission,
repositories.audio,
repositories.calling,
);
Expand Down
3 changes: 1 addition & 2 deletions src/script/repositories/media/MediaStreamHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
*
*/

import {PermissionRepository} from 'Repositories/permission/PermissionRepository';
import {UserState} from 'Repositories/user/UserState';

import {MediaConstraintsHandler} from './MediaConstraintsHandler';
Expand All @@ -33,7 +32,7 @@ describe('MediaStreamHandler', () => {
const mediaConstraintsHandler = new MediaConstraintsHandler(userState);

beforeEach(() => {
streamHandler = new MediaStreamHandler(mediaConstraintsHandler, new PermissionRepository());
streamHandler = new MediaStreamHandler(mediaConstraintsHandler);
});

describe('requestMediaStream', () => {
Expand Down
15 changes: 6 additions & 9 deletions src/script/repositories/media/MediaStreamHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {container} from 'tsyringe';
import {Runtime} from '@wireapp/commons';

import {CallingViewMode, CallState} from 'Repositories/calling/CallState';
import type {PermissionRepository} from 'Repositories/permission/PermissionRepository';
import {PermissionStatusState} from 'Repositories/permission/PermissionStatusState';
import {BrowserPermissionStatus} from 'Repositories/permission/BrowserPermissionStatus';
import {getPermissionStates} from 'Repositories/permission/permissionHandlers';
import {PermissionType} from 'Repositories/permission/PermissionType';
import {getLogger, Logger} from 'Util/Logger';

Expand All @@ -46,10 +46,7 @@ export class MediaStreamHandler {
private requestHintTimeout: number | undefined;
private readonly screensharingMethod: ScreensharingMethods;

constructor(
private readonly constraintsHandler: MediaConstraintsHandler,
private readonly permissionRepository: PermissionRepository,
) {
constructor(private readonly constraintsHandler: MediaConstraintsHandler) {
this.logger = getLogger('MediaStreamHandler');
this.requestHintTimeout = undefined;

Expand Down Expand Up @@ -106,16 +103,16 @@ export class MediaStreamHandler {
*/
private hasPermissionToAccess(audio: boolean, video: boolean): boolean {
const checkPermissionStates = (typesToCheck: PermissionType[]): boolean => {
const permissions = this.permissionRepository.getPermissionStates(typesToCheck);
const permissions = getPermissionStates(typesToCheck);
for (const permission of permissions) {
const {state, type} = permission;
const isPermissionPrompt = state === PermissionStatusState.PROMPT;
const isPermissionPrompt = state === BrowserPermissionStatus.PROMPT;
if (isPermissionPrompt) {
this.logger.info(`Need to prompt for '${type}' permission`);
return false;
}

const isPermissionDenied = state === PermissionStatusState.DENIED;
const isPermissionDenied = state === BrowserPermissionStatus.DENIED;
if (isPermissionDenied) {
this.logger.warn(`Permission for '${type}' is denied`);
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

/** @see https://developer.mozilla.org/en-US/docs/Web/API/Notification/permission */
export enum PermissionState {
export enum AppPermissionState {
DEFAULT = 'default',
DENIED = 'denied',
GRANTED = 'granted',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ import {RenameMessage} from 'Repositories/entity/message/RenameMessage';
import {Text} from 'Repositories/entity/message/Text';
import {User} from 'Repositories/entity/User';
import {NOTIFICATION_HANDLING_STATE} from 'Repositories/event/NotificationHandlingState';
import {PermissionRepository} from 'Repositories/permission/PermissionRepository';
import {PermissionStatusState} from 'Repositories/permission/PermissionStatusState';
import {BrowserPermissionStatus} from 'Repositories/permission/BrowserPermissionStatus';
import {UserMapper} from 'Repositories/user/UserMapper';
import {UserState} from 'Repositories/user/UserState';
import 'src/script/localization/Localizer';
Expand All @@ -72,7 +71,6 @@ function buildNotificationRepository() {
const userState = container.resolve(UserState);
const notificationRepository = new NotificationRepository(
{} as any,
new PermissionRepository(),
new AudioRepository(),
{} as CallingRepository,
userState,
Expand Down Expand Up @@ -132,7 +130,7 @@ describe('NotificationRepository', () => {

// Mocks
document.hasFocus = () => false;
notificationRepository.updatePermissionState(PermissionStatusState.GRANTED);
notificationRepository.updatePermissionState(BrowserPermissionStatus.GRANTED);
spyOn(Runtime, 'isSupportingNotifications').and.returnValue(true);
spyOn(notificationRepository['assetRepository'], 'getObjectUrl').and.returnValue(
Promise.resolve('/image/logo/notification.png'),
Expand Down Expand Up @@ -310,7 +308,7 @@ describe('NotificationRepository', () => {
});

it('if the user permission was denied', () => {
notificationRepository.updatePermissionState(PermissionStatusState.DENIED);
notificationRepository.updatePermissionState(BrowserPermissionStatus.DENIED);

return notificationRepository.notify(message, undefined, conversation).then(() => {
expect(notificationRepository['showNotification']).not.toHaveBeenCalled();
Expand Down Expand Up @@ -347,7 +345,7 @@ describe('NotificationRepository', () => {

it('filters all notifications (but composite) if user is "away"', () => {
userState.self().availability(Availability.Type.AWAY);
notificationRepository.updatePermissionState(PermissionStatusState.GRANTED);
notificationRepository.updatePermissionState(BrowserPermissionStatus.GRANTED);

const testPromises = Object.values(allMessageTypes).map(messageEntity => {
return notificationRepository.notify(messageEntity, undefined, conversation).then(() => {
Expand All @@ -364,7 +362,7 @@ describe('NotificationRepository', () => {

it('filters content and ping messages when user is "busy"', () => {
userState.self().availability(Availability.Type.BUSY);
notificationRepository.updatePermissionState(PermissionStatusState.GRANTED);
notificationRepository.updatePermissionState(BrowserPermissionStatus.GRANTED);

const ignoredMessages = Object.entries(allMessageTypes)
.filter(([type]) => ['content', 'ping'].includes(type))
Expand All @@ -381,7 +379,7 @@ describe('NotificationRepository', () => {

it('allows mentions, calls and composite when user is "busy"', () => {
userState.self().availability(Availability.Type.BUSY);
notificationRepository.updatePermissionState(PermissionStatusState.GRANTED);
notificationRepository.updatePermissionState(BrowserPermissionStatus.GRANTED);

const notifiedMessages = Object.entries(allMessageTypes)
.filter(([type]) => ['mention', 'call', 'composite'].includes(type))
Expand Down
44 changes: 22 additions & 22 deletions src/script/repositories/notification/NotificationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ import type {MessageTimerUpdateMessage} from 'Repositories/entity/message/Messag
import type {RenameMessage} from 'Repositories/entity/message/RenameMessage';
import type {SystemMessage} from 'Repositories/entity/message/SystemMessage';
import type {User} from 'Repositories/entity/User';
import type {PermissionRepository} from 'Repositories/permission/PermissionRepository';
import {PermissionStatusState} from 'Repositories/permission/PermissionStatusState';
import {BrowserPermissionStatus} from 'Repositories/permission/BrowserPermissionStatus';
import {getPermissionState, setPermissionState} from 'Repositories/permission/permissionHandlers';
import {normalizePermissionState} from 'Repositories/permission/Permissions.types';
import {PermissionType} from 'Repositories/permission/PermissionType';
import {UserState} from 'Repositories/user/UserState';
import {Declension, t, getUserName} from 'Util/LocalizerUtil';
Expand All @@ -58,7 +59,7 @@ import {truncate} from 'Util/StringUtil';
import {formatDuration, TIME_IN_MILLIS} from 'Util/TimeUtil';
import {ValidationUtilError} from 'Util/ValidationUtil';

import {PermissionState} from './PermissionState';
import {AppPermissionState} from './AppPermissionState';

import {SuperType} from '../../message/SuperType';
import {SystemMessageType} from '../../message/SystemMessageType';
Expand Down Expand Up @@ -91,8 +92,6 @@ export class NotificationRepository {
private readonly logger: Logger;
private readonly notifications: WebappNotifications[];
private readonly notificationsPreference: ko.Observable<NotificationPreference>;
private readonly permissionRepository: PermissionRepository;
private readonly permissionState: ko.Observable<PermissionState | PermissionStatusState | NotificationPermission>;
private readonly assetRepository: AssetRepository;
private isSoftLock = false;

Expand All @@ -118,7 +117,6 @@ export class NotificationRepository {
*/
constructor(
conversationRepository: ConversationRepository,
permissionRepository: PermissionRepository,
private readonly audioRepository: AudioRepository,
private readonly callingRepository: CallingRepository,
private readonly userState = container.resolve(UserState),
Expand All @@ -127,7 +125,6 @@ export class NotificationRepository {
) {
this.assetRepository = container.resolve(AssetRepository);
this.conversationRepository = conversationRepository;
this.permissionRepository = permissionRepository;

this.logger = getLogger('NotificationRepository');

Expand All @@ -141,8 +138,6 @@ export class NotificationRepository {
this.checkPermission();
}
});

this.permissionState = this.permissionRepository.permissionState[PermissionType.NOTIFICATIONS];
}

subscribeToEvents(): void {
Expand All @@ -169,17 +164,17 @@ export class NotificationRepository {
}

if (!Runtime.isSupportingNotifications()) {
return this.updatePermissionState(PermissionState.UNSUPPORTED);
return this.updatePermissionState(AppPermissionState.UNSUPPORTED);
}

if (Runtime.isSupportingPermissions()) {
const notificationState = this.permissionRepository.getPermissionState(PermissionType.NOTIFICATIONS);
const shouldRequestPermission = notificationState === PermissionStatusState.PROMPT;
const notificationState = getPermissionState(PermissionType.NOTIFICATIONS);
const shouldRequestPermission = notificationState === BrowserPermissionStatus.PROMPT;
return shouldRequestPermission ? this.requestPermission() : this.checkPermissionState();
}

const currentPermission = window.Notification.permission as PermissionState;
const shouldRequestPermission = currentPermission === PermissionState.DEFAULT;
const currentPermission = window.Notification.permission as BrowserPermissionStatus;
const shouldRequestPermission = currentPermission === BrowserPermissionStatus.PROMPT;
return shouldRequestPermission ? this.requestPermission() : this.updatePermissionState(currentPermission);
}

Expand Down Expand Up @@ -276,8 +271,12 @@ export class NotificationRepository {
* @param permissionState State of browser permission
* @returns Resolves with `true` if notifications are enabled
*/
readonly updatePermissionState = (permissionState: PermissionState | NotificationPermission): boolean | undefined => {
this.permissionState(permissionState);
readonly updatePermissionState = (
permissionState: AppPermissionState | BrowserPermissionStatus | NotificationPermission,
): boolean | undefined => {
// Normalize the permission state and set it in the store
const normalizedState = normalizePermissionState(permissionState);
setPermissionState(PermissionType.NOTIFICATIONS, normalizedState);
return this.checkPermissionState();
};

Expand Down Expand Up @@ -704,14 +703,15 @@ export class NotificationRepository {
* @returns Returns `true` if notifications are permitted
*/
private checkPermissionState(): boolean | undefined {
switch (this.permissionState()) {
case PermissionStatusState.GRANTED: {
const permissionState = getPermissionState(PermissionType.NOTIFICATIONS);
switch (permissionState) {
case BrowserPermissionStatus.GRANTED: {
return true;
}

case PermissionState.IGNORED:
case PermissionState.UNSUPPORTED:
case PermissionStatusState.DENIED: {
case AppPermissionState.IGNORED:
case AppPermissionState.UNSUPPORTED:
case BrowserPermissionStatus.DENIED: {
return false;
}

Expand Down Expand Up @@ -824,7 +824,7 @@ export class NotificationRepository {

const activeConversation = document.hasFocus() && inConversationView && inActiveConversation && !inMaximizedCall;
const messageFromSelf = messageEntity.user().isMe;
const permissionDenied = this.permissionState() === PermissionStatusState.DENIED;
const permissionDenied = getPermissionState(PermissionType.NOTIFICATIONS) === BrowserPermissionStatus.DENIED;

// The in-app notification settings should be ignored for alerts (which are composite messages for now)
const preferenceIsNone =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

/** @see https://developer.mozilla.org/en-US/docs/Web/API/PermissionStatus/state */
export enum PermissionStatusState {
export enum BrowserPermissionStatus {
DENIED = 'denied',
GRANTED = 'granted',
PROMPT = 'prompt',
Expand Down
Loading
Loading