Skip to content

Commit

Permalink
Merge pull request #4446 from wikimedia/talk-page-archives-2
Browse files Browse the repository at this point in the history
Talk Page Archives - Part 2
  • Loading branch information
mazevedofs authored Jan 23, 2023
2 parents ddeae94 + e3e43ec commit 7629089
Showing 28 changed files with 679 additions and 131 deletions.
23 changes: 23 additions & 0 deletions WMF Framework/Fetcher.swift
Original file line number Diff line number Diff line change
@@ -196,6 +196,29 @@ open class Fetcher: NSObject {
}
}

// MARK: Modern Swift Concurrency APIs

extension Fetcher {

public func performDecodableMediaWikiAPIGet<T: Decodable>(for URL: URL, with queryParameters: [String: Any]?) async throws -> T {
guard let url = configuration.mediaWikiAPIURLForURL(URL, with: queryParameters) else {
throw RequestError.invalidParameters
}

let (data, response) = try await session.data(for: url)

guard let httpResponse = (response as? HTTPURLResponse) else {
throw RequestError.unexpectedResponse
}

guard HTTPStatusCode.isSuccessful(httpResponse.statusCode) else {
throw RequestError.http(httpResponse.statusCode)
}

return try JSONDecoder().decode(T.self, from: data)
}
}

