From 567cb4cc47cbd22611c61cefbf3c44deb7cb2531 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Tue, 29 Nov 2022 11:46:02 +0100 Subject: [PATCH] New Routeur --- IceCubesApp.xcodeproj/project.pbxproj | 73 +++++++++++++++---- IceCubesApp/App/AppRouteur.swift | 17 +++++ IceCubesApp/App/IceCubesAppApp.swift | 41 +++++++++++ IceCubesApp/App/TimelineTabView.swift | 16 ++++ IceCubesApp/IceCubesAppApp.swift | 42 ----------- .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../Preview Assets.xcassets/Contents.json | 0 Packages/Account/.gitignore | 9 +++ Packages/Account/Package.swift | 31 ++++++++ Packages/Account/README.md | 3 + .../Account/Sources/Account/AccountView.swift | 14 ++++ .../Tests/AccountTests/AccountTests.swift | 11 +++ Packages/Routeur/.gitignore | 9 +++ Packages/Routeur/Package.swift | 25 +++++++ Packages/Routeur/README.md | 3 + .../Routeur/Sources/Routeur/Routeur.swift | 17 +++++ .../Tests/RouteurTests/RouteurTests.swift | 11 +++ Packages/Timeline/Package.swift | 4 +- .../Timeline/Status/StatusDetailVIew.swift | 13 ++++ .../Timeline/Status/StatusRowView.swift | 57 +++++++++------ .../Sources/Timeline/TimelineView.swift | 6 +- 23 files changed, 321 insertions(+), 81 deletions(-) create mode 100644 IceCubesApp/App/AppRouteur.swift create mode 100644 IceCubesApp/App/IceCubesAppApp.swift create mode 100644 IceCubesApp/App/TimelineTabView.swift delete mode 100644 IceCubesApp/IceCubesAppApp.swift rename IceCubesApp/{ => Resources}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename IceCubesApp/{ => Resources}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename IceCubesApp/{ => Resources}/Assets.xcassets/Contents.json (100%) rename IceCubesApp/{Preview Content => Resources}/Preview Assets.xcassets/Contents.json (100%) create mode 100644 Packages/Account/.gitignore create mode 100644 Packages/Account/Package.swift create mode 100644 Packages/Account/README.md create mode 100644 Packages/Account/Sources/Account/AccountView.swift create mode 100644 Packages/Account/Tests/AccountTests/AccountTests.swift create mode 100644 Packages/Routeur/.gitignore create mode 100644 Packages/Routeur/Package.swift create mode 100644 Packages/Routeur/README.md create mode 100644 Packages/Routeur/Sources/Routeur/Routeur.swift create mode 100644 Packages/Routeur/Tests/RouteurTests/RouteurTests.swift create mode 100644 Packages/Timeline/Sources/Timeline/Status/StatusDetailVIew.swift diff --git a/IceCubesApp.xcodeproj/project.pbxproj b/IceCubesApp.xcodeproj/project.pbxproj index 542ff4ff..6261214d 100644 --- a/IceCubesApp.xcodeproj/project.pbxproj +++ b/IceCubesApp.xcodeproj/project.pbxproj @@ -7,22 +7,31 @@ objects = { /* Begin PBXBuildFile section */ + 9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F24EEB729360C330042359D /* Preview Assets.xcassets */; }; + 9F24EEBB293619210042359D /* Routeur in Frameworks */ = {isa = PBXBuildFile; productRef = 9F24EEBA293619210042359D /* Routeur */; }; 9F295540292B6C3400E0E81B /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F29553F292B6C3400E0E81B /* Timeline */; }; + 9F398AA62935FE8A00A889F2 /* AppRouteur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F398AA52935FE8A00A889F2 /* AppRouteur.swift */; }; + 9F398AA92935FFDB00A889F2 /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AA82935FFDB00A889F2 /* Account */; }; + 9F398AAB2935FFDB00A889F2 /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AAA2935FFDB00A889F2 /* Models */; }; + 9F398AB329360A4C00A889F2 /* TimelineTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F398AB229360A4C00A889F2 /* TimelineTabView.swift */; }; 9FBFE63D292A715500C250E9 /* IceCubesAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBFE63C292A715500C250E9 /* IceCubesAppApp.swift */; }; 9FBFE641292A715600C250E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9FBFE640292A715600C250E9 /* Assets.xcassets */; }; - 9FBFE645292A715600C250E9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9FBFE644292A715600C250E9 /* Preview Assets.xcassets */; }; 9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 9F24EEB729360C330042359D /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 9F24EEB92936185B0042359D /* Routeur */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Routeur; path = Packages/Routeur; sourceTree = ""; }; 9F29553D292B67B600E0E81B /* Network */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Network; path = Packages/Network; sourceTree = ""; }; 9F29553E292B6AF600E0E81B /* Timeline */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Timeline; path = Packages/Timeline; sourceTree = ""; }; 9F398AA32935F90100A889F2 /* Models */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Models; path = Packages/Models; sourceTree = ""; }; + 9F398AA52935FE8A00A889F2 /* AppRouteur.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteur.swift; sourceTree = ""; }; + 9F398AAC2936005300A889F2 /* Account */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Account; path = Packages/Account; sourceTree = ""; }; + 9F398AB229360A4C00A889F2 /* TimelineTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTabView.swift; sourceTree = ""; }; 9FBFE639292A715500C250E9 /* IceCubesApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IceCubesApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 9FBFE63C292A715500C250E9 /* IceCubesAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesAppApp.swift; sourceTree = ""; }; 9FBFE640292A715600C250E9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9FBFE642292A715600C250E9 /* IceCubesApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IceCubesApp.entitlements; sourceTree = ""; }; - 9FBFE644292A715600C250E9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -30,7 +39,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9F398AA92935FFDB00A889F2 /* Account in Frameworks */, 9FBFE64E292A72BD00C250E9 /* Network in Frameworks */, + 9F398AAB2935FFDB00A889F2 /* Models in Frameworks */, + 9F24EEBB293619210042359D /* Routeur in Frameworks */, 9F295540292B6C3400E0E81B /* Timeline in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -38,14 +50,35 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 9F398AB429360A5800A889F2 /* App */ = { + isa = PBXGroup; + children = ( + 9FBFE63C292A715500C250E9 /* IceCubesAppApp.swift */, + 9F398AA52935FE8A00A889F2 /* AppRouteur.swift */, + 9F398AB229360A4C00A889F2 /* TimelineTabView.swift */, + ); + path = App; + sourceTree = ""; + }; + 9F398AB529360A6100A889F2 /* Resources */ = { + isa = PBXGroup; + children = ( + 9F24EEB729360C330042359D /* Preview Assets.xcassets */, + 9FBFE640292A715600C250E9 /* Assets.xcassets */, + ); + path = Resources; + sourceTree = ""; + }; 9FBFE630292A715500C250E9 = { isa = PBXGroup; children = ( 9FBFE63B292A715500C250E9 /* IceCubesApp */, 9FBFE63A292A715500C250E9 /* Products */, 9FBFE64C292A72BD00C250E9 /* Frameworks */, + 9F398AAC2936005300A889F2 /* Account */, 9F398AA32935F90100A889F2 /* Models */, 9F29553E292B6AF600E0E81B /* Timeline */, + 9F24EEB92936185B0042359D /* Routeur */, 9F29553D292B67B600E0E81B /* Network */, ); sourceTree = ""; @@ -61,22 +94,13 @@ 9FBFE63B292A715500C250E9 /* IceCubesApp */ = { isa = PBXGroup; children = ( - 9FBFE63C292A715500C250E9 /* IceCubesAppApp.swift */, - 9FBFE640292A715600C250E9 /* Assets.xcassets */, + 9F398AB429360A5800A889F2 /* App */, 9FBFE642292A715600C250E9 /* IceCubesApp.entitlements */, - 9FBFE643292A715600C250E9 /* Preview Content */, + 9F398AB529360A6100A889F2 /* Resources */, ); path = IceCubesApp; sourceTree = ""; }; - 9FBFE643292A715600C250E9 /* Preview Content */ = { - isa = PBXGroup; - children = ( - 9FBFE644292A715600C250E9 /* Preview Assets.xcassets */, - ); - path = "Preview Content"; - sourceTree = ""; - }; 9FBFE64C292A72BD00C250E9 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -103,6 +127,9 @@ packageProductDependencies = ( 9FBFE64D292A72BD00C250E9 /* Network */, 9F29553F292B6C3400E0E81B /* Timeline */, + 9F398AA82935FFDB00A889F2 /* Account */, + 9F398AAA2935FFDB00A889F2 /* Models */, + 9F24EEBA293619210042359D /* Routeur */, ); productName = IceCubesApp; productReference = 9FBFE639292A715500C250E9 /* IceCubesApp.app */; @@ -146,7 +173,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 9FBFE645292A715600C250E9 /* Preview Assets.xcassets in Resources */, + 9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */, 9FBFE641292A715600C250E9 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -158,6 +185,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9F398AB329360A4C00A889F2 /* TimelineTabView.swift in Sources */, + 9F398AA62935FE8A00A889F2 /* AppRouteur.swift in Sources */, 9FBFE63D292A715500C250E9 /* IceCubesAppApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -282,7 +311,7 @@ CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Preview Content\""; + DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Resources\""; DEVELOPMENT_TEAM = Z6P74P6T99; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; @@ -320,7 +349,7 @@ CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Preview Content\""; + DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Resources\""; DEVELOPMENT_TEAM = Z6P74P6T99; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; @@ -374,10 +403,22 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ + 9F24EEBA293619210042359D /* Routeur */ = { + isa = XCSwiftPackageProductDependency; + productName = Routeur; + }; 9F29553F292B6C3400E0E81B /* Timeline */ = { isa = XCSwiftPackageProductDependency; productName = Timeline; }; + 9F398AA82935FFDB00A889F2 /* Account */ = { + isa = XCSwiftPackageProductDependency; + productName = Account; + }; + 9F398AAA2935FFDB00A889F2 /* Models */ = { + isa = XCSwiftPackageProductDependency; + productName = Models; + }; 9FBFE64D292A72BD00C250E9 /* Network */ = { isa = XCSwiftPackageProductDependency; productName = Network; diff --git a/IceCubesApp/App/AppRouteur.swift b/IceCubesApp/App/AppRouteur.swift new file mode 100644 index 00000000..355b1141 --- /dev/null +++ b/IceCubesApp/App/AppRouteur.swift @@ -0,0 +1,17 @@ +import SwiftUI +import Timeline +import Account +import Routeur + +extension View { + func withAppRouteur() -> some View { + self.navigationDestination(for: RouteurDestinations.self) { destination in + switch destination { + case let .accountDetail(id): + AccountView(accountId: id) + case let .statusDetail(id): + StatusDetailView(statusId: id) + } + } + } +} diff --git a/IceCubesApp/App/IceCubesAppApp.swift b/IceCubesApp/App/IceCubesAppApp.swift new file mode 100644 index 00000000..c831ea74 --- /dev/null +++ b/IceCubesApp/App/IceCubesAppApp.swift @@ -0,0 +1,41 @@ +import SwiftUI +import Timeline +import Network +import Shared + +@main +struct IceCubesAppApp: App { + @State private var tabs: [String] = ["mastodon.social"] + @State private var isServerSelectDisplayed: Bool = false + @State private var newServerURL: String = "" + + var body: some Scene { + WindowGroup { + TabView { + ForEach(tabs, id: \.self) { tab in + TimelineTabView(tab: tab) + .tabItem { + Label(tab, systemImage: "globe") + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + isServerSelectDisplayed.toggle() + } label: { + Image(systemName: "globe") + } + } + } + .alert("Connect to another server", isPresented: $isServerSelectDisplayed) { + TextField(tab, text: $newServerURL) + Button("Connect", action: { + tabs.append(newServerURL) + newServerURL = "" + }) + Button("Cancel", role: .cancel, action: {}) + } + } + } + } + } +} diff --git a/IceCubesApp/App/TimelineTabView.swift b/IceCubesApp/App/TimelineTabView.swift new file mode 100644 index 00000000..331014ea --- /dev/null +++ b/IceCubesApp/App/TimelineTabView.swift @@ -0,0 +1,16 @@ +import SwiftUI +import Timeline +import Routeur + +struct TimelineTabView: View { + let tab: String + @StateObject private var routeurPath = RouterPath() + + var body: some View { + NavigationStack(path: $routeurPath.path) { + TimelineView(client: .init(server: tab)) + .withAppRouteur() + } + .environmentObject(routeurPath) + } +} diff --git a/IceCubesApp/IceCubesAppApp.swift b/IceCubesApp/IceCubesAppApp.swift deleted file mode 100644 index 38692671..00000000 --- a/IceCubesApp/IceCubesAppApp.swift +++ /dev/null @@ -1,42 +0,0 @@ -import SwiftUI -import Timeline -import Network - -@main -struct IceCubesAppApp: App { - @State private var tabs: [String] = ["mastodon.social"] - @State private var isServerSelectDisplayed: Bool = false - @State private var newServerURL: String = "" - - var body: some Scene { - WindowGroup { - TabView { - ForEach(tabs, id: \.self) { tab in - NavigationStack { - TimelineView(client: .init(server: tab)) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button { - isServerSelectDisplayed.toggle() - } label: { - Image(systemName: "globe") - } - } - } - .alert("Connect to another server", isPresented: $isServerSelectDisplayed) { - TextField(tab, text: $newServerURL) - Button("Connect", action: { - tabs.append(newServerURL) - newServerURL = "" - }) - Button("Cancel", role: .cancel, action: {}) - } - } - .tabItem { - Label(tab, systemImage: "globe") - } - } - } - } - } -} diff --git a/IceCubesApp/Assets.xcassets/AccentColor.colorset/Contents.json b/IceCubesApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from IceCubesApp/Assets.xcassets/AccentColor.colorset/Contents.json rename to IceCubesApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/IceCubesApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/IceCubesApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from IceCubesApp/Assets.xcassets/AppIcon.appiconset/Contents.json rename to IceCubesApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/IceCubesApp/Assets.xcassets/Contents.json b/IceCubesApp/Resources/Assets.xcassets/Contents.json similarity index 100% rename from IceCubesApp/Assets.xcassets/Contents.json rename to IceCubesApp/Resources/Assets.xcassets/Contents.json diff --git a/IceCubesApp/Preview Content/Preview Assets.xcassets/Contents.json b/IceCubesApp/Resources/Preview Assets.xcassets/Contents.json similarity index 100% rename from IceCubesApp/Preview Content/Preview Assets.xcassets/Contents.json rename to IceCubesApp/Resources/Preview Assets.xcassets/Contents.json diff --git a/Packages/Account/.gitignore b/Packages/Account/.gitignore new file mode 100644 index 00000000..3b298120 --- /dev/null +++ b/Packages/Account/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Packages/Account/Package.swift b/Packages/Account/Package.swift new file mode 100644 index 00000000..a83636c9 --- /dev/null +++ b/Packages/Account/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Account", + platforms: [ + .iOS(.v16), + ], + products: [ + .library( + name: "Account", + targets: ["Account"]), + ], + dependencies: [ + .package(name: "Network", path: "../Network"), + .package(name: "Models", path: "../Models"), + ], + targets: [ + .target( + name: "Account", + dependencies: [ + .product(name: "Network", package: "Network"), + .product(name: "Models", package: "Models") + ]), + .testTarget( + name: "AccountTests", + dependencies: ["Account"]), + ] +) diff --git a/Packages/Account/README.md b/Packages/Account/README.md new file mode 100644 index 00000000..87802e1c --- /dev/null +++ b/Packages/Account/README.md @@ -0,0 +1,3 @@ +# Account + +A description of this package. diff --git a/Packages/Account/Sources/Account/AccountView.swift b/Packages/Account/Sources/Account/AccountView.swift new file mode 100644 index 00000000..d3f060fd --- /dev/null +++ b/Packages/Account/Sources/Account/AccountView.swift @@ -0,0 +1,14 @@ +import SwiftUI +import Models + +public struct AccountView: View { + private let accountId: String + + public init(accountId: String) { + self.accountId = accountId + } + + public var body: some View { + Text("Account id \(accountId)") + } +} diff --git a/Packages/Account/Tests/AccountTests/AccountTests.swift b/Packages/Account/Tests/AccountTests/AccountTests.swift new file mode 100644 index 00000000..230dbfb7 --- /dev/null +++ b/Packages/Account/Tests/AccountTests/AccountTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import Account + +final class AccountTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(Account().text, "Hello, World!") + } +} diff --git a/Packages/Routeur/.gitignore b/Packages/Routeur/.gitignore new file mode 100644 index 00000000..3b298120 --- /dev/null +++ b/Packages/Routeur/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Packages/Routeur/Package.swift b/Packages/Routeur/Package.swift new file mode 100644 index 00000000..240ce084 --- /dev/null +++ b/Packages/Routeur/Package.swift @@ -0,0 +1,25 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Routeur", + platforms: [ + .iOS(.v16), + ], + products: [ + .library( + name: "Routeur", + targets: ["Routeur"]), + ], + dependencies: [], + targets: [ + .target( + name: "Routeur", + dependencies: []), + .testTarget( + name: "RouteurTests", + dependencies: ["Routeur"]), + ] +) diff --git a/Packages/Routeur/README.md b/Packages/Routeur/README.md new file mode 100644 index 00000000..0940740b --- /dev/null +++ b/Packages/Routeur/README.md @@ -0,0 +1,3 @@ +# Routeur + +A description of this package. diff --git a/Packages/Routeur/Sources/Routeur/Routeur.swift b/Packages/Routeur/Sources/Routeur/Routeur.swift new file mode 100644 index 00000000..464c67c0 --- /dev/null +++ b/Packages/Routeur/Sources/Routeur/Routeur.swift @@ -0,0 +1,17 @@ +import Foundation +import SwiftUI + +public enum RouteurDestinations: Hashable { + case accountDetail(id: String) + case statusDetail(id: String) +} + +public class RouterPath: ObservableObject { + @Published public var path: [RouteurDestinations] = [] + + public init() {} + + public func navigate(to: RouteurDestinations) { + path.append(to) + } +} diff --git a/Packages/Routeur/Tests/RouteurTests/RouteurTests.swift b/Packages/Routeur/Tests/RouteurTests/RouteurTests.swift new file mode 100644 index 00000000..72a84bab --- /dev/null +++ b/Packages/Routeur/Tests/RouteurTests/RouteurTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import Routeur + +final class RouteurTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(Routeur().text, "Hello, World!") + } +} diff --git a/Packages/Timeline/Package.swift b/Packages/Timeline/Package.swift index d80643e5..a8823460 100644 --- a/Packages/Timeline/Package.swift +++ b/Packages/Timeline/Package.swift @@ -16,13 +16,15 @@ let package = Package( dependencies: [ .package(name: "Network", path: "../Network"), .package(name: "Models", path: "../Models"), + .package(name: "Routeur", path: "../Routeur"), ], targets: [ .target( name: "Timeline", dependencies: [ .product(name: "Network", package: "Network"), - .product(name: "Models", package: "Models") + .product(name: "Models", package: "Models"), + .product(name: "Routeur", package: "Routeur") ]), .testTarget( name: "TimelineTests", diff --git a/Packages/Timeline/Sources/Timeline/Status/StatusDetailVIew.swift b/Packages/Timeline/Sources/Timeline/Status/StatusDetailVIew.swift new file mode 100644 index 00000000..c21d6ae6 --- /dev/null +++ b/Packages/Timeline/Sources/Timeline/Status/StatusDetailVIew.swift @@ -0,0 +1,13 @@ +import SwiftUI + +public struct StatusDetailView: View { + private let statusId: String + + public init(statusId: String) { + self.statusId = statusId + } + + public var body: some View { + Text("Status id \(statusId)") + } +} diff --git a/Packages/Timeline/Sources/Timeline/Status/StatusRowView.swift b/Packages/Timeline/Sources/Timeline/Status/StatusRowView.swift index c3a8e5f0..d0b3dd6d 100644 --- a/Packages/Timeline/Sources/Timeline/Status/StatusRowView.swift +++ b/Packages/Timeline/Sources/Timeline/Status/StatusRowView.swift @@ -1,38 +1,53 @@ import SwiftUI import Models +import Routeur struct StatusRowView: View { + @EnvironmentObject private var routeurPath: RouterPath + let status: Status var body: some View { VStack(alignment: .leading) { HStack(alignment: .top) { - AsyncImage( - url: status.account.avatar, - content: { image in - image.resizable() - .aspectRatio(contentMode: .fit) - .cornerRadius(4) - .frame(maxWidth: 40, maxHeight: 40) - }, - placeholder: { - ProgressView() - .frame(maxWidth: 40, maxHeight: 40) - } - ) - VStack(alignment: .leading) { - Text(status.account.displayName) - .font(.headline) - Text("@\(status.account.acct)") - .font(.footnote) - .foregroundColor(.gray) - } + Button { + routeurPath.navigate(to: .accountDetail(id: status.account.id)) + } label: { + accountView + }.buttonStyle(.plain) + Spacer() Text(status.createdAtFormatted) .font(.footnote) .foregroundColor(.gray) } - Text(try! AttributedString(markdown: status.contentAsMarkdown)) + NavigationLink(value: RouteurDestinations.statusDetail(id: status.id)) { + Text(try! AttributedString(markdown: status.contentAsMarkdown)) + } + } + } + + @ViewBuilder + private var accountView: some View { + AsyncImage( + url: status.account.avatar, + content: { image in + image.resizable() + .aspectRatio(contentMode: .fit) + .cornerRadius(4) + .frame(maxWidth: 40, maxHeight: 40) + }, + placeholder: { + ProgressView() + .frame(maxWidth: 40, maxHeight: 40) + } + ) + VStack(alignment: .leading) { + Text(status.account.displayName) + .font(.headline) + Text("@\(status.account.acct)") + .font(.footnote) + .foregroundColor(.gray) } } } diff --git a/Packages/Timeline/Sources/Timeline/TimelineView.swift b/Packages/Timeline/Sources/Timeline/TimelineView.swift index 862cff89..1e18c74a 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineView.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineView.swift @@ -3,6 +3,7 @@ import Network public struct TimelineView: View { @StateObject private var viewModel: TimelineViewModel + @State private var didAppear = false public init(client: Client) { _viewModel = StateObject(wrappedValue: TimelineViewModel(client: client)) @@ -36,7 +37,10 @@ public struct TimelineView: View { .navigationTitle("Public Timeline: \(viewModel.serverName)") .navigationBarTitleDisplayMode(.inline) .task { - await viewModel.refreshTimeline() + if !didAppear { + await viewModel.refreshTimeline() + didAppear = true + } } .refreshable { await viewModel.refreshTimeline()