Skip to content
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
16 changes: 16 additions & 0 deletions Core/Core/Common/CommonModels/Store/Scope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ public struct Scope: Equatable {
self.init(predicate: predicate, order: [sort], sectionNameKeyPath: sectionNameKeyPath)
}

public init<Root, OrderValue>(
predicate: NSPredicate,
orderBy orderKeyPath: ReferenceWritableKeyPath<Root, OrderValue>,
ascending: Bool = true,
naturally: Bool = false,
sectionNameKeyPath: String? = nil
) {
self.init(
predicate: predicate,
order: [
NSSortDescriptor(keyPath: orderKeyPath, ascending: ascending, naturally: naturally)
],
sectionNameKeyPath: sectionNameKeyPath
)
}

public init<Root, OrderValue, SectionNameValue>(
predicate: NSPredicate,
orderBy orderKeyPath: ReferenceWritableKeyPath<Root, OrderValue>,
Expand Down
3 changes: 2 additions & 1 deletion Core/Core/Common/CommonUI/Fonts/FontExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public extension Font {
static var medium16: Font { Font(UIFont.scaledNamedFont(.medium16)) }
static var medium20: Font { Font(UIFont.scaledNamedFont(.medium20)) }

static var semibold10: Font { Font(UIFont.scaledNamedFont(.semibold10)) }
static var semibold11: Font { Font(UIFont.scaledNamedFont(.semibold11)) }
static var semibold12: Font { Font(UIFont.scaledNamedFont(.semibold12)) }
static var semibold13: Font { Font(UIFont.scaledNamedFont(.semibold13)) }
Expand Down Expand Up @@ -128,7 +129,7 @@ extension UIFont.Name {
case .regular10, .regular11Monodigit, .regular12, .regular13, .regular14, .regular14Italic,
.regular15, .regular16, .regular17, .regular22, .regular23, .regular24,
.medium12, .medium14,
.semibold11, .semibold12, .semibold13,
.semibold10, .semibold11, .semibold12, .semibold13,
.bold10, .bold11, .bold12, .bold13:
return .body
case .regular20, .semibold14, .semibold16, .semibold16Italic, .semibold17:
Expand Down
4 changes: 3 additions & 1 deletion Core/Core/Common/CommonUI/Fonts/UIFontExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public extension UIFont {
enum Name: String, CaseIterable {
case regular10, regular11Monodigit, regular12, regular13, regular14, regular14Italic, regular15, regular16, regular17, regular20, regular22, regular23, regular24, regular20Monodigit, regular30
case medium10, medium12, medium14, medium16, medium20
case semibold11, semibold12, semibold13, semibold14, semibold16, semibold17, semibold16Italic, semibold18, semibold20, semibold22, semibold23, semibold28, semibold38
case semibold10, semibold11, semibold12, semibold13, semibold14, semibold16, semibold17, semibold16Italic, semibold18, semibold20, semibold22, semibold23, semibold28, semibold38
case bold10, bold11, bold12, bold13, bold14, bold15, bold16, bold17, bold20, bold22, bold24, bold34
case heavy24
}
Expand Down Expand Up @@ -75,6 +75,8 @@ public extension UIFont {
case .medium20:
return scaledFont(.title1, for: applicationFont(ofSize: 20, weight: .medium))

case .semibold10:
return scaledFont(.body, for: applicationFont(ofSize: 10, weight: .semibold))
case .semibold11:
return scaledFont(.body, for: applicationFont(ofSize: 11, weight: .semibold))
case .semibold12:
Expand Down
87 changes: 54 additions & 33 deletions Core/Core/Common/CommonUI/InstUI/Views/Badge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ extension View {
/// - isOverlayed:
/// - If `true`, the badge behaves like an `overlay` and the trailing part of the badge is ignored for horizontal layout.
/// - If `false`, the badge behaves like a `ZStack` and the trailing part of the badge is respected for horizontal layout.
/// - color: The fill color of the badge's pill. If it's `nil` then the current `.tint` color is used.
@ViewBuilder
public func instBadge(
_ count: Int?,
style: InstUI.BadgeStyle = .hostSize24,
isOverlayed: Bool = true,
color: Color = .backgroundDanger
color: Color? = nil
) -> some View {
modifier(InstUI.BadgeModifier(count: count ?? 0, style: style, isOverlayed: isOverlayed, color: color))
}
Expand All @@ -41,32 +42,45 @@ extension InstUI {
public enum BadgeStyle {
case hostSize24
case hostSize18
case accessory

var offsetBase: Alignment {
switch self {
case .hostSize24: .leading
case .hostSize18: .leading
case .accessory: .bottomTrailing
}
}

var offset: CGPoint {
switch self {
case .hostSize24: CGPoint(x: 10, y: -2)
case .hostSize18: CGPoint(x: 6, y: -2)
case .accessory: CGPoint(x: -8, y: -6)
}
}

var edgeInsets: EdgeInsets {
switch self {
case .hostSize24: EdgeInsets(top: 2.5, leading: 6.5, bottom: 3, trailing: 6.5)
case .hostSize18: EdgeInsets(top: 0.75, leading: 4, bottom: 1.25, trailing: 4)
case .accessory: EdgeInsets(top: 1.75, leading: 5, bottom: 2.25, trailing: 5)
}
}

var borderWidth: CGFloat {
switch self {
case .hostSize24: 0
case .hostSize18: 1
case .accessory: 0.5
}
}

var font: Font {
switch self {
case .hostSize24: .semibold12
case .hostSize18: .regular10
case .accessory: .semibold10
}
}
}
Expand All @@ -76,20 +90,21 @@ extension InstUI {
private let text: String?
private let style: BadgeStyle
private let isOverlayed: Bool
private let color: Color
private let color: Color?

@ScaledMetric(relativeTo: .body) private var uiScaleBody: CGFloat = 1
@ScaledMetric(relativeTo: .caption2) private var uiScaleCaption2: CGFloat = 1
private var uiScale: CGFloat {
switch style {
case .hostSize24: uiScaleBody
case .hostSize18: uiScaleCaption2
case .accessory: uiScaleBody
}
}

@State private var badgedContentWidth: CGFloat = 0

init(count: Int, style: BadgeStyle, isOverlayed: Bool, color: Color) {
init(count: Int, style: BadgeStyle, isOverlayed: Bool, color: Color?) {
text = switch count {
case ...0:
nil
Expand All @@ -116,8 +131,8 @@ extension InstUI {
let deltaX = style.offset.x * uiScale.iconScale
let deltaY = style.offset.y * uiScale.iconScale
pill(text)
.alignmentGuide(.trailing) { $0[HorizontalAlignment.leading] + deltaX }
.alignmentGuide(.top) { $0[VerticalAlignment.center] + deltaY }
.alignmentGuide(.trailing) { $0[style.offsetBase.horizontal] + deltaX }
.alignmentGuide(.top) { $0[style.offsetBase.vertical] + deltaY }
}
}
.onSizeChange {
Expand All @@ -133,8 +148,9 @@ extension InstUI {
.padding(style.edgeInsets * uiScale)
.background(
Capsule()
.fill(color)
.fill(.tint)
.stroke(Color.textLightest, lineWidth: style.borderWidth)
.customTint(color)
)
.fixedSize(horizontal: true, vertical: false)
.transition(.push(from: .top))
Expand All @@ -147,7 +163,7 @@ extension InstUI {

#Preview {
@Previewable @State var badgeValueIndex: Int = 0
let badgeValues: [Int?] = [nil, 1, 99, 100]
let badgeValues: [Int?] = [nil, 1, 3, 99, 100]

let clock18 = Image.clockLine.scaledIcon(size: 18)
let doc18 = Image.documentLine.scaledIcon(size: 18)
Expand All @@ -157,50 +173,52 @@ extension InstUI {
Divider()

HStack(spacing: 10) {
SwiftUI.Group {
clock18.instBadge(nil, style: .hostSize18)
clock18.instBadge(1, style: .hostSize18)
clock18.instBadge(3, style: .hostSize18)
clock18.instBadge(99, style: .hostSize18)
clock18.instBadge(100, style: .hostSize18)
ForEach(badgeValues, id: \.self) {
clock18.instBadge($0, style: .hostSize18)
}
.background(.green)
}
Divider()

HStack(spacing: 10) {
clock18.instBadge(nil, style: .hostSize18)
clock18.instBadge(1, style: .hostSize18)
clock18.instBadge(3, style: .hostSize18)
clock18.instBadge(99, style: .hostSize18)
clock18.instBadge(100, style: .hostSize18)
ForEach(badgeValues, id: \.self) {
clock18.instBadge($0, style: .hostSize18)
}
}
Divider()

HStack(spacing: 10) {
ForEach(badgeValues, id: \.self) {
doc18.instBadge($0, style: .hostSize18, color: .textSuccess)
}
}
Divider()

HStack(spacing: 10) {
doc18.instBadge(nil, style: .hostSize18)
doc18.instBadge(1, style: .hostSize18)
doc18.instBadge(3, style: .hostSize18)
doc18.instBadge(99, style: .hostSize18)
doc18.instBadge(100, style: .hostSize18)
ForEach(badgeValues, id: \.self) {
menu24.instBadge($0, style: .hostSize24)
}
}
Divider()

HStack(spacing: 10) {
menu24.instBadge(nil, style: .hostSize24)
menu24.instBadge(1, style: .hostSize24)
menu24.instBadge(3, style: .hostSize24)
menu24.instBadge(99, style: .hostSize24)
menu24.instBadge(100, style: .hostSize24)
ForEach(badgeValues, id: \.self) { value in
Button {} label: { menu24.instBadge(value, style: .hostSize24) }
}
}
Divider()

HStack(spacing: 10) {
Image.alertsTab.instBadge(nil)
Image.alertsTab.instBadge(1)
Image.alertsTab.instBadge(3)
Image.alertsTab.instBadge(99)
Image.alertsTab.instBadge(100)
ForEach(badgeValues, id: \.self) {
Image.alertsTab.instBadge($0)
}
}
Divider()

HStack(spacing: 10) {
ForEach(badgeValues, id: \.self) {
Image.announcementSolid.instBadge($0, style: .accessory)
}
}
Divider()

Expand All @@ -213,10 +231,13 @@ extension InstUI {
}
} label: {
Text(verbatim: "Change!")
.foregroundStyle(.course3)
}
Image.alertsTab.instBadge(badgeValues[badgeValueIndex])
}
}
.foregroundStyle(.textDarkest)
.tint(.backgroundDanger)
.background(Color.backgroundLightest)
}

Expand Down
20 changes: 10 additions & 10 deletions Core/Core/Common/CommonUI/InstUI/Views/NavigationBarButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ extension InstUI {
@ViewBuilder
private var button: some View {
if let menuContent {
if isAvailableOffline {
Menu(content: { menuContent }, label: label)
} else {
OfflineObservingMenu(content: { menuContent }, label: label)
}
OfflineObservingMenu(
isAvailableOffline: isAvailableOffline,
content: { menuContent },
label: label
)
} else {
if isAvailableOffline {
Button(action: action, label: label)
} else {
OfflineObservingButton(action: action, label: label)
}
OfflineObservingButton(
isAvailableOffline: isAvailableOffline,
action: action,
label: label
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ extension NSPredicate {
self.init(key: keyPath.string, equals: value)
}

public convenience init<Root, Value>(_ keyPath: ReferenceWritableKeyPath<Root, Value>, isContainedIn values: [CVarArg]) {
self.init(format: "%K IN %@", argumentArray: [keyPath.string, values])
}
}

// MARK: - AND / OR

extension NSPredicate {

public static func and(_ predicates: NSPredicate...) -> NSPredicate {
NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
}

public static func or(_ predicates: NSPredicate...) -> NSPredicate {
NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
}

/**
- parameters:
- predicate: The predicate to be combined with `self` using the logical AND operation.
Expand Down
Loading
Loading