Bitwarden-app-android-iphon.../src/watchOS/bitwarden/bitwarden WatchKit Extension/Views/CipherListView.swift

135 lines
4.8 KiB
Swift

import SwiftUI
struct CipherListView: View {
@ObservedObject var viewModel = CipherListViewModel(CipherService.shared)
let AVATAR_ID: String = "avatarId"
var isHeaderVisible: Bool {
return !viewModel.searchTerm.isEmpty || viewModel.filteredCiphers.count > 1
}
var body: some View {
NavigationView {
GeometryReader { geometry in
ScrollViewReader { scrollProxy in
List {
if isHeaderVisible {
Section() {
getSearchSection(geometry.size.width)
}
}
if viewModel.user?.email != nil {
Section() {
avatarHeader
.id(AVATAR_ID)
.background(
RoundedRectangle(cornerRadius: 5)
.foregroundColor(Color.ui.avatarItemBackground)
.frame(width: geometry.size.width + 10, height: 50)
)
.padding(0)
}
}
ForEach(viewModel.filteredCiphers, id: \.id) { cipher in
NavigationLink(destination: CipherDetailsView(cipher: cipher)){
CipherItemView(cipher, geometry.size.width)
}
.listRowInsets(EdgeInsets())
.listRowBackground(Color.clear)
.padding(0)
}
}
.emptyState(viewModel.filteredCiphers.isEmpty, emptyContent: {
emptyContent
.frame(width: geometry.size.width, alignment: .center)
})
.onReceive(self.viewModel.$updateHack) { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
scrollProxy.scrollTo(AVATAR_ID, anchor: .top)
}
}
}
}
}
.navigationTitle("Bitwarden")
.navigationBarTitleDisplayMode(.inline)
.onAppear {
#if targetEnvironment(simulator) // for the preview
self.viewModel.fetchCiphers()
#else
self.viewModel.checkStateAndFetch()
#endif
}
.fullScreenCover(isPresented: $viewModel.showingSheet) {
BWStateView(viewModel.currentState, viewModel.debugText)
}
}
var searchContent: some View {
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(Color(.white))
.frame(width: 20, height: 30)
TextField("", text: $viewModel.searchTerm)
.foregroundColor(.white)
.frame(width: .infinity, height: 33)
.placeholder(when: viewModel.searchTerm.isEmpty) {
Text("Search").foregroundColor(.white)
}
}
}
var avatarHeader: some View {
HStack {
AvatarView(viewModel.user)
Text(viewModel.user!.email!)
.font(.headline)
.lineLimit(1)
.truncationMode(.tail)
}
}
var emptyContent: some View {
VStack(alignment: .center) {
Image("EmptyListPlaceholder")
.resizable()
.scaledToFit()
.padding(20)
Text("ThereAreNoItemsToList")
.foregroundColor(Color.white)
.font(.headline)
.multilineTextAlignment(.center)
}
}
func getSearchSection(_ maxWidth:CGFloat) -> some View {
return ZStack {
searchContent
.padding(5)
.background(
RoundedRectangle(cornerRadius: 5)
.foregroundColor(Color.ui.primary)
.frame(width: maxWidth,
alignment: .leading)
)
}
.background(
RoundedRectangle(cornerRadius: 5)
.foregroundColor(Color.black)
.frame(width: maxWidth, height: 60)
)
.padding(0)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
var v = CipherListView()
StateService.shared.currentState = .valid
v.viewModel = CipherListViewModel(CipherServiceMock())
v.viewModel.user = User(id: "zxc", email: "testing@test.com", name: "Tester")
return v
}
}