Mercurial > public > lazybear
changeset 393:0a4c399170c4
Implementing WatchlistCreator
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj Sat May 01 13:11:32 2021 +0200 +++ b/LazyBear.xcodeproj/project.pbxproj Sun May 02 12:41:20 2021 +0200 @@ -30,8 +30,8 @@ 9550444C26111FED000E0BCB /* StockItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9550444B26111FED000E0BCB /* StockItem.swift */; }; 955E73392623568F005652FF /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955E73382623568F005652FF /* Home.swift */; }; 955E733C262356F3005652FF /* HomeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955E733B262356F3005652FF /* HomeResponse.swift */; }; - 9562404C263C766D00C6C511 /* CreateNewWatchlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9562404B263C766D00C6C511 /* CreateNewWatchlist.swift */; }; - 9562404E263C7D8800C6C511 /* NewWatchlistClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9562404D263C7D8800C6C511 /* NewWatchlistClass.swift */; }; + 9562404C263C766D00C6C511 /* WatchlistCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9562404B263C766D00C6C511 /* WatchlistCreator.swift */; }; + 9562404E263C7D8800C6C511 /* WatchlistCreatorClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9562404D263C7D8800C6C511 /* WatchlistCreatorClass.swift */; }; 95672B8F25DDA54700DCBE4A /* LazyBearApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95672B8E25DDA54700DCBE4A /* LazyBearApp.swift */; }; 95672B9325DDA54700DCBE4A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95672B9225DDA54700DCBE4A /* Assets.xcassets */; }; 95672B9625DDA54700DCBE4A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95672B9525DDA54700DCBE4A /* Preview Assets.xcassets */; }; @@ -46,6 +46,11 @@ 95A07F6C26305AC6009865AA /* QuoteModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A07F6B26305AC6009865AA /* QuoteModel.swift */; }; 95A07F7126305AD5009865AA /* SectorPerformanceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A07F7026305AD5009865AA /* SectorPerformanceModel.swift */; }; 95A07F7626305AE3009865AA /* TradingDatesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A07F7526305AE3009865AA /* TradingDatesModel.swift */; }; + 95A4B930263E9F530056F036 /* WatchlistCreatorList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A4B92F263E9F530056F036 /* WatchlistCreatorList.swift */; }; + 95A4B933263E9F810056F036 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 95A4B932263E9F810056F036 /* Introspect */; }; + 95A4B935263EA31C0056F036 /* WatchlistCreatorSearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A4B934263EA31C0056F036 /* WatchlistCreatorSearchBar.swift */; }; + 95A4B937263EA5C20056F036 /* WatchlistCreatorRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A4B936263EA5C20056F036 /* WatchlistCreatorRow.swift */; }; + 95A4B939263EB1C20056F036 /* WatchlistLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A4B938263EB1C20056F036 /* WatchlistLists.swift */; }; 95A5186A26185AAB0002D27C /* GenericRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A5186926185AAB0002D27C /* GenericRequest.swift */; }; 95A5188626186F590002D27C /* PriceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A5188526186F590002D27C /* PriceView.swift */; }; 95A7C066261639E0003E2EC1 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A7C065261639DF003E2EC1 /* SearchView.swift */; }; @@ -108,8 +113,8 @@ 955E73382623568F005652FF /* Home.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Home.swift; sourceTree = "<group>"; }; 955E733B262356F3005652FF /* HomeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeResponse.swift; sourceTree = "<group>"; }; 9562404A263C72E800C6C511 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; }; - 9562404B263C766D00C6C511 /* CreateNewWatchlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateNewWatchlist.swift; sourceTree = "<group>"; }; - 9562404D263C7D8800C6C511 /* NewWatchlistClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewWatchlistClass.swift; sourceTree = "<group>"; }; + 9562404B263C766D00C6C511 /* WatchlistCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistCreator.swift; sourceTree = "<group>"; }; + 9562404D263C7D8800C6C511 /* WatchlistCreatorClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistCreatorClass.swift; sourceTree = "<group>"; }; 95672B8B25DDA54700DCBE4A /* LazyBear.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LazyBear.app; sourceTree = BUILT_PRODUCTS_DIR; }; 95672B8E25DDA54700DCBE4A /* LazyBearApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyBearApp.swift; sourceTree = "<group>"; }; 95672B9225DDA54700DCBE4A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; @@ -127,6 +132,10 @@ 95A07F6B26305AC6009865AA /* QuoteModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteModel.swift; sourceTree = "<group>"; }; 95A07F7026305AD5009865AA /* SectorPerformanceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorPerformanceModel.swift; sourceTree = "<group>"; }; 95A07F7526305AE3009865AA /* TradingDatesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TradingDatesModel.swift; sourceTree = "<group>"; }; + 95A4B92F263E9F530056F036 /* WatchlistCreatorList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistCreatorList.swift; sourceTree = "<group>"; }; + 95A4B934263EA31C0056F036 /* WatchlistCreatorSearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistCreatorSearchBar.swift; sourceTree = "<group>"; }; + 95A4B936263EA5C20056F036 /* WatchlistCreatorRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistCreatorRow.swift; sourceTree = "<group>"; }; + 95A4B938263EB1C20056F036 /* WatchlistLists.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistLists.swift; sourceTree = "<group>"; }; 95A5186926185AAB0002D27C /* GenericRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericRequest.swift; sourceTree = "<group>"; }; 95A5188526186F590002D27C /* PriceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceView.swift; sourceTree = "<group>"; }; 95A7C065261639DF003E2EC1 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = "<group>"; }; @@ -163,6 +172,7 @@ buildActionMask = 2147483647; files = ( 958A735225E0170900FD7ECA /* CloudKit.framework in Frameworks */, + 95A4B933263E9F810056F036 /* Introspect in Frameworks */, 954D7EC2260BE70C00A13C50 /* SwiftlySearch in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -395,9 +405,13 @@ 95BD2F91263418F7008B6752 /* Helpers */ = { isa = PBXGroup; children = ( + 95A4B938263EB1C20056F036 /* WatchlistLists.swift */, 95BD2FAD26341BD1008B6752 /* TextfieldAlert.swift */, - 9562404B263C766D00C6C511 /* CreateNewWatchlist.swift */, - 9562404D263C7D8800C6C511 /* NewWatchlistClass.swift */, + 9562404B263C766D00C6C511 /* WatchlistCreator.swift */, + 9562404D263C7D8800C6C511 /* WatchlistCreatorClass.swift */, + 95A4B92F263E9F530056F036 /* WatchlistCreatorList.swift */, + 95A4B934263EA31C0056F036 /* WatchlistCreatorSearchBar.swift */, + 95A4B936263EA5C20056F036 /* WatchlistCreatorRow.swift */, ); path = Helpers; sourceTree = "<group>"; @@ -475,6 +489,7 @@ name = LazyBear; packageProductDependencies = ( 954D7EC1260BE70C00A13C50 /* SwiftlySearch */, + 95A4B932263E9F810056F036 /* Introspect */, ); productName = LazyBear; productReference = 95672B8B25DDA54700DCBE4A /* LazyBear.app */; @@ -513,6 +528,7 @@ mainGroup = 95672B8225DDA54700DCBE4A; packageReferences = ( 954D7EC0260BE70C00A13C50 /* XCRemoteSwiftPackageReference "SwiftlySearch" */, + 95A4B931263E9F810056F036 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */, ); productRefGroup = 95672B8C25DDA54700DCBE4A /* Products */; projectDirPath = ""; @@ -589,12 +605,13 @@ 951566E72613A2B6007C0F36 /* TradingDates.swift in Sources */, 955E73392623568F005652FF /* Home.swift in Sources */, 95721DA6262761E700EC527B /* CurrencyRow.swift in Sources */, - 9562404C263C766D00C6C511 /* CreateNewWatchlist.swift in Sources */, + 9562404C263C766D00C6C511 /* WatchlistCreator.swift in Sources */, 95672B8F25DDA54700DCBE4A /* LazyBearApp.swift in Sources */, 95E6C57626345CE700AC1518 /* WatchlistManagerTest.swift in Sources */, 95A7C066261639E0003E2EC1 /* SearchView.swift in Sources */, 95ECCA5D2612169200A67EFA /* LineShape.swift in Sources */, 9550444C26111FED000E0BCB /* StockItem.swift in Sources */, + 95A4B937263EA5C20056F036 /* WatchlistCreatorRow.swift in Sources */, 950D0E192618AA4900D17AD7 /* CompanyList.swift in Sources */, 952994822629CA46005F0AB0 /* SearchResponse.swift in Sources */, 95A07F6C26305AC6009865AA /* QuoteModel.swift in Sources */, @@ -611,8 +628,11 @@ 954D7EA7260BBA6600A13C50 /* WatchlistCompany+CoreDataClass.swift in Sources */, 95672B9B25DDA54800DCBE4A /* LazyBear.xcdatamodeld in Sources */, 95C8C0E0262A369F0082D1D9 /* ProfileResponse.swift in Sources */, + 95A4B935263EA31C0056F036 /* WatchlistCreatorSearchBar.swift in Sources */, 95AD4A2D26078C1400498079 /* ContentView.swift in Sources */, - 9562404E263C7D8800C6C511 /* NewWatchlistClass.swift in Sources */, + 95A4B939263EB1C20056F036 /* WatchlistLists.swift in Sources */, + 95A4B930263E9F530056F036 /* WatchlistCreatorList.swift in Sources */, + 9562404E263C7D8800C6C511 /* WatchlistCreatorClass.swift in Sources */, 95721DB4262787EF00EC527B /* ExtensiveList.swift in Sources */, 95C8C0DB262A36990082D1D9 /* Profile.swift in Sources */, 952045152610C7C600A76362 /* ConvertEpoch.swift in Sources */, @@ -934,6 +954,14 @@ minimumVersion = 1.2.4; }; }; + 95A4B931263E9F810056F036 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.1.3; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -942,6 +970,11 @@ package = 954D7EC0260BE70C00A13C50 /* XCRemoteSwiftPackageReference "SwiftlySearch" */; productName = SwiftlySearch; }; + 95A4B932263E9F810056F036 /* Introspect */ = { + isa = XCSwiftPackageProductDependency; + package = 95A4B931263E9F810056F036 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; + productName = Introspect; + }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */
--- a/LazyBear.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved Sat May 01 13:11:32 2021 +0200 +++ b/LazyBear.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved Sun May 02 12:41:20 2021 +0200 @@ -9,6 +9,15 @@ "revision": "7741806e979e59e9583962da43d09ec92f598026", "version": "1.2.4" } + }, + { + "package": "Introspect", + "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git", + "state": { + "branch": null, + "revision": "2e09be8af614401bc9f87d40093ec19ce56ccaf2", + "version": "0.1.3" + } } ] },
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- a/LazyBear/Views/Profile/Helpers/CreateNewWatchlist.swift Sat May 01 13:11:32 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -// -// CreateNewWatchlist.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 30/4/21. -// - -import SwiftUI - -struct CreateNewWatchlist: View { - @State private var showSearchView = false - @ObservedObject var newWatchlistClass = NewWatchlistClass() - @State private var showCancelAlert = false - - @Environment(\.managedObjectContext) private var moc - @Environment(\.presentationMode) private var presentationMode - - var body: some View { - NavigationView { - Form { - Section(header: Text("Watchlist name")) { - TextField("Technologies, banks", text: $newWatchlistClass.name) - } - - Section(header: Text("Companies")) { - Button("Add companies", action: { showSearchView = true }) - - ForEach(newWatchlistClass.companies, id: \.self) { company in - HStack { - VStack(alignment: .leading) { - Text(company.symbol!.uppercased()) - .fontWeight(.semibold) - - Text(company.securityName!.capitalized) - .lineLimit(1) - } - - Spacer() - Button(action: { remove(company) }, label: { - Image(systemName: "multiply.circle") - }) - } - } - } - } - .navigationTitle("New watchlist") - .navigationBarTitleDisplayMode(.inline) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button("Done", action: { saveWatchlist(newWatchlistClass.companies) }) - } - - ToolbarItem(placement: .navigationBarLeading) { - Button("Cancel", action: { self.showCancelAlert = true }) - } - } - } - // Show delete list alert - .alert(isPresented: $showCancelAlert) { - Alert( - title: Text("Your watchlist won't be saved"), - message: Text("This action can't be undo"), - primaryButton: .destructive(Text("Exit")) { presentationMode.wrappedValue.dismiss() }, - secondaryButton: .cancel() - ) - } - .sheet(isPresented: $showSearchView) { - SearchView(calledFromProfileView: true, newWatchlistClass: newWatchlistClass) - .environment(\.managedObjectContext, self.moc) - } - } - - /* - Search company in array and get the index -> Delete company at - this index from the array - */ - private func remove(_ company: SearchResponse) { - let index = newWatchlistClass.companies.firstIndex(of: company) - newWatchlistClass.companies.remove(at: index!) - } - - /* - Save companies to Core Data and create watchlist - */ - private func saveWatchlist(_ companies: [SearchResponse]) { - for company in companies { - let watchlistCompany = WatchlistCompany(context: moc) - watchlistCompany.name = company.securityName ?? "-" - watchlistCompany.symbol = company.symbol! - watchlistCompany.watchlist = newWatchlistClass.name - } - - do { - try moc.save() - print("Watchlist created") - presentationMode.wrappedValue.dismiss() // Dismiss view - } catch { - print(error.localizedDescription) - } - } -} - -struct CreateNewWatchlist_Previews: PreviewProvider { - static var previews: some View { - CreateNewWatchlist() - } -}
--- a/LazyBear/Views/Profile/Helpers/NewWatchlistClass.swift Sat May 01 13:11:32 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -// -// NewWatchlistClass.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 30/4/21. -// - -import SwiftUI - -class NewWatchlistClass: ObservableObject { - @Published var name = String() - @Published var companies = [SearchResponse]() -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Profile/Helpers/WatchlistCreator.swift Sun May 02 12:41:20 2021 +0200 @@ -0,0 +1,122 @@ +// +// WatchlistCreator.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 30/4/21. +// + +import SwiftUI + +struct WatchlistCreator: View { + @ObservedObject var watchlistCreatorClass = WatchlistCreatorClass() + @State private var showSearchView = false + @State private var showCancelAlert = false + @State private var watchlistNameIsEmpty = false + + @Environment(\.managedObjectContext) private var moc + @Environment(\.presentationMode) private var presentationMode + + var body: some View { + NavigationView { + Form { + Section(header: Text("Watchlist name")) { + TextField("Technologies, banks", text: $watchlistCreatorClass.name) + } + + Section(header: Text("Companies")) { + Button("Add companies", action: { showSearchView = true }) + + ForEach(watchlistCreatorClass.companies, id: \.self) { company in + HStack { + VStack(alignment: .leading) { + Text(company.symbol!.uppercased()) + .fontWeight(.semibold) + + Text(company.securityName!.capitalized) + .lineLimit(1) + } + + Spacer() + Button(action: { remove(company) }, label: { + Image(systemName: "multiply.circle") + .imageScale(.large) + }) + } + } + } + } + .navigationTitle("New watchlist") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button("Done", action: { save() }) + } + + ToolbarItem(placement: .navigationBarLeading) { + Button("Cancel", action: { self.showCancelAlert = true }) + } + } + // Show delete list alert + .alert(isPresented: $showCancelAlert) { + Alert( + title: Text("Your watchlist won't be saved"), + message: Text("This action can't be undo"), + primaryButton: .destructive(Text("Exit")) { presentationMode.wrappedValue.dismiss() }, + secondaryButton: .cancel() + ) + } + } + // Show alert when watchlist name is empty + .alert(isPresented: $watchlistNameIsEmpty) { + Alert( + title: Text("Give a name to your new watchlist"), + message: Text("Try My portfolio, Favourites, ..."), + dismissButton: .default(Text("Got it!")) + ) + } + .sheet(isPresented: $showSearchView) { + WatchlistCreatorList(watchlistCreatorClass: watchlistCreatorClass) + .environment(\.managedObjectContext, self.moc) + } + } + + /* + Search company in array and get the index -> Delete company at + this index from the array + */ + private func remove(_ company: SearchResponse) { + let index = watchlistCreatorClass.companies.firstIndex(of: company) + watchlistCreatorClass.companies.remove(at: index!) + } + + /* + Check if the watchlist name is empty when the user taps the Done button. + If it's not empty -> Save watchlist to Core Data + */ + private func save() { + if watchlistCreatorClass.name.isEmpty { + watchlistNameIsEmpty = true + } else { + for company in watchlistCreatorClass.companies { + let watchlistCompany = WatchlistCompany(context: moc) + watchlistCompany.name = company.securityName ?? "-" + watchlistCompany.symbol = company.symbol! + watchlistCompany.watchlist = watchlistCreatorClass.name + } + + do { + try moc.save() + print("Watchlist created") + presentationMode.wrappedValue.dismiss() // Dismiss view + } catch { + print(error.localizedDescription) + } + } + } +} + +struct CreateNewWatchlist_Previews: PreviewProvider { + static var previews: some View { + WatchlistCreator() + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Profile/Helpers/WatchlistCreatorClass.swift Sun May 02 12:41:20 2021 +0200 @@ -0,0 +1,13 @@ +// +// WatchlistCreatorClass.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 30/4/21. +// + +import SwiftUI + +class WatchlistCreatorClass: ObservableObject { + @Published var name = String() + @Published var companies = [SearchResponse]() +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Profile/Helpers/WatchlistCreatorList.swift Sun May 02 12:41:20 2021 +0200 @@ -0,0 +1,55 @@ +// +// WatchlistCreatorList.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 2/5/21. +// + +import SwiftUI + +struct WatchlistCreatorList: View { + @ObservedObject var watchlistCreatorClass: WatchlistCreatorClass + @State private var searchedCompany = String() + @State private var companies = [SearchResponse]() + + @Environment(\.presentationMode) private var presentationMode + + var body: some View { + NavigationView { + VStack { + WatchlistCreatorSearchBar(searchedCompany: $searchedCompany) + + List(companies, id: \.self) { company in + WatchlistCreatorRow(company: company, presentationMode: presentationMode, watchlistCreatorClass: watchlistCreatorClass) + } + } + .navigationTitle("Search") + .navigationBarTitleDisplayMode(.inline) + .onChange(of: searchedCompany, perform: { searchedCompany in + if !searchedCompany.isEmpty { + // Encode string with spaces + let encodedSearchedCompany = searchedCompany.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) + request("https://api.lazybear.app/search/text=\(encodedSearchedCompany ?? "")") + } + }) + + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button("Cancel", action: { presentationMode.wrappedValue.dismiss() }) + } + } + } + } + + private func request(_ url: String) { + genericRequest(url: url, model: [SearchResponse].self) { response in + self.companies = response + } + } +} + +struct SearchCompanies_Previews: PreviewProvider { + static var previews: some View { + WatchlistCreatorList(watchlistCreatorClass: WatchlistCreatorClass()) + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Profile/Helpers/WatchlistCreatorRow.swift Sun May 02 12:41:20 2021 +0200 @@ -0,0 +1,54 @@ +// +// WatchlistCreatorRow.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 2/5/21. +// + +import SwiftUI + +struct WatchlistCreatorRow: View { + var company: SearchResponse + @Binding var presentationMode: PresentationMode + @ObservedObject var watchlistCreatorClass: WatchlistCreatorClass + + var body: some View { + Button(action: { saveCompany() }) { + HStack { + VStack(alignment: .leading) { + Text(company.symbol!.uppercased()) + .fontWeight(.semibold) + + Text(company.securityName ?? "-") + .font(.callout) + .fontWeight(.semibold) + .opacity(0.6) + .lineLimit(1) + } + + Spacer() + Image(systemName: "plus.circle") + .imageScale(.large) + .foregroundColor(Color(.systemBlue)) + } + .contentShape(Rectangle()) + } + .buttonStyle(PlainButtonStyle()) + } + + /* + Save company when it's selected and dismiss view + */ + private func saveCompany() { + watchlistCreatorClass.companies.append(company) + $presentationMode.wrappedValue.dismiss() + } +} + +struct WatchlistCreatorRow_Previews: PreviewProvider { + @Environment(\.presentationMode) static var presentationMode + + static var previews: some View { + WatchlistCreatorRow(company: SearchResponse(currency: "USD", exchange: nil, region: "US", securityName: "Apple Inc", symbol: "AAPL"), presentationMode: presentationMode, watchlistCreatorClass: WatchlistCreatorClass()) + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Profile/Helpers/WatchlistCreatorSearchBar.swift Sun May 02 12:41:20 2021 +0200 @@ -0,0 +1,40 @@ +// +// WatchlistCreatorSearchBar.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 2/5/21. +// + +import SwiftUI +import Introspect + +struct WatchlistCreatorSearchBar: View { + @Binding var searchedCompany: String + + var body: some View { + TextField("", text: $searchedCompany) + .introspectTextField { textField in + textField.becomeFirstResponder() + } + .padding(10) + .padding(.leading, 40) + .overlay( + Image(systemName: "magnifyingglass") + .imageScale(.large) + .opacity(0.4) + .padding(.horizontal) + ,alignment: .leading + ) + .background( + Color(.secondarySystemBackground) + .cornerRadius(10) + ) + .padding() + } +} + +struct CustomSearchBar_Previews: PreviewProvider { + static var previews: some View { + WatchlistCreatorSearchBar(searchedCompany: .constant("")) + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Profile/Helpers/WatchlistLists.swift Sun May 02 12:41:20 2021 +0200 @@ -0,0 +1,38 @@ +// +// WatchlistLists.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 2/5/21. +// + +import SwiftUI +import CoreData + +struct WatchlistLists: View { + @ObservedObject var profile: Profile + var watchlistCompanies: [WatchlistCompany] + + var body: some View { + Text("Hello, World!") + } + + private func prepareUrl(isInitRequest: Bool) { + if watchlistCompanies.isEmpty { + profile.showView = true + } else { + let symbols = watchlistCompanies.map { $0.symbol } // Get symbols in watchlists + var url = "https://api.lazybear.app/profile/type=init/symbols=" + + var counter = 0 + for symbol in symbols { + counter += 1 + if counter == 1 { + url += symbol + } else { + url += ",\(symbol)" + } + } + profile.request(url, isInitRequest: isInitRequest) + } + } +}
--- a/LazyBear/Views/Profile/ProfileView.swift Sat May 01 13:11:32 2021 +0200 +++ b/LazyBear/Views/Profile/ProfileView.swift Sun May 02 12:41:20 2021 +0200 @@ -20,11 +20,12 @@ var body: some View { if profile.showView { NavigationView { + List { // Get Watchlist names -> Create rows for each watchlist -> in each row, show companies let watchlists = Set(watchlistCompanies.map { $0.watchlist }) // Set -> avoid duplicates names - + ForEach(Array(watchlists), id: \.self) { watchlist in let symbols = watchlistCompanies.filter({ $0.watchlist == watchlist }).map { $0.symbol } @@ -35,7 +36,6 @@ intradayPrices: profile.data.intradayPrices, addOnDelete: true ) - .onAppear { updateRows(symbols.count, filteredCompanies.count) } .listRowInsets(EdgeInsets()) } } @@ -51,7 +51,7 @@ } } .fullScreenCover(isPresented: $showCreateNewWatchlist) { - CreateNewWatchlist() + WatchlistCreator() .environment(\.managedObjectContext, self.moc) } } else { @@ -60,6 +60,9 @@ } } + /* + Get symbols in watchlists -> request + */ private func prepareUrl(isInitRequest: Bool) { if watchlistCompanies.isEmpty { profile.showView = true @@ -70,6 +73,7 @@ var counter = 0 for symbol in symbols { counter += 1 + if counter == 1 { url += symbol } else { @@ -79,16 +83,6 @@ profile.request(url, isInitRequest: isInitRequest) } } - - /* - If Core Data changes, companies is not updated because the API request is not called -> - Check if symbols.count (Core Data) is equal to filteredCompanies -> if not -> call API - */ - private func updateRows(_ numberOfCoreDataCompanies: Int, _ numberOfApiRequestedCompanies: Int) { - if numberOfCoreDataCompanies != numberOfApiRequestedCompanies { - prepareUrl(isInitRequest: true) // Call API - } - } } struct ProfileView_Previews: PreviewProvider {
--- a/LazyBear/Views/Search/CompanyList.swift Sat May 01 13:11:32 2021 +0200 +++ b/LazyBear/Views/Search/CompanyList.swift Sun May 02 12:41:20 2021 +0200 @@ -10,40 +10,9 @@ struct CompanyList: View { var searchResult: [SearchResponse] - // Only unseful when it's called from Profile View - var calledFromProfileView: Bool? - var newWatchlistClass: NewWatchlistClass? - @Binding var presentationMode: PresentationMode - var body: some View { List(searchResult, id: \.self) { company in - SearchedCompanyItem(company: company, calledFromProfileView: calledFromProfileView) - .if(calledFromProfileView ?? false ) { content in - Button(action: { save(company) }) { - content - } - } - } - } - - private func save(_ company: SearchResponse) { - newWatchlistClass!.companies.append(company) - $presentationMode.wrappedValue.dismiss() // Dismiss view - } -} - -/* - Wrap view on condition - */ -extension View { - @ViewBuilder - func `if`<Content: View>(_ conditional: Bool, content: (Self) -> Content) -> some View { - if conditional { - content(self) - } else { - NavigationLink(destination: Text("Hello")) { - self - } + SearchedCompanyItem(company: company) } } } @@ -52,6 +21,6 @@ @Environment(\.presentationMode) static var presentationMode static var previews: some View { - CompanyList(searchResult: [SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl")], presentationMode: presentationMode) + CompanyList(searchResult: [SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl"), SearchResponse(currency: "USD", region: "US", securityName: "aaple inc", symbol: "aapl")]) } }
--- a/LazyBear/Views/Search/Helpers/SearchedCompanyItem.swift Sat May 01 13:11:32 2021 +0200 +++ b/LazyBear/Views/Search/Helpers/SearchedCompanyItem.swift Sun May 02 12:41:20 2021 +0200 @@ -10,9 +10,6 @@ struct SearchedCompanyItem: View { var company: SearchResponse - // Only unseful when it's called from Profile View - var calledFromProfileView: Bool? - @Environment(\.managedObjectContext) private var moc @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: []) var watchlistCompany: FetchedResults<WatchlistCompany> @@ -22,20 +19,18 @@ var body: some View { let watchlistSymbols = watchlistCompany.map { $0.symbol } HStack { - if !(calledFromProfileView ?? false) { - Button(action: { self.showingActionSheet = true }) { - if watchlistSymbols.contains(company.symbol!) { - Image(systemName: "star.fill") - .foregroundColor(.yellow) - .imageScale(.large) - } else { - Image(systemName: "star") - .foregroundColor(.yellow) - .imageScale(.large) - } + Button(action: { self.showingActionSheet = true }) { + if watchlistSymbols.contains(company.symbol!) { + Image(systemName: "star.fill") + .foregroundColor(.yellow) + .imageScale(.large) + } else { + Image(systemName: "star") + .foregroundColor(.yellow) + .imageScale(.large) } - .buttonStyle(PlainButtonStyle()) } + .buttonStyle(PlainButtonStyle()) VStack(alignment: .leading) { Text(company.symbol!.uppercased())
--- a/LazyBear/Views/Search/SearchView.swift Sat May 01 13:11:32 2021 +0200 +++ b/LazyBear/Views/Search/SearchView.swift Sun May 02 12:41:20 2021 +0200 @@ -9,19 +9,15 @@ import SwiftlySearch struct SearchView: View { - // Only unseful when it's called from Profile View - var calledFromProfileView: Bool? - var newWatchlistClass: NewWatchlistClass? - @ObservedObject var search = Search() + @State private var searchedText = String() @Environment(\.presentationMode) private var presentationMode - @State private var searchedText = String() var body: some View { NavigationView { VStack(alignment: .leading) { if search.showSearchList { - CompanyList(searchResult: search.data, calledFromProfileView: calledFromProfileView, newWatchlistClass: newWatchlistClass, presentationMode: presentationMode) + CompanyList(searchResult: search.data) } else { VStack(alignment: .center) { Image("bearSleeping")