Skip to content

Commit

Permalink
Merge pull request #17799 from wordpress-mobile/issue/17780-use-uidat…
Browse files Browse the repository at this point in the history
…epicker-to-schedule-post

17780 Use UIDatePicker to schedule posts
  • Loading branch information
joshheald authored Jan 21, 2022
2 parents 9762750 + ada32ca commit bbab6db
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 93 deletions.
2 changes: 1 addition & 1 deletion RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* [*] Signup: Fixed bug where username selection screen could be pushed twice. [#17624]
* [**] Threaded comments: comments can now be moderated via a drop-down menu on each comment. [#17758]
* [**] Reader post details Comments snippet: added ability to manage conversation subscription and notifications. [#17749]
* [**] Accessibility: VoiceOver improvements on Activity Log and Schedule Post calendars [#17756, #17761]
* [**] Accessibility: VoiceOver and Dynamic Type improvements on Activity Log and Schedule Post calendars [#17756, #17761, #17780]
* [*] Weekly Roundup: Fix a crash which was preventing weekly roundup notifications from appearing [#17765]
* [*] Self-hosted login: Improved error messages. [#17724]
* [*] Share Sheet from Photos: Fix an issue where certain filenames would not upload or render in Post [#16773]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,11 @@ class PrepublishingViewController: UITableViewController {

func didTapSchedule(_ indexPath: IndexPath) {
transitionIfVoiceOverDisabled(to: .hidden)
SchedulingCalendarViewController.present(
from: self,
let viewController = PresentableSchedulingViewControllerProvider.viewController(
sourceView: tableView.cellForRow(at: indexPath)?.contentView,
sourceRect: nil,
viewModel: publishSettingsViewModel,
transitioningDelegate: nil,
updated: { [weak self] date in
WPAnalytics.track(.editorPostScheduledChanged, properties: Constants.analyticsDefaultProperty)
self?.publishSettingsViewModel.setDate(date)
Expand All @@ -345,6 +346,7 @@ class PrepublishingViewController: UITableViewController {
self?.transitionIfVoiceOverDisabled(to: .collapsed)
}
)
present(viewController, animated: true)
}

// MARK: - Publish Button
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import Foundation

class HalfScreenPresentationController: FancyAlertPresentationController {
class PartScreenPresentationController: FancyAlertPresentationController {

var minimumHeight: CGFloat {
return presentedViewController.preferredContentSize.height
}

private weak var tapGestureRecognizer: UITapGestureRecognizer?

override var frameOfPresentedViewInContainerView: CGRect {

/// If we are in compact mode, don't override the default
guard traitCollection.verticalSizeClass != .compact else {
return super.frameOfPresentedViewInContainerView
}
guard let containerView = containerView else {
return .zero
}
let height = max(containerView.bounds.height/2, minimumHeight)
let width = containerView.bounds.width

let height = containerView?.bounds.height ?? 0
let width = containerView?.bounds.width ?? 0

return CGRect(x: 0, y: height/2, width: width, height: height/2)
return CGRect(x: 0, y: containerView.bounds.height - height, width: width, height: height)
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
Expand All @@ -24,6 +29,11 @@ class HalfScreenPresentationController: FancyAlertPresentationController {
super.viewWillTransition(to: size, with: coordinator)
}

override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
super.preferredContentSizeDidChange(forChildContentContainer: container)
presentedViewController.view.frame = frameOfPresentedViewInContainerView
}

override func containerViewDidLayoutSubviews() {
super.containerViewDidLayoutSubviews()

Expand All @@ -50,7 +60,7 @@ class HalfScreenPresentationController: FancyAlertPresentationController {
}
}

extension HalfScreenPresentationController: UIGestureRecognizerDelegate {
extension PartScreenPresentationController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {

/// Shouldn't happen; should always have container & presented view when tapped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,49 +201,33 @@ private struct DateAndTimeRow: ImmuTableRow {
}

func dateTimeCalendarViewController(with model: PublishSettingsViewModel) -> (ImmuTableRow) -> UIViewController {
return { [weak self] row in

let schedulingCalendarViewController = SchedulingCalendarViewController()
schedulingCalendarViewController.coordinator = DateCoordinator(
date: model.date,
timeZone: model.timeZone,
dateFormatter: model.dateFormatter,
dateTimeFormatter: model.dateTimeFormatter,
updated: { [weak self] date in
WPAnalytics.track(.editorPostScheduledChanged, properties: ["via": "settings"])
self?.viewModel.setDate(date)
NotificationCenter.default.post(name: Foundation.Notification.Name(rawValue: ImmuTableViewController.modelChangedNotification), object: nil)
}
)

return self?.calendarNavigationController(rootViewController: schedulingCalendarViewController) ?? UINavigationController()
return { [weak self] _ in
return PresentableSchedulingViewControllerProvider.viewController(sourceView: self?.viewController?.tableView,
sourceRect: self?.rectForSelectedRow() ?? .zero,
viewModel: model,
transitioningDelegate: self,
updated: { [weak self] date in
WPAnalytics.track(.editorPostScheduledChanged, properties: ["via": "settings"])
self?.viewModel.setDate(date)
NotificationCenter.default.post(name: Foundation.Notification.Name(rawValue: ImmuTableViewController.modelChangedNotification), object: nil)
},
onDismiss: nil)
}
}

private func calendarNavigationController(rootViewController: UIViewController) -> UINavigationController {
let navigationController = LightNavigationController(rootViewController: rootViewController)

if viewController?.traitCollection.userInterfaceIdiom == .pad {
navigationController.modalPresentationStyle = .popover
} else {
navigationController.modalPresentationStyle = .custom
navigationController.transitioningDelegate = self
}

if let popoverController = navigationController.popoverPresentationController,
let selectedIndexPath = viewController?.tableView.indexPathForSelectedRow {
popoverController.sourceView = viewController?.tableView
popoverController.sourceRect = viewController?.tableView.rectForRow(at: selectedIndexPath) ?? .zero
private func rectForSelectedRow() -> CGRect? {
guard let viewController = viewController,
let selectedIndexPath = viewController.tableView.indexPathForSelectedRow else {
return nil
}

return navigationController
return viewController.tableView.rectForRow(at: selectedIndexPath)
}
}

// The calendar sheet is shown towards the bottom half of the screen so a custom transitioning delegate is needed.
extension PublishSettingsController: UIViewControllerTransitioningDelegate, UIAdaptivePresentationControllerDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let presentationController = HalfScreenPresentationController(presentedViewController: presented, presenting: presenting)
let presentationController = PartScreenPresentationController(presentedViewController: presented, presenting: presenting)
presentationController.delegate = self
return presentationController
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

extension SchedulingCalendarViewController {
extension SchedulingCalendarViewController: SchedulingViewControllerPresenting {
static func present(from viewController: UIViewController, sourceView: UIView?, viewModel: PublishSettingsViewModel, updated: @escaping (Date?) -> Void, onDismiss: @escaping () -> Void) {
let schedulingCalendarViewController = SchedulingCalendarViewController()
schedulingCalendarViewController.coordinator = DateCoordinator(date: viewModel.date, timeZone: viewModel.timeZone, dateFormatter: viewModel.dateFormatter, dateTimeFormatter: viewModel.dateTimeFormatter, updated: updated)
Expand Down Expand Up @@ -35,12 +35,3 @@ extension SchedulingCalendarViewController: UIViewControllerTransitioningDelegat
return traitCollection.verticalSizeClass == .compact ? .overFullScreen : .none
}
}

class SchedulingLightNavigationController: LightNavigationController {
var onDismiss: (() -> Void)?

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
onDismiss?()
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
import Foundation
import Gridicons

protocol DateCoordinatorHandler: AnyObject {
var coordinator: DateCoordinator? { get set }
}

class DateCoordinator {

var date: Date?
let timeZone: TimeZone
let dateFormatter: DateFormatter
let dateTimeFormatter: DateFormatter
let updated: (Date?) -> Void

init(date: Date?, timeZone: TimeZone, dateFormatter: DateFormatter, dateTimeFormatter: DateFormatter, updated: @escaping (Date?) -> Void) {
self.date = date
self.timeZone = timeZone
self.dateFormatter = dateFormatter
self.dateTimeFormatter = dateTimeFormatter
self.updated = updated
}
}

// MARK: - Date Picker

class SchedulingCalendarViewController: UIViewController, DatePickerSheet, DateCoordinatorHandler {
@available(iOS, deprecated: 14.0, message: "Use SchedulingDatePickerViewController, based on UIDatePicker.inline")
class SchedulingCalendarViewController: UIViewController, CalendarSheet, DateCoordinatorHandler, SchedulingViewControllerProtocol {

var coordinator: DateCoordinator? = nil

Expand Down Expand Up @@ -137,6 +116,18 @@ class SchedulingCalendarViewController: UIViewController, DatePickerSheet, DateC
}
}

extension SchedulingCalendarViewController {
@objc func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let presentationController = PartScreenPresentationController(presentedViewController: presented, presenting: presenting)
presentationController.delegate = self
return presentationController
}

@objc func adaptivePresentationStyle(for: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return traitCollection.verticalSizeClass == .compact ? .overFullScreen : .none
}
}

// MARK: Accessibility

private extension SchedulingCalendarViewController {
Expand Down Expand Up @@ -204,12 +195,11 @@ class TimePickerViewController: UIViewController, DatePickerSheet, DateCoordinat
}

// MARK: DatePickerSheet Protocol
protocol DatePickerSheet {
protocol CalendarSheet {
func configureStackView(topView: UIView, pickerView: UIView) -> UIView
}

extension DatePickerSheet {

extension CalendarSheet {
/// Constructs a view with `topView` on top and `pickerView` on bottom
/// - Parameter topView: A view to be shown above `pickerView`
/// - Parameter pickerView: A view to be shown on the bottom
Expand Down Expand Up @@ -248,8 +238,7 @@ extension DatePickerSheet {
}
}

extension DatePickerSheet where Self: UIViewController {

extension CalendarSheet where Self: UIViewController {
/// Adds `topView` and `pickerView` to view hierarchy + standard styling for the view controller's view
/// - Parameter topView: A view to show above `pickerView` (see `ChosenValueRow`)
/// - Parameter pickerView: A view to show below the top view
Expand Down
Loading

0 comments on commit bbab6db

Please sign in to comment.