Merge branch 'develop' into feature/listLeftVariableIconWithRightCaretAllTextLinks
* develop: update for review Review Changes Moved molecule to Miscellaneous group. Review changes for kvo cleanliness Move to ready logic instead of page dependency Removed redundant method call. Code changes after review. 22352(iOS - List star rating) initial commit.
This commit is contained in:
commit
82f6d1c7f4
@ -235,6 +235,8 @@
|
|||||||
AA71AD4024A32FE700ACA76F /* HeadersH2Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA71AD3F24A32FE700ACA76F /* HeadersH2Link.swift */; };
|
AA71AD4024A32FE700ACA76F /* HeadersH2Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA71AD3F24A32FE700ACA76F /* HeadersH2Link.swift */; };
|
||||||
AA7F32AB246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F32AA246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift */; };
|
AA7F32AB246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F32AA246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift */; };
|
||||||
AA7F32AD246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F32AC246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift */; };
|
AA7F32AD246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F32AC246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift */; };
|
||||||
|
AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F47722541AD560015A2C1 /* ListStarRatingModel.swift */; };
|
||||||
|
AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7F47752541AD6A0015A2C1 /* ListStarRating.swift */; };
|
||||||
AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */; };
|
AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */; };
|
||||||
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */; };
|
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */; };
|
||||||
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */; };
|
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */; };
|
||||||
@ -776,6 +778,8 @@
|
|||||||
AA71AD3F24A32FE700ACA76F /* HeadersH2Link.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Link.swift; sourceTree = "<group>"; };
|
AA71AD3F24A32FE700ACA76F /* HeadersH2Link.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Link.swift; sourceTree = "<group>"; };
|
||||||
AA7F32AA246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAllTextAndLinksModel.swift; sourceTree = "<group>"; };
|
AA7F32AA246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAllTextAndLinksModel.swift; sourceTree = "<group>"; };
|
||||||
AA7F32AC246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAllTextAndLinks.swift; sourceTree = "<group>"; };
|
AA7F32AC246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAllTextAndLinks.swift; sourceTree = "<group>"; };
|
||||||
|
AA7F47722541AD560015A2C1 /* ListStarRatingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStarRatingModel.swift; sourceTree = "<group>"; };
|
||||||
|
AA7F47752541AD6A0015A2C1 /* ListStarRating.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStarRating.swift; sourceTree = "<group>"; };
|
||||||
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = "<group>"; };
|
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||||
AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinksModel.swift; sourceTree = "<group>"; };
|
AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinksModel.swift; sourceTree = "<group>"; };
|
||||||
AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinks.swift; sourceTree = "<group>"; };
|
AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinks.swift; sourceTree = "<group>"; };
|
||||||
@ -1363,6 +1367,8 @@
|
|||||||
children = (
|
children = (
|
||||||
AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */,
|
AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */,
|
||||||
AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */,
|
AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */,
|
||||||
|
AA7F47722541AD560015A2C1 /* ListStarRatingModel.swift */,
|
||||||
|
AA7F47752541AD6A0015A2C1 /* ListStarRating.swift */,
|
||||||
);
|
);
|
||||||
path = Miscellaneous;
|
path = Miscellaneous;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2661,6 +2667,8 @@
|
|||||||
011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */,
|
011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */,
|
||||||
D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */,
|
D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */,
|
||||||
8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */,
|
8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */,
|
||||||
|
AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */,
|
||||||
|
AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */,
|
||||||
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
|
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
|
||||||
D2ED27EB254B0CE700A1C293 /* UIAlertActionStyle+Codable.swift in Sources */,
|
D2ED27EB254B0CE700A1C293 /* UIAlertActionStyle+Codable.swift in Sources */,
|
||||||
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
||||||
|
|||||||
@ -8,88 +8,60 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// Temporary, until we can move page checking logic into isReady of topAlertOperation.
|
public extension MVMCoreAlertHandler {
|
||||||
@objcMembers public class NotificationPagesOperation: Operation {
|
|
||||||
public let pages: [String]
|
/// Re-evaluates the queue operations
|
||||||
|
@objc func reevaluteQueue() {
|
||||||
public init(with pages: [String]) {
|
var highestReadyOperation: MVMCoreTopAlertOperation?
|
||||||
self.pages = pages
|
var executingOperation: MVMCoreTopAlertOperation?
|
||||||
|
for case let operation as MVMCoreTopAlertOperation in topAlertQueue.operations {
|
||||||
|
guard !operation.isCancelled,
|
||||||
|
!operation.isFinished else { continue }
|
||||||
|
if operation.isReady,
|
||||||
|
highestReadyOperation == nil || operation.queuePriority.rawValue > highestReadyOperation!.queuePriority.rawValue {
|
||||||
|
highestReadyOperation = operation
|
||||||
|
}
|
||||||
|
if operation.isExecuting {
|
||||||
|
executingOperation = operation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guard let currentOperation = executingOperation else { return }
|
||||||
|
|
||||||
|
// Cancel the executing operation if it is no longer ready to run. Re-add for later if it is persistent.
|
||||||
|
guard currentOperation.isReady else {
|
||||||
|
currentOperation.reAddAfterCancel = currentOperation.topAlertObject.persistent
|
||||||
|
currentOperation.cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the highest priority operation is not executing, and the executing operation is persistent, cancel it.
|
||||||
|
if let newOperation = highestReadyOperation,
|
||||||
|
currentOperation != newOperation,
|
||||||
|
currentOperation.topAlertObject.persistent {
|
||||||
|
currentOperation.reAddAfterCancel = true
|
||||||
|
currentOperation.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override var isReady: Bool {
|
/// Registers to know when pages change.
|
||||||
get {
|
@objc func registerForPageChanges() {
|
||||||
return super.isReady && isCancelled
|
MVMCoreNavigationHandler.shared()?.addDelegate(self)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move this type of logic into isReady for the top alert operation... then can remove this dependency operation.
|
extension MVMCoreAlertHandler: MVMCorePresentationDelegateProtocol {
|
||||||
public extension MVMCoreAlertHandler {
|
// Update displayable for each top alert operation when page type changes, in top queue priority order.
|
||||||
|
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
|
||||||
/// Adds a page type dependency to the operation
|
guard navigationController == MVMCoreUISplitViewController.main()?.navigationController else { return }
|
||||||
@objc func addPagesDependency(to operation: MVMCoreTopAlertOperation) {
|
let pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType
|
||||||
// This notification may only show for certain pages.
|
topAlertQueue.operations.compactMap {
|
||||||
guard let pages = operation.topAlertObject.json?.optionalArrayForKey("pages") as? [String],
|
$0 as? MVMCoreTopAlertOperation
|
||||||
pages.count > 0 else { return }
|
}.sorted {
|
||||||
let pagesOperation = NotificationPagesOperation(with: pages)
|
$0.queuePriority.rawValue > $1.queuePriority.rawValue
|
||||||
pageOperations.addOperation(pagesOperation)
|
}.forEach {
|
||||||
operation.addDependency(pagesOperation)
|
$0.updateDisplayable(byPageType: pageType)
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the pages requirement for the operation
|
|
||||||
@objc func updatePages(for operation: MVMCoreTopAlertOperation, with topAlertObject: MVMCoreTopAlertObject) {
|
|
||||||
// Add new dependencies, remove old.
|
|
||||||
let previousPages = operation.dependencies.filter { $0 as? NotificationPagesOperation != nil }
|
|
||||||
addPagesDependency(to: operation)
|
|
||||||
for pageOperation in previousPages {
|
|
||||||
pageOperation.cancel()
|
|
||||||
operation.removeDependency(pageOperation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handles page dependencies for all top alerts with the new pageType
|
|
||||||
@objc func handleAllPagesDependency(for pageType: String?) {
|
|
||||||
var currentOperation: MVMCoreTopAlertOperation? = nil
|
|
||||||
for case let operation as MVMCoreTopAlertOperation in topAlertQueue.operations {
|
|
||||||
// Handle the currently executing opration last to avoid race conditions.
|
|
||||||
guard !operation.isExecuting else {
|
|
||||||
currentOperation = operation
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
handlePageDependency(for: operation, with: pageType)
|
|
||||||
}
|
|
||||||
if let operation = currentOperation {
|
|
||||||
handlePageDependency(for: operation, with: pageType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the operation based on the page type and its dependencies.
|
|
||||||
@objc func handlePageDependency(for operation: MVMCoreTopAlertOperation, with pageType: String?) {
|
|
||||||
guard !operation.isCancelled else { return }
|
|
||||||
|
|
||||||
if let pages = operation.topAlertObject.json?.optionalArrayForKey("pages") as? [String],
|
|
||||||
pages.count > 0,
|
|
||||||
(pageType == nil || !pages.contains(pageType!)) {
|
|
||||||
if let dependency = operation.dependencies.first(where: { $0.isFinished && ($0 as? NotificationPagesOperation)?.pages == pages }) {
|
|
||||||
// Re-add the dependency if it was previously cancelled.
|
|
||||||
let pagesOperation = NotificationPagesOperation(with: pages)
|
|
||||||
pageOperations.addOperation(pagesOperation)
|
|
||||||
operation.addDependency(pagesOperation)
|
|
||||||
operation.removeDependency(dependency)
|
|
||||||
}
|
|
||||||
if operation.isExecuting {
|
|
||||||
// If the current running operation should not show on the current page, cancel it. If it's persistent, re-add it
|
|
||||||
operation.reAddAfterCancel = operation.topAlertObject.persistent
|
|
||||||
operation.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel any dependency if it contains the current page.
|
|
||||||
guard let pageType = pageType else { return }
|
|
||||||
for case let operation as NotificationPagesOperation in operation.dependencies {
|
|
||||||
if operation.pages.contains(pageType) {
|
|
||||||
operation.cancel()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
reevaluteQueue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,9 +23,6 @@
|
|||||||
// An operation queue for top alerts
|
// An operation queue for top alerts
|
||||||
@property (nonnull, strong, nonatomic) NSOperationQueue *topAlertQueue;
|
@property (nonnull, strong, nonatomic) NSOperationQueue *topAlertQueue;
|
||||||
|
|
||||||
/// Stores any page dependencies for top alerts
|
|
||||||
@property (nonnull, strong, nonatomic) NSOperationQueue *pageOperations;
|
|
||||||
|
|
||||||
/// Returns the shared instance of this singleton
|
/// Returns the shared instance of this singleton
|
||||||
+ (nullable instancetype)sharedAlertHandler;
|
+ (nullable instancetype)sharedAlertHandler;
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
#import <MVMCore/MVMCoreJSONConstants.h>
|
#import <MVMCore/MVMCoreJSONConstants.h>
|
||||||
#import <MVMCore/NSDictionary+MFConvenience.h>
|
#import <MVMCore/NSDictionary+MFConvenience.h>
|
||||||
#import <MVMCore/NSArray+MFConvenience.h>
|
#import <MVMCore/NSArray+MFConvenience.h>
|
||||||
#import <MVMCore/MVMCore-Swift.h>
|
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
||||||
|
|
||||||
@interface MVMCoreAlertHandler ()
|
@interface MVMCoreAlertHandler ()
|
||||||
|
|
||||||
@ -42,7 +42,7 @@
|
|||||||
self.popupAlertQueue.maxConcurrentOperationCount = 1;
|
self.popupAlertQueue.maxConcurrentOperationCount = 1;
|
||||||
self.topAlertQueue = [[NSOperationQueue alloc] init];
|
self.topAlertQueue = [[NSOperationQueue alloc] init];
|
||||||
self.topAlertQueue.maxConcurrentOperationCount = 1;
|
self.topAlertQueue.maxConcurrentOperationCount = 1;
|
||||||
self.pageOperations = [[NSOperationQueue alloc] init];
|
[self registerForPageChanges];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -172,17 +172,11 @@
|
|||||||
alertOperation = nil;
|
alertOperation = nil;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[self.topAlertQueue addOperation:alertOperation];
|
NSString *currentPageType = ((UIViewController<MVMCoreViewControllerProtocol> *)[[MVMCoreUISplitViewController mainSplitViewController] getCurrentDetailViewController]).pageType;
|
||||||
|
[alertOperation updateDisplayableByPageType:currentPageType];
|
||||||
|
|
||||||
// If the current running operation is persistent and has a lower queue priority then the added operation, cancel it and re-add it.
|
[self.topAlertQueue addOperation:alertOperation];
|
||||||
for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) {
|
[self reevaluteQueue];
|
||||||
|
|
||||||
if (operation.isExecuting && !operation.isCancelled && operation.topAlertObject.persistent && operation.queuePriority < alertOperation.queuePriority && alertOperation.isReady) {
|
|
||||||
operation.reAddAfterCancel = YES;
|
|
||||||
[operation cancel];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showTopAlertWithObject:(nullable MVMCoreTopAlertObject *)topAlertObject {
|
- (void)showTopAlertWithObject:(nullable MVMCoreTopAlertObject *)topAlertObject {
|
||||||
|
|||||||
@ -203,6 +203,7 @@ import Foundation
|
|||||||
MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageListItem.self, viewModelClass: ListFourColumnDataUsageListItemModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageListItem.self, viewModelClass: ListFourColumnDataUsageListItemModel.self)
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: ListProgressBarThin.self, viewModelClass: ListProgressBarThinModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: ListProgressBarThin.self, viewModelClass: ListProgressBarThinModel.self)
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: ListStoreLocator.self, viewModelClass: ListStoreLocatorModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: ListStoreLocator.self, viewModelClass: ListStoreLocatorModel.self)
|
||||||
|
MoleculeObjectMapping.shared()?.register(viewClass: ListStarRating.self, viewModelClass: ListStarRatingModel.self)
|
||||||
|
|
||||||
// MARK:- Designed Section Dividers
|
// MARK:- Designed Section Dividers
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self)
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// ListStarRating.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Lekshmi S on 22/10/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@objcMembers open class ListStarRating: TableViewCell {
|
||||||
|
//-----------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//-----------------------------------------------------
|
||||||
|
public let stars = Stars()
|
||||||
|
public var reviewsCount = Label(fontStyle: .RegularBodySmall)
|
||||||
|
public lazy var stack: Stack<StackModel> = {
|
||||||
|
return Stack<StackModel>.createStack(with: [(view: stars, model: StackItemModel(horizontalAlignment: .fill)),
|
||||||
|
(view: reviewsCount, model: StackItemModel(horizontalAlignment: .leading))],
|
||||||
|
axis: .horizontal, spacing: Padding.Two)
|
||||||
|
}()
|
||||||
|
|
||||||
|
//-----------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//-----------------------------------------------------
|
||||||
|
override open func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
addMolecule(stack)
|
||||||
|
stack.restack()
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------
|
||||||
|
// MARK: - Molecule
|
||||||
|
//----------------------------------------------------
|
||||||
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
|
guard let model = model as? ListStarRatingModel else { return }
|
||||||
|
stars.set(with: model.stars, delegateObject, additionalData)
|
||||||
|
reviewsCount.set(with: model.reviewsCount, delegateObject, additionalData)
|
||||||
|
updateAccessibilityLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
|
return 90
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Accessibility
|
||||||
|
func updateAccessibilityLabel() {
|
||||||
|
isAccessibilityElement = true
|
||||||
|
var message = ""
|
||||||
|
if let starsLabel = stars.accessibilityLabel {
|
||||||
|
message += starsLabel + ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
if let reviewsCountLabelText = reviewsCount.text, let reviewText = MVMCoreUIUtility.hardcodedString(withKey: "review_text") {
|
||||||
|
message += reviewsCountLabelText + reviewText
|
||||||
|
}
|
||||||
|
accessibilityLabel = message
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// ListStarRatingModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Lekshmi S on 22/10/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
open class ListStarRatingModel: ListItemModel, MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
public static var identifier: String = "listStarRating"
|
||||||
|
public var stars: StarsModel
|
||||||
|
public var reviewsCount: LabelModel
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
public init(stars: StarsModel, reviewsCount: LabelModel) {
|
||||||
|
self.stars = stars
|
||||||
|
self.reviewsCount = reviewsCount
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case moleculeName
|
||||||
|
case stars
|
||||||
|
case reviewsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
required public init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
stars = try typeContainer.decode(StarsModel.self, forKey: .stars)
|
||||||
|
reviewsCount = try typeContainer.decode(LabelModel.self, forKey: .reviewsCount)
|
||||||
|
try super.init(from: decoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func encode(to encoder: Encoder) throws {
|
||||||
|
try super.encode(to: encoder)
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encode(moleculeName, forKey: .moleculeName)
|
||||||
|
try container.encode(stars, forKey: .stars)
|
||||||
|
try container.encode(reviewsCount, forKey: .reviewsCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -92,3 +92,4 @@
|
|||||||
"star" = "Star";
|
"star" = "Star";
|
||||||
"star_percent" = "%d percent progress";
|
"star_percent" = "%d percent progress";
|
||||||
"stars_filled" = "%.1f out of %d stars";
|
"stars_filled" = "%.1f out of %d stars";
|
||||||
|
"review_text" = " reviews";
|
||||||
|
|||||||
@ -70,3 +70,4 @@
|
|||||||
"star" = "Estrella";
|
"star" = "Estrella";
|
||||||
"star_percent" = "%@ porcentaje de progreso";
|
"star_percent" = "%@ porcentaje de progreso";
|
||||||
"stars_filled" = "%.1f de %d estrellas";
|
"stars_filled" = "%.1f de %d estrellas";
|
||||||
|
"review_text" = " críticas";
|
||||||
|
|||||||
@ -75,3 +75,4 @@
|
|||||||
"star" = "Estrella";
|
"star" = "Estrella";
|
||||||
"star_percent" = "%@ porcentaje de progreso";
|
"star_percent" = "%@ porcentaje de progreso";
|
||||||
"stars_filled" = "%.1f de %d estrellas";
|
"stars_filled" = "%.1f de %d estrellas";
|
||||||
|
"review_text" = " críticas";
|
||||||
|
|||||||
@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
@property (readonly, getter=isPaused) BOOL paused;
|
@property (readonly, getter=isPaused) BOOL paused;
|
||||||
|
|
||||||
|
/// A bool for if this top alert can be displayed. It is only ready if true.
|
||||||
|
@property (nonatomic, getter=isDisplayable) BOOL displayable;
|
||||||
|
|
||||||
@property (nonatomic) BOOL reAddAfterCancel;
|
@property (nonatomic) BOOL reAddAfterCancel;
|
||||||
|
|
||||||
@property (nonnull, nonatomic, strong) MVMCoreTopAlertObject *topAlertObject;
|
@property (nonnull, nonatomic, strong) MVMCoreTopAlertObject *topAlertObject;
|
||||||
@ -24,6 +27,9 @@
|
|||||||
/// Updates the operation with a new object
|
/// Updates the operation with a new object
|
||||||
- (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject;
|
- (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject;
|
||||||
|
|
||||||
|
/// Updates the operation isDisplayable based on the page type.
|
||||||
|
- (void)updateDisplayableByPageType:(nullable NSString *)pageType;
|
||||||
|
|
||||||
// Pauses the operation. Temporarily removes any alert.
|
// Pauses the operation. Temporarily removes any alert.
|
||||||
- (void)pause;
|
- (void)pause;
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,13 @@
|
|||||||
#import "MVMCoreTopAlertObject.h"
|
#import "MVMCoreTopAlertObject.h"
|
||||||
#import "MVMCoreAlertHandler.h"
|
#import "MVMCoreAlertHandler.h"
|
||||||
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
||||||
|
#import <MVMCoreUI/MVMCoreUISplitViewController.h>
|
||||||
|
|
||||||
@interface MVMCoreTopAlertOperation () {
|
@interface MVMCoreTopAlertOperation () {
|
||||||
__block BOOL _paused;
|
__block BOOL _paused;
|
||||||
__block BOOL _displayed;
|
__block BOOL _displayed;
|
||||||
__block BOOL _animating;
|
__block BOOL _animating;
|
||||||
|
__block BOOL _displayable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (readwrite, getter=isPaused) BOOL paused;
|
@property (readwrite, getter=isPaused) BOOL paused;
|
||||||
@ -25,6 +27,7 @@
|
|||||||
@property (strong, nonatomic) dispatch_queue_t pausedQueue;
|
@property (strong, nonatomic) dispatch_queue_t pausedQueue;
|
||||||
@property (strong, nonatomic) dispatch_queue_t displayedQueue;
|
@property (strong, nonatomic) dispatch_queue_t displayedQueue;
|
||||||
@property (strong, nonatomic) dispatch_queue_t animatingQueue;
|
@property (strong, nonatomic) dispatch_queue_t animatingQueue;
|
||||||
|
@property (strong, nonatomic) dispatch_queue_t displayableQueue;
|
||||||
|
|
||||||
@property (nonatomic, strong) dispatch_source_t timerSource;
|
@property (nonatomic, strong) dispatch_source_t timerSource;
|
||||||
|
|
||||||
@ -39,6 +42,8 @@
|
|||||||
self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT);
|
self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT);
|
||||||
self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT);
|
self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT);
|
||||||
self.animatingQueue = dispatch_queue_create("animating", DISPATCH_QUEUE_CONCURRENT);
|
self.animatingQueue = dispatch_queue_create("animating", DISPATCH_QUEUE_CONCURRENT);
|
||||||
|
self.displayableQueue = dispatch_queue_create("displayable", DISPATCH_QUEUE_CONCURRENT);
|
||||||
|
self.displayable = YES;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -66,6 +71,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)updateDisplayableByPageType:(nullable NSString *)pageType {
|
||||||
|
NSArray <NSString *>*pages = [self.topAlertObject.json array:@"pages"];
|
||||||
|
if (pages.count == 0) {
|
||||||
|
self.displayable = YES;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pageType.length == 0) {
|
||||||
|
self.displayable = NO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.displayable = [pages containsObject:pageType];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)isPaused {
|
- (BOOL)isPaused {
|
||||||
__block BOOL isPaused;
|
__block BOOL isPaused;
|
||||||
dispatch_sync(self.pausedQueue, ^{
|
dispatch_sync(self.pausedQueue, ^{
|
||||||
@ -108,6 +126,37 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (BOOL)isDisplayable {
|
||||||
|
__block BOOL isDisplayable;
|
||||||
|
dispatch_sync(self.displayableQueue, ^{
|
||||||
|
isDisplayable = self->_displayable;
|
||||||
|
});
|
||||||
|
return isDisplayable;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDisplayable:(BOOL)displayable {
|
||||||
|
if (displayable != self.isDisplayable) {
|
||||||
|
BOOL isReady = [super isReady];
|
||||||
|
if (isReady) {
|
||||||
|
[self willChangeValueForKey:@"isReady"];
|
||||||
|
}
|
||||||
|
dispatch_barrier_async(self.displayableQueue, ^{
|
||||||
|
self->_displayable = displayable;
|
||||||
|
});
|
||||||
|
if (isReady) {
|
||||||
|
[self didChangeValueForKey:@"isReady"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isReady {
|
||||||
|
if (self.isCancelled) {
|
||||||
|
return [super isReady];
|
||||||
|
}
|
||||||
|
return [super isReady] && self.isDisplayable;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)main {
|
- (void)main {
|
||||||
|
|
||||||
// Always check for cancellation before launching the task.
|
// Always check for cancellation before launching the task.
|
||||||
@ -251,6 +300,7 @@
|
|||||||
copyObject.topAlertObject = self.topAlertObject;
|
copyObject.topAlertObject = self.topAlertObject;
|
||||||
copyObject.paused = self.paused;
|
copyObject.paused = self.paused;
|
||||||
copyObject.reAddAfterCancel = self.reAddAfterCancel;
|
copyObject.reAddAfterCancel = self.reAddAfterCancel;
|
||||||
|
copyObject.displayable = self.isDisplayable;
|
||||||
copyObject.queuePriority = self.queuePriority;
|
copyObject.queuePriority = self.queuePriority;
|
||||||
for (NSOperation *dependency in self.dependencies) {
|
for (NSOperation *dependency in self.dependencies) {
|
||||||
[copyObject addDependency:dependency];
|
[copyObject addDependency:dependency];
|
||||||
|
|||||||
@ -18,7 +18,6 @@ public extension MVMCoreUITopAlertView {
|
|||||||
/// Registers with the notification center to know when json is updated.
|
/// Registers with the notification center to know when json is updated.
|
||||||
@objc func registerWithNotificationCenter() {
|
@objc func registerWithNotificationCenter() {
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(responseJSONUpdated(notification:)), name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(responseJSONUpdated(notification:)), name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(viewControllerChanged(notification:)), name: NSNotification.Name(rawValue: MVMCoreNotificationViewControllerChanged), object: nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getDelegateObject() -> MVMCoreUIDelegateObject {
|
private func getDelegateObject() -> MVMCoreUIDelegateObject {
|
||||||
@ -42,42 +41,6 @@ public extension MVMCoreUITopAlertView {
|
|||||||
showTopAlert(with: model)
|
showTopAlert(with: model)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When a detail page changes, check top alerts.
|
|
||||||
@objc private func viewControllerChanged(notification: Notification) {
|
|
||||||
guard let controller = MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol else { return }
|
|
||||||
MVMCoreAlertHandler.shared()?.handleAllPagesDependency(for: controller.pageType)
|
|
||||||
reevalutePriority()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Re-evaluates the queue priority
|
|
||||||
private func reevalutePriority() {
|
|
||||||
guard let operations = MVMCoreAlertHandler.shared()?.topAlertQueue.operations else { return }
|
|
||||||
var highestReadyOperation: Operation?
|
|
||||||
var executingOperation: Operation?
|
|
||||||
for operation in operations {
|
|
||||||
guard !operation.isCancelled,
|
|
||||||
!operation.isFinished else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if operation.isReady,
|
|
||||||
highestReadyOperation == nil || operation.queuePriority.rawValue > highestReadyOperation!.queuePriority.rawValue {
|
|
||||||
highestReadyOperation = operation
|
|
||||||
}
|
|
||||||
if operation.isExecuting {
|
|
||||||
executingOperation = operation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the highest priority operation is not executing, and the executing operation is persistent, cancel it.
|
|
||||||
if let newOperation = highestReadyOperation,
|
|
||||||
let currentOperation = executingOperation as? MVMCoreTopAlertOperation,
|
|
||||||
currentOperation != newOperation,
|
|
||||||
currentOperation.topAlertObject.persistent {
|
|
||||||
currentOperation.reAddAfterCancel = true
|
|
||||||
currentOperation.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decodes the json into a TopNotificationModel
|
/// Decodes the json into a TopNotificationModel
|
||||||
private func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? {
|
private func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? {
|
||||||
do {
|
do {
|
||||||
@ -95,8 +58,6 @@ public extension MVMCoreUITopAlertView {
|
|||||||
let object = model.createTopAlertObject()
|
let object = model.createTopAlertObject()
|
||||||
guard !checkAndUpdateExisting(with: object),
|
guard !checkAndUpdateExisting(with: object),
|
||||||
let operation = MVMCoreTopAlertOperation(topAlertObject: object) else { return }
|
let operation = MVMCoreTopAlertOperation(topAlertObject: object) else { return }
|
||||||
MVMCoreAlertHandler.shared()?.addPagesDependency(to: operation)
|
|
||||||
MVMCoreAlertHandler.shared()?.handlePageDependency(for: operation, with: (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType)
|
|
||||||
MVMCoreAlertHandler.shared()?.add(operation)
|
MVMCoreAlertHandler.shared()?.add(operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,9 +68,9 @@ public extension MVMCoreUITopAlertView {
|
|||||||
guard topAlertObject.json != nil,
|
guard topAlertObject.json != nil,
|
||||||
operation.topAlertObject.type == topAlertObject.type else { continue }
|
operation.topAlertObject.type == topAlertObject.type else { continue }
|
||||||
operation.update(with: topAlertObject)
|
operation.update(with: topAlertObject)
|
||||||
MVMCoreAlertHandler.shared()?.updatePages(for: operation, with: topAlertObject)
|
let pageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType
|
||||||
MVMCoreAlertHandler.shared()?.handlePageDependency(for: operation, with: (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType)
|
operation.updateDisplayable(byPageType: pageType)
|
||||||
reevalutePriority()
|
MVMCoreAlertHandler.shared()?.reevaluteQueue()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user