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
11 changes: 0 additions & 11 deletions mobile/ios/Runner/InlinePhotoPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ import PhotosUI
import UIKit
import UniformTypeIdentifiers

enum EmbeddedPhotoPickerLayout {
static func applyPreferredScale(_ zoomIn: () -> Void) {
UIView.performWithoutAnimation {
zoomIn()
}
}
}

final class InlinePhotoPickerFactory: NSObject, FlutterPlatformViewFactory {
private let messenger: FlutterBinaryMessenger
private weak var parentViewController: UIViewController?
Expand Down Expand Up @@ -130,9 +122,6 @@ final class InlinePhotoPickerPlatformView: NSObject, FlutterPlatformView {
}
pickerViewController = picker
containerView.layoutIfNeeded()
EmbeddedPhotoPickerLayout.applyPreferredScale {
picker.zoomIn()
}
}

private func exportPickerResult(_ result: PHPickerResult) async throws -> String {
Expand Down
89 changes: 48 additions & 41 deletions mobile/ios/Runner/NativeAttachmentPopover.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ final class NativeAttachmentPopoverViewController:
case camera
}

private typealias ContentPreparation = (@escaping () -> Void) -> Void

private let channel: FlutterMethodChannel
private let expandedWidth: CGFloat
private let maximumMenuHeight: CGFloat
Expand Down Expand Up @@ -85,17 +83,29 @@ final class NativeAttachmentPopoverViewController:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
view.layer.cornerRadius = 22
view.layer.cornerRadius = NativeAttachmentPopoverStyle.cornerRadius
view.layer.cornerCurve = .continuous
view.clipsToBounds = true
view.layer.borderColor = UIColor.black.withAlphaComponent(0.04).cgColor
view.layer.borderWidth = NativeAttachmentPopoverStyle.borderWidth
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = NativeAttachmentPopoverStyle.shadowOpacity
view.layer.shadowRadius = NativeAttachmentPopoverStyle.shadowRadius
view.layer.shadowOffset = NativeAttachmentPopoverStyle.shadowOffset
view.clipsToBounds = false

let glassEffect = UIGlassEffect(style: .regular)
glassEffect.isInteractive = true
let glassView = UIVisualEffectView(effect: glassEffect)
glassView.translatesAutoresizingMaskIntoConstraints = false
glassView.layer.cornerRadius = NativeAttachmentPopoverStyle.cornerRadius
glassView.layer.cornerCurve = .continuous
glassView.clipsToBounds = true
view.addSubview(glassView)

