Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spankykong theme release #1146

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
7 changes: 4 additions & 3 deletions App/Composition/ComposeTextViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,13 @@ class ComposeTextViewController: ViewController {
fileprivate var imageUploadProgress: Progress?

fileprivate func submit() {
let overlay = MRProgressOverlayView.showOverlayAdded(to: viewToOverlay, title: submissionInProgressTitle, mode: .indeterminate, animated: true)
overlay?.tintColor = theme["tintColor"]
let loadingView = PostedTootLoadingView()
loadingView.backgroundColor = theme["backgroundColor"]

view.addSubview(loadingView)

imageUploadProgress = uploadImages(attachedTo: textView.attributedText, completion: { [weak self] (plainText, error) in
if let error = error {
overlay?.dismiss(false)

self?.enableEverything()

Expand Down
8 changes: 4 additions & 4 deletions App/Data Sources/ForumListDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,9 @@ extension ForumListDataSource: UITableViewDataSource {
return ForumListCell.ViewModel(
backgroundColor: theme["listBackgroundColor"]!,
expansion: .none,
expansionTintColor: theme["tintColor"]!,
expansionTintColor: theme["expansionTintColor"]!,
favoriteStar: .isFavorite,
favoriteStarTintColor: theme["tintColor"]!,
favoriteStarTintColor: theme["favoriteStarTintColor"]!,
forumName: NSAttributedString(string: forum.name ?? "", attributes: [
.font: UIFont.preferredFont(forTextStyle: .body),
.foregroundColor: theme[color: "listTextColor"]!]),
Expand All @@ -455,9 +455,9 @@ extension ForumListDataSource: UITableViewDataSource {
return .canExpand
}
}(),
expansionTintColor: theme["tintColor"]!,
expansionTintColor: theme["expansionTintColor"]!,
favoriteStar: forum.metadata.favorite ? .hidden : .canFavorite,
favoriteStarTintColor: theme["tintColor"]!,
favoriteStarTintColor: theme["favoriteStarTintColor"]!,
forumName: NSAttributedString(string: forum.name ?? "", attributes: [
.font: UIFont.preferredFont(forTextStyle: .body),
.foregroundColor: theme[color: "listTextColor"]!]),
Expand Down
61 changes: 52 additions & 9 deletions App/Data Sources/MessageListDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import AwfulCore
import CoreData
import UIKit
import HTMLReader

private let Log = Logger.get()

Expand Down Expand Up @@ -96,27 +97,69 @@ extension MessageListDataSource: UITableViewDataSource {
private func viewModelForMessage(at indexPath: IndexPath) -> MessageListCell.ViewModel {
let message = self.message(at: indexPath)
let theme = Theme.defaultTheme()

// Create Date Formatter
let dateFormatter = DateFormatter()
// Set Date/Time Style
dateFormatter.dateFormat = "d MMM"

var sentDateRawFont: UIFont
var senderFont: UIFont
var subjectFont: UIFont

if Theme.defaultTheme().roundedFonts {
sentDateRawFont = roundedFont(ofSize: 12, weight: .semibold)
senderFont = roundedFont(ofSize: 13, weight: .semibold)
subjectFont = roundedFont(ofSize: 17, weight: .regular)
} else {
sentDateRawFont = UIFont.systemFont(ofSize: 12)
senderFont = UIFont.systemFont(ofSize: 15, weight: .regular)
subjectFont = UIFont.systemFont(ofSize: 15, weight: .regular)
}

return MessageListCell.ViewModel(
backgroundColor: theme["listBackgroundColor"]!,
selectedBackgroundColor: theme["listSelectedBackgroundColor"]!,
sender: NSAttributedString(string: message.fromUsername ?? "", attributes: [
.font: UIFont.boldSystemFont(ofSize: UIFontDescriptor.preferredFontDescriptor(withTextStyle: UIFont.TextStyle.subheadline).pointSize),
.foregroundColor: theme[color: "listTextColor"]!]),
.font: senderFont,
.foregroundColor: theme[color: "listSecondaryTextColor"]!]),
sentDate: message.sentDate ?? .distantPast,
sentDateAttributes: [
.font: UIFont.preferredFontForTextStyle(.body, fontName: nil, sizeAdjustment: -2),
.foregroundColor: theme[color: "listTextColor"]!],
sentDateAttributes: [:
// .font: UIFont.preferredFontForTextStyle(.body, fontName: nil, sizeAdjustment: -2),
// .foregroundColor: theme[color: "listTextColor"]!
],
sentDateRaw: NSAttributedString(string: dateFormatter.string(from: message.sentDate!), attributes: [
.font: sentDateRawFont,
.foregroundColor: theme[color: "listSecondaryTextColor"]!]),
subject: NSAttributedString(string: message.subject ?? "", attributes: [
.font: UIFont.preferredFontForTextStyle(.body, fontName: nil, sizeAdjustment: -2),
.font: subjectFont,
.foregroundColor: theme[color: "listTextColor"]!]),
tagImage: .image(name: message.threadTag?.imageName, placeholder: .privateMessage),

tagOverlayImage: {
if message.replied {
return UIImage(named: "pmreplied")
let image = UIImage(named: "pmreplied")?
.stroked(with: theme["listBackgroundColor"]!, thickness: 3, quality: 1)
.withRenderingMode(.alwaysTemplate)

let imageView = UIImageView(image: image)
imageView.tintColor = theme["listBackgroundColor"]!

return imageView
} else if message.forwarded {
return UIImage(named: "pmforwarded")
let image = UIImage(named: "pmforwarded")?
.stroked(with: theme["listBackgroundColor"]!, thickness: 3, quality: 1)
.withRenderingMode(.alwaysTemplate)

let imageView = UIImageView(image: image)
imageView.tintColor = theme["listBackgroundColor"]!

return imageView
} else if !message.seen {
return UIImage(named: "newpm")
let image = UIImage(named: "newpm")
let imageView = UIImageView(image: image)

return imageView
} else {
return nil
}
Expand Down
66 changes: 55 additions & 11 deletions App/Data Sources/ThreadListDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,19 @@ extension ThreadListDataSource: UITableViewDataSource {

return ThreadListCell.ViewModel(
backgroundColor: theme["listBackgroundColor"]!,
pageCount: NSAttributedString(string: "\(thread.numberOfPages)", attributes: [
.font: UIFont.preferredFontForTextStyle(.footnote, fontName: theme["listFontName"]),
.foregroundColor: theme[color: "listSecondaryTextColor"]!]),
pageCount: {
var pagecountFont: UIFont
if Theme.defaultTheme().roundedFonts {
pagecountFont = roundedFont(ofSize: 13, weight: .semibold)
} else {
pagecountFont = UIFont.systemFont(ofSize: 13, weight: .medium)
}

return NSAttributedString(string: "\(thread.numberOfPages)", attributes: [
/* thread list view grey page count text */
.font: pagecountFont,
.foregroundColor: theme[color: "listSecondaryTextColor"]!])
}(),
pageIconColor: theme["threadListPageIconColor"]!,
postInfo: {
let text: String
Expand All @@ -159,9 +169,18 @@ extension ThreadListDataSource: UITableViewDataSource {
}
else {
text = String(format: LocalizedString("thread-list.posted-by"), thread.author?.username ?? "")
}/* killed by text */

var killedByFont: UIFont

if Theme.defaultTheme().roundedFonts {
killedByFont = roundedFont(ofSize: 13, weight: .semibold)
} else {
killedByFont = UIFont.systemFont(ofSize: 13, weight: .medium)
}

return NSAttributedString(string: text, attributes: [
.font: UIFont.preferredFontForTextStyle(.footnote, fontName: theme["listFontName"]),
.font: killedByFont,
.foregroundColor: theme[color: "listSecondaryTextColor"]!])
}(),
ratingImage: {
Expand All @@ -172,8 +191,16 @@ extension ThreadListDataSource: UITableViewDataSource {
if let tweaks = tweaks, tweaks.showRatingsAsThreadTags {
return nil
}

return thread.ratingImageName.flatMap { UIImage(named: $0) }

return thread.ratingImageName.flatMap {
if $0 != "Vote0.0" {
return UIImage(named: "Vote0")!
.withTintColor(Theme.defaultTheme()["ratingIconEmptyColor"]!)
.mergeWith(topImage: UIImage(named: $0)!)
}
return UIImage(named: "Vote0")!
.withTintColor(Theme.defaultTheme()["ratingIconEmptyColor"]!)
}
}(),
secondaryTagImageName: {
if !showsTagAndRating {
Expand All @@ -194,9 +221,19 @@ extension ThreadListDataSource: UITableViewDataSource {
return .image(name: thread.threadTag?.imageName, placeholder: placeholder)
}
}(),
title: NSAttributedString(string: thread.title ?? "", attributes: [
.font: UIFont.preferredFontForTextStyle(.body, fontName: theme["listFontName"]),
.foregroundColor: theme[color: thread.closed ? "listSecondaryTextColor" : "listTextColor"]!]),
title: {
var threadTitleFont: UIFont
if Theme.defaultTheme().roundedFonts {
threadTitleFont = roundedFont(ofSize: 17, weight: .regular)
} else {
threadTitleFont = UIFont.systemFont(ofSize: 17, weight: .regular)
}

return NSAttributedString(string: thread.title ?? "", attributes: [
.font: threadTitleFont,
.foregroundColor: theme[color: thread.closed ? "listSecondaryTextColor" : "listTextColor"]!])
}()
,
unreadCount: {
guard thread.beenSeen else { return NSAttributedString() }
let color: UIColor
Expand All @@ -213,9 +250,16 @@ extension ThreadListDataSource: UITableViewDataSource {
case .none: color = theme["unreadBadgeBlueColor"]!
}
}
var unreadCountFont: UIFont
if Theme.defaultTheme().roundedFonts {
unreadCountFont = roundedFont(ofSize: 13, weight: .semibold)
} else {
unreadCountFont = UIFont.systemFont(ofSize: 13, weight: .semibold)
}

return NSAttributedString(string: "\(thread.unreadPosts)", attributes: [
.font: UIFont.preferredFontForTextStyle(.caption1, fontName: theme["listFontName"], sizeAdjustment: 2),
.foregroundColor: color])
.font: unreadCountFont,
.foregroundColor: color])
}())
}

Expand Down
9 changes: 9 additions & 0 deletions App/Extensions/UIFont+MonospacedDigits.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ extension UIFontDescriptor {
return addingAttributes([.featureSettings: featureSettings])
}
}

public func roundedFont(ofSize fontSize: CGFloat, weight: UIFont.Weight) -> UIFont {
// Will be SF Compact or standard SF in case of failure.
if let descriptor = UIFont.systemFont(ofSize: fontSize, weight: weight).fontDescriptor.withDesign(.rounded) {
return UIFont(descriptor: descriptor, size: fontSize)
} else {
return UIFont.systemFont(ofSize: fontSize, weight: weight)
}
}
132 changes: 126 additions & 6 deletions App/Extensions/UIKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,32 @@ extension UIImage {
return UIImage(cgImage: imageBitmapContext, scale: self.scale, orientation: UIImage.Orientation.up)
}
}

// THREAD TITLE
extension UINavigationItem {
/// A replacement label for the title that shows two lines on iPhone.
var titleLabel: UILabel {
if let label = titleView as? UILabel { return label }
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 375, height: 44))
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
let label = UILabel(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.minY, height: 44))
// label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.textAlignment = .center
label.textColor = .white
label.textColor = Theme.defaultTheme()["navigationBarTextColor"]!
label.accessibilityTraits.insert(UIAccessibilityTraits.header)

var font: UIFont
if Theme.defaultTheme().roundedFonts {
font = roundedFont(ofSize: 16, weight: .medium)
} else {
font = UIFont.systemFont(ofSize: 13, weight: .medium)
}

switch UIDevice.current.userInterfaceIdiom {
/* thread title posts view text */
case .pad:
label.font = UIFont.systemFont(ofSize: 17)
label.font = font
// label.font = UIFont.systemFont(ofSize: 17)
default:
label.font = UIFont.systemFont(ofSize: 13)
label.font = font
// label.font = UIFont.systemFont(ofSize: 13)
label.numberOfLines = 2
}
titleView = label
Expand Down Expand Up @@ -395,3 +406,112 @@ extension UIViewController {
return nil
}
}

public extension UIImage {

/**
Returns the flat colorized version of the image, or self when something was wrong
- Parameters:
- color: The colors to user. By defaut, uses the ``UIColor.white`
- Returns: the flat colorized version of the image, or the self if something was wrong
*/
func colorized(with color: UIColor = .white) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)

defer {
UIGraphicsEndImageContext()
}

guard let context = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return self }


let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)

color.setFill()
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.clip(to: rect, mask: cgImage)
context.fill(rect)

guard let colored = UIGraphicsGetImageFromCurrentImageContext() else { return self }

return colored
}

