chromium/ios/chrome/browser/overlays/ui_bundled/infobar_modal/permissions/permissions_infobar_modal_overlay_mediator.mm

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/overlays/ui_bundled/infobar_modal/permissions/permissions_infobar_modal_overlay_mediator.h"

#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "ios/chrome/browser/overlays/model/public/default/default_infobar_overlay_request_config.h"
#import "ios/chrome/browser/overlays/ui_bundled/overlay_request_mediator+subclassing.h"
#import "ios/chrome/browser/permissions/model/permissions_infobar_delegate.h"
#import "ios/chrome/browser/permissions/ui_bundled/permission_info.h"
#import "ios/chrome/browser/permissions/ui_bundled/permission_metrics_util.h"
#import "ios/chrome/browser/permissions/ui_bundled/permissions_consumer.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/web/public/navigation/navigation_item.h"
#import "ios/web/public/navigation/navigation_manager.h"
#import "ios/web/public/permissions/permissions.h"
#import "ios/web/public/web_state.h"
#import "ios/web/public/web_state_observer_bridge.h"
#import "ui/base/l10n/l10n_util.h"

@interface PermissionsInfobarModalOverlayMediator () <CRWWebStateObserver> {
  std::unique_ptr<web::WebStateObserverBridge> _observer;
}

// The permissions modal config from the request.
@property(nonatomic, readonly) DefaultInfobarOverlayRequestConfig* config;
// The observed webState.
@property(nonatomic, assign) web::WebState* webState;

@end

@implementation PermissionsInfobarModalOverlayMediator

#pragma mark - Public

- (void)setConsumer:(id<PermissionsConsumer>)consumer {
  if (_consumer == consumer)
    return;

  _consumer = consumer;

  DefaultInfobarOverlayRequestConfig* config = self.config;
  if (!_consumer || !config) {
    return;
  }

  PermissionsInfobarDelegate* delegate =
      static_cast<PermissionsInfobarDelegate*>(config->delegate());
  self.webState = delegate->GetWebState();

  if (!self.webState) {
    return;
  }

  _observer = std::make_unique<web::WebStateObserverBridge>(self);
  self.webState->AddObserver(_observer.get());

  web::NavigationItem* visibleItem =
      self.webState->GetNavigationManager()->GetVisibleItem();
  const GURL& URL = visibleItem->GetURL();

  NSString* permissionsDescription =
      l10n_util::GetNSStringF(IDS_IOS_PERMISSIONS_INFOBAR_MODAL_DESCRIPTION,
                              base::UTF8ToUTF16(URL.host()));

  if ([_consumer respondsToSelector:@selector(setPermissionsDescription:)]) {
    [_consumer setPermissionsDescription:permissionsDescription];
  }
  [self dispatchInitialPermissionsInfo];
}

- (void)disconnect {
  [self detachFromWebState];
}

#pragma mark - Accessors

- (DefaultInfobarOverlayRequestConfig*)config {
  return self.request
             ? self.request->GetConfig<DefaultInfobarOverlayRequestConfig>()
             : nullptr;
}

#pragma mark - OverlayRequestMediator

+ (const OverlayRequestSupport*)requestSupport {
  return DefaultInfobarOverlayRequestConfig::RequestSupport();
}

#pragma mark - CRWWebStateObserver

- (void)webState:(web::WebState*)webState
    didChangeStateForPermission:(web::Permission)permission {
  PermissionInfo* permissionsDescription = [[PermissionInfo alloc] init];
  permissionsDescription.permission = permission;
  permissionsDescription.state =
      self.webState->GetStateForPermission(permission);
  [self.consumer permissionStateChanged:permissionsDescription];
}

- (void)webStateDestroyed:(web::WebState*)webState {
  [self detachFromWebState];
}

#pragma mark - PermissionsDelegate

- (void)updateStateForPermission:(PermissionInfo*)permissionDescription {
  RecordPermissionToogled();
  self.webState->SetStateForPermission(permissionDescription.state,
                                       permissionDescription.permission);
  RecordPermissionEventFromOrigin(
      permissionDescription,
      PermissionEventOrigin::PermissionEventOriginModalInfobar);
}

#pragma mark - Private

// Helper that creates and dispatches initial permissions information to the
// InfobarModal.
- (void)dispatchInitialPermissionsInfo {
  NSMutableDictionary<NSNumber*, NSNumber*>* permissionsInfo =
      [[NSMutableDictionary alloc] init];

  NSDictionary<NSNumber*, NSNumber*>* statesForAllPermissions =
      self.webState->GetStatesForAllPermissions();
  for (NSNumber* key in statesForAllPermissions) {
    web::PermissionState state =
        (web::PermissionState)statesForAllPermissions[key].unsignedIntValue;
    if (state != web::PermissionStateNotAccessible) {
      [permissionsInfo setObject:statesForAllPermissions[key] forKey:key];
    }
  }
  [self.consumer setPermissionsInfo:permissionsInfo];
}

- (void)detachFromWebState {
  if (_webState && _observer) {
    _webState->RemoveObserver(_observer.get());
    _observer.reset();
    _webState = nullptr;
  }
}

@end