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

Feature/1.2.0 #18

Merged
merged 8 commits into from
May 10, 2024
Merged
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: 5 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ let package = Package(
.target(
name: "RAKCodable",
dependencies: ["RAKCore"],
path: "Sources/CodableExtend"
path: "Sources/Codable"
),

.target(
Expand Down Expand Up @@ -100,7 +100,10 @@ let package = Package(

.target(
name: "RAKFixCrashOnInputKeyboard",
path: "Sources/FixCrashOnInputKeyboard"
path: "Sources/FixCrashOnInputKeyboard",
cSettings: [
.define("RAK_NOT_SUPPORT", .when(platforms: [.watchOS, .macOS])),
]
),

.target(
Expand Down
9 changes: 9 additions & 0 deletions Sources/Base/View/Fast/FastCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ public protocol FastCell: UIView {
config: ConfigClosure
) -> Self

#if !os(visionOS)
static func xibCell(
of view: FastListView,
for indexPath: IndexPath,
identifier: String?,
config: ConfigClosure
) -> Self
#endif
}

// MARK: - Defaults
Expand All @@ -40,6 +42,7 @@ extension FastCell {
createCell(of: view, for: indexPath, identifier: identifier, isCodeCell: true, config: config)
}

#if !os(visionOS)
public static func xibCell(
of view: FastListView,
for indexPath: IndexPath,
Expand All @@ -48,6 +51,7 @@ extension FastCell {
) -> Self {
createCell(of: view, for: indexPath, identifier: identifier, isCodeCell: false, config: config)
}
#endif
}

// MARK: - Tools
Expand All @@ -63,7 +67,12 @@ extension FastCell {
let id = identifier ?? String(describing: Self.self)

if _slowPath(!listView.registeredIdentifiers.contains(id)) {
#if os(visionOS)
listView.register(Self.self, with: id)
#else
listView.register(Self.self, with: id, isCodeCell: isCodeCell)
#endif

listView.registeredIdentifiers.append(id)
}

Expand Down
28 changes: 23 additions & 5 deletions Sources/Base/View/Fast/FastListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ public protocol FastListView: NSObjectProtocol {

// The following methods are used to bridge the differences between `UITableView` and `UICollectionView`.

#if os(visionOS)
func register(_ cell: (some FastCell).Type, with identifier: String)
#else
func register(_ cell: (some FastCell).Type, with identifier: String, isCodeCell: Bool)

#endif

func dequeueCell<Cell: FastCell>(with identifier: String, for indexPath: IndexPath) -> Cell?
}

Expand All @@ -30,14 +34,21 @@ extension UITableView: FastListView {
set { objc_setAssociatedObject(self, &tableViewKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
}

#if !os(visionOS)
@available(visionOS, unavailable, message: "Use `register(_: with:)` instead")
public func register(_ cell: (some FastCell).Type, with identifier: String, isCodeCell: Bool) {
if isCodeCell {
register(cell, forCellReuseIdentifier: identifier)
register(cell, with: identifier)
} else {
register(UINib(nibName: identifier, bundle: nil), forCellReuseIdentifier: identifier)
}
}

#endif

public func register(_ cell: (some FastCell).Type, with identifier: String) {
register(cell, forCellReuseIdentifier: identifier)
}

public func dequeueCell<Cell: FastCell>(with identifier: String, for indexPath: IndexPath) -> Cell? {
dequeueReusableCell(withIdentifier: identifier, for: indexPath) as? Cell
}
Expand All @@ -53,14 +64,21 @@ extension UICollectionView: FastListView {
set { objc_setAssociatedObject(self, &collectionViewKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
}

#if !os(visionOS)
@available(visionOS, unavailable, message: "Use `register(_: with:)` instead")
public func register(_ cell: (some FastCell).Type, with identifier: String, isCodeCell: Bool) {
if isCodeCell {
register(cell, forCellWithReuseIdentifier: identifier)
register(cell, with: identifier)
} else {
register(UINib(nibName: identifier, bundle: nil), forCellWithReuseIdentifier: identifier)
}
}

#endif

public func register(_ cell: (some FastCell).Type, with identifier: String) {
register(cell, forCellWithReuseIdentifier: identifier)
}

public func dequeueCell<Cell: FastCell>(with identifier: String, for indexPath: IndexPath) -> Cell? {
dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as? Cell
}
Expand Down
65 changes: 0 additions & 65 deletions Sources/Core/Extensions/DictionaryExtendable.swift

This file was deleted.

53 changes: 53 additions & 0 deletions Sources/Core/Extensions/DispatchQueue+RAK.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// DispatchQueue+RAK.swift
// RakuyoKit
//
// Created by Rakuyo on 2024/5/10.
// Copyright © 2024 RakuyoKit. All rights reserved.
//

import Foundation

extension Extendable where Base: DispatchQueue {
public typealias Task = (_ canceled: Bool) -> Void

/// Create a deferred task that can be canceled midway using the `cancel()` method.
///
/// - Parameters:
/// - time: Delay duration. Internal `.now() + time`
/// - task: Tasks to be performed after the time is reached. Will be executed on the main thread
/// - Returns: Action to cancel execution
@discardableResult
public static func after(
_ time: DispatchTimeInterval,
execute task: @escaping EmptyClosure
) -> Task? {
func _after(block: @escaping EmptyClosure) {
DispatchQueue.main.asyncAfter(deadline: .now() + time, execute: block)
}

var taskAction: EmptyClosure? = task
var result: Task?

let delayedClosure: Task = { canceled in
if let action = taskAction, !canceled {
DispatchQueue.main.async(execute: action)
}
taskAction = nil
result = nil
}

result = delayedClosure

_after { result?(false) }

return result
}

/// Cancel delayed tasks
///
/// - Parameter task: Task to be canceled
public static func cancel(_ task: Task?) {
task?(true)
}
}
1 change: 0 additions & 1 deletion Sources/Core/Extensions/Extendable/Extendable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ import struct Swift.Bool; extension Bool : NamespaceProvi
import struct Swift.Int; extension Int : NamespaceProviding { }
import struct Swift.Double; extension Double : NamespaceProviding { }
import struct Swift.Float; extension Float : NamespaceProviding { }
import struct Swift.Dictionary; extension Dictionary : NamespaceProviding { }
import struct Foundation.Date; extension Date : NamespaceProviding { }
import struct Foundation.URL; extension URL : NamespaceProviding { }
import struct Foundation.Data; extension Data : NamespaceProviding { }
Expand Down
67 changes: 67 additions & 0 deletions Sources/Core/Extensions/Extendable/TwoGenericExtendable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// TwoGenericExtendable.swift
// RakuyoKit
//
// Created by Rakuyo on 2024/5/10.
// Copyright © 2024 RakuyoKit. All rights reserved.
//

import Foundation

// MARK: - TwoGenericExtendable

public struct TwoGenericExtendable<Base, OG, TG>: HigherOrderFunctionalizable {
/// Base object to extend.
public var base: Base

/// Creates extensions with base object.
///
/// - parameter base: Base object.
public init(_ base: Base) { self.base = base }
}

// MARK: - TwoGenericNamespaceProviding

/// A type that has `TwoGenericExtendable` extensions.
public protocol TwoGenericNamespaceProviding {
/// Extended type
associatedtype CompatibleType

/// Generic type contained in `CompatibleType`
associatedtype OneGenericType

/// Generic type contained in `CompatibleType`
associatedtype TowGenericType

/// `DictionaryExtendable` extensions.
static var rak: TwoGenericExtendable<CompatibleType, OneGenericType, TowGenericType>.Type { get set }

/// `DictionaryExtendable` extensions.
var rak: TwoGenericExtendable<CompatibleType, OneGenericType, TowGenericType> { get set }
}

extension TwoGenericNamespaceProviding {
/// `DictionaryExtendable` extensions.
public static var rak: TwoGenericExtendable<Self, OneGenericType, TowGenericType>.Type {
get { TwoGenericExtendable<Self, OneGenericType, TowGenericType>.self }
// swiftlint:disable:next unused_setter_value
set { /* this enables using `TwoGenericExtendable` to "mutate" base type */ }
}

/// `DictionaryExtendable` extensions.
public var rak: TwoGenericExtendable<Self, OneGenericType, TowGenericType> {
get { TwoGenericExtendable(self) }
// swiftlint:disable:next unused_setter_value
set { /* this enables using `TwoGenericExtendable` to "mutate" base object */ }
}
}

// MARK: - Extend `rak` proxy.

// swiftformat:disable all
import struct Swift.Dictionary
extension Dictionary: TwoGenericNamespaceProviding {
public typealias OneGenericType = Key
public typealias TowGenericType = Value
}
// swiftformat:enable all
67 changes: 67 additions & 0 deletions Sources/Core/Extensions/UINavigationBar+RAK.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// UINavigationBar+RAK.swift
// RakuyoKit
//
// Created by Rakuyo on 2024/5/10.
// Copyright © 2024 RakuyoKit. All rights reserved.
//

#if !os(watchOS)
import UIKit

extension Extendable where Base: UINavigationBar {
/// Shadow view on navigation bar
public var shadowImageView: UIImageView? {
let backgroundView = base.subviews.first {
NSStringFromClass(type(of: $0)).contains("UIBarBackground")
}

return backgroundView?.subviews.compactMap { $0 as? UIImageView }.first
}

/// Whether the navigation bar shadow is hidden
///
/// https://stackoverflow.com/a/38745391
public var isShadowHidden: Bool {
get {
guard let hidesShadow = base.value(forKey: "hidesShadow") as? Bool else {
return false
}
return hidesShadow
}
set { base.setValue(newValue, forKey: "hidesShadow") }
}

/// Large title view on navigation bar
public var largeTitleView: UIView? {
base.subviews.first {
NSStringFromClass(type(of: $0)).contains("UINavigationBarLargeTitleView")
}
}

/// Set the large title view to multi-line mode
public func setLargeTitleToMultilineMode() {
guard let largeTitleView else { return }

for subview in largeTitleView.subviews {
guard let label = subview as? UILabel else {
continue
}

let originalHeight = label.bounds.height

label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.sizeToFit()

let heightIncrement = label.bounds.height - originalHeight

if heightIncrement > 0 {
base.frame.size.height = heightIncrement + label.bounds.height
}

break
}
}
}
#endif
Loading