contentHost.translatesAutoresizingMaskIntoConstraints = false
contentHost.layer.cornerRadius = NativeAttachmentPopoverStyle.cornerRadius
contentHost.layer.cornerCurve = .continuous
contentHost.clipsToBounds = true
view.addSubview(contentHost)
NSLayoutConstraint.activate([
glassView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
Expand All @@ -114,6 +124,11 @@ final class NativeAttachmentPopoverViewController:

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view.layer.shadowPath =
UIBezierPath(
roundedRect: view.bounds,
cornerRadius: NativeAttachmentPopoverStyle.cornerRadius
).cgPath
cameraPreviewLayer?.frame = cameraPreviewView?.bounds ?? .zero
}

Expand Down Expand Up @@ -198,21 +213,21 @@ final class NativeAttachmentPopoverViewController:
makeNativeAttachmentMenuButton(
title: "Camera",
symbol: "camera",
action: UIAction { [weak self] _ in self?.showCamera() }
action: { [weak self] in self?.showCamera() }
)
)
stack.addArrangedSubview(
makeNativeAttachmentMenuButton(
title: "Photos",
symbol: "photo.on.rectangle.angled",
action: UIAction { [weak self] _ in self?.showPhotos() }
action: { [weak self] in self?.showPhotos() }
)
)
stack.addArrangedSubview(
makeNativeAttachmentMenuButton(
title: "Video",
symbol: "video",
action: UIAction { [weak self] _ in
action: { [weak self] in
self?.finish(method: "pickVideo")
}
)
Expand All @@ -221,7 +236,7 @@ final class NativeAttachmentPopoverViewController:
makeNativeAttachmentMenuButton(
title: "Files",
symbol: "doc",
action: UIAction { [weak self] _ in
action: { [weak self] in
self?.finish(method: "pickFiles")
}
)
Expand Down Expand Up @@ -280,14 +295,14 @@ final class NativeAttachmentPopoverViewController:
title: nil,
symbol: "chevron.left",
accessibilityLabel: "Back to attachment options",
action: UIAction { [weak self] _ in self?.showMenu() }
action: { [weak self] in self?.showMenu() }
)
let actionButton = makeGlassControl(
title: "All Photos",
symbol: nil,
accessibilityLabel: "All Photos",
prominent: true,
action: UIAction { [weak self] _ in self?.performPhotoAction() }
action: { [weak self] in self?.performPhotoAction() }
)
photoActionButton = actionButton
addBottomControls(
Expand All @@ -296,27 +311,7 @@ final class NativeAttachmentPopoverViewController:
trailing: actionButton
)

transition(
to: .photos,
content: container,
preparation: { [weak picker] reveal in
guard let picker else {
reveal()
return
}
// PHPicker ignores scale changes while its remote grid is still
// adapting to the compact menu bounds. Give it one main-loop turn at
// the final popover size, apply the scale offscreen, then reveal it.
DispatchQueue.main.async {
picker.view.layoutIfNeeded()
EmbeddedPhotoPickerLayout.applyPreferredScale {
picker.zoomIn()
picker.view.layoutIfNeeded()
}
DispatchQueue.main.async(execute: reveal)
}
}
)
transition(to: .photos, content: container)
}

private func showCamera() {
Expand Down Expand Up @@ -353,7 +348,7 @@ final class NativeAttachmentPopoverViewController:
title: nil,
symbol: "chevron.left",
accessibilityLabel: "Back to attachment options",
action: UIAction { [weak self] _ in self?.showMenu() }
action: { [weak self] in self?.showMenu() }
)
let captureButton = makeCameraCaptureButton()
cameraCaptureButton = captureButton
Expand Down Expand Up @@ -415,7 +410,6 @@ final class NativeAttachmentPopoverViewController:
private func transition(
to nextSurface: Surface,
content nextView: UIView,
preparation: ContentPreparation? = nil,
completion: (() -> Void)? = nil
) {
let previousView = visibleContentView
Expand Down Expand Up @@ -485,11 +479,7 @@ final class NativeAttachmentPopoverViewController:
}
}

if let preparation {
preparation(reveal)
} else {
reveal()
}
reveal()
}
}

Expand All @@ -498,7 +488,7 @@ final class NativeAttachmentPopoverViewController:
symbol: String?,
accessibilityLabel: String,
prominent: Bool = false,
action: UIAction
action: @escaping () -> Void
) -> UIButton {
var configuration =
prominent
Expand All @@ -513,20 +503,37 @@ final class NativeAttachmentPopoverViewController:
}
configuration.imagePadding = 8
configuration.baseForegroundColor = .white
configuration.titleTextAttributesTransformer =
UIConfigurationTextAttributesTransformer { attributes in
var interAttributes = attributes
interAttributes.font = NativeAttachmentMenuTypography.font(
forTextStyle: .body
)
return interAttributes
}
configuration.contentInsets = NSDirectionalEdgeInsets(
top: 11,
leading: 15,
bottom: 11,
trailing: 15
)
let button = UIButton(configuration: configuration, primaryAction: action)
let button = UIButton(
configuration: configuration,
primaryAction: UIAction { _ in
UISelectionFeedbackGenerator().selectionChanged()
action()
}
)
button.accessibilityLabel = accessibilityLabel
return button
}

