mirror of
https://github.com/home-assistant/iOS.git
synced 2026-02-17 04:10:52 -06:00
183 lines
6.1 KiB
Swift
183 lines
6.1 KiB
Swift
import SFSafeSymbols
|
|
import Shared
|
|
import SwiftUI
|
|
|
|
struct ClientEventsLogView: View {
|
|
@Environment(\.dismiss) private var dismiss
|
|
@StateObject private var viewModel = ClientEventsLogViewModel()
|
|
@State private var showClearConfirmation = false
|
|
|
|
var body: some View {
|
|
List {
|
|
typeFilter
|
|
eventsList
|
|
}
|
|
.searchable(text: $viewModel.searchTerm)
|
|
.refreshable {
|
|
viewModel.loadEvents()
|
|
}
|
|
.navigationTitle(L10n.Settings.EventLog.title)
|
|
.navigationBarTitleDisplayMode(.large)
|
|
.toolbar {
|
|
ToolbarItem(placement: .topBarTrailing) {
|
|
Button {
|
|
showClearConfirmation = true
|
|
} label: {
|
|
Text(verbatim: L10n.ClientEvents.View.clear)
|
|
}
|
|
.confirmationDialog(
|
|
L10n.ClientEvents.View.ClearConfirm.title,
|
|
isPresented: $showClearConfirmation,
|
|
titleVisibility: .visible
|
|
) {
|
|
Button(L10n.cancelLabel, role: .cancel) {
|
|
/* no-op */
|
|
}
|
|
Button(L10n.yesLabel, role: .destructive) {
|
|
Current.clientEventStore.clearAllEvents()
|
|
dismiss()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onAppear {
|
|
viewModel.loadEvents()
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var eventsList: some View {
|
|
ForEach(filteredEvents, id: \.id) { event in
|
|
listItem(event)
|
|
}
|
|
if filteredEvents.isEmpty {
|
|
Text(verbatim: L10n.ClientEvents.noEvents)
|
|
.frame(maxWidth: .infinity, alignment: .center)
|
|
.listRowBackground(Color.clear)
|
|
.font(.headline)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
}
|
|
|
|
private var filteredEvents: [ClientEvent] {
|
|
viewModel.events.filter({ event in
|
|
if viewModel.searchTerm.isEmpty, viewModel.typeFilter == nil {
|
|
return true
|
|
} else {
|
|
if viewModel.searchTerm.isEmpty {
|
|
if let typeFilter = viewModel.typeFilter {
|
|
return event.type == typeFilter
|
|
} else {
|
|
return true
|
|
}
|
|
} else {
|
|
let containsSearchTerm = event.text.lowercased().contains(viewModel.searchTerm.lowercased())
|
|
if let typeFilter = viewModel.typeFilter {
|
|
return event.type == typeFilter && containsSearchTerm
|
|
} else {
|
|
return containsSearchTerm
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
private var typeFilter: some View {
|
|
Section {
|
|
ScrollView(.horizontal, showsIndicators: false) {
|
|
HStack {
|
|
Group {
|
|
Button {
|
|
viewModel.resetTypeFilter()
|
|
} label: {
|
|
PillView(
|
|
text: L10n.ClientEvents.EventType.all,
|
|
selected: viewModel.typeFilter == nil
|
|
)
|
|
}
|
|
ForEach(ClientEvent.EventType.allCases.sorted { e1, e2 in
|
|
e1.displayText < e2.displayText
|
|
}, id: \.self) { type in
|
|
Button {
|
|
viewModel.typeFilter = type
|
|
} label: {
|
|
PillView(
|
|
text: type.displayText,
|
|
selected: viewModel.typeFilter == type
|
|
)
|
|
}
|
|
}
|
|
}
|
|
.buttonStyle(.plain)
|
|
.animation(.easeIn(duration: 0.2), value: viewModel.typeFilter)
|
|
}
|
|
}
|
|
.listRowBackground(Color.clear)
|
|
.modify { view in
|
|
if #available(iOS 17.0, *) {
|
|
view.scrollClipDisabled(true)
|
|
} else {
|
|
view
|
|
}
|
|
}
|
|
}
|
|
.modify { view in
|
|
if #available(iOS 17.0, *) {
|
|
view.listSectionSpacing(DesignSystem.Spaces.one)
|
|
} else {
|
|
view
|
|
}
|
|
}
|
|
}
|
|
|
|
private func listItem(_ event: ClientEvent) -> some View {
|
|
NavigationLink {
|
|
eventDescription(event)
|
|
} label: {
|
|
VStack(spacing: DesignSystem.Spaces.one) {
|
|
HStack {
|
|
Group {
|
|
Group {
|
|
dateTimeLabel(event.date)
|
|
}
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
Text(event.type.displayText)
|
|
.frame(alignment: .trailing)
|
|
}
|
|
.font(.subheadline)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
Text(event.text)
|
|
.font(.headline)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func dateTimeLabel(_ date: Date) -> Text {
|
|
Text(date, style: .date)
|
|
+
|
|
Text(" ")
|
|
+
|
|
Text(date, style: .time)
|
|
}
|
|
|
|
private func eventDescription(_ event: ClientEvent) -> some View {
|
|
ScrollView {
|
|
Text(event.jsonPayloadDescription ?? "--")
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.multilineTextAlignment(.leading)
|
|
.lineLimit(nil)
|
|
.textSelection(.enabled)
|
|
.padding()
|
|
}
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
|
.navigationTitle(dateTimeLabel(event.date))
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
ClientEventsLogView()
|
|
}
|