changeset 393:0a4c399170c4

Implementing WatchlistCreator
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Sun, 02 May 2021 12:41:20 +0200
parents 13f3578def61
children 4c90e5b18632
files LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate LazyBear/Views/Profile/Helpers/CreateNewWatchlist.swift LazyBear/Views/Profile/Helpers/NewWatchlistClass.swift LazyBear/Views/Profile/Helpers/WatchlistCreator.swift LazyBear/Views/Profile/Helpers/WatchlistCreatorClass.swift LazyBear/Views/Profile/Helpers/WatchlistCreatorList.swift LazyBear/Views/Profile/Helpers/WatchlistCreatorRow.swift LazyBear/Views/Profile/Helpers/WatchlistCreatorSearchBar.swift LazyBear/Views/Profile/Helpers/WatchlistLists.swift LazyBear/Views/Profile/ProfileView.swift LazyBear/Views/Search/CompanyList.swift LazyBear/Views/Search/Helpers/SearchedCompanyItem.swift LazyBear/Views/Search/SearchView.swift
diffstat 15 files changed, 393 insertions(+), 195 deletions(-) [+]
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")