Skip to content

Commit

Permalink
Improvements to Mac Catalyst build
Browse files Browse the repository at this point in the history
  • Loading branch information
levinli303 committed Aug 27, 2022
1 parent 24bb285 commit 5d4f84a
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 31 deletions.
24 changes: 24 additions & 0 deletions CelestiaMacBridge/CELMacBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,28 @@ + (void)disableTabbingForAllWindows {
[NSWindow setAllowsAutomaticWindowTabbing:NO];
}

+ (void)showTextInputSheetForWindow:(NSWindow *)window title:(NSString *)title message:(nullable NSString *)message text:(nullable NSString *)text placeholder:(nullable NSString *)placeholder okButtonTitle:(NSString *)okButtonTitle cancelButtonTitle:(NSString *)cancelButtonTitle completionHandler:(void (^)(NSString * _Nullable))completionHandler {
const CGFloat alertTextInputWidth = 228;
const CGFloat alertTextInputDefaultHeight = 21;
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = title;
alert.informativeText = message == nil ? @"" : message;
[alert addButtonWithTitle:okButtonTitle];
[alert addButtonWithTitle:cancelButtonTitle];
NSTextField *textField = [NSTextField new];
CGFloat height = [textField fittingSize].height < 1 ? alertTextInputDefaultHeight : [textField fittingSize].height;
[textField setFrame:NSMakeRect(0, 0, alertTextInputWidth, height)];
[textField setStringValue:text == nil ? @"" : text];
[textField setPlaceholderString:placeholder];
alert.accessoryView = textField;
[alert layout];
[alert beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {
if (returnCode == NSAlertFirstButtonReturn) {
completionHandler(textField.stringValue);
} else {
completionHandler(nil);
}
}];
}

@end
17 changes: 17 additions & 0 deletions MobileCelestia/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -275,5 +275,22 @@ class MacBridge {
static func disableTabbingForAllWindows() {
clazz.perform(NSSelectorFromString("disableTabbingForAllWindows"))
}

static func showTextInputSheetForWindow(_ window: NSObject, title: String, message: String? = nil, text: String? = nil, placeholder: String? = nil, okButtonTitle: String, cancelButtonTitle: String, completion: @escaping (String?) -> Void) {
typealias ShowTextInputMethod = @convention(c)
(NSObject.Type, Selector, NSObject, NSString, NSString?, NSString?, NSString?, NSString, NSString, @escaping (NSString?) -> Void) -> Void
let selector = NSSelectorFromString("showTextInputSheetForWindow:title:message:text:placeholder:okButtonTitle:cancelButtonTitle:completionHandler:")
let methodIMP = clazz.method(for: selector)
let method = unsafeBitCast(methodIMP, to: ShowTextInputMethod.self)
method(clazz, selector, window, title as NSString, message as NSString?, text as NSString?, placeholder as NSString?, okButtonTitle as NSString, cancelButtonTitle as NSString, { result in
completion(result as String?)
})
}
}

