| | |
| | | let excludedTagNames: Set<String> |
| | | let isCustomColorUnlocked: Bool |
| | | let onLockedCustomColor: () -> Void |
| | | let onCustomContainerQuotaExceeded: (ProCustomContainerQuotaStatus) -> Void |
| | | let onCustomContainerQuotaStatusChanged: (ProCustomContainerQuotaStatus) -> Void |
| | | var topLeadingAccessory: AnyView? = nil |
| | | var onRefresh: (() -> Void)? |
| | | |
| | |
| | | HStack(spacing: 4) { |
| | | ForEach(TagColor.allIndices, id: \.self) { idx in |
| | | ColorSwatch(index: idx, isSelected: !hasCustomColor && idx == colorIndex) { |
| | | TagEditor.setColor(idx, for: tagName) |
| | | let result = TagEditor.setColor(idx, for: tagName) |
| | | guard handleMutationResult(result) else { return } |
| | | tagColors[tagName] = idx |
| | | tagCustomColors.removeValue(forKey: tagName) |
| | | onRefresh?() |
| | |
| | | private func commitTagRename(_ oldName: String) { |
| | | let newName = editingTagText.trimmingCharacters(in: .whitespaces) |
| | | guard !newName.isEmpty, newName != oldName else { editingTagName = nil; return } |
| | | TagEditor.renameTag(from: oldName, to: newName) |
| | | let result = TagEditor.renameTag(from: oldName, to: newName) |
| | | guard handleMutationResult(result) else { return } |
| | | tagColors[newName] = tagColors[oldName] |
| | | tagColors.removeValue(forKey: oldName) |
| | | tagCustomColors[newName] = tagCustomColors[oldName] |
| | |
| | | private func addNewTag() { |
| | | let name = newTagNameText.trimmingCharacters(in: .whitespaces) |
| | | guard !name.isEmpty else { return } |
| | | let result = TagEditor.createTag(name, color: newTagColorIndex) |
| | | guard handleMutationResult(result) else { return } |
| | | tagColors[name] = newTagColorIndex |
| | | TagEditor.createTag(name, color: newTagColorIndex) |
| | | addingNewTag = false |
| | | newTagNameText = "" |
| | | onRefresh?() |
| | | } |
| | | |
| | | private func deleteTag(_ name: String) { |
| | | TagEditor.deleteTagCompletely(name) |
| | | tagColors.removeValue(forKey: name) |
| | | tagCustomColors.removeValue(forKey: name) |
| | | onCustomContainerQuotaStatusChanged(ProEntitlementPolicy.customContainerQuotaStatus()) |
| | | onRefresh?() |
| | | } |
| | | |
| | |
| | | return |
| | | } |
| | | tagCustomColors[tagName] = customColor |
| | | onCustomContainerQuotaStatusChanged(ProEntitlementPolicy.customContainerQuotaStatus()) |
| | | onRefresh?() |
| | | } |
| | | ) |
| | | } |
| | | |
| | | @discardableResult |
| | | private func handleMutationResult(_ result: TagEditorMutationResult) -> Bool { |
| | | switch result { |
| | | case .saved: |
| | | onCustomContainerQuotaStatusChanged(ProEntitlementPolicy.customContainerQuotaStatus()) |
| | | return true |
| | | case .noChange: |
| | | return false |
| | | case .blockedCustomContainerQuota(let status): |
| | | onCustomContainerQuotaStatusChanged(status) |
| | | onCustomContainerQuotaExceeded(status) |
| | | return false |
| | | } |
| | | } |
| | | } |