Adding `verticalOffset` property to FluentNotification (#2045)
This commit is contained in:
Родитель
fe0730c427
Коммит
a7c83b5618
|
@ -49,6 +49,7 @@ struct NotificationDemoView: View {
|
|||
@State var showFromBottom: Bool = true
|
||||
@State var showBackgroundGradient: Bool = false
|
||||
@State var useCustomTheme: Bool = false
|
||||
@State var verticalOffset: CGFloat = 0.0
|
||||
@ObservedObject var fluentTheme: FluentTheme = .shared
|
||||
let customTheme: FluentTheme = {
|
||||
let foregroundColor = UIColor(light: GlobalTokens.sharedColor(.lavender, .shade30),
|
||||
|
@ -175,7 +176,7 @@ struct NotificationDemoView: View {
|
|||
Alert(title: Text("Button tapped"))
|
||||
})
|
||||
|
||||
Button("Show") {
|
||||
Button("Show Notification") {
|
||||
if isPresented == false {
|
||||
isPresented = true
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
|
||||
|
@ -183,99 +184,30 @@ struct NotificationDemoView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.fixedSize()
|
||||
.padding()
|
||||
.buttonStyle(FluentButtonStyle(style: .accent))
|
||||
.fixedSize()
|
||||
.padding()
|
||||
|
||||
ScrollView {
|
||||
Group {
|
||||
Group {
|
||||
VStack(spacing: 0) {
|
||||
Text("Content")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.font(.title)
|
||||
Divider()
|
||||
}
|
||||
|
||||
TextField("Title", text: $title)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
|
||||
TextField("Message", text: $message)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
|
||||
TextField("Action Button Title", text: $actionButtonTitle)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
|
||||
FluentUIDemoToggle(titleKey: "Has Attributed Text: Strikethrough", isOn: $hasBlueStrikethroughAttribute)
|
||||
FluentUIDemoToggle(titleKey: "Has Attributed Text: Large Red Papyrus Font", isOn: $hasLargeRedPapyrusFontAttribute)
|
||||
FluentUIDemoToggle(titleKey: "Set image", isOn: $showImage)
|
||||
FluentUIDemoToggle(titleKey: "Set trailing image", isOn: $showTrailingImage)
|
||||
}
|
||||
|
||||
Group {
|
||||
VStack(spacing: 0) {
|
||||
Text("Action")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.font(.title)
|
||||
Divider()
|
||||
}
|
||||
FluentUIDemoToggle(titleKey: "Has Action Button Action", isOn: $hasActionButtonAction)
|
||||
FluentUIDemoToggle(titleKey: "Show Default Dismiss Button", isOn: $showDefaultDismissActionButton)
|
||||
FluentUIDemoToggle(titleKey: "Has Message Action", isOn: $hasMessageAction)
|
||||
}
|
||||
|
||||
Group {
|
||||
VStack(spacing: 0) {
|
||||
Text("Style")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.font(.title)
|
||||
Divider()
|
||||
}
|
||||
|
||||
Picker(selection: $style, label: EmptyView()) {
|
||||
Text(".primaryToast").tag(MSFNotificationStyle.primaryToast)
|
||||
Text(".neutralToast").tag(MSFNotificationStyle.neutralToast)
|
||||
Text(".primaryBar").tag(MSFNotificationStyle.primaryBar)
|
||||
Text(".primaryOutlineBar").tag(MSFNotificationStyle.primaryOutlineBar)
|
||||
Text(".neutralBar").tag(MSFNotificationStyle.neutralBar)
|
||||
Text(".dangerToast").tag(MSFNotificationStyle.dangerToast)
|
||||
Text(".warningToast").tag(MSFNotificationStyle.warningToast)
|
||||
}
|
||||
.labelsHidden()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
FluentUIDemoToggle(titleKey: "Override Tokens (Image Color and Horizontal Spacing)", isOn: $overrideTokens)
|
||||
FluentUIDemoToggle(titleKey: "Flexible Width Toast", isOn: $isFlexibleWidthToast)
|
||||
FluentUIDemoToggle(titleKey: "Present From Bottom", isOn: $showFromBottom)
|
||||
FluentUIDemoToggle(titleKey: "Background Gradient", isOn: $showBackgroundGradient)
|
||||
FluentUIDemoToggle(titleKey: "Custom theme", isOn: $useCustomTheme)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
notificationSettings
|
||||
}
|
||||
.presentNotification(isPresented: $isPresented,
|
||||
isBlocking: false) {
|
||||
FluentNotification(style: style,
|
||||
isFlexibleWidthToast: $isFlexibleWidthToast.wrappedValue,
|
||||
message: hasMessage ? message : nil,
|
||||
attributedMessage: hasAttribute && hasMessage ? attributedMessage : nil,
|
||||
isPresented: $isPresented,
|
||||
title: hasTitle ? title : nil,
|
||||
attributedTitle: hasAttribute && hasTitle ? attributedTitle : nil,
|
||||
image: image,
|
||||
trailingImage: trailingImage,
|
||||
trailingImageAccessibilityLabel: trailingImageLabel,
|
||||
actionButtonTitle: actionButtonTitle,
|
||||
actionButtonAction: actionButtonAction,
|
||||
showDefaultDismissActionButton: showDefaultDismissActionButton,
|
||||
messageButtonAction: messageButtonAction,
|
||||
showFromBottom: showFromBottom)
|
||||
isFlexibleWidthToast: $isFlexibleWidthToast.wrappedValue,
|
||||
message: hasMessage ? message : nil,
|
||||
attributedMessage: hasAttribute && hasMessage ? attributedMessage : nil,
|
||||
isPresented: $isPresented,
|
||||
title: hasTitle ? title : nil,
|
||||
attributedTitle: hasAttribute && hasTitle ? attributedTitle : nil,
|
||||
image: image,
|
||||
trailingImage: trailingImage,
|
||||
trailingImageAccessibilityLabel: trailingImageLabel,
|
||||
actionButtonTitle: actionButtonTitle,
|
||||
actionButtonAction: actionButtonAction,
|
||||
showDefaultDismissActionButton: showDefaultDismissActionButton,
|
||||
messageButtonAction: messageButtonAction,
|
||||
showFromBottom: showFromBottom,
|
||||
verticalOffset: verticalOffset)
|
||||
.backgroundGradient(showBackgroundGradient ? backgroundGradient : nil)
|
||||
.overrideTokens($overrideTokens.wrappedValue ? notificationOverrideTokens : nil)
|
||||
}
|
||||
|
@ -283,6 +215,81 @@ struct NotificationDemoView: View {
|
|||
.tint(Color(theme.color(.brandForeground1)))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var notificationSettings: some View {
|
||||
FluentList {
|
||||
FluentListSection("Content") {
|
||||
LabeledContent {
|
||||
TextField("Title", text: $title)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.multilineTextAlignment(.trailing)
|
||||
} label: {
|
||||
Text("Title")
|
||||
}
|
||||
|
||||
LabeledContent {
|
||||
TextField("Message", text: $message)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.multilineTextAlignment(.trailing)
|
||||
} label: {
|
||||
Text("Message")
|
||||
}
|
||||
|
||||
LabeledContent {
|
||||
TextField("Action Button Title", text: $actionButtonTitle)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.multilineTextAlignment(.trailing)
|
||||
} label: {
|
||||
Text("Action Button Title")
|
||||
}
|
||||
|
||||
LabeledContent {
|
||||
TextField("Offset", value: $verticalOffset, format: FloatingPointFormatStyle())
|
||||
.keyboardType(.numberPad)
|
||||
.multilineTextAlignment(.trailing)
|
||||
} label: {
|
||||
Text("Vertical Offset")
|
||||
}
|
||||
|
||||
Toggle("Has Attributed Text: Strikethrough", isOn: $hasBlueStrikethroughAttribute)
|
||||
Toggle("Has Attributed Text: Large Red Papyrus Font", isOn: $hasLargeRedPapyrusFontAttribute)
|
||||
Toggle("Set image", isOn: $showImage)
|
||||
Toggle("Set trailing image", isOn: $showTrailingImage)
|
||||
}
|
||||
|
||||
FluentListSection("Action") {
|
||||
Toggle("Has Action Button Action", isOn: $hasActionButtonAction)
|
||||
Toggle("Show Default Dismiss Button", isOn: $showDefaultDismissActionButton)
|
||||
Toggle("Has Message Action", isOn: $hasMessageAction)
|
||||
}
|
||||
|
||||
FluentListSection("Style") {
|
||||
|
||||
Picker(selection: $style, label: EmptyView()) {
|
||||
Text(".primaryToast").tag(MSFNotificationStyle.primaryToast)
|
||||
Text(".neutralToast").tag(MSFNotificationStyle.neutralToast)
|
||||
Text(".primaryBar").tag(MSFNotificationStyle.primaryBar)
|
||||
Text(".primaryOutlineBar").tag(MSFNotificationStyle.primaryOutlineBar)
|
||||
Text(".neutralBar").tag(MSFNotificationStyle.neutralBar)
|
||||
Text(".dangerToast").tag(MSFNotificationStyle.dangerToast)
|
||||
Text(".warningToast").tag(MSFNotificationStyle.warningToast)
|
||||
}
|
||||
.labelsHidden()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Toggle("Override Tokens (Image Color and Horizontal Spacing)", isOn: $overrideTokens)
|
||||
Toggle("Flexible Width Toast", isOn: $isFlexibleWidthToast)
|
||||
Toggle("Present From Bottom", isOn: $showFromBottom)
|
||||
Toggle("Background Gradient", isOn: $showBackgroundGradient)
|
||||
Toggle("Custom theme", isOn: $useCustomTheme)
|
||||
}
|
||||
}
|
||||
.fluentListStyle(.insetGrouped)
|
||||
}
|
||||
|
||||
private var backgroundGradient: LinearGradientInfo {
|
||||
// It's a lovely blue-to-pink gradient
|
||||
let colors: [UIColor] = [UIColor(light: GlobalTokens.sharedColor(.pink, .tint50),
|
||||
|
|
|
@ -80,6 +80,7 @@ public struct FluentNotification: View, TokenizedControlView {
|
|||
/// - showDefaultDismissActionButton: Bool to control if the Notification has a dismiss action by default.
|
||||
/// - messageButtonAction: Action to be dispatched by tapping on the toast/bar notification.
|
||||
/// - showFromBottom: Defines whether the notification shows from the bottom of the presenting view or the top.
|
||||
/// - verticalOffset: How much to vertically offset the notification from its default position.
|
||||
public init(style: MSFNotificationStyle,
|
||||
shouldSelfPresent: Bool = true,
|
||||
isFlexibleWidthToast: Bool = false,
|
||||
|
@ -95,7 +96,8 @@ public struct FluentNotification: View, TokenizedControlView {
|
|||
actionButtonAction: (() -> Void)? = nil,
|
||||
showDefaultDismissActionButton: Bool? = nil,
|
||||
messageButtonAction: (() -> Void)? = nil,
|
||||
showFromBottom: Bool = true) {
|
||||
showFromBottom: Bool = true,
|
||||
verticalOffset: CGFloat = 0.0) {
|
||||
let state = MSFNotificationStateImpl(style: style,
|
||||
message: message,
|
||||
attributedMessage: attributedMessage,
|
||||
|
@ -108,7 +110,8 @@ public struct FluentNotification: View, TokenizedControlView {
|
|||
actionButtonAction: actionButtonAction,
|
||||
showDefaultDismissActionButton: showDefaultDismissActionButton,
|
||||
messageButtonAction: messageButtonAction,
|
||||
showFromBottom: showFromBottom)
|
||||
showFromBottom: showFromBottom,
|
||||
verticalOffset: verticalOffset)
|
||||
self.state = state
|
||||
self.shouldSelfPresent = shouldSelfPresent
|
||||
self.isFlexibleWidthToast = isFlexibleWidthToast && style.isToast
|
||||
|
@ -355,7 +358,7 @@ public struct FluentNotification: View, TokenizedControlView {
|
|||
withAnimation(.spring(response: state.style.animationDurationForShow / 2.0,
|
||||
dampingFraction: state.style.animationDampingRatio,
|
||||
blendDuration: 0)) {
|
||||
bottomOffset = 0
|
||||
bottomOffset = -state.verticalOffset
|
||||
opacity = 1
|
||||
}
|
||||
}
|
||||
|
@ -400,6 +403,7 @@ class MSFNotificationStateImpl: ControlState, MSFNotificationState {
|
|||
@Published var showDefaultDismissActionButton: Bool
|
||||
@Published var showFromBottom: Bool
|
||||
@Published var backgroundGradient: LinearGradientInfo?
|
||||
@Published var verticalOffset: CGFloat
|
||||
|
||||
/// Title to display in the action button on the trailing edge of the control.
|
||||
///
|
||||
|
@ -430,7 +434,8 @@ class MSFNotificationStateImpl: ControlState, MSFNotificationState {
|
|||
actionButtonAction: nil,
|
||||
showDefaultDismissActionButton: nil,
|
||||
messageButtonAction: nil,
|
||||
showFromBottom: true)
|
||||
showFromBottom: true,
|
||||
verticalOffset: 0.0)
|
||||
}
|
||||
|
||||
init(style: MSFNotificationStyle,
|
||||
|
@ -445,7 +450,8 @@ class MSFNotificationStateImpl: ControlState, MSFNotificationState {
|
|||
actionButtonAction: (() -> Void)? = nil,
|
||||
showDefaultDismissActionButton: Bool? = nil,
|
||||
messageButtonAction: (() -> Void)? = nil,
|
||||
showFromBottom: Bool = true) {
|
||||
showFromBottom: Bool = true,
|
||||
verticalOffset: CGFloat) {
|
||||
self.style = style
|
||||
self.message = message
|
||||
self.attributedMessage = attributedMessage
|
||||
|
@ -459,6 +465,7 @@ class MSFNotificationStateImpl: ControlState, MSFNotificationState {
|
|||
self.messageButtonAction = messageButtonAction
|
||||
self.showFromBottom = showFromBottom
|
||||
self.showDefaultDismissActionButton = showDefaultDismissActionButton ?? style.isToast
|
||||
self.verticalOffset = verticalOffset
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче