mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-28 19:21:16 +00:00
Account statuses and more packages
This commit is contained in:
parent
70d28e697c
commit
4c3809a95b
22 changed files with 232 additions and 26 deletions
|
@ -10,6 +10,7 @@
|
||||||
9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F24EEB729360C330042359D /* Preview Assets.xcassets */; };
|
9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F24EEB729360C330042359D /* Preview Assets.xcassets */; };
|
||||||
9F24EEBB293619210042359D /* Routeur in Frameworks */ = {isa = PBXBuildFile; productRef = 9F24EEBA293619210042359D /* Routeur */; };
|
9F24EEBB293619210042359D /* Routeur in Frameworks */ = {isa = PBXBuildFile; productRef = 9F24EEBA293619210042359D /* Routeur */; };
|
||||||
9F295540292B6C3400E0E81B /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F29553F292B6C3400E0E81B /* Timeline */; };
|
9F295540292B6C3400E0E81B /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F29553F292B6C3400E0E81B /* Timeline */; };
|
||||||
|
9F35DB44294F9A7D00B3281A /* Status in Frameworks */ = {isa = PBXBuildFile; productRef = 9F35DB43294F9A7D00B3281A /* Status */; };
|
||||||
9F398AA62935FE8A00A889F2 /* AppRouteur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F398AA52935FE8A00A889F2 /* AppRouteur.swift */; };
|
9F398AA62935FE8A00A889F2 /* AppRouteur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F398AA52935FE8A00A889F2 /* AppRouteur.swift */; };
|
||||||
9F398AA92935FFDB00A889F2 /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AA82935FFDB00A889F2 /* Account */; };
|
9F398AA92935FFDB00A889F2 /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AA82935FFDB00A889F2 /* Account */; };
|
||||||
9F398AAB2935FFDB00A889F2 /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AAA2935FFDB00A889F2 /* Models */; };
|
9F398AAB2935FFDB00A889F2 /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AAA2935FFDB00A889F2 /* Models */; };
|
||||||
|
@ -29,6 +30,8 @@
|
||||||
9F24EEB92936185B0042359D /* Routeur */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Routeur; path = Packages/Routeur; sourceTree = "<group>"; };
|
9F24EEB92936185B0042359D /* Routeur */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Routeur; path = Packages/Routeur; sourceTree = "<group>"; };
|
||||||
9F29553D292B67B600E0E81B /* Network */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Network; path = Packages/Network; sourceTree = "<group>"; };
|
9F29553D292B67B600E0E81B /* Network */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Network; path = Packages/Network; sourceTree = "<group>"; };
|
||||||
9F29553E292B6AF600E0E81B /* Timeline */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Timeline; path = Packages/Timeline; sourceTree = "<group>"; };
|
9F29553E292B6AF600E0E81B /* Timeline */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Timeline; path = Packages/Timeline; sourceTree = "<group>"; };
|
||||||
|
9F35DB42294F9A2900B3281A /* Status */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Status; path = Packages/Status; sourceTree = "<group>"; };
|
||||||
|
9F35DB45294FA04C00B3281A /* DesignSystem */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = DesignSystem; path = Packages/DesignSystem; sourceTree = "<group>"; };
|
||||||
9F398AA32935F90100A889F2 /* Models */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Models; path = Packages/Models; sourceTree = "<group>"; };
|
9F398AA32935F90100A889F2 /* Models */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Models; path = Packages/Models; sourceTree = "<group>"; };
|
||||||
9F398AA52935FE8A00A889F2 /* AppRouteur.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteur.swift; sourceTree = "<group>"; };
|
9F398AA52935FE8A00A889F2 /* AppRouteur.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteur.swift; sourceTree = "<group>"; };
|
||||||
9F398AAC2936005300A889F2 /* Account */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Account; path = Packages/Account; sourceTree = "<group>"; };
|
9F398AAC2936005300A889F2 /* Account */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Account; path = Packages/Account; sourceTree = "<group>"; };
|
||||||
|
@ -53,6 +56,7 @@
|
||||||
9F398AA92935FFDB00A889F2 /* Account in Frameworks */,
|
9F398AA92935FFDB00A889F2 /* Account in Frameworks */,
|
||||||
9FBFE64E292A72BD00C250E9 /* Network in Frameworks */,
|
9FBFE64E292A72BD00C250E9 /* Network in Frameworks */,
|
||||||
9F398AAB2935FFDB00A889F2 /* Models in Frameworks */,
|
9F398AAB2935FFDB00A889F2 /* Models in Frameworks */,
|
||||||
|
9F35DB44294F9A7D00B3281A /* Status in Frameworks */,
|
||||||
9F24EEBB293619210042359D /* Routeur in Frameworks */,
|
9F24EEBB293619210042359D /* Routeur in Frameworks */,
|
||||||
9F295540292B6C3400E0E81B /* Timeline in Frameworks */,
|
9F295540292B6C3400E0E81B /* Timeline in Frameworks */,
|
||||||
);
|
);
|
||||||
|
@ -105,10 +109,12 @@
|
||||||
9FBFE63A292A715500C250E9 /* Products */,
|
9FBFE63A292A715500C250E9 /* Products */,
|
||||||
9FBFE64C292A72BD00C250E9 /* Frameworks */,
|
9FBFE64C292A72BD00C250E9 /* Frameworks */,
|
||||||
9F398AAC2936005300A889F2 /* Account */,
|
9F398AAC2936005300A889F2 /* Account */,
|
||||||
|
9F35DB45294FA04C00B3281A /* DesignSystem */,
|
||||||
9F398AA32935F90100A889F2 /* Models */,
|
9F398AA32935F90100A889F2 /* Models */,
|
||||||
|
9F29553D292B67B600E0E81B /* Network */,
|
||||||
9F29553E292B6AF600E0E81B /* Timeline */,
|
9F29553E292B6AF600E0E81B /* Timeline */,
|
||||||
9F24EEB92936185B0042359D /* Routeur */,
|
9F24EEB92936185B0042359D /* Routeur */,
|
||||||
9F29553D292B67B600E0E81B /* Network */,
|
9F35DB42294F9A2900B3281A /* Status */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
@ -171,6 +177,7 @@
|
||||||
9F398AAA2935FFDB00A889F2 /* Models */,
|
9F398AAA2935FFDB00A889F2 /* Models */,
|
||||||
9F24EEBA293619210042359D /* Routeur */,
|
9F24EEBA293619210042359D /* Routeur */,
|
||||||
9FAE4ACD29379A5A00772766 /* KeychainSwift */,
|
9FAE4ACD29379A5A00772766 /* KeychainSwift */,
|
||||||
|
9F35DB43294F9A7D00B3281A /* Status */,
|
||||||
);
|
);
|
||||||
productName = IceCubesApp;
|
productName = IceCubesApp;
|
||||||
productReference = 9FBFE639292A715500C250E9 /* IceCubesApp.app */;
|
productReference = 9FBFE639292A715500C250E9 /* IceCubesApp.app */;
|
||||||
|
@ -360,7 +367,7 @@
|
||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 150;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Resources\"";
|
DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Resources\"";
|
||||||
DEVELOPMENT_TEAM = Z6P74P6T99;
|
DEVELOPMENT_TEAM = Z6P74P6T99;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
@ -381,7 +388,7 @@
|
||||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = 0.0.1;
|
MARKETING_VERSION = 0.0.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.thomasricouard.IceCubesApp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.thomasricouard.IceCubesApp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
|
@ -401,7 +408,7 @@
|
||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 150;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Resources\"";
|
DEVELOPMENT_ASSET_PATHS = "\"IceCubesApp/Resources\"";
|
||||||
DEVELOPMENT_TEAM = Z6P74P6T99;
|
DEVELOPMENT_TEAM = Z6P74P6T99;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
@ -422,7 +429,7 @@
|
||||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = 0.0.1;
|
MARKETING_VERSION = 0.0.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.thomasricouard.IceCubesApp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.thomasricouard.IceCubesApp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
|
@ -476,6 +483,10 @@
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = Timeline;
|
productName = Timeline;
|
||||||
};
|
};
|
||||||
|
9F35DB43294F9A7D00B3281A /* Status */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = Status;
|
||||||
|
};
|
||||||
9F398AA82935FFDB00A889F2 /* Account */ = {
|
9F398AA82935FFDB00A889F2 /* Account */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = Account;
|
productName = Account;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import SwiftUI
|
||||||
import Timeline
|
import Timeline
|
||||||
import Account
|
import Account
|
||||||
import Routeur
|
import Routeur
|
||||||
|
import Status
|
||||||
|
|
||||||
extension View {
|
extension View {
|
||||||
func withAppRouteur() -> some View {
|
func withAppRouteur() -> some View {
|
||||||
|
|
|
@ -16,13 +16,15 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Network", path: "../Network"),
|
.package(name: "Network", path: "../Network"),
|
||||||
.package(name: "Models", path: "../Models"),
|
.package(name: "Models", path: "../Models"),
|
||||||
|
.package(name: "Status", path: "../Status"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
name: "Account",
|
name: "Account",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "Network", package: "Network"),
|
.product(name: "Network", package: "Network"),
|
||||||
.product(name: "Models", package: "Models")
|
.product(name: "Models", package: "Models"),
|
||||||
|
.product(name: "Status", package: "Status"),
|
||||||
]),
|
]),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "AccountTests",
|
name: "AccountTests",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Models
|
import Models
|
||||||
|
import DesignSystem
|
||||||
|
|
||||||
struct AccountDetailHeaderView: View {
|
struct AccountDetailHeaderView: View {
|
||||||
@Environment(\.redactionReasons) private var reasons
|
@Environment(\.redactionReasons) private var reasons
|
||||||
|
@ -70,17 +71,17 @@ struct AccountDetailHeaderView: View {
|
||||||
.font(.body)
|
.font(.body)
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, DS.Constants.layoutPadding)
|
||||||
.offset(y: -40)
|
.offset(y: -40)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeCustomInfoLabel(title: String, count: Int) -> some View {
|
private func makeCustomInfoLabel(title: String, count: Int) -> some View {
|
||||||
VStack {
|
VStack {
|
||||||
|
Text("\(count)")
|
||||||
|
.font(.headline)
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
Text("\(count)")
|
|
||||||
.font(.headline)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import Status
|
||||||
|
import Shimmer
|
||||||
|
import DesignSystem
|
||||||
|
|
||||||
public struct AccountDetailView: View {
|
public struct AccountDetailView: View {
|
||||||
@EnvironmentObject private var client: Client
|
@EnvironmentObject private var client: Client
|
||||||
|
@ -17,6 +20,21 @@ public struct AccountDetailView: View {
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
|
headerView
|
||||||
|
statusesView
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.edgesIgnoringSafeArea(.top)
|
||||||
|
.task {
|
||||||
|
viewModel.client = client
|
||||||
|
await viewModel.fetchAccount()
|
||||||
|
await viewModel.fetchStatuses()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var headerView: some View {
|
||||||
switch viewModel.state {
|
switch viewModel.state {
|
||||||
case .loading:
|
case .loading:
|
||||||
AccountDetailHeaderView(account: .placeholder())
|
AccountDetailHeaderView(account: .placeholder())
|
||||||
|
@ -26,12 +44,47 @@ public struct AccountDetailView: View {
|
||||||
case let .error(error):
|
case let .error(error):
|
||||||
Text("Error: \(error.localizedDescription)")
|
Text("Error: \(error.localizedDescription)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var statusesView: some View {
|
||||||
|
switch viewModel.statusesState {
|
||||||
|
case .loading:
|
||||||
|
ForEach(Status.placeholders()) { status in
|
||||||
|
StatusRowView(status: status)
|
||||||
|
.redacted(reason: .placeholder)
|
||||||
|
.shimmering()
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
case let .error(error):
|
||||||
|
Text(error.localizedDescription)
|
||||||
|
case let .display(statuses, nextPageState):
|
||||||
|
ForEach(statuses) { status in
|
||||||
|
StatusRowView(status: status)
|
||||||
|
Divider()
|
||||||
|
.padding(.bottom, DS.Constants.layoutPadding)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch nextPageState {
|
||||||
|
case .hasNextPage:
|
||||||
|
loadingRow
|
||||||
|
.onAppear {
|
||||||
|
Task {
|
||||||
|
await viewModel.loadNextPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.edgesIgnoringSafeArea(.top)
|
case .loadingNextPage:
|
||||||
.task {
|
loadingRow
|
||||||
viewModel.client = client
|
}
|
||||||
await viewModel.fetchAccount()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var loadingRow: some View {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
ProgressView()
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,19 @@ class AccountDetailViewModel: ObservableObject {
|
||||||
case loading, data(account: Account), error(error: Error)
|
case loading, data(account: Account), error(error: Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum StatusesState {
|
||||||
|
enum PagingState {
|
||||||
|
case hasNextPage, loadingNextPage
|
||||||
|
}
|
||||||
|
case loading
|
||||||
|
case display(statuses: [Status], nextPageState: StatusesState.PagingState)
|
||||||
|
case error(error: Error)
|
||||||
|
}
|
||||||
|
|
||||||
@Published var state: State = .loading
|
@Published var state: State = .loading
|
||||||
|
@Published var statusesState: StatusesState = .loading
|
||||||
|
|
||||||
|
private var statuses: [Status] = []
|
||||||
|
|
||||||
init(accountId: String) {
|
init(accountId: String) {
|
||||||
self.accountId = accountId
|
self.accountId = accountId
|
||||||
|
@ -29,4 +41,26 @@ class AccountDetailViewModel: ObservableObject {
|
||||||
state = .error(error: error)
|
state = .error(error: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchStatuses() async {
|
||||||
|
do {
|
||||||
|
statusesState = .loading
|
||||||
|
statuses = try await client.get(endpoint: Accounts.statuses(id: accountId, sinceId: nil))
|
||||||
|
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
||||||
|
} catch {
|
||||||
|
statusesState = .error(error: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNextPage() async {
|
||||||
|
do {
|
||||||
|
guard let lastId = statuses.last?.id else { return }
|
||||||
|
statusesState = .display(statuses: statuses, nextPageState: .loadingNextPage)
|
||||||
|
let newStatuses: [Status] = try await client.get(endpoint: Accounts.statuses(id: accountId, sinceId: lastId))
|
||||||
|
statuses.append(contentsOf: newStatuses)
|
||||||
|
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
||||||
|
} catch {
|
||||||
|
statusesState = .error(error: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
9
Packages/DesignSystem/.gitignore
vendored
Normal file
9
Packages/DesignSystem/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
xcuserdata/
|
||||||
|
DerivedData/
|
||||||
|
.swiftpm/config/registries.json
|
||||||
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||||
|
.netrc
|
23
Packages/DesignSystem/Package.swift
Normal file
23
Packages/DesignSystem/Package.swift
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// 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: "DesignSystem",
|
||||||
|
platforms: [
|
||||||
|
.iOS(.v16),
|
||||||
|
],
|
||||||
|
products: [
|
||||||
|
.library(
|
||||||
|
name: "DesignSystem",
|
||||||
|
targets: ["DesignSystem"]),
|
||||||
|
],
|
||||||
|
dependencies: [],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "DesignSystem",
|
||||||
|
dependencies: []),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
3
Packages/DesignSystem/README.md
Normal file
3
Packages/DesignSystem/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# DesignSystem
|
||||||
|
|
||||||
|
A description of this package.
|
|
@ -0,0 +1,7 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct DS {
|
||||||
|
public enum Constants {
|
||||||
|
public static let layoutPadding: CGFloat = 16
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import Foundation
|
||||||
public enum Accounts: Endpoint {
|
public enum Accounts: Endpoint {
|
||||||
case accounts(id: String)
|
case accounts(id: String)
|
||||||
case verifyCredentials
|
case verifyCredentials
|
||||||
|
case statuses(id: String, sinceId: String?)
|
||||||
|
|
||||||
public func path() -> String {
|
public func path() -> String {
|
||||||
switch self {
|
switch self {
|
||||||
|
@ -10,10 +11,18 @@ public enum Accounts: Endpoint {
|
||||||
return "accounts/\(id)"
|
return "accounts/\(id)"
|
||||||
case .verifyCredentials:
|
case .verifyCredentials:
|
||||||
return "accounts/verify_credentials"
|
return "accounts/verify_credentials"
|
||||||
|
case .statuses(let id, _):
|
||||||
|
return "accounts/\(id)/statuses"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
nil
|
switch self {
|
||||||
|
case .statuses(_, let sinceId):
|
||||||
|
guard let sinceId else { return nil }
|
||||||
|
return [.init(name: "max_id", value: sinceId)]
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,10 @@ public enum Timelines: Endpoint {
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case .pub(let sinceId):
|
case .pub(let sinceId):
|
||||||
|
guard let sinceId else { return nil }
|
||||||
return [.init(name: "max_id", value: sinceId)]
|
return [.init(name: "max_id", value: sinceId)]
|
||||||
case .home(let sinceId):
|
case .home(let sinceId):
|
||||||
|
guard let sinceId else { return nil }
|
||||||
return [.init(name: "max_id", value: sinceId)]
|
return [.init(name: "max_id", value: sinceId)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
9
Packages/Status/.gitignore
vendored
Normal file
9
Packages/Status/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
xcuserdata/
|
||||||
|
DerivedData/
|
||||||
|
.swiftpm/config/registries.json
|
||||||
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||||
|
.netrc
|
31
Packages/Status/Package.swift
Normal file
31
Packages/Status/Package.swift
Normal file
|
@ -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: "Status",
|
||||||
|
platforms: [
|
||||||
|
.iOS(.v16),
|
||||||
|
],
|
||||||
|
products: [
|
||||||
|
.library(
|
||||||
|
name: "Status",
|
||||||
|
targets: ["Status"]),
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
.package(name: "Models", path: "../Models"),
|
||||||
|
.package(name: "Routeur", path: "../Routeur"),
|
||||||
|
.package(name: "DesignSystem", path: "../DesignSystem"),
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "Status",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "Models", package: "Models"),
|
||||||
|
.product(name: "Routeur", package: "Routeur"),
|
||||||
|
.product(name: "DesignSystem", package: "DesignSystem"),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
3
Packages/Status/README.md
Normal file
3
Packages/Status/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Status
|
||||||
|
|
||||||
|
A description of this package.
|
|
@ -30,6 +30,6 @@ struct StatusActionsView: View {
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "square.and.arrow.up")
|
Image(systemName: "square.and.arrow.up")
|
||||||
}
|
}
|
||||||
}
|
}.tint(.black)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,7 +31,7 @@ public struct StatusMediaPreviewView: View {
|
||||||
content: { image in
|
content: { image in
|
||||||
image.resizable()
|
image.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.frame(maxHeight: 200)
|
.frame(maxHeight: attachements.count > 2 ? 100 : 200)
|
||||||
.clipped()
|
.clipped()
|
||||||
.cornerRadius(4)
|
.cornerRadius(4)
|
||||||
},
|
},
|
|
@ -2,13 +2,17 @@ import SwiftUI
|
||||||
import Models
|
import Models
|
||||||
import Routeur
|
import Routeur
|
||||||
|
|
||||||
struct StatusRowView: View {
|
public struct StatusRowView: View {
|
||||||
@Environment(\.redactionReasons) private var reasons
|
@Environment(\.redactionReasons) private var reasons
|
||||||
@EnvironmentObject private var routeurPath: RouterPath
|
@EnvironmentObject private var routeurPath: RouterPath
|
||||||
|
|
||||||
let status: Status
|
private let status: Status
|
||||||
|
|
||||||
var body: some View {
|
public init(status: Status) {
|
||||||
|
self.status = status
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
reblogView
|
reblogView
|
||||||
statusView
|
statusView
|
|
@ -17,6 +17,7 @@ let package = Package(
|
||||||
.package(name: "Network", path: "../Network"),
|
.package(name: "Network", path: "../Network"),
|
||||||
.package(name: "Models", path: "../Models"),
|
.package(name: "Models", path: "../Models"),
|
||||||
.package(name: "Routeur", path: "../Routeur"),
|
.package(name: "Routeur", path: "../Routeur"),
|
||||||
|
.package(name: "Status", path: "../Status"),
|
||||||
.package(url: "https://github.com/markiv/SwiftUI-Shimmer", exact: "1.1.0")
|
.package(url: "https://github.com/markiv/SwiftUI-Shimmer", exact: "1.1.0")
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
|
@ -26,6 +27,7 @@ let package = Package(
|
||||||
.product(name: "Network", package: "Network"),
|
.product(name: "Network", package: "Network"),
|
||||||
.product(name: "Models", package: "Models"),
|
.product(name: "Models", package: "Models"),
|
||||||
.product(name: "Routeur", package: "Routeur"),
|
.product(name: "Routeur", package: "Routeur"),
|
||||||
|
.product(name: "Status", package: "Status"),
|
||||||
.product(name: "Shimmer", package: "SwiftUI-Shimmer")
|
.product(name: "Shimmer", package: "SwiftUI-Shimmer")
|
||||||
]),
|
]),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
|
@ -33,3 +35,4 @@ let package = Package(
|
||||||
dependencies: ["Timeline"]),
|
dependencies: ["Timeline"]),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import SwiftUI
|
||||||
import Network
|
import Network
|
||||||
import Models
|
import Models
|
||||||
import Shimmer
|
import Shimmer
|
||||||
|
import Status
|
||||||
|
|
||||||
public struct TimelineView: View {
|
public struct TimelineView: View {
|
||||||
@EnvironmentObject private var client: Client
|
@EnvironmentObject private var client: Client
|
||||||
|
|
|
@ -5,11 +5,11 @@ import Models
|
||||||
@MainActor
|
@MainActor
|
||||||
class TimelineViewModel: ObservableObject {
|
class TimelineViewModel: ObservableObject {
|
||||||
enum State {
|
enum State {
|
||||||
enum PadingState {
|
enum PagingState {
|
||||||
case hasNextPage, loadingNextPage
|
case hasNextPage, loadingNextPage
|
||||||
}
|
}
|
||||||
case loading
|
case loading
|
||||||
case display(statuses: [Status], nextPageState: State.PadingState)
|
case display(statuses: [Status], nextPageState: State.PagingState)
|
||||||
case error(error: Error)
|
case error(error: Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue