diff --git a/Pr0gramm/Pr0gramm/Detail/Comments/CommentsViewController.swift b/Pr0gramm/Pr0gramm/Detail/Comments/CommentsViewController.swift index 9e84738..cd6db27 100644 --- a/Pr0gramm/Pr0gramm/Detail/Comments/CommentsViewController.swift +++ b/Pr0gramm/Pr0gramm/Detail/Comments/CommentsViewController.swift @@ -133,14 +133,31 @@ class CommentsViewController: UIViewController, Storyboarded, UIScrollViewDelega @objc func expand() { - self.topConstraint.constant = 0 + changeHeight(distanceFromTop: 0, draggerColor: #colorLiteral(red: 0.0862745098, green: 0.0862745098, blue: 0.09411764706, alpha: 1)) + } + + func collapse() { + guard let hostingViewController = hostingViewController else { return } + changeHeight(distanceFromTop: hostingViewController.view.frame.height - draggerView.frame.height, draggerColor: .clear) + } + + func toggle() { + if topConstraint.constant == 0 { + collapse() + } else { + expand() + } + } + + private func changeHeight(distanceFromTop: CGFloat, draggerColor: UIColor) { + self.topConstraint.constant = distanceFromTop UIView.animate(withDuration: 0.25, delay: 0.0, options: [.allowUserInteraction, .curveEaseInOut], animations: { self.hostingViewController?.view.layoutIfNeeded() - self.draggerView.backgroundColor = #colorLiteral(red: 0.0862745098, green: 0.0862745098, blue: 0.09411764706, alpha: 1) + self.draggerView.backgroundColor = draggerColor }) reloadDataIfNeeded() diff --git a/Pr0gramm/Pr0gramm/Detail/DetailCollectionViewController.swift b/Pr0gramm/Pr0gramm/Detail/DetailCollectionViewController.swift index 3a3cb74..60de1b5 100644 --- a/Pr0gramm/Pr0gramm/Detail/DetailCollectionViewController.swift +++ b/Pr0gramm/Pr0gramm/Detail/DetailCollectionViewController.swift @@ -57,6 +57,26 @@ class DetailCollectionViewController: UICollectionViewController, Storyboarded { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) } + + override var keyCommands: [UIKeyCommand]? { + return [ + UIKeyCommand(action: #selector(previousItem), input: UIKeyCommand.inputLeftArrow, discoverabilityTitle: "Vorheriger Post"), + UIKeyCommand(action: #selector(nextItem), input: UIKeyCommand.inputRightArrow, discoverabilityTitle: "Nächster Post"), + UIKeyCommand(action: #selector(upvoteCurrentPost), input: UIKeyCommand.inputUpArrow, discoverabilityTitle: "Blussi geben"), + UIKeyCommand(action: #selector(downvoteCurrentPost), input: UIKeyCommand.inputDownArrow, discoverabilityTitle: "Minus geben"), + + UIKeyCommand(action: #selector(previousItem), input: "a", discoverabilityTitle: "Vorheriger Post"), + UIKeyCommand(action: #selector(nextItem), input: "d", discoverabilityTitle: "Nächster Post"), + UIKeyCommand(action: #selector(upvoteCurrentPost), input: "w", discoverabilityTitle: "Blussi geben"), + UIKeyCommand(action: #selector(downvoteCurrentPost), input: "s", discoverabilityTitle: "Minus geben"), + UIKeyCommand(action: #selector(favoriteCurrentPost), input: "f", discoverabilityTitle: "Favorisieren"), + UIKeyCommand(action: #selector(toggleCommentPanel), input: "c", discoverabilityTitle: "Kommentare öffnen"), + + UIKeyCommand(action: #selector(enterFullscreen), input: "f", modifierFlags: [.control, .command], discoverabilityTitle: "Vollbild"), + UIKeyCommand(action: #selector(toggleMute), input: "m", discoverabilityTitle: "Video stummschalten"), + UIKeyCommand(action: #selector(toggleVideoPlayback), input: " ", discoverabilityTitle: "Video starten") + ] + } @objc func nextItem() { @@ -76,6 +96,39 @@ class DetailCollectionViewController: UICollectionViewController, Storyboarded { collectionView.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true) } + @objc func upvoteCurrentPost() { + getCurrentDetailController()?.upvotePost() + } + + @objc func downvoteCurrentPost() { + getCurrentDetailController()?.downvotePost() + } + + @objc func favoriteCurrentPost() { + getCurrentDetailController()?.favoritePost() + } + + @objc func toggleCommentPanel() { + getCurrentDetailController()?.toggleCommentPanel() + } + + @objc func enterFullscreen() { + getCurrentDetailController()?.enterFullscreen() + } + + @objc func toggleMute() { + getCurrentDetailController()?.toggleMute() + } + + @objc func toggleVideoPlayback() { + getCurrentDetailController()?.toggleVideoPlayback() + } + + func getCurrentDetailController() -> DetailViewController? { + guard let cell = collectionView.visibleCells.first as? DetailCollectionViewCell else { return nil } + return cell.detailViewController + } + override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { viewModel.items.count diff --git a/Pr0gramm/Pr0gramm/Detail/DetailViewController.swift b/Pr0gramm/Pr0gramm/Detail/DetailViewController.swift index ddfd697..7a75cdd 100644 --- a/Pr0gramm/Pr0gramm/Detail/DetailViewController.swift +++ b/Pr0gramm/Pr0gramm/Detail/DetailViewController.swift @@ -126,8 +126,8 @@ class DetailViewController: ScrollingContentViewController, Storyboarded { infoView.showReplyAction = { [unowned self] in self.coordinator?.showReplyForPost(viewModel: self.viewModel) } infoView.showCommentsAction = { [unowned self] in self.showComments() } - infoView.upvoteAction = { [weak self] in self?.navigation?.showBanner(with: "Han blussert") } - infoView.downvoteAction = { [weak self] in self?.navigation?.showBanner(with: "Han miesert") } + infoView.upvoteAction = { [weak self] in self?.didFinishUpvote() } + infoView.downvoteAction = { [weak self] in self?.didFinishDownvote() } infoView.showUserAction = { [weak self] name in guard let navigationController = self?.navigationController else { return } self?.coordinator?.showUserProfile(for: name, viewController: navigationController) @@ -142,6 +142,51 @@ class DetailViewController: ScrollingContentViewController, Storyboarded { setupVideo(for: item) } } + + func upvotePost() { + viewModel.vote(.up) + didFinishUpvote() + } + + func downvotePost() { + viewModel.vote(.down) + didFinishDownvote() + } + + func favoritePost() { + viewModel.vote(.favorite) + } + + func toggleCommentPanel() { + commentsViewController?.toggle() + } + + func enterFullscreen() { + showImageDetail() + avPlayerViewController?.goFullScreen() + } + + func toggleMute() { + avPlayerViewController?.player?.isMuted.toggle() + } + + func toggleVideoPlayback() { + guard let player = avPlayerViewController?.player, + player.error == nil else { return } + if player.rate != 0 { + player.pause() + } else { + player.play() + } + } + + private func didFinishUpvote() { + navigation?.showBanner(with: "Han blussert") + } + + private func didFinishDownvote() { + navigation?.showBanner(with: "Han miesert") + } func cleanup() { avPlayer = nil @@ -245,8 +290,7 @@ extension DetailViewController: UIContextMenuInteractionDelegate { } let fullscreenAction = UIAction(title: "Vollbild", image: UIImage(systemName: "rectangle.expand.vertical")) { [unowned self] _ in - self.showImageDetail() - self.avPlayerViewController?.goFullScreen() + self.enterFullscreen() } let saveToCameraRollAction = UIAction(title: "In Fotos speichern", image: UIImage(systemName: "photo")) { [unowned self] _ in diff --git a/Pr0gramm/Pr0gramm/Misc/Theme.swift b/Pr0gramm/Pr0gramm/Misc/Theme.swift index 0d002dd..96b3caa 100755 --- a/Pr0gramm/Pr0gramm/Misc/Theme.swift +++ b/Pr0gramm/Pr0gramm/Misc/Theme.swift @@ -128,6 +128,14 @@ extension Theme { $0.font = font15 } + // Prevent theming of text in the keyboard shortcut discovery overlay (appearing when holding the Command key) + // TODO: The overlay class should be more specific, but I can't find any resource about the name or class of this system overlay. + // TODO: Maybe it is a wise idea to scrap the global styling of UITextViews altogether because of the side-effects. + UITextView.appearance(whenContainedInInstancesOf: [UIVisualEffectView.self]).with { + $0.textColor = nil + $0.font = nil + } + UITextField.appearance().with { $0.font = font15 } @@ -172,6 +180,13 @@ extension Theme { $0.tintColor = tint } + // Prevent theming of text containing icons in the keyboard shortcut discovery overlay (appearing when holding the Command key) + // TODO: The overlay class should be more specific, but I can't find any resource about the name or class of this system overlay. + // TODO: Maybe it is a wise idea to scrap the global styling of UIImageView altogether because of the side-effects. + UIImageView.appearance(whenContainedInInstancesOf: [UIVisualEffectView.self]).with { + $0.tintColor = nil + } + UISegmentedControl.appearance().with { $0.setTitleTextAttributes([.font: font12, .foregroundColor: #colorLiteral(red: 0.9490196078, green: 0.9607843137, blue: 0.9568627451, alpha: 1)], for: .normal)