private func makeCameraCaptureButton() -> UIButton {
let button = UIButton(
primaryAction: UIAction { [weak self] _ in self?.capturePhoto() }
primaryAction: UIAction { [weak self] _ in
UISelectionFeedbackGenerator().selectionChanged()
self?.capturePhoto()
}
)
button.accessibilityLabel = "Take photo"
button.translatesAutoresizingMaskIntoConstraints = false
Expand Down
68 changes: 64 additions & 4 deletions mobile/ios/Runner/NativeAttachmentPopoverCoordinator.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CoreText
import Flutter
import UIKit

Expand Down Expand Up @@ -276,7 +277,7 @@ enum NativeAttachmentMenuLayout {
static func itemHeight(
compatibleWith traitCollection: UITraitCollection
) -> CGFloat {
let labelHeight = UIFont.preferredFont(
let labelHeight = NativeAttachmentMenuTypography.font(
forTextStyle: labelTextStyle,
compatibleWith: traitCollection
).lineHeight
Expand Down Expand Up @@ -313,12 +314,71 @@ enum NativeAttachmentMenuLayout {
}
}

enum NativeAttachmentMenuTypography {
static let interPostScriptName = "InterVariable"

private static let registeredInter: Bool = {
let fontURL = Bundle.main.bundleURL
.appendingPathComponent("Frameworks")
.appendingPathComponent("App.framework")
.appendingPathComponent("flutter_assets")
.appendingPathComponent("assets")
.appendingPathComponent("fonts")
.appendingPathComponent("InterVariable.ttf")
guard FileManager.default.fileExists(atPath: fontURL.path) else {
return false
}
return CTFontManagerRegisterFontsForURL(
fontURL as CFURL,
.process,
nil
)
}()

static func font(
forTextStyle textStyle: UIFont.TextStyle,
compatibleWith traitCollection: UITraitCollection? = nil
) -> UIFont {
_ = registeredInter
let scaledPointSize = UIFontMetrics(forTextStyle: textStyle).scaledValue(
for: 20,
compatibleWith: traitCollection
)
let preferredFont = UIFont.preferredFont(
forTextStyle: textStyle,
compatibleWith: traitCollection
)
guard
let interFont = UIFont(
name: interPostScriptName,
size: scaledPointSize
)
else {
return preferredFont
}
return interFont
}
}

enum NativeAttachmentPopoverStyle {
static let cornerRadius: CGFloat = 20
static let shadowOpacity: Float = 0.18
static let shadowRadius: CGFloat = 12
static let shadowOffset = CGSize(width: 0, height: 6)
static let borderWidth: CGFloat = 1
}

func makeNativeAttachmentMenuButton(
title: String,
symbol: String,
action: UIAction
action: @escaping () -> Void
) -> UIButton {
let button = UIButton(primaryAction: action)
let button = UIButton(
primaryAction: UIAction { _ in
UISelectionFeedbackGenerator().selectionChanged()
action()
}
)
button.accessibilityLabel = title

let symbolConfiguration = UIImage.SymbolConfiguration(
Expand All @@ -338,7 +398,7 @@ func makeNativeAttachmentMenuButton(
let titleLabel = UILabel()
titleLabel.text = title
titleLabel.textColor = .label
titleLabel.font = .preferredFont(
titleLabel.font = NativeAttachmentMenuTypography.font(
forTextStyle: NativeAttachmentMenuLayout.labelTextStyle
)
titleLabel.adjustsFontForContentSizeCategory = true
Expand Down
35 changes: 22 additions & 13 deletions mobile/ios/RunnerTests/RunnerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,6 @@ class RunnerTests: XCTestCase {
)
}

func testEmbeddedPhotoPickerAppliesOneZoomInStepWithoutAnimation() {
var zoomInCalls = 0
var animationsWereEnabled = true

EmbeddedPhotoPickerLayout.applyPreferredScale {
zoomInCalls += 1
animationsWereEnabled = UIView.areAnimationsEnabled
}

XCTAssertEqual(zoomInCalls, 1)
XCTAssertFalse(animationsWereEnabled)
}

func testNativeAttachmentMenuUsesRoomyRowsAndInsets() {
let traits = UITraitCollection(preferredContentSizeCategory: .large)
let size = NativeAttachmentMenuLayout.size(compatibleWith: traits)
Expand All @@ -155,6 +142,28 @@ class RunnerTests: XCTestCase {
XCTAssertEqual(NativeAttachmentMenuLayout.labelTextStyle, .title3)
}

func testNativeAttachmentMenuUsesInterAndSharedPopoverChrome() {
let font = NativeAttachmentMenuTypography.font(
forTextStyle: NativeAttachmentMenuLayout.labelTextStyle
)
var didSelect = false
let button = makeNativeAttachmentMenuButton(
title: "Photos",
symbol: "photo",
action: { didSelect = true }
)
let titleLabel = button.subviews.compactMap { $0 as? UILabel }.first

XCTAssertTrue(font.fontName.hasPrefix("Inter"))
XCTAssertTrue(titleLabel?.font.fontName.hasPrefix("Inter") == true)
XCTAssertEqual(NativeAttachmentPopoverStyle.cornerRadius, 20)
XCTAssertEqual(NativeAttachmentPopoverStyle.borderWidth, 1)
XCTAssertEqual(NativeAttachmentPopoverStyle.shadowOpacity, 0.18)

button.sendActions(for: .primaryActionTriggered)
XCTAssertTrue(didSelect)
}

func testNativeAttachmentMenuGrowsAndScrollsForAccessibilityText() {
let traits = UITraitCollection(
preferredContentSizeCategory: .accessibilityExtraExtraExtraLarge
Expand Down
Loading
Loading