Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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 @@ -380,7 +380,9 @@ private extension UNMutableNotificationContent {
convenience init(notice: Notice) {
self.init()

title = notice.notificationInfo?.title ?? notice.title
if let title = notice.notificationInfo?.title ?? notice.title {
self.title = title
}

if let body = notice.notificationInfo?.body {
self.body = body
Expand Down
41 changes: 39 additions & 2 deletions WooCommerce/Classes/Tools/Notices/Notice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct Notice {

/// The title that contains the reason for the notice
///
let title: String
let title: String?

/// An optional subtitle that contains a secondary description of the reason for the notice
///
Expand All @@ -35,7 +35,6 @@ struct Notice {
///
let actionHandler: (() -> Void)?


/// Designated Initializer
///
init(title: String,
Expand Down Expand Up @@ -65,3 +64,41 @@ extension Notice: Equatable {
lhs.actionTitle == rhs.actionTitle
}
}

/// Convenience initializers to init without a`title`
/// These initializers help to ensure that at least one of title/subtitle/message is non-nil.
///
extension Notice {
/// To init using `subtitle` and/or `message`
///
init(subtitle: String,
message: String? = nil,
feedbackType: UINotificationFeedbackGenerator.FeedbackType? = nil,
notificationInfo: NoticeNotificationInfo? = nil,
actionTitle: String? = nil,
actionHandler: ((() -> Void))? = nil) {
self.title = nil
self.subtitle = subtitle
self.message = message
self.feedbackType = feedbackType
self.notificationInfo = notificationInfo
self.actionTitle = actionTitle
self.actionHandler = actionHandler
}

/// To init using only `message`
///
init(message: String,
feedbackType: UINotificationFeedbackGenerator.FeedbackType? = nil,
notificationInfo: NoticeNotificationInfo? = nil,
actionTitle: String? = nil,
actionHandler: ((() -> Void))? = nil) {
self.title = nil
self.subtitle = nil
self.message = message
self.feedbackType = feedbackType
self.notificationInfo = notificationInfo
self.actionTitle = actionTitle
self.actionHandler = actionHandler
}
}
16 changes: 9 additions & 7 deletions WooCommerce/Classes/View Modifiers/View+NoticesModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ struct NoticeModifier: ViewModifier {
Spacer()
HStack(spacing: 0.0) {
VStack {
HStack {
Text(notice.title)
.lineLimit(notice.message.isNilOrEmpty ? 0 : 2)
Spacer()
if let title = notice.title {
HStack {
Text(title)
.lineLimit(notice.message.isNilOrEmpty ? 0 : 2)
Spacer()
}
.font(Constants.titleFont)
.foregroundColor(Constants.titleColor)
}
.font(Constants.titleFont)
.foregroundColor(Constants.titleColor)
if let subtitle = notice.subtitle {
HStack {
Text(subtitle)
Expand All @@ -81,7 +83,7 @@ struct NoticeModifier: ViewModifier {
}
if let message = notice.message {
HStack {
Text(message)
BoldableTextView(message)
Spacer()
}
.font(Constants.messageFont)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ final class CollapsibleShipmentCardViewModel: ObservableObject, Identifiable {
/// Child shipment rows, if the shipment has more than one quantity
let childShipmentRows: [SelectableShipmentRowViewModel]

var onSelectionChange: (() -> Void)?

var hasSelectedAnItem: Bool {
if mainShipmentRow.selected {
return true
}

return childShipmentRows
.filter { $0.selected }
.isNotEmpty
}

init(parentShipmentId: String,
childShipmentIds: [String],
item: ShippingLabelPackageItem,
Expand Down Expand Up @@ -47,13 +59,15 @@ private extension CollapsibleShipmentCardViewModel {
guard let self else { return }

childShipmentRows.forEach({ $0.setSelected(row.selected) })
onSelectionChange?()
}

childShipmentRows.forEach({
$0.onSelectedChange = { [weak self] row in
guard let self else { return }

mainShipmentRow.setSelected(false)
onSelectionChange?()
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Yosemite
struct WooShippingSplitShipmentsDetailView: View {
@Environment(\.dismiss) private var dismiss

let viewModel: WooShippingSplitShipmentsViewModel
@ObservedObject var viewModel: WooShippingSplitShipmentsViewModel

var body: some View {
NavigationView {
Expand Down Expand Up @@ -41,6 +41,10 @@ struct WooShippingSplitShipmentsDetailView: View {
}
}
}
.notice($viewModel.instructionsNotice, autoDismiss: false)
.onAppear {
viewModel.onAppear()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ final class WooShippingSplitShipmentsViewModel: ObservableObject {
"\(itemsWeightLabel) • \(itemsPriceLabel)"
}

@Published var selectedItemIDs: [String: [String]] = [:]

let shipmentCardViewModels: [CollapsibleShipmentCardViewModel]

@Published var instructionsNotice: Notice?

init(order: Order,
config: WooShippingConfig,
items: [ShippingLabelPackageItem],
Expand Down Expand Up @@ -70,6 +70,11 @@ final class WooShippingSplitShipmentsViewModel: ObservableObject {
}()

configureSectionHeader()
configureSelectionCallback()
}

func onAppear() {
showInstructionsNotice()
}

func selectAll() {
Expand All @@ -80,6 +85,34 @@ final class WooShippingSplitShipmentsViewModel: ObservableObject {
}

private extension WooShippingSplitShipmentsViewModel {
func configureSelectionCallback() {
shipmentCardViewModels.forEach { viewModel in
viewModel.onSelectionChange = { [weak self] in
self?.checkSelectionAndHideInstructions()
}
}
}

func showInstructionsNotice() {
if hasSelectedAnItem() == false {
instructionsNotice = Notice(message: Localization.SelectionInstructionsNotice.message,
feedbackType: .success,
actionTitle: Localization.SelectionInstructionsNotice.dismiss) { [weak self] in
self?.instructionsNotice = nil
}
}
}

func checkSelectionAndHideInstructions() {
if hasSelectedAnItem() {
instructionsNotice = nil
}
}

func hasSelectedAnItem() -> Bool {
shipmentCardViewModels.contains(where: { $0.hasSelectedAnItem })
}

/// Configures the labels in the section header.
///
func configureSectionHeader() {
Expand Down Expand Up @@ -113,6 +146,16 @@ private extension WooShippingSplitShipmentsViewModel {
// MARK: Constants
private extension WooShippingSplitShipmentsViewModel {
enum Localization {
enum SelectionInstructionsNotice {
static let message = NSLocalizedString("wooShipping.createLabels.splitShipment.SelectionInstructionsNotice.message",
value: "To split, select the items, and tap **move to new shipment** when the toolbar appears.",
comment: "Instructions to ask customer to select items to split during shipping label creation."
+ " The content inside two double asterisks **...** denote bolded text.")

static let dismiss = NSLocalizedString("wooShipping.createLabels.splitShipment.SelectionInstructionsNotice.dismiss",
value: "Dismiss",
comment: "Label of the button to dismiss the instructions notice in split shipments flow.")
}
static func itemsCount(_ count: Decimal) -> String {
return String.pluralize(count, singular: Localization.itemsCountSingularFormat, plural: Localization.itemsCountPluralFormat)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private extension WooShippingCreateLabelsView {
WooShippingPostPurchaseView(viewModel: postPurchase)
}

if let splitShipmentsViewModel = viewModel.splitShipmentsViewModel {
if !viewModel.canViewLabel, let splitShipmentsViewModel = viewModel.splitShipmentsViewModel {
WooShippingSplitShipmentsRow(viewModel: splitShipmentsViewModel)
}

Expand Down