Add update timeline articles statuses back in
This commit is contained in:
parent
d3399e8632
commit
1de3c75d4f
@ -129,25 +129,25 @@ struct AddWebFeedView: View {
|
||||
@ViewBuilder var folderPicker: some View {
|
||||
#if os(iOS)
|
||||
Picker("Folder", selection: $viewModel.selectedFolderIndex, content: {
|
||||
ForEach(0..<viewModel.containers.count, id: \.self, content: { index in
|
||||
if let containerName = (viewModel.containers[index] as? DisplayNameProvider)?.nameForDisplay {
|
||||
if viewModel.containers[index] is Folder {
|
||||
ForEach(0..<viewModel.containers.count, id: \.self, content: { position in
|
||||
if let containerName = (viewModel.containers[position] as? DisplayNameProvider)?.nameForDisplay {
|
||||
if viewModel.containers[position] is Folder {
|
||||
HStack(alignment: .top) {
|
||||
if let image = viewModel.smallIconImage(for: viewModel.containers[index]) {
|
||||
if let image = viewModel.smallIconImage(for: viewModel.containers[position]) {
|
||||
Image(rsImage: image)
|
||||
.foregroundColor(Color("AccentColor"))
|
||||
}
|
||||
Text("\(containerName)")
|
||||
.tag(index)
|
||||
.tag(position)
|
||||
}.padding(.leading, 16)
|
||||
} else {
|
||||
HStack(alignment: .top) {
|
||||
if let image = viewModel.smallIconImage(for: viewModel.containers[index]) {
|
||||
if let image = viewModel.smallIconImage(for: viewModel.containers[position]) {
|
||||
Image(rsImage: image)
|
||||
.foregroundColor(Color("AccentColor"))
|
||||
}
|
||||
Text(containerName)
|
||||
.tag(index)
|
||||
.tag(position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ enum TimelineItemStatus {
|
||||
struct TimelineItem: Identifiable {
|
||||
|
||||
var id: String
|
||||
var index: Int
|
||||
var position: Int
|
||||
var article: Article
|
||||
|
||||
var status: TimelineItemStatus = .showNone
|
||||
@ -27,9 +27,9 @@ struct TimelineItem: Identifiable {
|
||||
var byline: String
|
||||
var dateTimeString: String
|
||||
|
||||
init(index: Int, article: Article) {
|
||||
init(position: Int, article: Article) {
|
||||
self.id = article.articleID
|
||||
self.index = index
|
||||
self.position = position
|
||||
self.article = article
|
||||
self.byline = article.webFeed?.nameForDisplay ?? ""
|
||||
self.dateTimeString = ArticleStringFormatter.dateString(article.logicalDatePublished)
|
||||
@ -38,6 +38,10 @@ struct TimelineItem: Identifiable {
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
var isReadOnly: Bool {
|
||||
return article.status.read == true && article.status.starred == false
|
||||
}
|
||||
|
||||
mutating func updateStatus() {
|
||||
if article.status.starred == true {
|
||||
status = .showStar
|
||||
|
32
Multiplatform/Shared/Timeline/TimelineItems.swift
Normal file
32
Multiplatform/Shared/Timeline/TimelineItems.swift
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// TimelineItems.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 7/25/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TimelineItems {
|
||||
|
||||
var index = [String: Int]()
|
||||
var items = [TimelineItem]()
|
||||
|
||||
init() {}
|
||||
|
||||
subscript(key: String) -> TimelineItem? {
|
||||
get {
|
||||
if let position = index[key] {
|
||||
return items[position]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
mutating func append(_ item: TimelineItem) {
|
||||
index[item.id] = item.position
|
||||
items.append(item)
|
||||
}
|
||||
|
||||
}
|
@ -30,11 +30,12 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
@Published var selectedTimelineItemID: String? = nil // Don't use directly. Use selectedTimelineItemsPublisher
|
||||
@Published var isReadFiltered: Bool? = nil
|
||||
|
||||
var timelineItemsPublisher: AnyPublisher<OrderedDictionary<String, TimelineItem>, Never>?
|
||||
var timelineItemsPublisher: AnyPublisher<TimelineItems, Never>?
|
||||
var articlesPublisher: AnyPublisher<[Article], Never>?
|
||||
var selectedTimelineItemsPublisher: AnyPublisher<[TimelineItem], Never>?
|
||||
var selectedArticlesPublisher: AnyPublisher<[Article], Never>?
|
||||
|
||||
var articleStatusChangePublisher: AnyPublisher<Set<String>, Never>?
|
||||
|
||||
var readFilterEnabledTable = [FeedIdentifier: Bool]()
|
||||
|
||||
var undoManager: UndoManager?
|
||||
@ -45,7 +46,7 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
private var sortDirectionSubject = ReplaySubject<Bool, Never>(bufferSize: 1)
|
||||
private var groupByFeedSubject = ReplaySubject<Bool, Never>(bufferSize: 1)
|
||||
|
||||
private var timelineItems = OrderedDictionary<String, TimelineItem>()
|
||||
private var timelineItems = TimelineItems()
|
||||
|
||||
init(delegate: TimelineModelDelegate) {
|
||||
self.delegate = delegate
|
||||
@ -53,24 +54,17 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
subscribeToReadFilterChanges()
|
||||
subscribeToArticleFetchChanges()
|
||||
subscribeToSelectedArticleSelectionChanges()
|
||||
// subscribeToArticleStatusChanges()
|
||||
subscribeToArticleStatusChanges()
|
||||
// subscribeToAccountDidDownloadArticles()
|
||||
}
|
||||
|
||||
// MARK: Subscriptions
|
||||
|
||||
// func subscribeToArticleStatusChanges() {
|
||||
// NotificationCenter.default.publisher(for: .StatusesDidChange).sink { [weak self] note in
|
||||
// guard let self = self, let articleIDs = note.userInfo?[Account.UserInfoKey.articleIDs] as? Set<String> else {
|
||||
// return
|
||||
// }
|
||||
// articleIDs.forEach { articleID in
|
||||
// if let timelineItemIndex = self.idToTimelineItemDictionary[articleID] {
|
||||
// self.timelineItems[timelineItemIndex].updateStatus()
|
||||
// }
|
||||
// }
|
||||
// }.store(in: &cancellables)
|
||||
// }
|
||||
func subscribeToArticleStatusChanges() {
|
||||
articleStatusChangePublisher = NotificationCenter.default.publisher(for: .StatusesDidChange)
|
||||
.compactMap { $0.userInfo?[Account.UserInfoKey.articleIDs] as? Set<String> }
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
// func subscribeToAccountDidDownloadArticles() {
|
||||
// NotificationCenter.default.publisher(for: .AccountDidDownloadArticles).sink { [weak self] note in
|
||||
@ -131,7 +125,7 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
.combineLatest(sortDirectionPublisher, groupByPublisher)
|
||||
.compactMap { [weak self] articles, sortDirection, groupBy in
|
||||
let sortedArticles = Array(articles).sortedByDate(sortDirection ? .orderedDescending : .orderedAscending, groupByFeed: groupBy)
|
||||
return self?.buildTimelineItems(articles: sortedArticles) ?? OrderedDictionary<String, TimelineItem>()
|
||||
return self?.buildTimelineItems(articles: sortedArticles) ?? TimelineItems()
|
||||
}
|
||||
.share(replay: 1)
|
||||
.eraseToAnyPublisher()
|
||||
@ -145,7 +139,7 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
// Transform to articles for those that just need articles
|
||||
articlesPublisher = timelineItemsPublisher!
|
||||
.map { timelineItems in
|
||||
timelineItems.values.values.map { $0.article }
|
||||
timelineItems.items.map { $0.article }
|
||||
}
|
||||
.share()
|
||||
.eraseToAnyPublisher()
|
||||
@ -318,11 +312,10 @@ private extension TimelineModel {
|
||||
return fetchedArticles
|
||||
}
|
||||
|
||||
func buildTimelineItems(articles: [Article]) -> OrderedDictionary<String, TimelineItem> {
|
||||
var items = OrderedDictionary<String, TimelineItem>()
|
||||
for (index, article) in articles.enumerated() {
|
||||
let item = TimelineItem(index: index, article: article)
|
||||
items[item.id] = item
|
||||
func buildTimelineItems(articles: [Article]) -> TimelineItems {
|
||||
var items = TimelineItems()
|
||||
for (position, article) in articles.enumerated() {
|
||||
items.append(TimelineItem(position: position, article: article))
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import SwiftUI
|
||||
struct TimelineView: View {
|
||||
|
||||
@EnvironmentObject private var timelineModel: TimelineModel
|
||||
@State private var timelineItems = OrderedDictionary<String, TimelineItem>()
|
||||
@State private var timelineItems = TimelineItems()
|
||||
@State private var timelineItemFrames = [String: CGRect]()
|
||||
|
||||
@ViewBuilder var body: some View {
|
||||
@ -38,12 +38,10 @@ struct TimelineView: View {
|
||||
.help(timelineModel.isReadFiltered ?? false ? "Show Read Articles" : "Filter Read Articles")
|
||||
}
|
||||
ScrollViewReader { scrollViewProxy in
|
||||
List(timelineItems.keys, id: \.self, selection: $timelineModel.selectedTimelineItemIDs) { timelineItemID in
|
||||
if let timelineItem = timelineItems[timelineItemID] {
|
||||
let selected = timelineModel.selectedTimelineItemIDs.contains(timelineItem.article.articleID)
|
||||
TimelineItemView(selected: selected, width: geometryReaderProxy.size.width, timelineItem: timelineItem)
|
||||
.background(TimelineItemFramePreferenceView(timelineItem: timelineItem))
|
||||
}
|
||||
List(timelineItems.items, selection: $timelineModel.selectedTimelineItemIDs) { timelineItem in
|
||||
let selected = timelineModel.selectedTimelineItemIDs.contains(timelineItem.article.articleID)
|
||||
TimelineItemView(selected: selected, width: geometryReaderProxy.size.width, timelineItem: timelineItem)
|
||||
.background(TimelineItemFramePreferenceView(timelineItem: timelineItem))
|
||||
}
|
||||
.onPreferenceChange(TimelineItemFramePreferenceKey.self) { preferences in
|
||||
for pref in preferences {
|
||||
@ -69,6 +67,19 @@ struct TimelineView: View {
|
||||
timelineItems = items
|
||||
}
|
||||
}
|
||||
.onReceive(timelineModel.articleStatusChangePublisher!) { articleIDs in
|
||||
articleIDs.forEach { articleID in
|
||||
if let position = timelineItems.index[articleID] {
|
||||
if timelineItems.items[position].isReadOnly {
|
||||
withAnimation {
|
||||
timelineItems.items[position].updateStatus()
|
||||
}
|
||||
} else {
|
||||
timelineItems.items[position].updateStatus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(Text(verbatim: timelineModel.nameForDisplay))
|
||||
#else
|
||||
ScrollViewReader { scrollViewProxy in
|
||||
|
@ -477,11 +477,8 @@
|
||||
51C452AF2265108300C03939 /* ArticleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DF1FAACBB30076E152 /* ArticleArray.swift */; };
|
||||
51C452B42265141B00C03939 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C452B32265141B00C03939 /* WebKit.framework */; };
|
||||
51C452B82265178500C03939 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 51C452B72265178500C03939 /* styleSheet.css */; };
|
||||
51C65AD524CC834F008EB3BD /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AD424CC834F008EB3BD /* OrderedDictionary.swift */; };
|
||||
51C65AD624CC834F008EB3BD /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AD424CC834F008EB3BD /* OrderedDictionary.swift */; };
|
||||
51C65AD724CC834F008EB3BD /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AD424CC834F008EB3BD /* OrderedDictionary.swift */; };
|
||||
51C65AD824CC834F008EB3BD /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AD424CC834F008EB3BD /* OrderedDictionary.swift */; };
|
||||
51C65AD924CC834F008EB3BD /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AD424CC834F008EB3BD /* OrderedDictionary.swift */; };
|
||||
51C65AFC24CCB2C9008EB3BD /* TimelineItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AFB24CCB2C9008EB3BD /* TimelineItems.swift */; };
|
||||
51C65AFD24CCB2C9008EB3BD /* TimelineItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AFB24CCB2C9008EB3BD /* TimelineItems.swift */; };
|
||||
51C9DE5823EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C9DE5723EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift */; };
|
||||
51CE1C0923621EDA005548FC /* RefreshProgressView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51CE1C0823621EDA005548FC /* RefreshProgressView.xib */; };
|
||||
51CE1C0B23622007005548FC /* RefreshProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CE1C0A23622006005548FC /* RefreshProgressView.swift */; };
|
||||
@ -2113,7 +2110,7 @@
|
||||
51C4528B2265095F00C03939 /* AddFolderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderViewController.swift; sourceTree = "<group>"; };
|
||||
51C452B32265141B00C03939 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
51C452B72265178500C03939 /* styleSheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = styleSheet.css; sourceTree = "<group>"; };
|
||||
51C65AD424CC834F008EB3BD /* OrderedDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderedDictionary.swift; sourceTree = "<group>"; };
|
||||
51C65AFB24CCB2C9008EB3BD /* TimelineItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItems.swift; sourceTree = "<group>"; };
|
||||
51C9DE5723EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrapperScriptMessageHandler.swift; sourceTree = "<group>"; };
|
||||
51CE1C0823621EDA005548FC /* RefreshProgressView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RefreshProgressView.xib; sourceTree = "<group>"; };
|
||||
51CE1C0A23622006005548FC /* RefreshProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshProgressView.swift; sourceTree = "<group>"; };
|
||||
@ -3012,6 +3009,7 @@
|
||||
51919FED24AB85E400541E64 /* TimelineContainerView.swift */,
|
||||
51B8BCE524C25F7C00360B00 /* TimelineContextMenu.swift */,
|
||||
51919FF324AB869C00541E64 /* TimelineItem.swift */,
|
||||
51C65AFB24CCB2C9008EB3BD /* TimelineItems.swift */,
|
||||
514E6C0124AD29A300AC6F6E /* TimelineItemStatusView.swift */,
|
||||
514E6BD924ACEA0400AC6F6E /* TimelineItemView.swift */,
|
||||
51919FF024AB864A00541E64 /* TimelineModel.swift */,
|
||||
@ -3588,7 +3586,6 @@
|
||||
51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */,
|
||||
84411E701FE5FBFA004B527F /* SmallIconProvider.swift */,
|
||||
51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */,
|
||||
51C65AD424CC834F008EB3BD /* OrderedDictionary.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -5209,6 +5206,7 @@
|
||||
51E4990D24A808C500B667CB /* RSHTMLMetadata+Extension.swift in Sources */,
|
||||
51919FF424AB869C00541E64 /* TimelineItem.swift in Sources */,
|
||||
514E6C0224AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */,
|
||||
51C65AFC24CCB2C9008EB3BD /* TimelineItems.swift in Sources */,
|
||||
51E49A0024A91FC100B667CB /* SidebarContainerView.swift in Sources */,
|
||||
5177471824B3812200EB0F74 /* IconView.swift in Sources */,
|
||||
51E4995C24A875F300B667CB /* ArticleRenderer.swift in Sources */,
|
||||
@ -5254,7 +5252,6 @@
|
||||
51E4995324A8734D00B667CB /* RedditFeedProvider-Extensions.swift in Sources */,
|
||||
5177471024B3029400EB0F74 /* ArticleViewController.swift in Sources */,
|
||||
65082A5224C72B88009FA994 /* SettingsCredentialsAccountModel.swift in Sources */,
|
||||
51C65AD824CC834F008EB3BD /* OrderedDictionary.swift in Sources */,
|
||||
172199C924AB228900A31D04 /* SettingsView.swift in Sources */,
|
||||
51B8BCC224C25C3E00360B00 /* SidebarContextMenu.swift in Sources */,
|
||||
51A8005124CC453C00F41F1D /* ReplaySubject.swift in Sources */,
|
||||
@ -5373,6 +5370,7 @@
|
||||
17D5F17224B0BC6700375168 /* SidebarToolbarModel.swift in Sources */,
|
||||
514E6C0724AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */,
|
||||
51E4994D24A8734C00B667CB /* ExtensionPointIdentifer.swift in Sources */,
|
||||
51C65AFD24CCB2C9008EB3BD /* TimelineItems.swift in Sources */,
|
||||
51B54A6724B549FE0014348B /* ArticleIconSchemeHandler.swift in Sources */,
|
||||
51E4992224A8095600B667CB /* URL-Extensions.swift in Sources */,
|
||||
51E4990424A808C300B667CB /* WebFeedIconDownloader.swift in Sources */,
|
||||
@ -5393,7 +5391,6 @@
|
||||
1769E32224BC5925000E1E8E /* AccountsPreferencesModel.swift in Sources */,
|
||||
51E4991624A8090300B667CB /* ArticleUtilities.swift in Sources */,
|
||||
51919FF224AB864A00541E64 /* TimelineModel.swift in Sources */,
|
||||
51C65AD924CC834F008EB3BD /* OrderedDictionary.swift in Sources */,
|
||||
51E4991A24A8090F00B667CB /* IconImage.swift in Sources */,
|
||||
1799E6AA24C2F93F00511E91 /* InspectorPlatformModifier.swift in Sources */,
|
||||
51B8104624C0E6D200C6C32D /* TimelineTextSizer.swift in Sources */,
|
||||
@ -5649,7 +5646,6 @@
|
||||
65ED403F235DEF6C0081F399 /* ArticleRenderer.swift in Sources */,
|
||||
65ED4040235DEF6C0081F399 /* GeneralPrefencesViewController.swift in Sources */,
|
||||
179DB1DFBCF9177104B12E0F /* AccountsNewsBlurWindowController.swift in Sources */,
|
||||
51C65AD624CC834F008EB3BD /* OrderedDictionary.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -5807,7 +5803,6 @@
|
||||
D3555BF524664566005E48C3 /* ArticleSearchBar.swift in Sources */,
|
||||
B24E9ADE245AB88400DA5718 /* NSAttributedString+NetNewsWire.swift in Sources */,
|
||||
C5A6ED5223C9AF4300AB6BE2 /* TitleActivityItemSource.swift in Sources */,
|
||||
51C65AD724CC834F008EB3BD /* OrderedDictionary.swift in Sources */,
|
||||
51DC37092402F1470095D371 /* MasterFeedDataSourceOperation.swift in Sources */,
|
||||
51C4529B22650A1000C03939 /* FaviconDownloader.swift in Sources */,
|
||||
84DEE56622C32CA4005FC42C /* SmartFeedDelegate.swift in Sources */,
|
||||
@ -5939,7 +5934,6 @@
|
||||
848F6AE51FC29CFB002D422E /* FaviconDownloader.swift in Sources */,
|
||||
511B9806237DCAC90028BCAA /* UserInfoKey.swift in Sources */,
|
||||
84C9FC7722629E1200D921D6 /* AdvancedPreferencesViewController.swift in Sources */,
|
||||
51C65AD524CC834F008EB3BD /* OrderedDictionary.swift in Sources */,
|
||||
849EE72120391F560082A1EA /* SharingServicePickerDelegate.swift in Sources */,
|
||||
5108F6B62375E612001ABC45 /* CacheCleaner.swift in Sources */,
|
||||
849A97981ED9EFAA007D329B /* Node-Extensions.swift in Sources */,
|
||||
|
@ -1,64 +0,0 @@
|
||||
//
|
||||
// OrderedDictionary.swift
|
||||
// SwiftDataStructures
|
||||
//
|
||||
// Created by Tim Ekl on 6/2/14.
|
||||
// Copyright (c) 2014 Tim Ekl. Available under MIT License. See LICENSE.md.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct OrderedDictionary<Tk: Hashable, Tv> {
|
||||
var keys: Array<Tk> = []
|
||||
var values: Dictionary<Tk,Tv> = [:]
|
||||
|
||||
var count: Int {
|
||||
assert(keys.count == values.count, "Keys and values array out of sync")
|
||||
return self.keys.count;
|
||||
}
|
||||
|
||||
// Explicitly define an empty initializer to prevent the default memberwise initializer from being generated
|
||||
init() {}
|
||||
|
||||
subscript(index: Int) -> Tv? {
|
||||
get {
|
||||
let key = self.keys[index]
|
||||
return self.values[key]
|
||||
}
|
||||
set(newValue) {
|
||||
let key = self.keys[index]
|
||||
if (newValue != nil) {
|
||||
self.values[key] = newValue
|
||||
} else {
|
||||
self.values[key] = nil
|
||||
self.keys.remove(at: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscript(key: Tk) -> Tv? {
|
||||
get {
|
||||
return self.values[key]
|
||||
}
|
||||
set(newValue) {
|
||||
if newValue == nil {
|
||||
self.values[key] = nil
|
||||
self.keys = self.keys.filter {$0 != key}
|
||||
} else {
|
||||
let oldValue = self.values.updateValue(newValue!, forKey: key)
|
||||
if oldValue == nil {
|
||||
self.keys.append(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
var result = "{\n"
|
||||
for i in 0..<self.count {
|
||||
result += "[\(i)]: \(self.keys[i]) => \(String(describing: self[i]))\n"
|
||||
}
|
||||
result += "}"
|
||||
return result
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user