···11+# Xcode
22+#
33+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
44+55+## User settings
66+xcuserdata/
77+88+## Obj-C/Swift specific
99+*.hmap
1010+1111+## App packaging
1212+*.ipa
1313+*.dSYM.zip
1414+*.dSYM
1515+1616+## Playgrounds
1717+timeline.xctimeline
1818+playground.xcworkspace
1919+2020+# Swift Package Manager
2121+#
2222+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
2323+# Packages/
2424+# Package.pins
2525+# Package.resolved
2626+# *.xcodeproj
2727+#
2828+# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
2929+# hence it is not needed unless you have added a package configuration file to your project
3030+# .swiftpm
3131+3232+.build/
3333+PLAN.md
3434+CLAUDE.md
3535+3636+# CocoaPods
3737+#
3838+# We recommend against adding the Pods directory to your .gitignore. However
3939+# you should judge for yourself, the pros and cons are mentioned at:
4040+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
4141+#
4242+# Pods/
4343+#
4444+# Add this line if you want to avoid checking in source code from the Xcode workspace
4545+# *.xcworkspace
4646+4747+# Carthage
4848+#
4949+# Add this line if you want to avoid checking in source code from Carthage dependencies.
5050+# Carthage/Checkouts
5151+5252+Carthage/Build/
5353+5454+# fastlane
5555+#
5656+# It is recommended to not store the screenshots in the git repo.
5757+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
5858+# For more information about the recommended setup visit:
5959+# https://docs.fastlane.tools/best-practices/source-control/#source-control
6060+6161+fastlane/report.xml
6262+fastlane/Preview.html
6363+fastlane/screenshots/**/*.png
6464+fastlane/test_output
···11+# Frayed
22+33+A native iOS client for [Tangled](https://tangled.org), a code collaboration platform built on the AT Protocol.
44+55+> Early development. Not yet functional.
66+77+## About
88+99+Frayed is being built as a learning project in Swift and SwiftUI. The goal is a clean, native iOS experience for browsing Tangled repositories, issues, and profiles.
1010+1111+## Hosted on Tangled, mirrored to GitHub.
···11+//
22+// ContentView.swift
33+// frayed
44+//
55+// Created by daniel daum on 4/3/26.
66+//
77+88+import SwiftUI
99+1010+struct ContentView: View {
1111+ var body: some View {
1212+ VStack {
1313+ Image(systemName: "globe")
1414+ .imageScale(.large)
1515+ .foregroundStyle(.tint)
1616+ Text("Hello, world!")
1717+ }
1818+ .padding()
1919+ }
2020+}
2121+2222+#Preview {
2323+ ContentView()
2424+}
+17
frayed/frayedApp.swift
···11+//
22+// frayedApp.swift
33+// frayed
44+//
55+// Created by daniel daum on 4/3/26.
66+//
77+88+import SwiftUI
99+1010+@main
1111+struct frayedApp: App {
1212+ var body: some Scene {
1313+ WindowGroup {
1414+ ContentView()
1515+ }
1616+ }
1717+}
+19
frayedTests/frayedTests.swift
···11+//
22+// frayedTests.swift
33+// frayedTests
44+//
55+// Created by daniel daum on 4/3/26.
66+//
77+88+import Testing
99+@testable import frayed
1010+1111+struct frayedTests {
1212+1313+ @Test func example() async throws {
1414+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
1515+ // Swift Testing Documentation
1616+ // https://developer.apple.com/documentation/testing
1717+ }
1818+1919+}
+43
frayedUITests/frayedUITests.swift
···11+//
22+// frayedUITests.swift
33+// frayedUITests
44+//
55+// Created by daniel daum on 4/3/26.
66+//
77+88+import XCTest
99+1010+final class frayedUITests: XCTestCase {
1111+1212+ override func setUpWithError() throws {
1313+ // Put setup code here. This method is called before the invocation of each test method in the class.
1414+1515+ // In UI tests it is usually best to stop immediately when a failure occurs.
1616+ continueAfterFailure = false
1717+1818+ // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
1919+ }
2020+2121+ override func tearDownWithError() throws {
2222+ // Put teardown code here. This method is called after the invocation of each test method in the class.
2323+ }
2424+2525+ @MainActor
2626+ func testExample() throws {
2727+ // UI tests must launch the application that they test.
2828+ let app = XCUIApplication()
2929+ app.launch()
3030+3131+ // Use XCTAssert and related functions to verify your tests produce the correct results.
3232+ // XCUIAutomation Documentation
3333+ // https://developer.apple.com/documentation/xcuiautomation
3434+ }
3535+3636+ @MainActor
3737+ func testLaunchPerformance() throws {
3838+ // This measures how long it takes to launch your application.
3939+ measure(metrics: [XCTApplicationLaunchMetric()]) {
4040+ XCUIApplication().launch()
4141+ }
4242+ }
4343+}
+35
frayedUITests/frayedUITestsLaunchTests.swift
···11+//
22+// frayedUITestsLaunchTests.swift
33+// frayedUITests
44+//
55+// Created by daniel daum on 4/3/26.
66+//
77+88+import XCTest
99+1010+final class frayedUITestsLaunchTests: XCTestCase {
1111+1212+ override class var runsForEachTargetApplicationUIConfiguration: Bool {
1313+ true
1414+ }
1515+1616+ override func setUpWithError() throws {
1717+ continueAfterFailure = false
1818+ }
1919+2020+ @MainActor
2121+ func testLaunch() throws {
2222+ let app = XCUIApplication()
2323+ app.launch()
2424+2525+ // Insert steps here to perform after app launch but before taking a screenshot,
2626+ // such as logging into a test account or navigating somewhere in the app
2727+ // XCUIAutomation Documentation
2828+ // https://developer.apple.com/documentation/xcuiautomation
2929+3030+ let attachment = XCTAttachment(screenshot: app.screenshot())
3131+ attachment.name = "Launch Screen"
3232+ attachment.lifetime = .keepAlways
3333+ add(attachment)
3434+ }
3535+}