├── .gitignore ├── Historian-ios ├── Historian.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── Historian │ ├── .gitignore │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json │ └── SceneDelegate.swift ├── Historian-macos ├── Historian.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── Historian │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ └── Main.storyboard │ ├── Historian.entitlements │ ├── Info.plist │ └── Preview Content │ └── Preview Assets.xcassets │ └── Contents.json ├── HistoryView ├── Extensions │ └── RangeReplaceableCollection+ext.swift ├── HistoryView+CA.swift ├── HistoryView.swift ├── RowView.swift └── Step.swift └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata/ 2 | -------------------------------------------------------------------------------- /Historian-ios/Historian.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5A27802A241E522F00D015F2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A278029241E522F00D015F2 /* AppDelegate.swift */; }; 11 | 5A27802C241E522F00D015F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A27802B241E522F00D015F2 /* SceneDelegate.swift */; }; 12 | 5A278030241E523100D015F2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A27802F241E523100D015F2 /* Assets.xcassets */; }; 13 | 5A278033241E523100D015F2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A278032241E523100D015F2 /* Preview Assets.xcassets */; }; 14 | 5A278036241E523100D015F2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A278034241E523100D015F2 /* LaunchScreen.storyboard */; }; 15 | 5A278045241E55E900D015F2 /* CompArch in Frameworks */ = {isa = PBXBuildFile; productRef = 5A278044241E55E900D015F2 /* CompArch */; }; 16 | 5A4871132420FF4500C05EBE /* HistoryTransceiver in Frameworks */ = {isa = PBXBuildFile; productRef = 5A4871122420FF4500C05EBE /* HistoryTransceiver */; }; 17 | 5A64C38F2420F0B800B167C3 /* CasePaths in Frameworks */ = {isa = PBXBuildFile; productRef = 5A64C38E2420F0B800B167C3 /* CasePaths */; }; 18 | 5A64C39B2420F1F400B167C3 /* HistoryView+CA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C3932420F1F400B167C3 /* HistoryView+CA.swift */; }; 19 | 5A64C39C2420F1F400B167C3 /* RangeReplaceableCollection+ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C3952420F1F400B167C3 /* RangeReplaceableCollection+ext.swift */; }; 20 | 5A64C39D2420F1F400B167C3 /* Step.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C3962420F1F400B167C3 /* Step.swift */; }; 21 | 5A64C39E2420F1F400B167C3 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C3972420F1F400B167C3 /* HistoryView.swift */; }; 22 | 5A64C39F2420F1F400B167C3 /* RowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C3982420F1F400B167C3 /* RowView.swift */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 5A278026241E522F00D015F2 /* Historian.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Historian.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 5A278029241E522F00D015F2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 28 | 5A27802B241E522F00D015F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 29 | 5A27802F241E523100D015F2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 5A278032241E523100D015F2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 31 | 5A278035241E523100D015F2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | 5A278037241E523100D015F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | 5A64C3932420F1F400B167C3 /* HistoryView+CA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HistoryView+CA.swift"; sourceTree = ""; }; 34 | 5A64C3952420F1F400B167C3 /* RangeReplaceableCollection+ext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RangeReplaceableCollection+ext.swift"; sourceTree = ""; }; 35 | 5A64C3962420F1F400B167C3 /* Step.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Step.swift; sourceTree = ""; }; 36 | 5A64C3972420F1F400B167C3 /* HistoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = ""; }; 37 | 5A64C3982420F1F400B167C3 /* RowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowView.swift; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | 5A278023241E522F00D015F2 /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | 5A4871132420FF4500C05EBE /* HistoryTransceiver in Frameworks */, 46 | 5A278045241E55E900D015F2 /* CompArch in Frameworks */, 47 | 5A64C38F2420F0B800B167C3 /* CasePaths in Frameworks */, 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXFrameworksBuildPhase section */ 52 | 53 | /* Begin PBXGroup section */ 54 | 5A27801D241E522F00D015F2 = { 55 | isa = PBXGroup; 56 | children = ( 57 | 5A278028241E522F00D015F2 /* Historian */, 58 | 5A64C3902420F1F400B167C3 /* HistoryView */, 59 | 5A278027241E522F00D015F2 /* Products */, 60 | ); 61 | sourceTree = ""; 62 | }; 63 | 5A278027241E522F00D015F2 /* Products */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 5A278026241E522F00D015F2 /* Historian.app */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | 5A278028241E522F00D015F2 /* Historian */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 5A278037241E523100D015F2 /* Info.plist */, 75 | 5A278029241E522F00D015F2 /* AppDelegate.swift */, 76 | 5A27802B241E522F00D015F2 /* SceneDelegate.swift */, 77 | 5A27802F241E523100D015F2 /* Assets.xcassets */, 78 | 5A278034241E523100D015F2 /* LaunchScreen.storyboard */, 79 | 5A278031241E523100D015F2 /* Preview Content */, 80 | ); 81 | path = Historian; 82 | sourceTree = ""; 83 | }; 84 | 5A278031241E523100D015F2 /* Preview Content */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 5A278032241E523100D015F2 /* Preview Assets.xcassets */, 88 | ); 89 | path = "Preview Content"; 90 | sourceTree = ""; 91 | }; 92 | 5A64C3902420F1F400B167C3 /* HistoryView */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 5A64C3972420F1F400B167C3 /* HistoryView.swift */, 96 | 5A64C3932420F1F400B167C3 /* HistoryView+CA.swift */, 97 | 5A64C3982420F1F400B167C3 /* RowView.swift */, 98 | 5A64C3962420F1F400B167C3 /* Step.swift */, 99 | 5A64C3942420F1F400B167C3 /* Extensions */, 100 | ); 101 | name = HistoryView; 102 | path = ../HistoryView; 103 | sourceTree = ""; 104 | }; 105 | 5A64C3942420F1F400B167C3 /* Extensions */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 5A64C3952420F1F400B167C3 /* RangeReplaceableCollection+ext.swift */, 109 | ); 110 | path = Extensions; 111 | sourceTree = ""; 112 | }; 113 | /* End PBXGroup section */ 114 | 115 | /* Begin PBXNativeTarget section */ 116 | 5A278025241E522F00D015F2 /* Historian */ = { 117 | isa = PBXNativeTarget; 118 | buildConfigurationList = 5A27803A241E523100D015F2 /* Build configuration list for PBXNativeTarget "Historian" */; 119 | buildPhases = ( 120 | 5A278022241E522F00D015F2 /* Sources */, 121 | 5A278023241E522F00D015F2 /* Frameworks */, 122 | 5A278024241E522F00D015F2 /* Resources */, 123 | ); 124 | buildRules = ( 125 | ); 126 | dependencies = ( 127 | ); 128 | name = Historian; 129 | packageProductDependencies = ( 130 | 5A278044241E55E900D015F2 /* CompArch */, 131 | 5A64C38E2420F0B800B167C3 /* CasePaths */, 132 | 5A4871122420FF4500C05EBE /* HistoryTransceiver */, 133 | ); 134 | productName = Historian; 135 | productReference = 5A278026241E522F00D015F2 /* Historian.app */; 136 | productType = "com.apple.product-type.application"; 137 | }; 138 | /* End PBXNativeTarget section */ 139 | 140 | /* Begin PBXProject section */ 141 | 5A27801E241E522F00D015F2 /* Project object */ = { 142 | isa = PBXProject; 143 | attributes = { 144 | LastSwiftUpdateCheck = 1140; 145 | LastUpgradeCheck = 1140; 146 | ORGANIZATIONNAME = finestructure; 147 | TargetAttributes = { 148 | 5A278025241E522F00D015F2 = { 149 | CreatedOnToolsVersion = 11.4; 150 | }; 151 | }; 152 | }; 153 | buildConfigurationList = 5A278021241E522F00D015F2 /* Build configuration list for PBXProject "Historian" */; 154 | compatibilityVersion = "Xcode 9.3"; 155 | developmentRegion = en; 156 | hasScannedForEncodings = 0; 157 | knownRegions = ( 158 | en, 159 | Base, 160 | ); 161 | mainGroup = 5A27801D241E522F00D015F2; 162 | packageReferences = ( 163 | 5A278043241E55E900D015F2 /* XCRemoteSwiftPackageReference "CompArch" */, 164 | 5A64C38D2420F0B800B167C3 /* XCRemoteSwiftPackageReference "swift-case-paths" */, 165 | 5A4871112420FF4500C05EBE /* XCRemoteSwiftPackageReference "HistoryTransceiver" */, 166 | ); 167 | productRefGroup = 5A278027241E522F00D015F2 /* Products */; 168 | projectDirPath = ""; 169 | projectRoot = ""; 170 | targets = ( 171 | 5A278025241E522F00D015F2 /* Historian */, 172 | ); 173 | }; 174 | /* End PBXProject section */ 175 | 176 | /* Begin PBXResourcesBuildPhase section */ 177 | 5A278024241E522F00D015F2 /* Resources */ = { 178 | isa = PBXResourcesBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | 5A278036241E523100D015F2 /* LaunchScreen.storyboard in Resources */, 182 | 5A278033241E523100D015F2 /* Preview Assets.xcassets in Resources */, 183 | 5A278030241E523100D015F2 /* Assets.xcassets in Resources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXResourcesBuildPhase section */ 188 | 189 | /* Begin PBXSourcesBuildPhase section */ 190 | 5A278022241E522F00D015F2 /* Sources */ = { 191 | isa = PBXSourcesBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | 5A64C39B2420F1F400B167C3 /* HistoryView+CA.swift in Sources */, 195 | 5A64C39E2420F1F400B167C3 /* HistoryView.swift in Sources */, 196 | 5A64C39C2420F1F400B167C3 /* RangeReplaceableCollection+ext.swift in Sources */, 197 | 5A64C39F2420F1F400B167C3 /* RowView.swift in Sources */, 198 | 5A64C39D2420F1F400B167C3 /* Step.swift in Sources */, 199 | 5A27802A241E522F00D015F2 /* AppDelegate.swift in Sources */, 200 | 5A27802C241E522F00D015F2 /* SceneDelegate.swift in Sources */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | /* End PBXSourcesBuildPhase section */ 205 | 206 | /* Begin PBXVariantGroup section */ 207 | 5A278034241E523100D015F2 /* LaunchScreen.storyboard */ = { 208 | isa = PBXVariantGroup; 209 | children = ( 210 | 5A278035241E523100D015F2 /* Base */, 211 | ); 212 | name = LaunchScreen.storyboard; 213 | sourceTree = ""; 214 | }; 215 | /* End PBXVariantGroup section */ 216 | 217 | /* Begin XCBuildConfiguration section */ 218 | 5A278038241E523100D015F2 /* Debug */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | ALWAYS_SEARCH_USER_PATHS = NO; 222 | CLANG_ANALYZER_NONNULL = YES; 223 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 224 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 225 | CLANG_CXX_LIBRARY = "libc++"; 226 | CLANG_ENABLE_MODULES = YES; 227 | CLANG_ENABLE_OBJC_ARC = YES; 228 | CLANG_ENABLE_OBJC_WEAK = YES; 229 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 230 | CLANG_WARN_BOOL_CONVERSION = YES; 231 | CLANG_WARN_COMMA = YES; 232 | CLANG_WARN_CONSTANT_CONVERSION = YES; 233 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 234 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 235 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INFINITE_RECURSION = YES; 239 | CLANG_WARN_INT_CONVERSION = YES; 240 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 241 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 242 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 243 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 244 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 245 | CLANG_WARN_STRICT_PROTOTYPES = YES; 246 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 247 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 248 | CLANG_WARN_UNREACHABLE_CODE = YES; 249 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 250 | COPY_PHASE_STRIP = NO; 251 | DEBUG_INFORMATION_FORMAT = dwarf; 252 | ENABLE_STRICT_OBJC_MSGSEND = YES; 253 | ENABLE_TESTABILITY = YES; 254 | GCC_C_LANGUAGE_STANDARD = gnu11; 255 | GCC_DYNAMIC_NO_PIC = NO; 256 | GCC_NO_COMMON_BLOCKS = YES; 257 | GCC_OPTIMIZATION_LEVEL = 0; 258 | GCC_PREPROCESSOR_DEFINITIONS = ( 259 | "DEBUG=1", 260 | "$(inherited)", 261 | ); 262 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 263 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 264 | GCC_WARN_UNDECLARED_SELECTOR = YES; 265 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 266 | GCC_WARN_UNUSED_FUNCTION = YES; 267 | GCC_WARN_UNUSED_VARIABLE = YES; 268 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 269 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 270 | MTL_FAST_MATH = YES; 271 | ONLY_ACTIVE_ARCH = YES; 272 | SDKROOT = iphoneos; 273 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 274 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 275 | }; 276 | name = Debug; 277 | }; 278 | 5A278039241E523100D015F2 /* Release */ = { 279 | isa = XCBuildConfiguration; 280 | buildSettings = { 281 | ALWAYS_SEARCH_USER_PATHS = NO; 282 | CLANG_ANALYZER_NONNULL = YES; 283 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 284 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 285 | CLANG_CXX_LIBRARY = "libc++"; 286 | CLANG_ENABLE_MODULES = YES; 287 | CLANG_ENABLE_OBJC_ARC = YES; 288 | CLANG_ENABLE_OBJC_WEAK = YES; 289 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 290 | CLANG_WARN_BOOL_CONVERSION = YES; 291 | CLANG_WARN_COMMA = YES; 292 | CLANG_WARN_CONSTANT_CONVERSION = YES; 293 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 294 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 295 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 296 | CLANG_WARN_EMPTY_BODY = YES; 297 | CLANG_WARN_ENUM_CONVERSION = YES; 298 | CLANG_WARN_INFINITE_RECURSION = YES; 299 | CLANG_WARN_INT_CONVERSION = YES; 300 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 301 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 302 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 303 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 304 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 305 | CLANG_WARN_STRICT_PROTOTYPES = YES; 306 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 307 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 308 | CLANG_WARN_UNREACHABLE_CODE = YES; 309 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 310 | COPY_PHASE_STRIP = NO; 311 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 312 | ENABLE_NS_ASSERTIONS = NO; 313 | ENABLE_STRICT_OBJC_MSGSEND = YES; 314 | GCC_C_LANGUAGE_STANDARD = gnu11; 315 | GCC_NO_COMMON_BLOCKS = YES; 316 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 317 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 318 | GCC_WARN_UNDECLARED_SELECTOR = YES; 319 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 320 | GCC_WARN_UNUSED_FUNCTION = YES; 321 | GCC_WARN_UNUSED_VARIABLE = YES; 322 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 323 | MTL_ENABLE_DEBUG_INFO = NO; 324 | MTL_FAST_MATH = YES; 325 | SDKROOT = iphoneos; 326 | SWIFT_COMPILATION_MODE = wholemodule; 327 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 328 | VALIDATE_PRODUCT = YES; 329 | }; 330 | name = Release; 331 | }; 332 | 5A27803B241E523100D015F2 /* Debug */ = { 333 | isa = XCBuildConfiguration; 334 | buildSettings = { 335 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 336 | CODE_SIGN_STYLE = Automatic; 337 | DEVELOPMENT_ASSET_PATHS = "\"Historian/Preview Content\""; 338 | DEVELOPMENT_TEAM = A42K5AU657; 339 | ENABLE_PREVIEWS = YES; 340 | INFOPLIST_FILE = Historian/Info.plist; 341 | LD_RUNPATH_SEARCH_PATHS = ( 342 | "$(inherited)", 343 | "@executable_path/Frameworks", 344 | ); 345 | PRODUCT_BUNDLE_IDENTIFIER = co.finestructure.Historian; 346 | PRODUCT_NAME = "$(TARGET_NAME)"; 347 | SWIFT_VERSION = 5.0; 348 | TARGETED_DEVICE_FAMILY = "1,2"; 349 | }; 350 | name = Debug; 351 | }; 352 | 5A27803C241E523100D015F2 /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 356 | CODE_SIGN_STYLE = Automatic; 357 | DEVELOPMENT_ASSET_PATHS = "\"Historian/Preview Content\""; 358 | DEVELOPMENT_TEAM = A42K5AU657; 359 | ENABLE_PREVIEWS = YES; 360 | INFOPLIST_FILE = Historian/Info.plist; 361 | LD_RUNPATH_SEARCH_PATHS = ( 362 | "$(inherited)", 363 | "@executable_path/Frameworks", 364 | ); 365 | PRODUCT_BUNDLE_IDENTIFIER = co.finestructure.Historian; 366 | PRODUCT_NAME = "$(TARGET_NAME)"; 367 | SWIFT_VERSION = 5.0; 368 | TARGETED_DEVICE_FAMILY = "1,2"; 369 | }; 370 | name = Release; 371 | }; 372 | /* End XCBuildConfiguration section */ 373 | 374 | /* Begin XCConfigurationList section */ 375 | 5A278021241E522F00D015F2 /* Build configuration list for PBXProject "Historian" */ = { 376 | isa = XCConfigurationList; 377 | buildConfigurations = ( 378 | 5A278038241E523100D015F2 /* Debug */, 379 | 5A278039241E523100D015F2 /* Release */, 380 | ); 381 | defaultConfigurationIsVisible = 0; 382 | defaultConfigurationName = Release; 383 | }; 384 | 5A27803A241E523100D015F2 /* Build configuration list for PBXNativeTarget "Historian" */ = { 385 | isa = XCConfigurationList; 386 | buildConfigurations = ( 387 | 5A27803B241E523100D015F2 /* Debug */, 388 | 5A27803C241E523100D015F2 /* Release */, 389 | ); 390 | defaultConfigurationIsVisible = 0; 391 | defaultConfigurationName = Release; 392 | }; 393 | /* End XCConfigurationList section */ 394 | 395 | /* Begin XCRemoteSwiftPackageReference section */ 396 | 5A278043241E55E900D015F2 /* XCRemoteSwiftPackageReference "CompArch" */ = { 397 | isa = XCRemoteSwiftPackageReference; 398 | repositoryURL = "https://github.com/finestructure/CompArch"; 399 | requirement = { 400 | kind = upToNextMajorVersion; 401 | minimumVersion = 0.7.1; 402 | }; 403 | }; 404 | 5A4871112420FF4500C05EBE /* XCRemoteSwiftPackageReference "HistoryTransceiver" */ = { 405 | isa = XCRemoteSwiftPackageReference; 406 | repositoryURL = "https://github.com/finestructure/HistoryTransceiver"; 407 | requirement = { 408 | kind = upToNextMajorVersion; 409 | minimumVersion = 0.0.1; 410 | }; 411 | }; 412 | 5A64C38D2420F0B800B167C3 /* XCRemoteSwiftPackageReference "swift-case-paths" */ = { 413 | isa = XCRemoteSwiftPackageReference; 414 | repositoryURL = "https://github.com/pointfreeco/swift-case-paths"; 415 | requirement = { 416 | kind = upToNextMajorVersion; 417 | minimumVersion = 0.1.0; 418 | }; 419 | }; 420 | /* End XCRemoteSwiftPackageReference section */ 421 | 422 | /* Begin XCSwiftPackageProductDependency section */ 423 | 5A278044241E55E900D015F2 /* CompArch */ = { 424 | isa = XCSwiftPackageProductDependency; 425 | package = 5A278043241E55E900D015F2 /* XCRemoteSwiftPackageReference "CompArch" */; 426 | productName = CompArch; 427 | }; 428 | 5A4871122420FF4500C05EBE /* HistoryTransceiver */ = { 429 | isa = XCSwiftPackageProductDependency; 430 | package = 5A4871112420FF4500C05EBE /* XCRemoteSwiftPackageReference "HistoryTransceiver" */; 431 | productName = HistoryTransceiver; 432 | }; 433 | 5A64C38E2420F0B800B167C3 /* CasePaths */ = { 434 | isa = XCSwiftPackageProductDependency; 435 | package = 5A64C38D2420F0B800B167C3 /* XCRemoteSwiftPackageReference "swift-case-paths" */; 436 | productName = CasePaths; 437 | }; 438 | /* End XCSwiftPackageProductDependency section */ 439 | }; 440 | rootObject = 5A27801E241E522F00D015F2 /* Project object */; 441 | } 442 | -------------------------------------------------------------------------------- /Historian-ios/Historian.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Historian-ios/Historian.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Historian-ios/Historian.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "CompArch", 6 | "repositoryURL": "https://github.com/finestructure/CompArch", 7 | "state": { 8 | "branch": null, 9 | "revision": "b3bbb247b18b29549e905e31e5a19ebc46d1cefb", 10 | "version": "0.7.2" 11 | } 12 | }, 13 | { 14 | "package": "HistoryTransceiver", 15 | "repositoryURL": "https://github.com/finestructure/HistoryTransceiver", 16 | "state": { 17 | "branch": null, 18 | "revision": "fd88668d1648e5f7f61843e676ecbe4cafa4a642", 19 | "version": "0.0.3" 20 | } 21 | }, 22 | { 23 | "package": "MultipeerKit", 24 | "repositoryURL": "https://github.com/insidegui/MultipeerKit", 25 | "state": { 26 | "branch": null, 27 | "revision": "3f430bc28e1426ba42cdaa8b19fb4d89ce6d1c3b", 28 | "version": "0.1.2" 29 | } 30 | }, 31 | { 32 | "package": "CasePaths", 33 | "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", 34 | "state": { 35 | "branch": null, 36 | "revision": "a9c1e05518b6d95cf5844d823020376f2b6ff842", 37 | "version": "0.1.0" 38 | } 39 | } 40 | ] 41 | }, 42 | "version": 1 43 | } 44 | -------------------------------------------------------------------------------- /Historian-ios/Historian/.gitignore: -------------------------------------------------------------------------------- 1 | ######################### 2 | # .gitignore file for Xcode4 and Xcode5 Source projects 3 | # 4 | # Apple bugs, waiting for Apple to fix/respond: 5 | # 6 | # 15564624 - what does the xccheckout file in Xcode5 do? Where's the documentation? 7 | # 8 | # Version 2.6 9 | # For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects 10 | # 11 | # 2015 updates: 12 | # - Fixed typo in "xccheckout" line - thanks to @lyck for pointing it out! 13 | # - Fixed the .idea optional ignore. Thanks to @hashier for pointing this out 14 | # - Finally added "xccheckout" to the ignore. Apple still refuses to answer support requests about this, but in practice it seems you should ignore it. 15 | # - minor tweaks from Jona and Coeur (slightly more precise xc* filtering/names) 16 | # 2014 updates: 17 | # - appended non-standard items DISABLED by default (uncomment if you use those tools) 18 | # - removed the edit that an SO.com moderator made without bothering to ask me 19 | # - researched CocoaPods .lock more carefully, thanks to Gokhan Celiker 20 | # 2013 updates: 21 | # - fixed the broken "save personal Schemes" 22 | # - added line-by-line explanations for EVERYTHING (some were missing) 23 | # 24 | # NB: if you are storing "built" products, this WILL NOT WORK, 25 | # and you should use a different .gitignore (or none at all) 26 | # This file is for SOURCE projects, where there are many extra 27 | # files that we want to exclude 28 | # 29 | ######################### 30 | 31 | ##### 32 | # OS X temporary files that should never be committed 33 | # 34 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 35 | 36 | .DS_Store 37 | 38 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 39 | 40 | .Trashes 41 | 42 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 43 | 44 | *.swp 45 | 46 | # 47 | # *.lock - this is used and abused by many editors for many different things. 48 | # For the main ones I use (e.g. Eclipse), it should be excluded 49 | # from source-control, but YMMV. 50 | # (lock files are usually local-only file-synchronization on the local FS that should NOT go in git) 51 | # c.f. the "OPTIONAL" section at bottom though, for tool-specific variations! 52 | # 53 | # In particular, if you're using CocoaPods, you'll want to comment-out this line: 54 | *.lock 55 | 56 | 57 | # 58 | # profile - REMOVED temporarily (on double-checking, I can't find it in OS X docs?) 59 | #profile 60 | 61 | 62 | #### 63 | # Xcode temporary files that should never be committed 64 | # 65 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this... 66 | 67 | *~.nib 68 | 69 | 70 | #### 71 | # Xcode build files - 72 | # 73 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData" 74 | 75 | DerivedData/ 76 | 77 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build" 78 | 79 | build/ 80 | 81 | 82 | ##### 83 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) 84 | # 85 | # This is complicated: 86 | # 87 | # SOMETIMES you need to put this file in version control. 88 | # Apple designed it poorly - if you use "custom executables", they are 89 | # saved in this file. 90 | # 99% of projects do NOT use those, so they do NOT want to version control this file. 91 | # ..but if you're in the 1%, comment out the line "*.pbxuser" 92 | 93 | # .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html 94 | 95 | *.pbxuser 96 | 97 | # .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html 98 | 99 | *.mode1v3 100 | 101 | # .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html 102 | 103 | *.mode2v3 104 | 105 | # .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file 106 | 107 | *.perspectivev3 108 | 109 | # NB: also, whitelist the default ones, some projects need to use these 110 | !default.pbxuser 111 | !default.mode1v3 112 | !default.mode2v3 113 | !default.perspectivev3 114 | 115 | 116 | #### 117 | # Xcode 4 - semi-personal settings 118 | # 119 | # Apple Shared data that Apple put in the wrong folder 120 | # c.f. http://stackoverflow.com/a/19260712/153422 121 | # FROM ANSWER: Apple says "don't ignore it" 122 | # FROM COMMENTS: Apple is wrong; Apple code is too buggy to trust; there are no known negative side-effects to ignoring Apple's unofficial advice and instead doing the thing that actively fixes bugs in Xcode 123 | # Up to you, but ... current advice: ignore it. 124 | *.xccheckout 125 | 126 | # 127 | # 128 | # OPTION 1: --------------------------------- 129 | # throw away ALL personal settings (including custom schemes! 130 | # - unless they are "shared") 131 | # As per build/ and DerivedData/, this ought to have a trailing slash 132 | # 133 | # NB: this is exclusive with OPTION 2 below 134 | xcuserdata/ 135 | 136 | # OPTION 2: --------------------------------- 137 | # get rid of ALL personal settings, but KEEP SOME OF THEM 138 | # - NB: you must manually uncomment the bits you want to keep 139 | # 140 | # NB: this *requires* git v1.8.2 or above; you may need to upgrade to latest OS X, 141 | # or manually install git over the top of the OS X version 142 | # NB: this is exclusive with OPTION 1 above 143 | # 144 | #xcuserdata/**/* 145 | 146 | # (requires option 2 above): Personal Schemes 147 | # 148 | #!xcuserdata/**/xcschemes/* 149 | 150 | #### 151 | # XCode 4 workspaces - more detailed 152 | # 153 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :) 154 | # 155 | # Workspace layout is quite spammy. For reference: 156 | # 157 | # /(root)/ 158 | # /(project-name).xcodeproj/ 159 | # project.pbxproj 160 | # /project.xcworkspace/ 161 | # contents.xcworkspacedata 162 | # /xcuserdata/ 163 | # /(your name)/xcuserdatad/ 164 | # UserInterfaceState.xcuserstate 165 | # /xcshareddata/ 166 | # /xcschemes/ 167 | # (shared scheme name).xcscheme 168 | # /xcuserdata/ 169 | # /(your name)/xcuserdatad/ 170 | # (private scheme).xcscheme 171 | # xcschememanagement.plist 172 | # 173 | # 174 | 175 | #### 176 | # Xcode 4 - Deprecated classes 177 | # 178 | # Allegedly, if you manually "deprecate" your classes, they get moved here. 179 | # 180 | # We're using source-control, so this is a "feature" that we do not want! 181 | 182 | *.moved-aside 183 | 184 | #### 185 | # OPTIONAL: Some well-known tools that people use side-by-side with Xcode / iOS development 186 | # 187 | # NB: I'd rather not include these here, but gitignore's design is weak and doesn't allow 188 | # modular gitignore: you have to put EVERYTHING in one file. 189 | # 190 | # COCOAPODS: 191 | # 192 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#what-is-a-podfilelock 193 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 194 | # 195 | #!Podfile.lock 196 | # 197 | # RUBY: 198 | # 199 | # c.f. http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/ 200 | # 201 | #!Gemfile.lock 202 | # 203 | # IDEA: 204 | # 205 | # c.f. https://www.jetbrains.com/objc/help/managing-projects-under-version-control.html?search=workspace.xml 206 | # 207 | #.idea/workspace.xml 208 | # 209 | # TEXTMATE: 210 | # 211 | # -- UNVERIFIED: c.f. http://stackoverflow.com/a/50283/153422 212 | # 213 | #tm_build_errors 214 | 215 | #### 216 | # UNKNOWN: recommended by others, but I can't discover what these files are 217 | # -------------------------------------------------------------------------------- /Historian-ios/Historian/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Historian 4 | // 5 | // Created by Sven A. Schmidt on 15/03/2020. 6 | // Copyright © 2020 finestructure. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | // MARK: UISceneSession Lifecycle 23 | 24 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 25 | // Called when a new scene session is being created. 26 | // Use this method to select a configuration to create the new scene with. 27 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 28 | } 29 | 30 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 31 | // Called when the user discards a scene session. 32 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 33 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 34 | } 35 | 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Historian-ios/Historian/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Historian-ios/Historian/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Historian-ios/Historian/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Historian-ios/Historian/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | 37 | 38 | 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationPortraitUpsideDown 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Historian-ios/Historian/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Historian-ios/Historian/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // Historian 4 | // 5 | // Created by Sven A. Schmidt on 15/03/2020. 6 | // Copyright © 2020 finestructure. All rights reserved. 7 | // 8 | 9 | import HistoryTransceiver 10 | import UIKit 11 | import SwiftUI 12 | 13 | 14 | var historyStore = HistoryView.store(history: [], broadcastEnabled: true) 15 | 16 | 17 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 18 | 19 | var window: UIWindow? 20 | 21 | 22 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 23 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 24 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 25 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 26 | 27 | Transceiver.shared.receive(Message.self) { msg in 28 | historyStore.send(HistoryView.Action.appendStep("\(msg.action)", msg.state)) 29 | } 30 | Transceiver.shared.resume() 31 | 32 | // Create the SwiftUI view that provides the window contents. 33 | let contentView = HistoryView(store: historyStore) 34 | .environmentObject(Transceiver.dataSource) 35 | 36 | // Use a UIHostingController as window root view controller. 37 | if let windowScene = scene as? UIWindowScene { 38 | let window = UIWindow(windowScene: windowScene) 39 | window.rootViewController = UIHostingController(rootView: contentView) 40 | self.window = window 41 | window.makeKeyAndVisible() 42 | } 43 | } 44 | 45 | func sceneDidDisconnect(_ scene: UIScene) { 46 | // Called as the scene is being released by the system. 47 | // This occurs shortly after the scene enters the background, or when its session is discarded. 48 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 49 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 50 | } 51 | 52 | func sceneDidBecomeActive(_ scene: UIScene) { 53 | // Called when the scene has moved from an inactive state to an active state. 54 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 55 | } 56 | 57 | func sceneWillResignActive(_ scene: UIScene) { 58 | // Called when the scene will move from an active state to an inactive state. 59 | // This may occur due to temporary interruptions (ex. an incoming phone call). 60 | } 61 | 62 | func sceneWillEnterForeground(_ scene: UIScene) { 63 | // Called as the scene transitions from the background to the foreground. 64 | // Use this method to undo the changes made on entering the background. 65 | } 66 | 67 | func sceneDidEnterBackground(_ scene: UIScene) { 68 | // Called as the scene transitions from the foreground to the background. 69 | // Use this method to save data, release shared resources, and store enough scene-specific state information 70 | // to restore the scene back to its current state. 71 | } 72 | 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /Historian-macos/Historian.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5A2780B6241F911A00D015F2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A2780B5241F911A00D015F2 /* AppDelegate.swift */; }; 11 | 5A2780BA241F911B00D015F2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A2780B9241F911B00D015F2 /* Assets.xcassets */; }; 12 | 5A2780BD241F911B00D015F2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A2780BC241F911B00D015F2 /* Preview Assets.xcassets */; }; 13 | 5A2780C0241F911B00D015F2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A2780BE241F911B00D015F2 /* Main.storyboard */; }; 14 | 5A4871162421015D00C05EBE /* HistoryTransceiver in Frameworks */ = {isa = PBXBuildFile; productRef = 5A4871152421015D00C05EBE /* HistoryTransceiver */; }; 15 | 5A64C37F24200BE900B167C3 /* HistoryView+CA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C37724200BE900B167C3 /* HistoryView+CA.swift */; }; 16 | 5A64C38024200BE900B167C3 /* RangeReplaceableCollection+ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C37924200BE900B167C3 /* RangeReplaceableCollection+ext.swift */; }; 17 | 5A64C38124200BE900B167C3 /* Step.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C37A24200BE900B167C3 /* Step.swift */; }; 18 | 5A64C38224200BE900B167C3 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C37B24200BE900B167C3 /* HistoryView.swift */; }; 19 | 5A64C38324200BE900B167C3 /* RowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A64C37C24200BE900B167C3 /* RowView.swift */; }; 20 | 5A64C3862420B5F500B167C3 /* CompArch in Frameworks */ = {isa = PBXBuildFile; productRef = 5A64C3852420B5F500B167C3 /* CompArch */; }; 21 | 5A64C38C2420B65500B167C3 /* CasePaths in Frameworks */ = {isa = PBXBuildFile; productRef = 5A64C38B2420B65500B167C3 /* CasePaths */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 5A2780B2241F911A00D015F2 /* Historian.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Historian.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 5A2780B5241F911A00D015F2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | 5A2780B9241F911B00D015F2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | 5A2780BC241F911B00D015F2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 29 | 5A2780BF241F911B00D015F2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | 5A2780C1241F911B00D015F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | 5A2780C2241F911B00D015F2 /* Historian.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Historian.entitlements; sourceTree = ""; }; 32 | 5A64C37724200BE900B167C3 /* HistoryView+CA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HistoryView+CA.swift"; sourceTree = ""; }; 33 | 5A64C37924200BE900B167C3 /* RangeReplaceableCollection+ext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RangeReplaceableCollection+ext.swift"; sourceTree = ""; }; 34 | 5A64C37A24200BE900B167C3 /* Step.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Step.swift; sourceTree = ""; }; 35 | 5A64C37B24200BE900B167C3 /* HistoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = ""; }; 36 | 5A64C37C24200BE900B167C3 /* RowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowView.swift; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 5A2780AF241F911A00D015F2 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | 5A4871162421015D00C05EBE /* HistoryTransceiver in Frameworks */, 45 | 5A64C3862420B5F500B167C3 /* CompArch in Frameworks */, 46 | 5A64C38C2420B65500B167C3 /* CasePaths in Frameworks */, 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | 5A2780A9241F911A00D015F2 = { 54 | isa = PBXGroup; 55 | children = ( 56 | 5A2780B4241F911A00D015F2 /* Historian */, 57 | 5A64C37424200BE900B167C3 /* HistoryView */, 58 | 5A2780B3241F911A00D015F2 /* Products */, 59 | ); 60 | sourceTree = ""; 61 | }; 62 | 5A2780B3241F911A00D015F2 /* Products */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 5A2780B2241F911A00D015F2 /* Historian.app */, 66 | ); 67 | name = Products; 68 | sourceTree = ""; 69 | }; 70 | 5A2780B4241F911A00D015F2 /* Historian */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 5A2780B5241F911A00D015F2 /* AppDelegate.swift */, 74 | 5A2780B9241F911B00D015F2 /* Assets.xcassets */, 75 | 5A2780BE241F911B00D015F2 /* Main.storyboard */, 76 | 5A2780C1241F911B00D015F2 /* Info.plist */, 77 | 5A2780C2241F911B00D015F2 /* Historian.entitlements */, 78 | 5A2780BB241F911B00D015F2 /* Preview Content */, 79 | ); 80 | path = Historian; 81 | sourceTree = ""; 82 | }; 83 | 5A2780BB241F911B00D015F2 /* Preview Content */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 5A2780BC241F911B00D015F2 /* Preview Assets.xcassets */, 87 | ); 88 | path = "Preview Content"; 89 | sourceTree = ""; 90 | }; 91 | 5A64C37424200BE900B167C3 /* HistoryView */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 5A64C37B24200BE900B167C3 /* HistoryView.swift */, 95 | 5A64C37724200BE900B167C3 /* HistoryView+CA.swift */, 96 | 5A64C37C24200BE900B167C3 /* RowView.swift */, 97 | 5A64C37A24200BE900B167C3 /* Step.swift */, 98 | 5A64C37824200BE900B167C3 /* Extensions */, 99 | ); 100 | name = HistoryView; 101 | path = ../HistoryView; 102 | sourceTree = ""; 103 | }; 104 | 5A64C37824200BE900B167C3 /* Extensions */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 5A64C37924200BE900B167C3 /* RangeReplaceableCollection+ext.swift */, 108 | ); 109 | path = Extensions; 110 | sourceTree = ""; 111 | }; 112 | /* End PBXGroup section */ 113 | 114 | /* Begin PBXNativeTarget section */ 115 | 5A2780B1241F911A00D015F2 /* Historian */ = { 116 | isa = PBXNativeTarget; 117 | buildConfigurationList = 5A2780C5241F911B00D015F2 /* Build configuration list for PBXNativeTarget "Historian" */; 118 | buildPhases = ( 119 | 5A2780AE241F911A00D015F2 /* Sources */, 120 | 5A2780AF241F911A00D015F2 /* Frameworks */, 121 | 5A2780B0241F911A00D015F2 /* Resources */, 122 | ); 123 | buildRules = ( 124 | ); 125 | dependencies = ( 126 | ); 127 | name = Historian; 128 | packageProductDependencies = ( 129 | 5A64C3852420B5F500B167C3 /* CompArch */, 130 | 5A64C38B2420B65500B167C3 /* CasePaths */, 131 | 5A4871152421015D00C05EBE /* HistoryTransceiver */, 132 | ); 133 | productName = Historian; 134 | productReference = 5A2780B2241F911A00D015F2 /* Historian.app */; 135 | productType = "com.apple.product-type.application"; 136 | }; 137 | /* End PBXNativeTarget section */ 138 | 139 | /* Begin PBXProject section */ 140 | 5A2780AA241F911A00D015F2 /* Project object */ = { 141 | isa = PBXProject; 142 | attributes = { 143 | LastSwiftUpdateCheck = 1140; 144 | LastUpgradeCheck = 1140; 145 | ORGANIZATIONNAME = finestructure; 146 | TargetAttributes = { 147 | 5A2780B1241F911A00D015F2 = { 148 | CreatedOnToolsVersion = 11.4; 149 | }; 150 | }; 151 | }; 152 | buildConfigurationList = 5A2780AD241F911A00D015F2 /* Build configuration list for PBXProject "Historian" */; 153 | compatibilityVersion = "Xcode 9.3"; 154 | developmentRegion = en; 155 | hasScannedForEncodings = 0; 156 | knownRegions = ( 157 | en, 158 | Base, 159 | ); 160 | mainGroup = 5A2780A9241F911A00D015F2; 161 | packageReferences = ( 162 | 5A64C3842420B5F500B167C3 /* XCRemoteSwiftPackageReference "CompArch" */, 163 | 5A64C38A2420B65500B167C3 /* XCRemoteSwiftPackageReference "swift-case-paths" */, 164 | 5A4871142421015D00C05EBE /* XCRemoteSwiftPackageReference "HistoryTransceiver" */, 165 | ); 166 | productRefGroup = 5A2780B3241F911A00D015F2 /* Products */; 167 | projectDirPath = ""; 168 | projectRoot = ""; 169 | targets = ( 170 | 5A2780B1241F911A00D015F2 /* Historian */, 171 | ); 172 | }; 173 | /* End PBXProject section */ 174 | 175 | /* Begin PBXResourcesBuildPhase section */ 176 | 5A2780B0241F911A00D015F2 /* Resources */ = { 177 | isa = PBXResourcesBuildPhase; 178 | buildActionMask = 2147483647; 179 | files = ( 180 | 5A2780C0241F911B00D015F2 /* Main.storyboard in Resources */, 181 | 5A2780BD241F911B00D015F2 /* Preview Assets.xcassets in Resources */, 182 | 5A2780BA241F911B00D015F2 /* Assets.xcassets in Resources */, 183 | ); 184 | runOnlyForDeploymentPostprocessing = 0; 185 | }; 186 | /* End PBXResourcesBuildPhase section */ 187 | 188 | /* Begin PBXSourcesBuildPhase section */ 189 | 5A2780AE241F911A00D015F2 /* Sources */ = { 190 | isa = PBXSourcesBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | 5A64C38224200BE900B167C3 /* HistoryView.swift in Sources */, 194 | 5A64C38024200BE900B167C3 /* RangeReplaceableCollection+ext.swift in Sources */, 195 | 5A64C38324200BE900B167C3 /* RowView.swift in Sources */, 196 | 5A2780B6241F911A00D015F2 /* AppDelegate.swift in Sources */, 197 | 5A64C37F24200BE900B167C3 /* HistoryView+CA.swift in Sources */, 198 | 5A64C38124200BE900B167C3 /* Step.swift in Sources */, 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | /* End PBXSourcesBuildPhase section */ 203 | 204 | /* Begin PBXVariantGroup section */ 205 | 5A2780BE241F911B00D015F2 /* Main.storyboard */ = { 206 | isa = PBXVariantGroup; 207 | children = ( 208 | 5A2780BF241F911B00D015F2 /* Base */, 209 | ); 210 | name = Main.storyboard; 211 | sourceTree = ""; 212 | }; 213 | /* End PBXVariantGroup section */ 214 | 215 | /* Begin XCBuildConfiguration section */ 216 | 5A2780C3241F911B00D015F2 /* Debug */ = { 217 | isa = XCBuildConfiguration; 218 | buildSettings = { 219 | ALWAYS_SEARCH_USER_PATHS = NO; 220 | CLANG_ANALYZER_NONNULL = YES; 221 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 223 | CLANG_CXX_LIBRARY = "libc++"; 224 | CLANG_ENABLE_MODULES = YES; 225 | CLANG_ENABLE_OBJC_ARC = YES; 226 | CLANG_ENABLE_OBJC_WEAK = YES; 227 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 228 | CLANG_WARN_BOOL_CONVERSION = YES; 229 | CLANG_WARN_COMMA = YES; 230 | CLANG_WARN_CONSTANT_CONVERSION = YES; 231 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 232 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 233 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 234 | CLANG_WARN_EMPTY_BODY = YES; 235 | CLANG_WARN_ENUM_CONVERSION = YES; 236 | CLANG_WARN_INFINITE_RECURSION = YES; 237 | CLANG_WARN_INT_CONVERSION = YES; 238 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 239 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 240 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 241 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 242 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 243 | CLANG_WARN_STRICT_PROTOTYPES = YES; 244 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 245 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 246 | CLANG_WARN_UNREACHABLE_CODE = YES; 247 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 248 | COPY_PHASE_STRIP = NO; 249 | DEBUG_INFORMATION_FORMAT = dwarf; 250 | ENABLE_STRICT_OBJC_MSGSEND = YES; 251 | ENABLE_TESTABILITY = YES; 252 | GCC_C_LANGUAGE_STANDARD = gnu11; 253 | GCC_DYNAMIC_NO_PIC = NO; 254 | GCC_NO_COMMON_BLOCKS = YES; 255 | GCC_OPTIMIZATION_LEVEL = 0; 256 | GCC_PREPROCESSOR_DEFINITIONS = ( 257 | "DEBUG=1", 258 | "$(inherited)", 259 | ); 260 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 261 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 262 | GCC_WARN_UNDECLARED_SELECTOR = YES; 263 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 264 | GCC_WARN_UNUSED_FUNCTION = YES; 265 | GCC_WARN_UNUSED_VARIABLE = YES; 266 | MACOSX_DEPLOYMENT_TARGET = 10.15; 267 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 268 | MTL_FAST_MATH = YES; 269 | ONLY_ACTIVE_ARCH = YES; 270 | SDKROOT = macosx; 271 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 272 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 273 | }; 274 | name = Debug; 275 | }; 276 | 5A2780C4241F911B00D015F2 /* Release */ = { 277 | isa = XCBuildConfiguration; 278 | buildSettings = { 279 | ALWAYS_SEARCH_USER_PATHS = NO; 280 | CLANG_ANALYZER_NONNULL = YES; 281 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 282 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 283 | CLANG_CXX_LIBRARY = "libc++"; 284 | CLANG_ENABLE_MODULES = YES; 285 | CLANG_ENABLE_OBJC_ARC = YES; 286 | CLANG_ENABLE_OBJC_WEAK = YES; 287 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 288 | CLANG_WARN_BOOL_CONVERSION = YES; 289 | CLANG_WARN_COMMA = YES; 290 | CLANG_WARN_CONSTANT_CONVERSION = YES; 291 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 292 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 293 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 294 | CLANG_WARN_EMPTY_BODY = YES; 295 | CLANG_WARN_ENUM_CONVERSION = YES; 296 | CLANG_WARN_INFINITE_RECURSION = YES; 297 | CLANG_WARN_INT_CONVERSION = YES; 298 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 299 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 300 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 301 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 302 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 303 | CLANG_WARN_STRICT_PROTOTYPES = YES; 304 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 305 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 306 | CLANG_WARN_UNREACHABLE_CODE = YES; 307 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 308 | COPY_PHASE_STRIP = NO; 309 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 310 | ENABLE_NS_ASSERTIONS = NO; 311 | ENABLE_STRICT_OBJC_MSGSEND = YES; 312 | GCC_C_LANGUAGE_STANDARD = gnu11; 313 | GCC_NO_COMMON_BLOCKS = YES; 314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 316 | GCC_WARN_UNDECLARED_SELECTOR = YES; 317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 318 | GCC_WARN_UNUSED_FUNCTION = YES; 319 | GCC_WARN_UNUSED_VARIABLE = YES; 320 | MACOSX_DEPLOYMENT_TARGET = 10.15; 321 | MTL_ENABLE_DEBUG_INFO = NO; 322 | MTL_FAST_MATH = YES; 323 | SDKROOT = macosx; 324 | SWIFT_COMPILATION_MODE = wholemodule; 325 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 326 | }; 327 | name = Release; 328 | }; 329 | 5A2780C6241F911B00D015F2 /* Debug */ = { 330 | isa = XCBuildConfiguration; 331 | buildSettings = { 332 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 333 | CODE_SIGN_ENTITLEMENTS = Historian/Historian.entitlements; 334 | CODE_SIGN_STYLE = Automatic; 335 | COMBINE_HIDPI_IMAGES = YES; 336 | DEVELOPMENT_ASSET_PATHS = "\"Historian/Preview Content\""; 337 | DEVELOPMENT_TEAM = A42K5AU657; 338 | ENABLE_HARDENED_RUNTIME = YES; 339 | ENABLE_PREVIEWS = YES; 340 | INFOPLIST_FILE = Historian/Info.plist; 341 | LD_RUNPATH_SEARCH_PATHS = ( 342 | "$(inherited)", 343 | "@executable_path/../Frameworks", 344 | ); 345 | MACOSX_DEPLOYMENT_TARGET = 10.15; 346 | PRODUCT_BUNDLE_IDENTIFIER = co.finestructure.Historian; 347 | PRODUCT_NAME = "$(TARGET_NAME)"; 348 | SWIFT_VERSION = 5.0; 349 | }; 350 | name = Debug; 351 | }; 352 | 5A2780C7241F911B00D015F2 /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 356 | CODE_SIGN_ENTITLEMENTS = Historian/Historian.entitlements; 357 | CODE_SIGN_STYLE = Automatic; 358 | COMBINE_HIDPI_IMAGES = YES; 359 | DEVELOPMENT_ASSET_PATHS = "\"Historian/Preview Content\""; 360 | DEVELOPMENT_TEAM = A42K5AU657; 361 | ENABLE_HARDENED_RUNTIME = YES; 362 | ENABLE_PREVIEWS = YES; 363 | INFOPLIST_FILE = Historian/Info.plist; 364 | LD_RUNPATH_SEARCH_PATHS = ( 365 | "$(inherited)", 366 | "@executable_path/../Frameworks", 367 | ); 368 | MACOSX_DEPLOYMENT_TARGET = 10.15; 369 | PRODUCT_BUNDLE_IDENTIFIER = co.finestructure.Historian; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | SWIFT_VERSION = 5.0; 372 | }; 373 | name = Release; 374 | }; 375 | /* End XCBuildConfiguration section */ 376 | 377 | /* Begin XCConfigurationList section */ 378 | 5A2780AD241F911A00D015F2 /* Build configuration list for PBXProject "Historian" */ = { 379 | isa = XCConfigurationList; 380 | buildConfigurations = ( 381 | 5A2780C3241F911B00D015F2 /* Debug */, 382 | 5A2780C4241F911B00D015F2 /* Release */, 383 | ); 384 | defaultConfigurationIsVisible = 0; 385 | defaultConfigurationName = Release; 386 | }; 387 | 5A2780C5241F911B00D015F2 /* Build configuration list for PBXNativeTarget "Historian" */ = { 388 | isa = XCConfigurationList; 389 | buildConfigurations = ( 390 | 5A2780C6241F911B00D015F2 /* Debug */, 391 | 5A2780C7241F911B00D015F2 /* Release */, 392 | ); 393 | defaultConfigurationIsVisible = 0; 394 | defaultConfigurationName = Release; 395 | }; 396 | /* End XCConfigurationList section */ 397 | 398 | /* Begin XCRemoteSwiftPackageReference section */ 399 | 5A4871142421015D00C05EBE /* XCRemoteSwiftPackageReference "HistoryTransceiver" */ = { 400 | isa = XCRemoteSwiftPackageReference; 401 | repositoryURL = "https://github.com/finestructure/HistoryTransceiver"; 402 | requirement = { 403 | kind = upToNextMajorVersion; 404 | minimumVersion = 0.0.3; 405 | }; 406 | }; 407 | 5A64C3842420B5F500B167C3 /* XCRemoteSwiftPackageReference "CompArch" */ = { 408 | isa = XCRemoteSwiftPackageReference; 409 | repositoryURL = "https://github.com/finestructure/CompArch"; 410 | requirement = { 411 | kind = upToNextMajorVersion; 412 | minimumVersion = 0.7.2; 413 | }; 414 | }; 415 | 5A64C38A2420B65500B167C3 /* XCRemoteSwiftPackageReference "swift-case-paths" */ = { 416 | isa = XCRemoteSwiftPackageReference; 417 | repositoryURL = "https://github.com/pointfreeco/swift-case-paths"; 418 | requirement = { 419 | kind = upToNextMajorVersion; 420 | minimumVersion = 0.1.0; 421 | }; 422 | }; 423 | /* End XCRemoteSwiftPackageReference section */ 424 | 425 | /* Begin XCSwiftPackageProductDependency section */ 426 | 5A4871152421015D00C05EBE /* HistoryTransceiver */ = { 427 | isa = XCSwiftPackageProductDependency; 428 | package = 5A4871142421015D00C05EBE /* XCRemoteSwiftPackageReference "HistoryTransceiver" */; 429 | productName = HistoryTransceiver; 430 | }; 431 | 5A64C3852420B5F500B167C3 /* CompArch */ = { 432 | isa = XCSwiftPackageProductDependency; 433 | package = 5A64C3842420B5F500B167C3 /* XCRemoteSwiftPackageReference "CompArch" */; 434 | productName = CompArch; 435 | }; 436 | 5A64C38B2420B65500B167C3 /* CasePaths */ = { 437 | isa = XCSwiftPackageProductDependency; 438 | package = 5A64C38A2420B65500B167C3 /* XCRemoteSwiftPackageReference "swift-case-paths" */; 439 | productName = CasePaths; 440 | }; 441 | /* End XCSwiftPackageProductDependency section */ 442 | }; 443 | rootObject = 5A2780AA241F911A00D015F2 /* Project object */; 444 | } 445 | -------------------------------------------------------------------------------- /Historian-macos/Historian.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Historian-macos/Historian.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Historian-macos/Historian.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "CompArch", 6 | "repositoryURL": "https://github.com/finestructure/CompArch", 7 | "state": { 8 | "branch": null, 9 | "revision": "b3bbb247b18b29549e905e31e5a19ebc46d1cefb", 10 | "version": "0.7.2" 11 | } 12 | }, 13 | { 14 | "package": "HistoryTransceiver", 15 | "repositoryURL": "https://github.com/finestructure/HistoryTransceiver", 16 | "state": { 17 | "branch": null, 18 | "revision": "fd88668d1648e5f7f61843e676ecbe4cafa4a642", 19 | "version": "0.0.3" 20 | } 21 | }, 22 | { 23 | "package": "MultipeerKit", 24 | "repositoryURL": "https://github.com/insidegui/MultipeerKit", 25 | "state": { 26 | "branch": null, 27 | "revision": "3f430bc28e1426ba42cdaa8b19fb4d89ce6d1c3b", 28 | "version": "0.1.2" 29 | } 30 | }, 31 | { 32 | "package": "CasePaths", 33 | "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", 34 | "state": { 35 | "branch": null, 36 | "revision": "a9c1e05518b6d95cf5844d823020376f2b6ff842", 37 | "version": "0.1.0" 38 | } 39 | } 40 | ] 41 | }, 42 | "version": 1 43 | } 44 | -------------------------------------------------------------------------------- /Historian-macos/Historian/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Historian 4 | // 5 | // Created by Sven A. Schmidt on 16/03/2020. 6 | // Copyright © 2020 finestructure. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import HistoryTransceiver 11 | import SwiftUI 12 | 13 | 14 | var historyStore = HistoryView.store(history: [], broadcastEnabled: true) 15 | 16 | 17 | @NSApplicationMain 18 | class AppDelegate: NSObject, NSApplicationDelegate { 19 | 20 | var window: NSWindow! 21 | 22 | 23 | func applicationDidFinishLaunching(_ aNotification: Notification) { 24 | Transceiver.shared.receive(Message.self) { msg in 25 | historyStore.send(HistoryView.Action.appendStep("\(msg.action)", msg.state)) 26 | } 27 | Transceiver.shared.resume() 28 | 29 | let contentView = HistoryView(store: historyStore) 30 | .environmentObject(Transceiver.dataSource) 31 | 32 | // Create the window and set the content view. 33 | window = NSWindow( 34 | contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), 35 | styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], 36 | backing: .buffered, defer: false) 37 | window.center() 38 | window.setFrameAutosaveName("Main Window") 39 | window.contentView = NSHostingView(rootView: contentView) 40 | window.makeKeyAndOrderFront(nil) 41 | } 42 | 43 | func applicationWillTerminate(_ aNotification: Notification) { 44 | // Insert code here to tear down your application 45 | } 46 | 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Historian-macos/Historian/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Historian-macos/Historian/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Historian-macos/Historian/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | Default 529 | 530 | 531 | 532 | 533 | 534 | 535 | Left to Right 536 | 537 | 538 | 539 | 540 | 541 | 542 | Right to Left 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | Default 554 | 555 | 556 | 557 | 558 | 559 | 560 | Left to Right 561 | 562 | 563 | 564 | 565 | 566 | 567 | Right to Left 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | -------------------------------------------------------------------------------- /Historian-macos/Historian/Historian.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Historian-macos/Historian/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2020 finestructure. All rights reserved. 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | NSSupportsAutomaticTermination 32 | 33 | NSSupportsSuddenTermination 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Historian-macos/Historian/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /HistoryView/Extensions/RangeReplaceableCollection+ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RangeReplaceableCollection+ext.swift 3 | // Playgrounder 4 | // 5 | // Created by Sven A. Schmidt on 18/01/2020. 6 | // Copyright © 2020 finestructure. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | extension RangeReplaceableCollection where Element: Equatable { 13 | @discardableResult 14 | mutating func removeFirst(value: Element) -> Element? { 15 | guard let idx = firstIndex(of: value) else { return nil } 16 | return remove(at: idx) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /HistoryView/HistoryView+CA.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryView+CA.swift 3 | // 4 | // 5 | // Created by Sven A. Schmidt on 16/03/2020. 6 | // 7 | 8 | import HistoryTransceiver 9 | import CompArch 10 | import Foundation 11 | 12 | 13 | // MARK: - State, Action, Reducer - CA machinery 14 | 15 | extension HistoryView { 16 | public struct State { 17 | var history: [Step] = [] 18 | var selection: Step? = nil 19 | var broadcastEnabled = false 20 | 21 | func stepAfter(_ step: Step) -> Step? { 22 | guard 23 | let idx = history.firstIndex(of: step), 24 | case let nextIdx = history.index(after: idx), 25 | history.indices.contains(nextIdx) 26 | else { return nil } 27 | return history[nextIdx] 28 | } 29 | 30 | func stepBefore(_ step: Step) -> Step? { 31 | guard 32 | let idx = history.firstIndex(of: step), 33 | case let prevIdx = history.index(before: idx), 34 | history.indices.contains(prevIdx) 35 | else { return nil } 36 | return history[prevIdx] 37 | } 38 | 39 | public init(history: [Step] = [], selection: Step? = nil, broadcastEnabled: Bool = false) { 40 | self.history = history 41 | self.selection = selection 42 | self.broadcastEnabled = broadcastEnabled 43 | } 44 | } 45 | 46 | public enum Action { 47 | case appendStep(String, Data?) 48 | case selection(Step?) 49 | case deleteTapped 50 | case backTapped 51 | case forwardTapped 52 | case newState(Data?) 53 | case row(IdentifiedRow) 54 | } 55 | 56 | public static var reducer: Reducer { 57 | return { state, action in 58 | switch action { 59 | case let .appendStep(stepAction, .some(postActionState)): 60 | if state.history.isEmpty { 61 | state.history.append(.initial) 62 | } 63 | let newStep = Step(index: state.history.count, 64 | action: stepAction, 65 | resultingState: postActionState) 66 | state.history.append(newStep) 67 | state.selection = newStep 68 | return [] 69 | case .appendStep(_, .none): 70 | // ignore empty data when appending 71 | return [] 72 | case .selection(let step): 73 | state.selection = step 74 | guard let step = step else { return [] } 75 | return [ .sync { .newState(step.resultingState) } ] 76 | case .deleteTapped: 77 | guard 78 | let current = state.selection, 79 | current != .initial 80 | else { return [] } 81 | defer { state.history.removeFirst(value: current) } 82 | let previous = state.stepBefore(current) 83 | state.selection = previous 84 | return [ .sync { .newState(previous?.resultingState) } ] 85 | case .backTapped: 86 | guard 87 | let current = state.selection, 88 | current != .initial 89 | else { return [] } 90 | let previous = state.stepBefore(current) 91 | state.selection = previous 92 | return [ .sync { .newState(previous?.resultingState) } ] 93 | case .forwardTapped: 94 | guard let current = state.selection else { return [] } 95 | guard 96 | let idx = state.history.firstIndex(of: current), 97 | idx != state.history.count - 1 98 | // can't advance further than tip 99 | else { return [] } 100 | guard let next = state.stepAfter(current) else { return [] } 101 | state.selection = next 102 | return [ .sync { .newState(next.resultingState) } ] 103 | case .newState(let newState): 104 | if state.broadcastEnabled { 105 | let msg = Message(command: .reset, action: "", state: newState) 106 | Transceiver.shared.broadcast(msg) 107 | } 108 | return [] 109 | case .row((let step, .rowTapped)): 110 | state.selection = step 111 | return [ .sync { .newState(step.resultingState) } ] 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /HistoryView/HistoryView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryView.swift 3 | // Playgrounder 4 | // 5 | // Created by Sven A. Schmidt on 11/03/2020. 6 | // Copyright © 2020 finestructure. All rights reserved. 7 | // 8 | 9 | import CasePaths 10 | import CompArch 11 | import HistoryTransceiver 12 | import MultipeerKit 13 | import SwiftUI 14 | 15 | 16 | struct Config { 17 | #if os(macOS) 18 | var minWidth: CGFloat? = 500 19 | var minHeight: CGFloat? = 300 20 | var titlePadding: Edge.Set = [.leading, .top] 21 | var peerListHeight: CGFloat = 100 22 | #else 23 | var minWidth: CGFloat? = nil 24 | var minHeight: CGFloat? = nil 25 | var titlePadding: Edge.Set = .all 26 | var peerListHeight: CGFloat = 150 27 | #endif 28 | } 29 | 30 | 31 | public struct HistoryView: View { 32 | @ObservedObject var store: Store 33 | @EnvironmentObject var dataSource: MultipeerDataSource 34 | @SwiftUI.State var targeted = false 35 | var config = Config() 36 | 37 | public var body: some View { 38 | VStack(alignment: .leading) { 39 | peerList 40 | historyList.frame(minWidth: config.minWidth, minHeight: config.minHeight) 41 | } 42 | } 43 | 44 | var peerList: some View { 45 | VStack(alignment: .leading) { 46 | Text("Peers").font(.system(.headline)).padding(config.titlePadding) 47 | List { 48 | ForEach(dataSource.availablePeers) { peer in 49 | HStack { 50 | Circle() 51 | .frame(width: 12, height: 12) 52 | .foregroundColor(peer.isConnected ? .green : .gray) 53 | Text(peer.name) 54 | Spacer() 55 | } 56 | } 57 | } 58 | .frame(height: config.peerListHeight) 59 | } 60 | } 61 | 62 | var historyList: some View { 63 | VStack(alignment: .leading) { 64 | Text("History").font(.system(.headline)).padding(config.titlePadding) 65 | 66 | List(selection: store.binding(value: \.selection, action: /Action.selection)) { 67 | ForEach(store.value.history.reversed(), id: \.self) { 68 | self.rowView(for: $0) 69 | } 70 | } 71 | ._onDrop(of: [uti], isTargeted: $targeted, perform: dropHandler) 72 | 73 | HStack { 74 | Button(action: { self.store.send(.deleteTapped) }, label: { 75 | self.buttonLabel(title: "Delete", systemImage: "trash") 76 | }) 77 | Spacer() 78 | Button(action: { self.store.send(.backTapped) }, label: { 79 | self.buttonLabel(title: "←", systemImage: "backward") 80 | }) 81 | Button(action: { self.store.send(.forwardTapped) }, label: { 82 | self.buttonLabel(title: "→", systemImage: "forward") 83 | }) 84 | } 85 | .padding() 86 | } 87 | } 88 | 89 | func buttonLabel(title: String, systemImage: String) -> some View { 90 | #if os(macOS) 91 | return AnyView(Text(title)) 92 | #else 93 | return AnyView(Image(systemName: systemImage).padding()) 94 | #endif 95 | } 96 | 97 | func rowView(for step: Step) -> AnyView { 98 | guard let step = store.value.history.first(where: { $0.id == step.id }) else { 99 | return AnyView(EmptyView()) 100 | } 101 | let row = RowView.State(step: step, selected: step.id == store.value.selection?.id) 102 | return AnyView( 103 | RowView(store: self.store.view( 104 | value: { _ in row }, 105 | action: { .row(IdentifiedRow(id: row.id, action: $0)) })) 106 | ) 107 | } 108 | 109 | } 110 | 111 | 112 | 113 | // MARK: - Initializers / Setup 114 | 115 | extension HistoryView { 116 | public static func store(history: [Step], broadcastEnabled: Bool) -> Store { 117 | return Store(initialValue: State(history: history, broadcastEnabled: broadcastEnabled), 118 | reducer: reducer) 119 | } 120 | 121 | public init(store: Store) { self.store = store } 122 | 123 | public init(history: [Step], broadcastEnabled: Bool) { 124 | self.store = Self.store(history: history, broadcastEnabled: broadcastEnabled) 125 | } 126 | } 127 | 128 | 129 | 130 | // MARK: - Drop handling 131 | 132 | extension View { 133 | func _onDrop(of supportedTypes: [String], 134 | isTargeted targeted: Binding?, 135 | perform action: @escaping ([NSItemProvider]) -> Bool) -> some View { 136 | #if os(macOS) 137 | return AnyView(self.onDrop(of: supportedTypes, isTargeted: targeted, perform: action)) 138 | #else 139 | return AnyView(self) 140 | #endif 141 | } 142 | } 143 | 144 | 145 | extension HistoryView { 146 | var uti: String { "public.utf8-plain-text" } 147 | 148 | func dropHandler(_ items: [NSItemProvider]) -> Bool { 149 | guard let item = items.first else { return false } 150 | print(item.registeredTypeIdentifiers) 151 | item.loadItem(forTypeIdentifier: uti, options: nil) { (data, error) in 152 | DispatchQueue.main.async { 153 | if self.store.value.broadcastEnabled, let data = data as? Data { 154 | let msg = Message(command: .reset, action: "", state: data) 155 | Transceiver.shared.broadcast(msg) 156 | } 157 | } 158 | } 159 | return true 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /HistoryView/RowView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowView.swift 3 | // Historian 4 | // 5 | // Created by Sven A. Schmidt on 15/03/2020. 6 | // Copyright © 2020 finestructure. All rights reserved. 7 | // 8 | 9 | import CompArch 10 | import SwiftUI 11 | 12 | 13 | public typealias IdentifiedRow = Identified 14 | 15 | 16 | public struct RowView: View { 17 | @ObservedObject var store: Store 18 | 19 | var indexLabel: String { 20 | switch self.store.value.step { 21 | case .initial: return "0" 22 | case .step(let step): return "\(step.index)" 23 | } 24 | } 25 | 26 | var actionLabel: String { 27 | switch self.store.value.step { 28 | case .initial: return "initial" 29 | case .step(let step): return step.action 30 | } 31 | } 32 | 33 | public var body: some View { 34 | #if os(macOS) 35 | let view = HStack { 36 | Text(indexLabel) 37 | .frame(width: 30, alignment: .trailing) 38 | Text(actionLabel) 39 | } 40 | .onDrag { 41 | NSItemProvider(object: String(decoding: self.store.value.step.resultingState ?? Data(), 42 | as: UTF8.self) as NSString) 43 | } 44 | #else 45 | let view = HStack { 46 | Button(action: { self.store.send(.rowTapped) }, 47 | label: { 48 | HStack { 49 | #if os(iOS) 50 | Image(systemName: "arrowtriangle.right.fill") 51 | .foregroundColor(self.store.value.selected ? .blue : .clear) 52 | #endif 53 | Text(indexLabel) 54 | .frame(width: 30, alignment: .trailing) 55 | Text(actionLabel) 56 | } 57 | }) 58 | } 59 | #endif 60 | return view 61 | } 62 | } 63 | 64 | 65 | extension RowView { 66 | public struct State: Identifiable { 67 | public var id: Step { step } 68 | var step: Step 69 | var selected = false 70 | } 71 | 72 | public enum Action { 73 | case rowTapped 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /HistoryView/Step.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Step.swift 3 | // 4 | // 5 | // Created by Sven A. Schmidt on 16/03/2020. 6 | // 7 | 8 | import CasePaths 9 | import Foundation 10 | 11 | 12 | public enum Step: Hashable { 13 | case initial 14 | case step(Value) 15 | 16 | public struct Value: Hashable { 17 | var index: Int 18 | var action: String 19 | var resultingState: Data 20 | } 21 | 22 | public init(index: Int, action: String, resultingState: Data) { 23 | self = .step(.init(index: index, action: action, resultingState: resultingState)) 24 | } 25 | } 26 | 27 | 28 | extension Step { 29 | var value: Value? { (/Step.step).extract(from: self) } 30 | 31 | var resultingState: Data? { 32 | switch self { 33 | case .initial: return nil 34 | case .step(let step): return step.resultingState 35 | } 36 | } 37 | } 38 | 39 | 40 | extension Step: Identifiable { 41 | public var id: Step { self } 42 | } 43 | 44 | 45 | extension Step: Equatable { 46 | public static func == (lhs: Step, rhs: Step) -> Bool { 47 | switch (lhs, rhs) { 48 | case (.initial, .initial): 49 | return true 50 | case let (.step(a), .step(b)): 51 | return a.index == b.index 52 | default: 53 | return false 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Historian 2 | 3 | Historian is an app state viewer and manipulator for apps written in [Pointfree.co's Composable Architecture](https://www.pointfree.co/collections/composable-architecture). 4 | 5 | Screenshot 2020-03-22 at 18 24 03 6 | 7 | For more information see this [introductory blog post](https://finestructure.co/blog/2020/3/30/state-of-the-app-state-surfing). 8 | 9 | ## OS variants 10 | 11 | The iOS and macOS apps are only minimally different and can probably be merged soon. 12 | 13 | The main reason it's not the case yet is that using a single app target seems to make the whole app a catalyst app, even when using SwiftUI. 14 | 15 | It would probably be possible to integrate both into single app even without doing so but since most of the code really sits in the dependency `HistoryView` and the apps are simple viewer shell it's likely more hassle that it's worth. 16 | --------------------------------------------------------------------------------