[PM-26063] Move IllustratedMessageView to BitwardenKit (#2096)
@ -4,8 +4,9 @@ import SnapshotTesting
|
||||
import SwiftUI
|
||||
import XCTest
|
||||
|
||||
@testable import BitwardenShared
|
||||
@testable import BitwardenKit
|
||||
|
||||
@MainActor
|
||||
class IllustratedMessageViewTests: BitwardenTestCase {
|
||||
// MARK: Tests
|
||||
|
||||
@ -29,7 +30,7 @@ class IllustratedMessageViewTests: BitwardenTestCase {
|
||||
/// Test snapshots of the mediumImage style.
|
||||
func disabletest_snapshot_mediumImage() {
|
||||
let subject = IllustratedMessageView(
|
||||
image: Asset.Images.Illustrations.biometricsPhone,
|
||||
image: SharedAsset.Icons.unlocked24,
|
||||
style: .mediumImage,
|
||||
title: Localizations.setUpUnlock,
|
||||
message: Localizations.setUpBiometricsOrChooseAPinCodeToQuicklyAccessYourVaultAndAutofillYourLogins,
|
||||
@ -46,7 +47,7 @@ class IllustratedMessageViewTests: BitwardenTestCase {
|
||||
/// Test snapshots of the mediumImage style with a button.
|
||||
func disabletest_snapshot_mediumImage_withButton() {
|
||||
let subject = IllustratedMessageView(
|
||||
image: Asset.Images.Illustrations.biometricsPhone,
|
||||
image: SharedAsset.Icons.unlocked24,
|
||||
style: .mediumImage,
|
||||
title: Localizations.setUpUnlock,
|
||||
message: Localizations.setUpBiometricsOrChooseAPinCodeToQuicklyAccessYourVaultAndAutofillYourLogins,
|
||||
@ -69,7 +70,7 @@ class IllustratedMessageViewTests: BitwardenTestCase {
|
||||
/// Test snapshots of the smallImage style.
|
||||
func disabletest_snapshot_smallImage() {
|
||||
let subject = IllustratedMessageView(
|
||||
image: Asset.Images.Illustrations.biometricsPhone,
|
||||
image: SharedAsset.Icons.unlocked24,
|
||||
style: .smallImage,
|
||||
title: Localizations.setUpUnlock,
|
||||
message: Localizations.setUpBiometricsOrChooseAPinCodeToQuicklyAccessYourVaultAndAutofillYourLogins,
|
||||
@ -4,7 +4,7 @@ import SwiftUI
|
||||
import ViewInspector
|
||||
import XCTest
|
||||
|
||||
@testable import BitwardenShared
|
||||
@testable import BitwardenKit
|
||||
|
||||
class IllustratedMessageViewTests: BitwardenTestCase {
|
||||
// MARK: Tests
|
||||
@ -14,7 +14,7 @@ class IllustratedMessageViewTests: BitwardenTestCase {
|
||||
func test_button_tap() throws {
|
||||
var tapped = false
|
||||
let subject = IllustratedMessageView(
|
||||
image: Asset.Images.Illustrations.biometricsPhone,
|
||||
image: SharedAsset.Icons.unlocked24,
|
||||
style: .mediumImage,
|
||||
title: Localizations.setUpUnlock,
|
||||
message: Localizations.setUpBiometricsOrChooseAPinCodeToQuicklyAccessYourVaultAndAutofillYourLogins,
|
||||
@ -1,4 +1,3 @@
|
||||
import BitwardenKit
|
||||
import BitwardenResources
|
||||
import SwiftUI
|
||||
|
||||
@ -7,7 +6,7 @@ import SwiftUI
|
||||
/// A view that renders a message view with an image on top. This support displaying a square image,
|
||||
/// title, and message.
|
||||
///
|
||||
struct IllustratedMessageView<Accessory: View>: View {
|
||||
public struct IllustratedMessageView<Accessory: View>: View {
|
||||
// MARK: Properties
|
||||
|
||||
/// An optional accessory to display after the message, such as a button.
|
||||
@ -30,7 +29,7 @@ struct IllustratedMessageView<Accessory: View>: View {
|
||||
|
||||
// MARK: View
|
||||
|
||||
var body: some View {
|
||||
public var body: some View {
|
||||
dynamicStackView {
|
||||
image
|
||||
.resizable()
|
||||
@ -73,7 +72,7 @@ struct IllustratedMessageView<Accessory: View>: View {
|
||||
/// - message: The message to display.
|
||||
/// - accessory: An optional accessory view to display.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
image: Image,
|
||||
style: IllustratedMessageStyle = .smallImage,
|
||||
title: String? = nil,
|
||||
@ -96,30 +95,7 @@ struct IllustratedMessageView<Accessory: View>: View {
|
||||
/// - message: The message to display.
|
||||
/// - accessory: An optional accessory view to display.
|
||||
///
|
||||
init(
|
||||
image: ImageAsset,
|
||||
style: IllustratedMessageStyle = .smallImage,
|
||||
title: String? = nil,
|
||||
message: String,
|
||||
@ViewBuilder accessory: () -> Accessory,
|
||||
) {
|
||||
self.accessory = accessory()
|
||||
self.image = image.swiftUIImage
|
||||
self.message = message
|
||||
self.style = style
|
||||
self.title = title
|
||||
}
|
||||
|
||||
/// Initialize a `IllustratedMessageView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - image: The image asset to display.
|
||||
/// - style: The style of the message view.
|
||||
/// - title: The title to display.
|
||||
/// - message: The message to display.
|
||||
/// - accessory: An optional accessory view to display.
|
||||
///
|
||||
init(
|
||||
public init(
|
||||
image: SharedImageAsset,
|
||||
style: IllustratedMessageStyle = .smallImage,
|
||||
title: String? = nil,
|
||||
@ -148,7 +124,7 @@ struct IllustratedMessageView<Accessory: View>: View {
|
||||
}
|
||||
}
|
||||
|
||||
extension IllustratedMessageView where Accessory == EmptyView {
|
||||
public extension IllustratedMessageView where Accessory == EmptyView {
|
||||
/// Initialize a `IllustratedMessageView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
@ -170,27 +146,6 @@ extension IllustratedMessageView where Accessory == EmptyView {
|
||||
self.title = title
|
||||
}
|
||||
|
||||
/// Initialize a `IllustratedMessageView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - image: The image asset to display.
|
||||
/// - style: The style of the message view.
|
||||
/// - title: The title to display.
|
||||
/// - message: The message to display.
|
||||
///
|
||||
init(
|
||||
image: ImageAsset,
|
||||
style: IllustratedMessageStyle = .smallImage,
|
||||
title: String? = nil,
|
||||
message: String,
|
||||
) {
|
||||
accessory = nil
|
||||
self.image = image.swiftUIImage
|
||||
self.message = message
|
||||
self.style = style
|
||||
self.title = title
|
||||
}
|
||||
|
||||
/// Initialize a `IllustratedMessageView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
@ -218,7 +173,7 @@ extension IllustratedMessageView where Accessory == EmptyView {
|
||||
#if DEBUG
|
||||
#Preview("SmallImage") {
|
||||
IllustratedMessageView(
|
||||
image: Asset.Images.Illustrations.biometricsPhone,
|
||||
image: SharedAsset.Icons.plus24,
|
||||
style: .smallImage,
|
||||
title: Localizations.setUpUnlock,
|
||||
message: Localizations.setUpBiometricsOrChooseAPinCodeToQuicklyAccessYourVaultAndAutofillYourLogins,
|
||||
@ -227,7 +182,7 @@ extension IllustratedMessageView where Accessory == EmptyView {
|
||||
|
||||
#Preview("MediumImage") {
|
||||
IllustratedMessageView(
|
||||
image: Asset.Images.Illustrations.biometricsPhone,
|
||||
image: SharedAsset.Icons.plus24,
|
||||
style: .mediumImage,
|
||||
title: Localizations.setUpUnlock,
|
||||
message: Localizations.setUpBiometricsOrChooseAPinCodeToQuicklyAccessYourVaultAndAutofillYourLogins,
|
||||
@ -236,7 +191,7 @@ extension IllustratedMessageView where Accessory == EmptyView {
|
||||
|
||||
#Preview("MediumImage With Button") {
|
||||
IllustratedMessageView(
|
||||
image: Asset.Images.Illustrations.biometricsPhone,
|
||||
image: SharedAsset.Icons.plus24,
|
||||
style: .mediumImage,
|
||||
title: Localizations.setUpUnlock,
|
||||
message: Localizations.setUpBiometricsOrChooseAPinCodeToQuicklyAccessYourVaultAndAutofillYourLogins,
|
||||
@ -263,7 +218,7 @@ extension IllustratedMessageView where Accessory == EmptyView {
|
||||
|
||||
/// A `IllustratedMessageStyle` contains the metrics for rendering a `IllustratedMessageView`.
|
||||
///
|
||||
struct IllustratedMessageStyle: Sendable {
|
||||
public struct IllustratedMessageStyle: Sendable {
|
||||
// MARK: Properties
|
||||
|
||||
/// A foreground tint to apply to the image. Only applied if this has a value.
|
||||
@ -317,7 +272,8 @@ private extension IllustratedMessageStyle {
|
||||
|
||||
// MARK: - IllustratedMessageStyle Constants
|
||||
|
||||
extension IllustratedMessageStyle {
|
||||
public extension IllustratedMessageStyle {
|
||||
/// A style with a large title text and a tinted icon image.
|
||||
static let largeTextTintedIcon = IllustratedMessageStyle(
|
||||
imageColor: SharedAsset.Colors.iconSecondary.swiftUIColor,
|
||||
imageSize: OrientationBasedValue(
|
||||
@ -331,6 +287,7 @@ extension IllustratedMessageStyle {
|
||||
titleTextStyle: .hugeTitle,
|
||||
)
|
||||
|
||||
/// A style with a medium-sized image.
|
||||
static let mediumImage = IllustratedMessageStyle(
|
||||
imageColor: nil,
|
||||
imageSize: OrientationBasedValue(
|
||||
@ -346,6 +303,7 @@ extension IllustratedMessageStyle {
|
||||
titleTextStyle: .title2,
|
||||
)
|
||||
|
||||
/// A style with a small-sized image.
|
||||
static let smallImage = IllustratedMessageStyle(
|
||||
imageColor: nil,
|
||||
imageSize: OrientationBasedValue(
|
||||
@ -4,7 +4,7 @@ import SwiftUI
|
||||
|
||||
/// An `OrientationBasedValue` encapsulates values that might be different
|
||||
/// for rendering based on orientation, such as image size or space between text.
|
||||
struct OrientationBasedValue<T: Equatable & Sendable>: Equatable, Sendable {
|
||||
public struct OrientationBasedValue<T: Equatable & Sendable>: Equatable, Sendable {
|
||||
// MARK: Properties
|
||||
|
||||
/// The dimension size in portrait mode.
|
||||
@ -20,7 +20,7 @@ struct OrientationBasedValue<T: Equatable & Sendable>: Equatable, Sendable {
|
||||
/// - portrait: The value in portrait mode.
|
||||
/// - landscape: The value in landscape mode.
|
||||
///
|
||||
init(portrait: T, landscape: T) {
|
||||
public init(portrait: T, landscape: T) {
|
||||
self.portrait = portrait
|
||||
self.landscape = landscape
|
||||
}
|
||||
@ -29,7 +29,7 @@ struct OrientationBasedValue<T: Equatable & Sendable>: Equatable, Sendable {
|
||||
/// - Parameters:
|
||||
/// - both: The value in both portrait and landscape mode.
|
||||
///
|
||||
init(both: T) {
|
||||
public init(both: T) {
|
||||
portrait = both
|
||||
landscape = both
|
||||
}
|
||||
@ -38,7 +38,7 @@ struct OrientationBasedValue<T: Equatable & Sendable>: Equatable, Sendable {
|
||||
|
||||
/// Convenience function for getting the correct value based on the orientation.
|
||||
///
|
||||
func value(_ verticalSizeClass: UserInterfaceSizeClass) -> T {
|
||||
public func value(_ verticalSizeClass: UserInterfaceSizeClass) -> T {
|
||||
verticalSizeClass == .regular ? portrait : landscape
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
@ -0,0 +1,53 @@
|
||||
import BitwardenKit
|
||||
import SwiftUI
|
||||
|
||||
extension IllustratedMessageView {
|
||||
/// Initialize a `IllustratedMessageView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - image: The image asset to display.
|
||||
/// - style: The style of the message view.
|
||||
/// - title: The title to display.
|
||||
/// - message: The message to display.
|
||||
/// - accessory: An optional accessory view to display.
|
||||
///
|
||||
init(
|
||||
image: ImageAsset,
|
||||
style: IllustratedMessageStyle = .smallImage,
|
||||
title: String? = nil,
|
||||
message: String,
|
||||
@ViewBuilder accessory: () -> Accessory,
|
||||
) {
|
||||
self.init(
|
||||
image: image.swiftUIImage,
|
||||
style: style,
|
||||
title: title,
|
||||
message: message,
|
||||
accessory: accessory,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension IllustratedMessageView where Accessory == EmptyView {
|
||||
/// Initialize a `IllustratedMessageView`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - image: The image asset to display.
|
||||
/// - style: The style of the message view.
|
||||
/// - title: The title to display.
|
||||
/// - message: The message to display.
|
||||
///
|
||||
init(
|
||||
image: ImageAsset,
|
||||
style: IllustratedMessageStyle = .smallImage,
|
||||
title: String? = nil,
|
||||
message: String,
|
||||
) {
|
||||
self.init(
|
||||
image: image.swiftUIImage,
|
||||
style: style,
|
||||
title: title,
|
||||
message: message,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -26,6 +26,13 @@
|
||||
"testTimeoutsEnabled" : true
|
||||
},
|
||||
"testTargets" : [
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:BitwardenKit.xcodeproj",
|
||||
"identifier" : "11D20029373CEF56CBBCF0AA",
|
||||
"name" : "AuthenticatorBridgeKitTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Authenticator.xcodeproj",
|
||||
|
||||
@ -29,6 +29,13 @@
|
||||
"testTimeoutsEnabled" : true
|
||||
},
|
||||
"testTargets" : [
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:BitwardenKit.xcodeproj",
|
||||
"identifier" : "11D20029373CEF56CBBCF0AA",
|
||||
"name" : "AuthenticatorBridgeKitTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Authenticator.xcodeproj",
|
||||
|
||||
@ -54,6 +54,20 @@
|
||||
"name" : "BitwardenKitTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:BitwardenKit.xcodeproj",
|
||||
"identifier" : "0F0F8167EDD3A9370CA429CE",
|
||||
"name" : "BitwardenKitSnapshotTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:BitwardenKit.xcodeproj",
|
||||
"identifier" : "27C53FBF98252CF56973FD34",
|
||||
"name" : "BitwardenKitViewInspectorTests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"target" : {
|
||||
"containerPath" : "container:Bitwarden.xcodeproj",
|
||||
|
||||