/**
Returns the stroked version of the fransparent image with the given stroke color and the thickness.
- Parameters:
- color: The colors to user. By defaut, uses the ``UIColor.white`
- thickness: the thickness of the border. Default to `2`
- quality: The number of degrees (out of 360): the smaller the best, but the slower. Defaults to `10`.
- Returns: the stroked version of the image, or self if something was wrong
*/

func stroked(with color: UIColor = .white, thickness: CGFloat = 2, quality: CGFloat = 10) -> UIImage {

guard let cgImage = cgImage else { return self }

// Colorize the stroke image to reflect border color
let strokeImage = colorized(with: color)

guard let strokeCGImage = strokeImage.cgImage else { return self }

/// Rendering quality of the stroke
let step = quality == 0 ? 10 : abs(quality)

let oldRect = CGRect(x: thickness, y: thickness, width: size.width, height: size.height).integral
let newSize = CGSize(width: size.width + 2 * thickness, height: size.height + 2 * thickness)
let translationVector = CGPoint(x: thickness, y: 0)


UIGraphicsBeginImageContextWithOptions(newSize, false, scale)

guard let context = UIGraphicsGetCurrentContext() else { return self }

defer {
UIGraphicsEndImageContext()
}
context.translateBy(x: 0, y: newSize.height)
context.scaleBy(x: 1.0, y: -1.0)
context.interpolationQuality = .high

for angle: CGFloat in stride(from: 0, to: 360, by: step) {
let vector = translationVector.rotated(around: .zero, byDegrees: angle)
let transform = CGAffineTransform(translationX: vector.x, y: vector.y)

context.concatenate(transform)

context.draw(strokeCGImage, in: oldRect)

let resetTransform = CGAffineTransform(translationX: -vector.x, y: -vector.y)
context.concatenate(resetTransform)
}

context.draw(cgImage, in: oldRect)

guard let stroked = UIGraphicsGetImageFromCurrentImageContext() else { return self }

return stroked
}
}


extension CGPoint {
/**
Rotates the point from the center `origin` by `byDegrees` degrees along the Z axis.
- Parameters:
- origin: The center of he rotation;
- byDegrees: Amount of degrees to rotate around the Z axis.
- Returns: The rotated point.
*/
func rotated(around origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
let dx = x - origin.x
let dy = y - origin.y
let radius = sqrt(dx * dx + dy * dy)
let azimuth = atan2(dy, dx) // in radians
let newAzimuth = azimuth + byDegrees * .pi / 180.0 // to radians
let x = origin.x + radius * cos(newAzimuth)
let y = origin.y + radius * sin(newAzimuth)
return CGPoint(x: x, y: y)
}
}
Loading