// These are for bridging to Obj-C only
@objc public extension Fetcher {
@objc class var unexpectedResponseError: NSError {
68 changes: 58 additions & 10 deletions Wikipedia.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions Wikipedia/Code/BackgroundHighlightingButtonStyle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation
import SwiftUI

struct BackgroundHighlightingButtonStyle: ButtonStyle {

@EnvironmentObject var observableTheme: ObservableTheme

func makeBody(configuration: SwiftUI.ButtonStyle.Configuration) -> some View {
configuration.label
.background(configuration.isPressed ? Color(observableTheme.theme.colors.midBackground) : Color(observableTheme.theme.colors.paperBackground))
}
}
80 changes: 0 additions & 80 deletions Wikipedia/Code/DemoShiftingThreeLineHeaderView.swift

This file was deleted.

31 changes: 31 additions & 0 deletions Wikipedia/Code/DisclosureButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Foundation
import SwiftUI

struct DisclosureButton<Element: CustomStringConvertible>: View {

let item: Element
let action: (Element) -> Void

@EnvironmentObject var observableTheme: ObservableTheme

var body: some View {
Button(action: { action(item) }) {
VStack(spacing: 0) {
HStack {
Text(item.description)
.foregroundColor(Color(observableTheme.theme.colors.primaryText))
.font(.callout)
.fontWeight(.semibold)
Spacer(minLength: 12)
Image(systemName: "chevron.right").font(Font.system(.footnote).weight(.semibold))
.foregroundColor(Color(observableTheme.theme.colors.secondaryText))
}
.padding(EdgeInsets(top: 12, leading: 16, bottom: 12, trailing: 16))
Divider()
.frame(height: 1)
.background(Color(observableTheme.theme.colors.midBackground))
}
}
.buttonStyle(BackgroundHighlightingButtonStyle())
}
}
6 changes: 6 additions & 0 deletions Wikipedia/Code/Loadable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Foundation

protocol Loadable {
func startLoading()
func stopLoading()
}
2 changes: 1 addition & 1 deletion Wikipedia/Code/RandomArticleViewController.swift
Original file line number Diff line number Diff line change
@@ -93,7 +93,7 @@ class RandomArticleViewController: ArticleViewController {
let articleURL = articleURL,
let randomVC = RandomArticleViewController(articleURL: articleURL, dataStore: self.dataStore, theme: self.theme)
else {
self.alertManager.showErrorAlert(error ?? RequestError.unexpectedResponse, sticky: true, dismissPreviousAlerts: true)
WMFAlertManager.sharedInstance.showErrorAlert(error ?? RequestError.unexpectedResponse, sticky: true, dismissPreviousAlerts: true)
return
}
self.secondToolbar.items = []
10 changes: 10 additions & 0 deletions Wikipedia/Code/Session.swift
Original file line number Diff line number Diff line change
@@ -583,6 +583,16 @@ public class Session: NSObject {
}
}

// MARK: Modern Swift Concurrency APIs

extension Session {

public func data(for url: URL) async throws -> (Data, URLResponse) {
let request = request(with: url)
return try await defaultURLSession.data(for: request)
}
}

// MARK: PermanentlyPersistableURLCache Passthroughs

enum SessionPermanentCacheError: Error {
156 changes: 150 additions & 6 deletions Wikipedia/Code/ShiftingNavigationBarView.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import UIKit

class ShiftingNavigationBarView: ShiftingTopView, Themeable {
class ShiftingNavigationBarView: ShiftingTopView, Themeable, Loadable {

private let navigationItems: [UINavigationItem]
private let hidesOnScroll: Bool
private weak var popDelegate: UIViewController? // Navigation back actions will be forwarded to this view controller

private var topConstraint: NSLayoutConstraint?
@@ -13,9 +14,31 @@ class ShiftingNavigationBarView: ShiftingTopView, Themeable {
bar.delegate = self
return bar
}()

// MARK: Loading bar properties

private lazy var fakeProgressController: FakeProgressController = {
let progressController = FakeProgressController(progress: self, delegate: self)
progressController.delay = 0.0
return progressController
}()

init(shiftOrder: Int, navigationItems: [UINavigationItem], popDelegate: UIViewController) {
private lazy var progressView: UIProgressView = {
let progressView = UIProgressView()
progressView.translatesAutoresizingMaskIntoConstraints = false
progressView.progressViewStyle = .bar
return progressView
}()

// MARK: Tracking properties for reappearance upon flick up

private var lastAmount: CGFloat = 0
private var amountWhenDirectionChanged: CGFloat = 0
private var scrollingUp = false

init(shiftOrder: Int, navigationItems: [UINavigationItem], hidesOnScroll: Bool, popDelegate: UIViewController) {
self.navigationItems = navigationItems
self.hidesOnScroll = hidesOnScroll
self.popDelegate = popDelegate
super.init(shiftOrder: shiftOrder)
}
@@ -34,12 +57,17 @@ class ShiftingNavigationBarView: ShiftingTopView, Themeable {
let bottom = bottomAnchor.constraint(equalTo: bar.bottomAnchor)
let leading = bar.leadingAnchor.constraint(equalTo: leadingAnchor)
let trailing = trailingAnchor.constraint(equalTo: bar.trailingAnchor)


addSubview(progressView)

NSLayoutConstraint.activate([
top,
bottom,
leading,
trailing
trailing,
progressView.leadingAnchor.constraint(equalTo: bar.leadingAnchor),
progressView.trailingAnchor.constraint(equalTo: bar.trailingAnchor),
progressView.bottomAnchor.constraint(equalTo: bar.bottomAnchor)
])

self.topConstraint = top
@@ -56,11 +84,85 @@ class ShiftingNavigationBarView: ShiftingTopView, Themeable {
private var isFullyHidden: Bool {
return -(topConstraint?.constant ?? 0) == contentHeight
}

private var isFullyShowing: Bool {
return -(topConstraint?.constant ?? 0) == 0
}

override func shift(amount: CGFloat) -> ShiftingTopView.AmountShifted {

defer {
lastAmount = amount
}

// Early exit if navigation bar shouldn't move.
guard hidesOnScroll else {
return 0
}

// Calculate amountWhenDirectionChanged, so that new hiding offsets can begin from wherever user flicked up
let oldScrollingUp = scrollingUp
scrollingUp = lastAmount > amount

if oldScrollingUp != scrollingUp {

// Clear out if it's near the top...otherwise it throws off top bouncing calculations
if amount <= contentHeight {
amountWhenDirectionChanged = 0
} else {

if isFullyShowing || isFullyHidden { // If it is in the middle of collapsing, resetting this property thows things off. Only set change direction amount if it's already fully collapsed or expanded
amountWhenDirectionChanged = lastAmount
}
}
}

// Adjust constant for sensitivity
let flickingUp = (lastAmount - amount) > 8

// If flicking up and fully collapsed, animate nav bar back in
if flickingUp && isFullyHidden {
topConstraint?.constant = 0

setNeedsLayout()
UIView.animate(withDuration: 0.2) {
self.alpha = 1.0
let resetTransform = CGAffineTransform.identity
for subview in self.bar.subviews {
for subview in subview.subviews {
subview.transform = resetTransform
}
}
self.layoutIfNeeded()
}
return contentHeight
}

// Various cases where it helps to bail early

// Do not re-appear if slowly scrolling up when further down the scroll view. But when slowly going up near the top (amount <= contentHeight), allow it to go through and adjust height constraint.
if scrollingUp && isFullyHidden && amount > contentHeight {
return contentHeight
}

// If scrolling up and already showing, don't do anything.
if scrollingUp && isFullyShowing {
return contentHeight
}

// If scrolling down and fully collapsed, don't do anything
if !scrollingUp && isFullyHidden {
return contentHeight
}

var adjustedAmount = amount
// Adjust shift amount to be against wherever direction last changed, if needed. This is so that bar can slowly disappear again when scrolling down further in the view after flicking to show it
if amount > contentHeight {
adjustedAmount = amount - amountWhenDirectionChanged
}

// Only allow navigation bar to move just out of frame
let limitedShiftAmount = max(0, min(amount, contentHeight))
let limitedShiftAmount = max(0, min(adjustedAmount, contentHeight))

// Shrink and fade
let percent = limitedShiftAmount / contentHeight
@@ -89,10 +191,24 @@ class ShiftingNavigationBarView: ShiftingTopView, Themeable {
bar.barTintColor = theme.colors.chromeBackground
bar.shadowImage = theme.navigationBarShadowImage
bar.tintColor = theme.colors.chromeText

progressView.progressViewStyle = .bar
progressView.trackTintColor = .clear
progressView.progressTintColor = theme.colors.link
}

// MARK: Loadable

func startLoading() {
fakeProgressController.start()
}

func stopLoading() {
fakeProgressController.stop()
}
}

// MARK: Themeable
// MARK: UINavigationBarDelegate

extension ShiftingNavigationBarView: UINavigationBarDelegate {
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
@@ -115,3 +231,31 @@ extension ShiftingNavigationBarView: UINavigationBarDelegate {
}
}
}

// MARK: FakeProgressReceiving, FakeProgressDelegate

extension ShiftingNavigationBarView: FakeProgressReceiving, FakeProgressDelegate {
func setProgressHidden(_ hidden: Bool, animated: Bool) {
let changes = {
self.progressView.alpha = hidden ? 0 : 1
}
if animated {
UIView.animate(withDuration: 0.2, animations: changes)
} else {
changes()
}
}

func setProgress(_ progress: Float, animated: Bool) {
progressView.setProgress(progress, animated: animated)
}

var progress: Float {
get {
return progressView.progress
}
set {
progressView.progress = newValue
}
}
}
Loading

0 comments on commit 7629089

Please sign in to comment.