Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ struct ButtonPreview: View {
Text("Leading").tag(ButtonVM.ImageLocation.leading)
Text("Trailing").tag(ButtonVM.ImageLocation.trailing)
}
Picker("Image Rendering Mode", selection: self.$model.imageRenderingMode) {
Text("Default").tag(Optional<ImageRenderingMode>.none)
Text("Template").tag(ImageRenderingMode.template)
Text("Original").tag(ImageRenderingMode.original)
}
Picker("Image Source", selection: self.$model.imageSrc) {
Text("SF Symbol").tag(ButtonVM.ImageSource.sfSymbol("camera.fill"))
Text("Local").tag(ButtonVM.ImageSource.local("avatar_placeholder"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ extension AvatarVM {
self.placeholderBackgroundColor.setFill()
UIBezierPath(rect: CGRect(origin: .zero, size: size)).fill()

icon?.withTintColor(self.placeholderForegroundColor, renderingMode: .alwaysOriginal).draw(in: CGRect(
icon?.withTintColor(self.placeholderForegroundColor).draw(in: CGRect(
x: (size.width - iconSize.width) / 2,
y: (size.height - iconSize.height) / 2,
width: iconSize.width,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

/// Defines the image source options for a button.
extension ButtonVM {
/// Defines the image source options for a button.
public enum ImageSource: Hashable {
/// An image loaded from a system SF Symbol.
///
Expand Down
30 changes: 20 additions & 10 deletions Sources/ComponentsKit/Components/Button/Models/ButtonVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public struct ButtonVM: ComponentVM {
/// Defaults to `.leading`.
public var imageLocation: ImageLocation = .leading

/// Defines how image is rendered.
public var imageRenderingMode: ImageRenderingMode?

/// The source of the image to be displayed.
public var imageSrc: ImageSource?

Expand Down Expand Up @@ -164,10 +167,18 @@ extension ButtonVM {
case .minimal:
return 0
case .light, .filled, .bordered, .plain:
return switch self.size {
case .small: 16
case .medium: 20
case .large: 24
if self.title.isNotEmpty || self.isLoading {
return switch self.size {
case .small: 16
case .medium: 20
case .large: 24
}
} else {
return switch self.size {
case .small: 8
case .medium: 10
case .large: 12
}
}
}
}
Expand All @@ -176,15 +187,14 @@ extension ButtonVM {
extension ButtonVM {
var image: UIImage? {
guard let imageSrc else { return nil }
switch imageSrc {

let image = switch imageSrc {
case .sfSymbol(let name):
return UIImage(systemName: name)?.withTintColor(
self.foregroundColor.uiColor,
renderingMode: .alwaysOriginal
)
UIImage(systemName: name)
case .local(let name, let bundle):
return UIImage(named: name, in: bundle, compatibleWith: nil)
UIImage(named: name, in: bundle, compatibleWith: nil)
}
return image?.withRenderingMode(self.imageRenderingMode)
}
}

Expand Down
34 changes: 25 additions & 9 deletions Sources/ComponentsKit/Components/Button/SUButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,31 @@ public struct SUButton: View {
SULoading(model: self.model.preferredLoadingVM)
Text(self.model.title)
case (false, let uiImage?, .leading) where self.model.title.isEmpty:
ButtonImageView(image: uiImage)
.frame(width: self.model.imageSide, height: self.model.imageSide)
ButtonImageView(
image: uiImage,
tintColor: self.model.foregroundColor.uiColor
)
.frame(width: self.model.imageSide, height: self.model.imageSide)
case (false, let uiImage?, .leading):
ButtonImageView(image: uiImage)
.frame(width: self.model.imageSide, height: self.model.imageSide)
ButtonImageView(
image: uiImage,
tintColor: self.model.foregroundColor.uiColor
)
.frame(width: self.model.imageSide, height: self.model.imageSide)
Text(self.model.title)
case (false, let uiImage?, .trailing) where self.model.title.isEmpty:
ButtonImageView(image: uiImage)
.frame(width: self.model.imageSide, height: self.model.imageSide)
ButtonImageView(
image: uiImage,
tintColor: self.model.foregroundColor.uiColor
)
.frame(width: self.model.imageSide, height: self.model.imageSide)
case (false, let uiImage?, .trailing):
Text(self.model.title)
ButtonImageView(image: uiImage)
.frame(width: self.model.imageSide, height: self.model.imageSide)
ButtonImageView(
image: uiImage,
tintColor: self.model.foregroundColor.uiColor
)
.frame(width: self.model.imageSide, height: self.model.imageSide)
case (false, _, _):
Text(self.model.title)
}
Expand All @@ -88,16 +100,20 @@ private struct ButtonImageView: UIViewRepresentable {
}

let image: UIImage
let tintColor: UIColor

func makeUIView(context: Context) -> UIImageView {
let imageView = InternalImageView()
imageView.image = self.image
imageView.tintColor = self.tintColor
imageView.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = true
return imageView
}

func updateUIView(_ imageView: UIImageView, context: Context) {
imageView.image = self.image
imageView.tintColor = self.tintColor
}
}

Expand All @@ -108,10 +124,10 @@ private struct CustomButtonStyle: SwiftUI.ButtonStyle {
configuration.label
.font(self.model.preferredFont.font)
.lineLimit(1)
.contentShape(.rect)
.padding(.horizontal, self.model.horizontalPadding)
.frame(maxWidth: self.model.width)
.frame(height: self.model.height)
.contentShape(.rect)
.foregroundStyle(self.model.foregroundColor.color)
.background(self.model.backgroundColor?.color ?? .clear)
.clipShape(
Expand Down
2 changes: 2 additions & 0 deletions Sources/ComponentsKit/Components/Button/UKButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ extension UKButton {
imageView.image = model.image
imageView.contentMode = .scaleAspectFit
imageView.isHidden = model.isLoading || model.imageSrc.isNil
imageView.tintColor = model.foregroundColor.uiColor
imageView.isUserInteractionEnabled = true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ struct ModalPresentationModifier<Modal: View>: ViewModifier {
}
}
.fullScreenCover(
isPresented: self.$isPresented,
isPresented: .init(
get: { self.isPresented },
set: { self.isContentVisible = $0 }
),
onDismiss: self.onDismiss,
content: {
self.content()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ struct ModalPresentationWithItemModifier<Modal: View, Item: Identifiable>: ViewM
}
}
.fullScreenCover(
item: self.$presentedItem,
item: .init(
get: { self.presentedItem },
set: { self.visibleItem = $0 }
),
onDismiss: self.onDismiss,
content: { item in
self.content(item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ extension View {
return self.bottomModal(
item: item,
model: model,
onDismiss: onDismiss,
header: { _ in EmptyView() },
body: body,
footer: { _ in EmptyView() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ extension View {
return self.centerModal(
item: item,
model: model,
onDismiss: onDismiss,
header: { _ in EmptyView() },
body: body,
footer: { _ in EmptyView() }
Expand Down
50 changes: 50 additions & 0 deletions Sources/ComponentsKit/Shared/Types/ImageRenderingMode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import SwiftUI
import UIKit

/// A type that indicates how images are rendered.
public enum ImageRenderingMode {
/// A mode that renders all non-transparent pixels as the foreground
/// color.
case template
/// A mode that renders pixels of bitmap images as-is.
///
/// For system images created from the SF Symbol set, multicolor symbols
/// respect the current foreground and accent colors.
case original
}

// MARK: - UIKit Helpers

extension ImageRenderingMode {
var uiImageRenderingMode: UIImage.RenderingMode {
switch self {
case .template:
return .alwaysTemplate
case .original:
return .alwaysOriginal
}
}
}

extension UIImage {
func withRenderingMode(_ mode: ImageRenderingMode?) -> UIImage {
if let mode {
return self.withRenderingMode(mode.uiImageRenderingMode)
} else {
return self
}
}
}

// MARK: - SwiftUI Helpers

extension ImageRenderingMode {
var imageRenderingModel: Image.TemplateRenderingMode {
switch self {
case .template:
return .template
case .original:
return .original
}
}
}