mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Make RSTree a local module.
This commit is contained in:
@@ -18,7 +18,7 @@ dependencies.append(contentsOf: [
|
||||
let package = Package(
|
||||
name: "Account",
|
||||
platforms: [.macOS(.v13), .iOS(.v17)],
|
||||
products: [
|
||||
products: [
|
||||
.library(
|
||||
name: "Account",
|
||||
type: .dynamic,
|
||||
|
||||
@@ -93,8 +93,6 @@
|
||||
5137C2E426F3F52D009EFEDB /* Sepia.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */; };
|
||||
5137C2E626F3F52D009EFEDB /* Sepia.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */; };
|
||||
51386A8E25673277005F3762 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51386A8D25673276005F3762 /* AccountCell.swift */; };
|
||||
5138E93A24D33E5600AFF0FE /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 5138E93924D33E5600AFF0FE /* RSTree */; };
|
||||
5138E93B24D33E5600AFF0FE /* RSTree in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 5138E93924D33E5600AFF0FE /* RSTree */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
5138E94C24D3417A00AFF0FE /* RSDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = 5138E94B24D3417A00AFF0FE /* RSDatabase */; };
|
||||
5138E94D24D3417A00AFF0FE /* RSDatabase in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 5138E94B24D3417A00AFF0FE /* RSDatabase */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
513C5CF0232571C2003D4054 /* NetNewsWire iOS Share Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
@@ -116,8 +114,6 @@
|
||||
5144EA51227B8E4500D19003 /* AccountsFeedbinWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4F227B8E4500D19003 /* AccountsFeedbinWindowController.swift */; };
|
||||
5144EA52227B8E4500D19003 /* AccountsFeedbin.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA50227B8E4500D19003 /* AccountsFeedbin.xib */; };
|
||||
514C16CE24D2E63F009A3AFA /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 514C16CD24D2E63F009A3AFA /* Account */; };
|
||||
514C16DE24D2EF15009A3AFA /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 514C16DD24D2EF15009A3AFA /* RSTree */; };
|
||||
514C16DF24D2EF15009A3AFA /* RSTree in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 514C16DD24D2EF15009A3AFA /* RSTree */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; };
|
||||
515D4FCA23257CB500EE1167 /* Node-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97971ED9EFAA007D329B /* Node-Extensions.swift */; };
|
||||
515D4FCC2325815A00EE1167 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; };
|
||||
@@ -158,8 +154,6 @@
|
||||
51B5C8E623F4BBFA00032075 /* ExtensionFeedAddRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87A23F2317700032075 /* ExtensionFeedAddRequest.swift */; };
|
||||
51B5C8E723F4BBFA00032075 /* ExtensionFeedAddRequestFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C8BF23F3866C00032075 /* ExtensionFeedAddRequestFile.swift */; };
|
||||
51BC2F3824D3439A00E90810 /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 51BC2F3724D3439A00E90810 /* Account */; };
|
||||
51BC2F4824D3439E00E90810 /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 51BC2F4724D3439E00E90810 /* RSTree */; };
|
||||
51BC2F4D24D343AB00E90810 /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 51BC2F4C24D343AB00E90810 /* RSTree */; };
|
||||
51BC4AFF247277E0000A6ED8 /* URL-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */; };
|
||||
51BC4B01247277E0000A6ED8 /* URL-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */; };
|
||||
51C03081257D815A00609262 /* UnifiedWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C0307F257D815A00609262 /* UnifiedWindow.storyboard */; };
|
||||
@@ -373,6 +367,12 @@
|
||||
84E8E0DB202EC49300562D8F /* TimelineViewController+ContextualMenus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8E0DA202EC49300562D8F /* TimelineViewController+ContextualMenus.swift */; };
|
||||
84E8E0EB202F693600562D8F /* DetailWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8E0EA202F693600562D8F /* DetailWebView.swift */; };
|
||||
84E95D241FB1087500552D99 /* ArticlePasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E95D231FB1087500552D99 /* ArticlePasteboardWriter.swift */; };
|
||||
84EE3F122DB8A088009D3A8D /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 84EE3F112DB8A088009D3A8D /* RSTree */; };
|
||||
84EE3F132DB8A088009D3A8D /* RSTree in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 84EE3F112DB8A088009D3A8D /* RSTree */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
84EE3F152DB8A0A0009D3A8D /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 84EE3F142DB8A0A0009D3A8D /* RSTree */; };
|
||||
84EE3F162DB8A0A0009D3A8D /* RSTree in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 84EE3F142DB8A0A0009D3A8D /* RSTree */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
84EE3F182DB8A0AC009D3A8D /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 84EE3F172DB8A0AC009D3A8D /* RSTree */; };
|
||||
84EE3F1B2DB8A0B6009D3A8D /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 84EE3F1A2DB8A0B6009D3A8D /* RSTree */; };
|
||||
84F204E01FAACBB30076E152 /* ArticleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DF1FAACBB30076E152 /* ArticleArray.swift */; };
|
||||
84F2D5371FC22FCC00998D64 /* PseudoFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5351FC22FCB00998D64 /* PseudoFeed.swift */; };
|
||||
84F2D5381FC22FCC00998D64 /* TodayFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5361FC22FCB00998D64 /* TodayFeedDelegate.swift */; };
|
||||
@@ -548,9 +548,9 @@
|
||||
513F32782593EE6F0003048F /* Secrets in Embed Frameworks */,
|
||||
843E2F1B2CF2B8C500ED170F /* RSWeb in Embed Frameworks */,
|
||||
513F327B2593EE6F0003048F /* SyncDatabase in Embed Frameworks */,
|
||||
84EE3F162DB8A0A0009D3A8D /* RSTree in Embed Frameworks */,
|
||||
513F32722593EE6F0003048F /* Articles in Embed Frameworks */,
|
||||
513F32812593EF180003048F /* Account in Embed Frameworks */,
|
||||
5138E93B24D33E5600AFF0FE /* RSTree in Embed Frameworks */,
|
||||
5138E94D24D3417A00AFF0FE /* RSDatabase in Embed Frameworks */,
|
||||
513F32752593EE6F0003048F /* ArticlesDatabase in Embed Frameworks */,
|
||||
);
|
||||
@@ -594,11 +594,11 @@
|
||||
513277442590FBB60064F1E7 /* Account in Embed Frameworks */,
|
||||
5132775F2590FC640064F1E7 /* Articles in Embed Frameworks */,
|
||||
843E2F182CF2B8A700ED170F /* RSWeb in Embed Frameworks */,
|
||||
84EE3F132DB8A088009D3A8D /* RSTree in Embed Frameworks */,
|
||||
51A737C024DB197F0015FA66 /* RSDatabase in Embed Frameworks */,
|
||||
513277662590FC780064F1E7 /* Secrets in Embed Frameworks */,
|
||||
513277652590FC640064F1E7 /* SyncDatabase in Embed Frameworks */,
|
||||
513277622590FC640064F1E7 /* ArticlesDatabase in Embed Frameworks */,
|
||||
514C16DF24D2EF15009A3AFA /* RSTree in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -863,6 +863,7 @@
|
||||
84E8E0DA202EC49300562D8F /* TimelineViewController+ContextualMenus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimelineViewController+ContextualMenus.swift"; sourceTree = "<group>"; };
|
||||
84E8E0EA202F693600562D8F /* DetailWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailWebView.swift; sourceTree = "<group>"; };
|
||||
84E95D231FB1087500552D99 /* ArticlePasteboardWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticlePasteboardWriter.swift; sourceTree = "<group>"; };
|
||||
84EE3F102DB8A078009D3A8D /* RSTree */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = RSTree; sourceTree = "<group>"; };
|
||||
84F204DF1FAACBB30076E152 /* ArticleArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleArray.swift; sourceTree = "<group>"; };
|
||||
84F2D5351FC22FCB00998D64 /* PseudoFeed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PseudoFeed.swift; sourceTree = "<group>"; };
|
||||
84F2D5361FC22FCB00998D64 /* TodayFeedDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodayFeedDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -994,7 +995,7 @@
|
||||
files = (
|
||||
27B86EEB25A53AAB00264340 /* Account in Frameworks */,
|
||||
848E84DB2DB749860023F3BA /* RSCore in Frameworks */,
|
||||
51BC2F4D24D343AB00E90810 /* RSTree in Frameworks */,
|
||||
84EE3F1B2DB8A0B6009D3A8D /* RSTree in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1004,7 +1005,7 @@
|
||||
files = (
|
||||
51BC2F3824D3439A00E90810 /* Account in Frameworks */,
|
||||
848E84D82DB749720023F3BA /* RSCore in Frameworks */,
|
||||
51BC2F4824D3439E00E90810 /* RSTree in Frameworks */,
|
||||
84EE3F182DB8A0AC009D3A8D /* RSTree in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1026,6 +1027,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84EE3F152DB8A0A0009D3A8D /* RSTree in Frameworks */,
|
||||
848E84D52DB749670023F3BA /* RSCore in Frameworks */,
|
||||
179D280B26F6F93D003B2E0A /* Zip in Frameworks */,
|
||||
8424B31B2DB73D530053AA11 /* RSParser in Frameworks */,
|
||||
@@ -1038,7 +1040,6 @@
|
||||
51E4DB082425F9EB0091EB5B /* CloudKit.framework in Frameworks */,
|
||||
513F32742593EE6F0003048F /* ArticlesDatabase in Frameworks */,
|
||||
513F327A2593EE6F0003048F /* SyncDatabase in Frameworks */,
|
||||
5138E93A24D33E5600AFF0FE /* RSTree in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1050,8 +1051,8 @@
|
||||
848E84D02DB749440023F3BA /* RSCoreResources in Frameworks */,
|
||||
513277642590FC640064F1E7 /* SyncDatabase in Frameworks */,
|
||||
17192ADA2567B3D500AAEACA /* RSSparkle in Frameworks */,
|
||||
514C16DE24D2EF15009A3AFA /* RSTree in Frameworks */,
|
||||
5132775E2590FC640064F1E7 /* Articles in Frameworks */,
|
||||
84EE3F122DB8A088009D3A8D /* RSTree in Frameworks */,
|
||||
513277612590FC640064F1E7 /* ArticlesDatabase in Frameworks */,
|
||||
51C4CFF624D37DD500AF9874 /* Secrets in Frameworks */,
|
||||
179C39EA26F76B0500D4E741 /* Zip in Frameworks */,
|
||||
@@ -1534,6 +1535,7 @@
|
||||
51CD32C724D2E06C009ABAEF /* Secrets */,
|
||||
51CD32A824D2CB25009ABAEF /* SyncDatabase */,
|
||||
8424B3162DB73D320053AA11 /* RSParser */,
|
||||
84EE3F102DB8A078009D3A8D /* RSTree */,
|
||||
843E2F152CF2B43700ED170F /* RSWeb */,
|
||||
848E84CB2DB749300023F3BA /* RSCore */,
|
||||
);
|
||||
@@ -1908,8 +1910,8 @@
|
||||
name = "NetNewsWire iOS Intents Extension";
|
||||
packageProductDependencies = (
|
||||
51BC2F4A24D343A500E90810 /* Account */,
|
||||
51BC2F4C24D343AB00E90810 /* RSTree */,
|
||||
848E84DA2DB749860023F3BA /* RSCore */,
|
||||
84EE3F1A2DB8A0B6009D3A8D /* RSTree */,
|
||||
);
|
||||
productName = "NetNewsWire iOS Intents Extension";
|
||||
productReference = 51314637235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex */;
|
||||
@@ -1932,8 +1934,8 @@
|
||||
name = "NetNewsWire iOS Share Extension";
|
||||
packageProductDependencies = (
|
||||
51BC2F3724D3439A00E90810 /* Account */,
|
||||
51BC2F4724D3439E00E90810 /* RSTree */,
|
||||
848E84D72DB749720023F3BA /* RSCore */,
|
||||
84EE3F172DB8A0AC009D3A8D /* RSTree */,
|
||||
);
|
||||
productName = "NetNewsWire iOS Share Extension";
|
||||
productReference = 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */;
|
||||
@@ -1998,7 +2000,6 @@
|
||||
name = "NetNewsWire-iOS";
|
||||
packageProductDependencies = (
|
||||
516B695E24D2F33B00B5702F /* Account */,
|
||||
5138E93924D33E5600AFF0FE /* RSTree */,
|
||||
5138E94B24D3417A00AFF0FE /* RSDatabase */,
|
||||
513F32702593EE6F0003048F /* Articles */,
|
||||
513F32732593EE6F0003048F /* ArticlesDatabase */,
|
||||
@@ -2008,6 +2009,7 @@
|
||||
843E2F192CF2B8C500ED170F /* RSWeb */,
|
||||
8424B31A2DB73D530053AA11 /* RSParser */,
|
||||
848E84D42DB749670023F3BA /* RSCore */,
|
||||
84EE3F142DB8A0A0009D3A8D /* RSTree */,
|
||||
);
|
||||
productName = "NetNewsWire-iOS";
|
||||
productReference = 840D617C2029031C009BC708 /* NetNewsWire.app */;
|
||||
@@ -2037,7 +2039,6 @@
|
||||
name = NetNewsWire;
|
||||
packageProductDependencies = (
|
||||
514C16CD24D2E63F009A3AFA /* Account */,
|
||||
514C16DD24D2EF15009A3AFA /* RSTree */,
|
||||
51C4CFF524D37DD500AF9874 /* Secrets */,
|
||||
51A737BE24DB197F0015FA66 /* RSDatabase */,
|
||||
17192AD92567B3D500AAEACA /* RSSparkle */,
|
||||
@@ -2050,6 +2051,7 @@
|
||||
8424B3172DB73D4C0053AA11 /* RSParser */,
|
||||
848E84CC2DB749440023F3BA /* RSCore */,
|
||||
848E84CF2DB749440023F3BA /* RSCoreResources */,
|
||||
84EE3F112DB8A088009D3A8D /* RSTree */,
|
||||
);
|
||||
productName = NetNewsWire;
|
||||
productReference = 849C64601ED37A5D003D8FC0 /* NetNewsWire.app */;
|
||||
@@ -2154,7 +2156,6 @@
|
||||
);
|
||||
mainGroup = 849C64571ED37A5D003D8FC0;
|
||||
packageReferences = (
|
||||
510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */,
|
||||
51B0DF0D24D24E3B000AD99E /* XCRemoteSwiftPackageReference "RSDatabase" */,
|
||||
17192AD82567B3D500AAEACA /* XCRemoteSwiftPackageReference "Sparkle-Binary" */,
|
||||
519CA8E325841DB700EB079A /* XCRemoteSwiftPackageReference "plcrashreporter" */,
|
||||
@@ -3185,14 +3186,6 @@
|
||||
revision = 059e7346082d02de16220cd79df7db18ddeba8c3;
|
||||
};
|
||||
};
|
||||
510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/Ranchero-Software/RSTree.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
519CA8E325841DB700EB079A /* XCRemoteSwiftPackageReference "plcrashreporter" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/microsoft/plcrashreporter.git";
|
||||
@@ -3247,11 +3240,6 @@
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = SyncDatabase;
|
||||
};
|
||||
5138E93924D33E5600AFF0FE /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */;
|
||||
productName = RSTree;
|
||||
};
|
||||
5138E94B24D3417A00AFF0FE /* RSDatabase */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 51B0DF0D24D24E3B000AD99E /* XCRemoteSwiftPackageReference "RSDatabase" */;
|
||||
@@ -3277,11 +3265,6 @@
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Account;
|
||||
};
|
||||
514C16DD24D2EF15009A3AFA /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */;
|
||||
productName = RSTree;
|
||||
};
|
||||
516B695E24D2F33B00B5702F /* Account */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Account;
|
||||
@@ -3300,20 +3283,10 @@
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Account;
|
||||
};
|
||||
51BC2F4724D3439E00E90810 /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */;
|
||||
productName = RSTree;
|
||||
};
|
||||
51BC2F4A24D343A500E90810 /* Account */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Account;
|
||||
};
|
||||
51BC2F4C24D343AB00E90810 /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */;
|
||||
productName = RSTree;
|
||||
};
|
||||
51C4CFF524D37DD500AF9874 /* Secrets */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Secrets;
|
||||
@@ -3366,6 +3339,22 @@
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = RSCore;
|
||||
};
|
||||
84EE3F112DB8A088009D3A8D /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = RSTree;
|
||||
};
|
||||
84EE3F142DB8A0A0009D3A8D /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = RSTree;
|
||||
};
|
||||
84EE3F172DB8A0AC009D3A8D /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = RSTree;
|
||||
};
|
||||
84EE3F1A2DB8A0B6009D3A8D /* RSTree */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = RSTree;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 849C64581ED37A5D003D8FC0 /* Project object */;
|
||||
|
||||
@@ -19,15 +19,6 @@
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "RSTree",
|
||||
"repositoryURL": "https://github.com/Ranchero-Software/RSTree.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "9d051f42cfc4faa991fd79cdb32e4cc8c545e334",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "RSSparkle",
|
||||
"repositoryURL": "https://github.com/Ranchero-Software/Sparkle-Binary.git",
|
||||
|
||||
18
RSTree/Package.swift
Normal file
18
RSTree/Package.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
// swift-tools-version:5.10
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "RSTree",
|
||||
platforms: [.macOS(.v13), .iOS(.v17)],
|
||||
products: [
|
||||
.library(
|
||||
name: "RSTree",
|
||||
type: .dynamic,
|
||||
targets: ["RSTree"]),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "RSTree",
|
||||
dependencies: []),
|
||||
]
|
||||
)
|
||||
58
RSTree/Sources/RSTree/NSOutlineView+RSTree.swift
Normal file
58
RSTree/Sources/RSTree/NSOutlineView+RSTree.swift
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// NSOutlineView+RSTree.swift
|
||||
// RSTree
|
||||
//
|
||||
// Created by Brent Simmons on 9/5/16.
|
||||
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
#if os(OSX)
|
||||
|
||||
import AppKit
|
||||
|
||||
public extension NSOutlineView {
|
||||
|
||||
@discardableResult
|
||||
func revealAndSelectNodeAtPath(_ nodePath: NodePath) -> Bool {
|
||||
|
||||
// Returns true on success. Expands folders on the way. May succeed partially (returns false, in that case).
|
||||
|
||||
let numberOfNodes = nodePath.components.count
|
||||
if numberOfNodes < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
let indexOfNodeToSelect = numberOfNodes - 1
|
||||
|
||||
for i in 1...indexOfNodeToSelect { // Start at 1 to skip root node.
|
||||
|
||||
let oneNode = nodePath.components[i]
|
||||
let oneRow = row(forItem: oneNode)
|
||||
if oneRow < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if i == indexOfNodeToSelect {
|
||||
selectRowIndexes(NSIndexSet(index: oneRow) as IndexSet, byExtendingSelection: false)
|
||||
scrollRowToVisible(oneRow)
|
||||
return true
|
||||
}
|
||||
else {
|
||||
expandItem(oneNode)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func revealAndSelectRepresentedObject(_ representedObject: AnyObject, _ treeController: TreeController) -> Bool {
|
||||
|
||||
guard let nodePath = NodePath(representedObject: representedObject, treeController: treeController) else {
|
||||
return false
|
||||
}
|
||||
return revealAndSelectNodeAtPath(nodePath)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
224
RSTree/Sources/RSTree/Node.swift
Normal file
224
RSTree/Sources/RSTree/Node.swift
Normal file
@@ -0,0 +1,224 @@
|
||||
//
|
||||
// Node.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Brent Simmons on 7/21/15.
|
||||
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// Main thread only.
|
||||
|
||||
public final class Node: Hashable {
|
||||
|
||||
public weak var parent: Node?
|
||||
public let representedObject: AnyObject
|
||||
public var canHaveChildNodes = false
|
||||
public var isGroupItem = false
|
||||
public var childNodes = [Node]()
|
||||
public let uniqueID: Int
|
||||
private static var incrementingID = 0
|
||||
|
||||
public var isRoot: Bool {
|
||||
if let _ = parent {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public var numberOfChildNodes: Int {
|
||||
return childNodes.count
|
||||
}
|
||||
|
||||
public var indexPath: IndexPath {
|
||||
if let parent = parent {
|
||||
let parentPath = parent.indexPath
|
||||
if let childIndex = parent.indexOfChild(self) {
|
||||
return parentPath.appending(childIndex)
|
||||
}
|
||||
preconditionFailure("A Node’s parent must contain it as a child.")
|
||||
}
|
||||
return IndexPath(index: 0) //root node
|
||||
}
|
||||
|
||||
public var level: Int {
|
||||
if let parent = parent {
|
||||
return parent.level + 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public var isLeaf: Bool {
|
||||
return numberOfChildNodes < 1
|
||||
}
|
||||
|
||||
public init(representedObject: AnyObject, parent: Node?) {
|
||||
|
||||
precondition(Thread.isMainThread)
|
||||
|
||||
self.representedObject = representedObject
|
||||
self.parent = parent
|
||||
|
||||
self.uniqueID = Node.incrementingID
|
||||
Node.incrementingID += 1
|
||||
}
|
||||
|
||||
public class func genericRootNode() -> Node {
|
||||
|
||||
let node = Node(representedObject: TopLevelRepresentedObject(), parent: nil)
|
||||
node.canHaveChildNodes = true
|
||||
return node
|
||||
}
|
||||
|
||||
public func existingOrNewChildNode(with representedObject: AnyObject) -> Node {
|
||||
|
||||
if let node = childNodeRepresentingObject(representedObject) {
|
||||
return node
|
||||
}
|
||||
return createChildNode(representedObject)
|
||||
}
|
||||
|
||||
public func createChildNode(_ representedObject: AnyObject) -> Node {
|
||||
|
||||
// Just creates — doesn’t add it.
|
||||
return Node(representedObject: representedObject, parent: self)
|
||||
}
|
||||
|
||||
public func childAtIndex(_ index: Int) -> Node? {
|
||||
|
||||
if index >= childNodes.count || index < 0 {
|
||||
return nil
|
||||
}
|
||||
return childNodes[index]
|
||||
}
|
||||
|
||||
public func indexOfChild(_ node: Node) -> Int? {
|
||||
|
||||
return childNodes.firstIndex{ (oneChildNode) -> Bool in
|
||||
oneChildNode === node
|
||||
}
|
||||
}
|
||||
|
||||
public func childNodeRepresentingObject(_ obj: AnyObject) -> Node? {
|
||||
return findNodeRepresentingObject(obj, recursively: false)
|
||||
}
|
||||
|
||||
public func descendantNodeRepresentingObject(_ obj: AnyObject) -> Node? {
|
||||
return findNodeRepresentingObject(obj, recursively: true)
|
||||
}
|
||||
|
||||
public func descendantNode(where test: (Node) -> Bool) -> Node? {
|
||||
return findNode(where: test, recursively: true)
|
||||
}
|
||||
|
||||
public func hasAncestor(in nodes: [Node]) -> Bool {
|
||||
|
||||
for node in nodes {
|
||||
if node.isAncestor(of: self) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public func isAncestor(of node: Node) -> Bool {
|
||||
|
||||
if node == self {
|
||||
return false
|
||||
}
|
||||
|
||||
var nomad = node
|
||||
while true {
|
||||
guard let parent = nomad.parent else {
|
||||
return false
|
||||
}
|
||||
if parent == self {
|
||||
return true
|
||||
}
|
||||
nomad = parent
|
||||
}
|
||||
}
|
||||
|
||||
public class func nodesOrganizedByParent(_ nodes: [Node]) -> [Node: [Node]] {
|
||||
|
||||
let nodesWithParents = nodes.filter { $0.parent != nil }
|
||||
return Dictionary(grouping: nodesWithParents, by: { $0.parent! })
|
||||
}
|
||||
|
||||
public class func indexSetsGroupedByParent(_ nodes: [Node]) -> [Node: IndexSet] {
|
||||
|
||||
let d = nodesOrganizedByParent(nodes)
|
||||
let indexSetDictionary = d.mapValues { (nodes) -> IndexSet in
|
||||
|
||||
var indexSet = IndexSet()
|
||||
if nodes.isEmpty {
|
||||
return indexSet
|
||||
}
|
||||
|
||||
let parent = nodes.first!.parent!
|
||||
for node in nodes {
|
||||
if let index = parent.indexOfChild(node) {
|
||||
indexSet.insert(index)
|
||||
}
|
||||
}
|
||||
|
||||
return indexSet
|
||||
}
|
||||
|
||||
return indexSetDictionary
|
||||
}
|
||||
|
||||
// MARK: - Hashable
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(uniqueID)
|
||||
}
|
||||
|
||||
// MARK: - Equatable
|
||||
|
||||
public class func ==(lhs: Node, rhs: Node) -> Bool {
|
||||
return lhs === rhs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public extension Array where Element == Node {
|
||||
|
||||
func representedObjects() -> [AnyObject] {
|
||||
|
||||
return self.map{ $0.representedObject }
|
||||
}
|
||||
}
|
||||
|
||||
private extension Node {
|
||||
|
||||
func findNodeRepresentingObject(_ obj: AnyObject, recursively: Bool = false) -> Node? {
|
||||
|
||||
for childNode in childNodes {
|
||||
if childNode.representedObject === obj {
|
||||
return childNode
|
||||
}
|
||||
if recursively, let foundNode = childNode.descendantNodeRepresentingObject(obj) {
|
||||
return foundNode
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findNode(where test: (Node) -> Bool, recursively: Bool = false) -> Node? {
|
||||
|
||||
for childNode in childNodes {
|
||||
if test(childNode) {
|
||||
return childNode
|
||||
}
|
||||
if recursively, let foundNode = childNode.findNode(where: test, recursively: recursively) {
|
||||
return foundNode
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
42
RSTree/Sources/RSTree/NodePath.swift
Normal file
42
RSTree/Sources/RSTree/NodePath.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// NodePath.swift
|
||||
// RSTree
|
||||
//
|
||||
// Created by Brent Simmons on 9/5/16.
|
||||
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct NodePath {
|
||||
|
||||
let components: [Node]
|
||||
|
||||
public init(node: Node) {
|
||||
|
||||
var tempArray = [node]
|
||||
|
||||
var nomad: Node = node
|
||||
while true {
|
||||
if let parent = nomad.parent {
|
||||
tempArray.append(parent)
|
||||
nomad = parent
|
||||
}
|
||||
else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self.components = tempArray.reversed()
|
||||
}
|
||||
|
||||
public init?(representedObject: AnyObject, treeController: TreeController) {
|
||||
|
||||
if let node = treeController.nodeInTreeRepresentingObject(representedObject) {
|
||||
self.init(node: node)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
3
RSTree/Sources/RSTree/RSTree.swift
Normal file
3
RSTree/Sources/RSTree/RSTree.swift
Normal file
@@ -0,0 +1,3 @@
|
||||
struct RSTree {
|
||||
var text = "Hello, World!"
|
||||
}
|
||||
15
RSTree/Sources/RSTree/TopLevelRepresentedObject.swift
Normal file
15
RSTree/Sources/RSTree/TopLevelRepresentedObject.swift
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// TopLevelRepresentedObject.swift
|
||||
// RSTree
|
||||
//
|
||||
// Created by Brent Simmons on 8/10/16.
|
||||
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// Handy to use as the represented object for a root node. Not required to use it, though.
|
||||
|
||||
final class TopLevelRepresentedObject {
|
||||
|
||||
}
|
||||
135
RSTree/Sources/RSTree/TreeController.swift
Normal file
135
RSTree/Sources/RSTree/TreeController.swift
Normal file
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// TreeController.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Brent Simmons on 5/29/16.
|
||||
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol TreeControllerDelegate: class {
|
||||
|
||||
func treeController(treeController: TreeController, childNodesFor: Node) -> [Node]?
|
||||
}
|
||||
|
||||
public typealias NodeVisitBlock = (_ : Node) -> Void
|
||||
|
||||
public final class TreeController {
|
||||
|
||||
private weak var delegate: TreeControllerDelegate?
|
||||
public let rootNode: Node
|
||||
|
||||
public init(delegate: TreeControllerDelegate, rootNode: Node) {
|
||||
|
||||
self.delegate = delegate
|
||||
self.rootNode = rootNode
|
||||
rebuild()
|
||||
}
|
||||
|
||||
public convenience init(delegate: TreeControllerDelegate) {
|
||||
|
||||
self.init(delegate: delegate, rootNode: Node.genericRootNode())
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func rebuild() -> Bool {
|
||||
|
||||
// Rebuild and re-sort. Return true if any changes in the entire tree.
|
||||
|
||||
return rebuildChildNodes(node: rootNode)
|
||||
}
|
||||
|
||||
public func visitNodes(_ visitBlock: NodeVisitBlock) {
|
||||
|
||||
visitNode(rootNode, visitBlock)
|
||||
}
|
||||
|
||||
public func nodeInArrayRepresentingObject(nodes: [Node], representedObject: AnyObject, recurse: Bool = false) -> Node? {
|
||||
|
||||
for oneNode in nodes {
|
||||
|
||||
if oneNode.representedObject === representedObject {
|
||||
return oneNode
|
||||
}
|
||||
|
||||
if recurse, oneNode.canHaveChildNodes {
|
||||
if let foundNode = nodeInArrayRepresentingObject(nodes: oneNode.childNodes, representedObject: representedObject, recurse: recurse) {
|
||||
return foundNode
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func nodeInTreeRepresentingObject(_ representedObject: AnyObject) -> Node? {
|
||||
|
||||
return nodeInArrayRepresentingObject(nodes: [rootNode], representedObject: representedObject, recurse: true)
|
||||
}
|
||||
|
||||
public func normalizedSelectedNodes(_ nodes: [Node]) -> [Node] {
|
||||
|
||||
// An array of nodes might include a leaf node and its parent. Remove the leaf node.
|
||||
|
||||
var normalizedNodes = [Node]()
|
||||
|
||||
for node in nodes {
|
||||
if !node.hasAncestor(in: nodes) {
|
||||
normalizedNodes += [node]
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedNodes
|
||||
}
|
||||
}
|
||||
|
||||
private extension TreeController {
|
||||
|
||||
func visitNode(_ node: Node, _ visitBlock: NodeVisitBlock) {
|
||||
|
||||
visitBlock(node)
|
||||
node.childNodes.forEach{ (oneChildNode) in
|
||||
visitNode(oneChildNode, visitBlock)
|
||||
}
|
||||
}
|
||||
|
||||
func nodeArraysAreEqual(_ nodeArray1: [Node]?, _ nodeArray2: [Node]?) -> Bool {
|
||||
|
||||
if nodeArray1 == nil && nodeArray2 == nil {
|
||||
return true
|
||||
}
|
||||
if nodeArray1 != nil && nodeArray2 == nil {
|
||||
return false
|
||||
}
|
||||
if nodeArray1 == nil && nodeArray2 != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return nodeArray1! == nodeArray2!
|
||||
}
|
||||
|
||||
func rebuildChildNodes(node: Node) -> Bool {
|
||||
|
||||
if !node.canHaveChildNodes {
|
||||
return false
|
||||
}
|
||||
|
||||
var childNodesDidChange = false
|
||||
|
||||
let childNodes = delegate?.treeController(treeController: self, childNodesFor: node) ?? [Node]()
|
||||
|
||||
childNodesDidChange = !nodeArraysAreEqual(childNodes, node.childNodes)
|
||||
if (childNodesDidChange) {
|
||||
node.childNodes = childNodes
|
||||
}
|
||||
|
||||
childNodes.forEach{ (oneChildNode) in
|
||||
if rebuildChildNodes(node: oneChildNode) {
|
||||
childNodesDidChange = true
|
||||
}
|
||||
}
|
||||
|
||||
return childNodesDidChange
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user