extension UIWindow {
var nsWindow: NSObject? {
return MacBridge.nsWindowForUIWindow(self)
}
}
#endif
2 changes: 2 additions & 0 deletions MobileCelestia/Celestia/CelestiaControlView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class ControlButton: ImageButtonView<ControlButton.Configuration> {
var pressEnd: ((CelestiaControlAction) -> Void)?
var toggle: ((CelestiaControlAction) -> Void)?

var shouldScaleOnMacCatalyst: Bool { return false }

func provideImage(selected: Bool) -> UIImage? {
switch button {
case .pressAndHold(let image, _):
Expand Down
4 changes: 2 additions & 2 deletions MobileCelestia/Celestia/CelestiaDisplayController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ class CelestiaDisplayController: AsyncGLViewController {
@objc private func windowWillStartLiveResizing(_ notification: Notification) {
guard let window = view.window else { return }

if notification.object as? NSObject == MacBridge.nsWindowForUIWindow(window) {
if notification.object as? NSObject == window.nsWindow {
isPaused = true
}
}

@objc private func windowDidEndLiveResizing(_ notification: Notification) {
guard let window = view.window else { return }

if notification.object as? NSObject == MacBridge.nsWindowForUIWindow(window) {
if notification.object as? NSObject == window.nsWindow {
isPaused = false
}
}
Expand Down
4 changes: 3 additions & 1 deletion MobileCelestia/Common/ButtonView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import UIKit

protocol ImageProvider {
func provideImage(selected: Bool) -> UIImage?
var shouldScaleOnMacCatalyst: Bool { get }
}

struct ImageButtonViewConfiguration<T: ImageProvider>: AutoSizingViewConfiguration {
func baseSizeForView(_ view: UIView) -> CGSize {
guard let size = configuration.provideImage(selected: (view as? UIButton)?.isSelected == true)?.size, size.width > 0, size.height > 0 else {
return boundingBoxSize
}
let ratio = min(boundingBoxSize.width / size.width, boundingBoxSize.height / size.height)
let scaling = configuration.shouldScaleOnMacCatalyst ? GlobalConstants.preferredUIElementScaling(for: view.traitCollection) : 1
let ratio = min(boundingBoxSize.width / size.width, boundingBoxSize.height / size.height) * scaling
return CGSize(width: ratio * size.width, height: ratio * size.height)
}
var boundingBoxSize: CGSize
Expand Down
4 changes: 2 additions & 2 deletions MobileCelestia/GoTo/GoToInputViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ extension GoToInputViewController {
self.reload()
}
} else if let valueItem = item as? DoubleValueItem {
showTextInput("", text: item.detail) { [weak self] string in
showTextInput(item.title, text: item.detail) { [weak self] string in
guard let self = self else { return }
guard let newString = string, let value = Double(newString) else { return }
switch valueItem.type {
Expand All @@ -198,7 +198,7 @@ extension GoToInputViewController {
self.reload()
}
} else if let valueItem = item as? FloatValueItem {
showTextInput("", text: item.detail) { [weak self] string in
showTextInput(item.title, text: item.detail) { [weak self] string in
guard let self = self else { return }
guard let newString = string, let value = Float(newString) else { return }
switch valueItem.type {
Expand Down
6 changes: 0 additions & 6 deletions MobileCelestia/PanelSceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,4 @@ class PanelSceneDelegate: CommonSceneDelegate {
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil) { _ in }
}
}

fileprivate extension UIWindow {
var nsWindow: NSObject? {
return MacBridge.nsWindowForUIWindow(self)
}
}
#endif
6 changes: 4 additions & 2 deletions MobileCelestia/Toolbar/BottomControlViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class BottomControlViewController: UIViewController {

override var preferredContentSize: CGSize {
get {
let scaling = view.textScaling
let scaling = view.textScaling * GlobalConstants.preferredUIElementScaling(for: view.traitCollection)
return CGSize(
width: GlobalConstants.bottomControlViewDimension * CGFloat(actions.count) * scaling + GlobalConstants.bottomControlViewMarginHorizontal * 2 + GlobalConstants.pageMediumMarginHorizontal,
height: (GlobalConstants.bottomControlViewDimension * scaling + GlobalConstants.bottomControlViewMarginVertical * 2 + GlobalConstants.pageMediumMarginVertical).rounded(.up)
Expand Down Expand Up @@ -230,7 +230,9 @@ class BottomActionLayout: UICollectionViewFlowLayout {
private let baseItemSize = CGSize(width: GlobalConstants.bottomControlViewDimension, height: GlobalConstants.bottomControlViewDimension)

override func prepare() {
let scaling = collectionView?.textScaling ?? 1
defer { super.prepare() }
guard let collectionView = self.collectionView else { return }
let scaling = GlobalConstants.preferredUIElementScaling(for: collectionView.traitCollection) * collectionView.textScaling
itemSize = baseItemSize.applying(CGAffineTransform(scaleX: scaling, y: scaling))
minimumLineSpacing = 0
minimumInteritemSpacing = 0
Expand Down
4 changes: 4 additions & 0 deletions MobileCelestia/Toolbar/ToolbarButtonCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ class ToolbarImageButton: ImageButtonView<ToolbarImageButton.Configuration> {
var touchDownHandler: ((UIButton) -> Void)?
var touchUpHandler: ((UIButton, Bool) -> Void)?

var shouldScaleOnMacCatalyst: Bool {
return true
}

func provideImage(selected: Bool) -> UIImage? {
return image
}
Expand Down
41 changes: 23 additions & 18 deletions MobileCelestia/Utils/UIViewController+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,18 @@ extension UIViewController {
return alert
}

@discardableResult func showTextInput(_ title: String, message: String? = nil, text: String? = nil, placeholder: String? = nil, source: PopoverSource? = nil, completion: ((String?) -> Void)? = nil) -> UIAlertController {
func showTextInput(_ title: String, message: String? = nil, text: String? = nil, placeholder: String? = nil, source: PopoverSource? = nil, completion: ((String?) -> Void)? = nil) {
#if targetEnvironment(macCatalyst)
if let window = view.window?.nsWindow {
MacBridge.showTextInputSheetForWindow(window, title: title, message: message, text: text, placeholder: placeholder, okButtonTitle: CelestiaString("OK", comment: ""), cancelButtonTitle: CelestiaString("Cancel", comment: "")) { result in
completion?(result)
}
return
}
#endif
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let confirmAction = UIAlertAction(title: CelestiaString("OK", comment: ""), style: .default, handler: { [unowned alert] (_) in
completion?(alert.textFields?.first?.text)
completion?(alert.textFields?.first?.text ?? "")
})
alert.addTextField { (textField) in
textField.text = text
Expand All @@ -83,26 +91,18 @@ extension UIViewController {
}))
alert.preferredAction = confirmAction
presentAlert(alert, source: source)
return alert
}

@discardableResult func showDateInput(_ title: String, format: String, source: PopoverSource? = nil, completion: ((Date?) -> Void)? = nil) -> UIAlertController {
let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
func showDateInput(_ title: String, format: String, source: PopoverSource? = nil, completion: ((Date?) -> Void)? = nil) {
let formatter = DateFormatter()
formatter.dateFormat = format
let confirmAction = UIAlertAction(title: CelestiaString("OK", comment: ""), style: .default, handler: { [unowned alert] _ in
guard let text = alert.textFields?.first?.text else { return }
completion?(formatter.date(from: text))
})
alert.addTextField { textField in
textField.keyboardAppearance = .dark
textField.placeholder = formatter.string(from: Date())
showTextInput(title, message: nil, text: nil, placeholder: formatter.string(from: Date()), source: source) { result in
guard let result = result else {
// cancelled, do not call completion
return
}
completion?(formatter.date(from: result))
}
alert.addAction(confirmAction)
alert.addAction(UIAlertAction(title: CelestiaString("Cancel", comment: ""), style: .cancel, handler: nil))
alert.preferredAction = confirmAction
presentAlert(alert, source: source)
return alert
}

@discardableResult func showLoading(_ title: String, source: PopoverSource? = nil, cancelHandelr: (() -> Void)? = nil) -> UIAlertController {
Expand All @@ -117,7 +117,12 @@ extension UIViewController {
}

private func commonSelectionActionSheet(_ title: String?, options: [String], permittedArrowDirections: UIPopoverArrowDirection = .any, completion: ((Int?) -> Void)?) -> UIAlertController {
let alert = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet)
#if targetEnvironment(macCatalyst)
let alertStyle = UIAlertController.Style.alert
#else
let alertStyle = UIAlertController.Style.actionSheet
#endif
let alert = UIAlertController(title: title, message: nil, preferredStyle: alertStyle)
for (index, option) in options.enumerated() {
alert.addAction(UIAlertAction(title: option, style: .default) { _ in
completion?(index)
Expand Down

0 comments on commit 5d4f84a

Please sign in to comment.