Make max width more consistent on iPad fix #236

This commit is contained in:
Thomas Ricouard 2023-01-29 08:14:08 +01:00
parent 33a7bd57ff
commit 6ea2d9cb78
4 changed files with 99 additions and 90 deletions

View file

@ -32,6 +32,8 @@ public struct AppAccountView: View {
HStack { HStack {
if let account = viewModel.account { if let account = viewModel.account {
AvatarView(url: account.avatar) AvatarView(url: account.avatar)
} else {
ProgressView()
} }
} }
} }
@ -47,6 +49,8 @@ public struct AppAccountView: View {
.offset(x: 5, y: -5) .offset(x: 5, y: -5)
} }
} }
} else {
ProgressView()
} }
VStack(alignment: .leading) { VStack(alignment: .leading) {
if let account = viewModel.account { if let account = viewModel.account {

View file

@ -10,62 +10,65 @@ public struct ConversationsListView: View {
@EnvironmentObject private var watcher: StreamWatcher @EnvironmentObject private var watcher: StreamWatcher
@EnvironmentObject private var client: Client @EnvironmentObject private var client: Client
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
@StateObject private var viewModel = ConversationsListViewModel() @StateObject private var viewModel = ConversationsListViewModel()
public init() {} public init() {}
private var conversations: [Conversation] { private var conversations: [Conversation] {
if viewModel.isLoadingFirstPage { if viewModel.isLoadingFirstPage {
return Conversation.placeholders() return Conversation.placeholders()
} }
return viewModel.conversations return viewModel.conversations
} }
public var body: some View { public var body: some View {
ScrollView { ScrollView {
LazyVStack { LazyVStack {
if !conversations.isEmpty || viewModel.isLoadingFirstPage { Group {
ForEach(conversations) { conversation in if !conversations.isEmpty || viewModel.isLoadingFirstPage {
if viewModel.isLoadingFirstPage { ForEach(conversations) { conversation in
ConversationsListRow(conversation: conversation, viewModel: viewModel) if viewModel.isLoadingFirstPage {
.padding(.horizontal, .layoutPadding) ConversationsListRow(conversation: conversation, viewModel: viewModel)
.redacted(reason: .placeholder) .padding(.horizontal, .layoutPadding)
.shimmering() .redacted(reason: .placeholder)
} else { .shimmering()
ConversationsListRow(conversation: conversation, viewModel: viewModel) } else {
.padding(.horizontal, .layoutPadding) ConversationsListRow(conversation: conversation, viewModel: viewModel)
.padding(.horizontal, .layoutPadding)
}
Divider()
} }
Divider() } else if conversations.isEmpty && !viewModel.isLoadingFirstPage && !viewModel.isError {
} EmptyView(iconName: "tray",
} else if conversations.isEmpty && !viewModel.isLoadingFirstPage && !viewModel.isError { title: "conversations.empty.title",
EmptyView(iconName: "tray", message: "conversations.empty.message")
title: "conversations.empty.title", } else if viewModel.isError {
message: "conversations.empty.message") ErrorView(title: "conversations.error.title",
} else if viewModel.isError { message: "conversations.error.message",
ErrorView(title: "conversations.error.title", buttonTitle: "conversations.error.button") {
message: "conversations.error.message",
buttonTitle: "conversations.error.button") {
Task {
await viewModel.fetchConversations()
}
}
}
if viewModel.nextPage != nil {
HStack {
Spacer()
ProgressView()
Spacer()
}
.onAppear {
if !viewModel.isLoadingNextPage {
Task { Task {
await viewModel.fetchNextPage() await viewModel.fetchConversations()
}
}
}
if viewModel.nextPage != nil {
HStack {
Spacer()
ProgressView()
Spacer()
}
.onAppear {
if !viewModel.isLoadingNextPage {
Task {
await viewModel.fetchNextPage()
}
} }
} }
} }
} }
.frame(maxWidth: .maxColumnWidth)
} }
.padding(.top, .layoutPadding) .padding(.top, .layoutPadding)
} }

View file

@ -23,8 +23,7 @@ extension Color: RawRepresentable {
let red = Double((rawValue & 0xFF0000) >> 16) / 0xFF let red = Double((rawValue & 0xFF0000) >> 16) / 0xFF
let green = Double((rawValue & 0x00FF00) >> 8) / 0xFF let green = Double((rawValue & 0x00FF00) >> 8) / 0xFF
let blue = Double(rawValue & 0x0000FF) / 0xFF let blue = Double(rawValue & 0x0000FF) / 0xFF
let opacity = Double((rawValue & 0xFF000000) >> 24) / 0xFF self = Color(red: red, green: green, blue: blue)
self = Color(red: red, green: green, blue: blue, opacity: opacity == 0 ? 1 : 0)
} }
public var rawValue: Int { public var rawValue: Int {
@ -34,8 +33,7 @@ extension Color: RawRepresentable {
let red = Int(coreImageColor.red * 255 + 0.5) let red = Int(coreImageColor.red * 255 + 0.5)
let green = Int(coreImageColor.green * 255 + 0.5) let green = Int(coreImageColor.green * 255 + 0.5)
let blue = Int(coreImageColor.blue * 255 + 0.5) let blue = Int(coreImageColor.blue * 255 + 0.5)
let alpha = Int(coreImageColor.alpha * 255 + 0.5) return (red << 16) | (green << 8) | blue
return (alpha << 24) | (red << 16) | (green << 8) | blue
} }
private var coreImageColor: CIColor? { private var coreImageColor: CIColor? {

View file

@ -14,68 +14,72 @@ public struct StatusDetailView: View {
@Environment(\.openURL) private var openURL @Environment(\.openURL) private var openURL
@StateObject private var viewModel: StatusDetailViewModel @StateObject private var viewModel: StatusDetailViewModel
@State private var isLoaded: Bool = false @State private var isLoaded: Bool = false
public init(statusId: String) { public init(statusId: String) {
_viewModel = StateObject(wrappedValue: .init(statusId: statusId)) _viewModel = StateObject(wrappedValue: .init(statusId: statusId))
} }
public init(remoteStatusURL: URL) { public init(remoteStatusURL: URL) {
_viewModel = StateObject(wrappedValue: .init(remoteStatusURL: remoteStatusURL)) _viewModel = StateObject(wrappedValue: .init(remoteStatusURL: remoteStatusURL))
} }
public var body: some View { public var body: some View {
ScrollViewReader { proxy in ScrollViewReader { proxy in
ScrollView { ZStack {
LazyVStack { ScrollView {
switch viewModel.state { LazyVStack {
case .loading: Group {
ForEach(Status.placeholders()) { status in switch viewModel.state {
StatusRowView(viewModel: .init(status: status, isCompact: false)) case .loading:
ForEach(Status.placeholders()) { status in
StatusRowView(viewModel: .init(status: status, isCompact: false))
.padding(.horizontal, .layoutPadding)
.redacted(reason: .placeholder)
.shimmering()
Divider()
.padding(.vertical, .dividerPadding)
}
case let .display(status, context):
if !context.ancestors.isEmpty {
ForEach(context.ancestors) { ancestor in
StatusRowView(viewModel: .init(status: ancestor, isCompact: false))
.padding(.horizontal, .layoutPadding)
Divider()
.padding(.vertical, .dividerPadding)
}
}
StatusRowView(viewModel: .init(status: status,
isCompact: false,
isFocused: true))
.padding(.horizontal, .layoutPadding) .padding(.horizontal, .layoutPadding)
.redacted(reason: .placeholder) .id(status.id)
.shimmering()
Divider()
.padding(.vertical, .dividerPadding)
}
case let .display(status, context):
if !context.ancestors.isEmpty {
ForEach(context.ancestors) { ancestor in
StatusRowView(viewModel: .init(status: ancestor, isCompact: false))
.padding(.horizontal, .layoutPadding)
Divider() Divider()
.padding(.vertical, .dividerPadding) .padding(.bottom, .dividerPadding * 2)
} if !context.descendants.isEmpty {
} ForEach(context.descendants) { descendant in
StatusRowView(viewModel: .init(status: status, StatusRowView(viewModel: .init(status: descendant, isCompact: false))
isCompact: false, .padding(.horizontal, .layoutPadding)
isFocused: true)) Divider()
.padding(.horizontal, .layoutPadding) .padding(.vertical, .dividerPadding)
.id(status.id) }
Divider() }
.padding(.bottom, .dividerPadding * 2)
if !context.descendants.isEmpty { case .error:
ForEach(context.descendants) { descendant in ErrorView(title: "status.error.title",
StatusRowView(viewModel: .init(status: descendant, isCompact: false)) message: "status.error.message",
.padding(.horizontal, .layoutPadding) buttonTitle: "action.retry") {
Divider() Task {
.padding(.vertical, .dividerPadding) await viewModel.fetch()
} }
} }
case .error:
ErrorView(title: "status.error.title",
message: "status.error.message",
buttonTitle: "action.retry") {
Task {
await viewModel.fetch()
} }
} }
.frame(maxWidth: .maxColumnWidth)
} }
.padding(.top, .layoutPadding)
} }
.padding(.top, .layoutPadding) .background(theme.primaryBackgroundColor)
} }
.scrollContentBackground(.hidden)
.background(theme.primaryBackgroundColor)
.task { .task {
guard !isLoaded else { return } guard !isLoaded else { return }
isLoaded = true isLoaded = true