changeset 417:5f21f7c23c5e

Add comments and clean code
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Fri, 11 Jun 2021 11:37:42 +0200
parents 1662a41e2c1a
children 83438c010b29
files LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate LazyBear/Global Models/RequestType.swift LazyBear/Global functions/ConvertStringToDate.swift LazyBear/Global functions/ParseJSON.swift LazyBear/Views/Company/Chart.swift LazyBear/Views/Company/CompanyView.swift LazyBear/Views/Company/Helpers/InsiderList.swift LazyBear/Views/Company/Helpers/StatsView.swift LazyBear/Views/Company/Helpers/TransactionList.swift LazyBear/Views/Company/Helpers/TransactionRow.swift LazyBear/Views/Global Helpers/Company list/ExtensiveList.swift LazyBear/Views/Global Helpers/Company list/Helpers/ToolbarMenu.swift LazyBear/Views/Global Helpers/Extensive List/ExtensiveList.swift LazyBear/Views/Global Helpers/Extensive List/Helpers/ToolbarMenu.swift LazyBear/Views/Global Helpers/RequestType.swift LazyBear/Views/Global Helpers/StockRow.swift LazyBear/Views/Home/Helpers/SectorItem.swift LazyBear/Views/Home/HomeView.swift LazyBear/Views/Home/TradingDates.swift LazyBear/Views/Profile/Helpers/TextfieldAlert.swift LazyBear/Views/Profile/Helpers/WatchlistCreator.swift LazyBear/Views/Profile/Helpers/WatchlistCreatorList.swift LazyBear/Views/Profile/Helpers/WatchlistCreatorSearchBar.swift LazyBear/Views/Profile/ProfileView.swift LazyBear/Views/Search/CompanyList.swift LazyBear/Views/Search/Helpers/SearchedCompanyItem.swift LazyBear/Views/Search/SearchView.swift
diffstat 28 files changed, 408 insertions(+), 349 deletions(-) [+]
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear.xcodeproj/project.pbxproj	Fri Jun 11 11:37:42 2021 +0200
@@ -230,13 +230,13 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		950272CA2635AA9F003E779D /* Company list */ = {
+		950272CA2635AA9F003E779D /* Extensive List */ = {
 			isa = PBXGroup;
 			children = (
 				95721DB3262787EF00EC527B /* ExtensiveList.swift */,
 				950272CB2635AABC003E779D /* Helpers */,
 			);
-			path = "Company list";
+			path = "Extensive List";
 			sourceTree = "<group>";
 		};
 		950272CB2635AABC003E779D /* Helpers */ = {
@@ -326,6 +326,7 @@
 				95CCFB55266E7A0F00C384A1 /* InsiderTransactionModel.swift */,
 				95BB05B12670B8C3005A2029 /* KeyStatsModel.swift */,
 				95AF0FF82671342E0049C4AB /* DisplayWordsModel.swift */,
+				95E8BAA22656D86E0016AE72 /* RequestType.swift */,
 			);
 			path = "Global Models";
 			sourceTree = "<group>";
@@ -418,12 +419,11 @@
 		95893DD22613CAB5003698C5 /* Global Helpers */ = {
 			isa = PBXGroup;
 			children = (
-				950272CA2635AA9F003E779D /* Company list */,
+				950272CA2635AA9F003E779D /* Extensive List */,
 				95A5188526186F590002D27C /* PriceView.swift */,
 				9550444826111FC9000E0BCB /* StockRow.swift */,
 				9550444B26111FED000E0BCB /* StockItem.swift */,
 				95BD2FB226341D36008B6752 /* BlurBackground.swift */,
-				95E8BAA22656D86E0016AE72 /* RequestType.swift */,
 				950857D2266BE55F005357BA /* RowShape.swift */,
 			);
 			path = "Global Helpers";
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/Global Models/RequestType.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -0,0 +1,14 @@
+//
+//  RequestType.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 20/5/21.
+//
+
+import SwiftUI
+
+enum RequestType {
+    case initial
+    case streaming
+    case refresh
+}
--- a/LazyBear/Global functions/ConvertStringToDate.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Global functions/ConvertStringToDate.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -7,8 +7,10 @@
 
 import SwiftUI
 
+/*
+ Convert String to date with the format specified
+ */
 func convertStringToDate(_ stringDate: String) -> Date {
-    // Convert string to date
     let dateFormatter = DateFormatter()
     dateFormatter.dateFormat = "yyyy-MM-dd"
     
--- a/LazyBear/Global functions/ParseJSON.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Global functions/ParseJSON.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -8,6 +8,9 @@
 import Foundation
 
 
+/*
+ Read JSON File
+ */
 func parseJSON<T: Decodable>(_ filename: String) -> T {
     let data: Data
     
--- a/LazyBear/Views/Company/Chart.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Company/Chart.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -11,15 +11,11 @@
 struct Chart: View {
     @ObservedObject var company: Company
     var symbol: String
-    
-    // Date picker
-    var ranges = ["1D", "5D", "1M", "3M", "6M", "1Y", "5Y"]
-    @State private var selectedRange = "3M"
+    var ranges = ["1D", "5D", "1M", "3M", "6M", "1Y", "5Y"]  /// DatePicker ranges
     
-    // Set recurrent price request
-    @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()
-    
-    @State private var showingStatistics = false
+    @State private var selectedRange = "3M"  /// Selected DatePicker range
+    @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect() /// Set recurrent price request
+    @State private var showingStatistics = false  /// Show StatisticsView of the company
     
     var body: some View {
         if company.showChartView {
@@ -34,12 +30,15 @@
                     .foregroundColor(Color(.secondarySystemBackground))
                     .frame(height: 270)
                     .overlay(
+                        /*
+                         Show PriceView and Chart
+                         */
                         VStack {
                             HStack {
                                 if let quote = company.chartData.quote![symbol.uppercased()] {
                                     let latestPrice = quote.latestPrice ?? 0
                                     let changePercent = quote.changePercent ?? 0
-                                    let priceViewStyle = PriceViewStyle(
+                                    let priceViewStyle = PriceViewStyle(  /// Define PriceView style
                                         horizontalAlignment: .leading,
                                         verticalAlignment: .center,
                                         orientation: .HStack,
@@ -53,7 +52,7 @@
                                 }
                                 Spacer()
                                 
-                                if let _ = company.chartData.keyStats {
+                                if let _ = company.chartData.keyStats {  /// Check if keyStats is empty -> Hide button
                                     Button("See stats", action: { showingStatistics = true })
                                 }
                             }
@@ -63,13 +62,15 @@
                             if let historicalPrices = company.chartData.historicalPrices {
                                 let prices = historicalPrices.compactMap { $0.close }
                                 let dates = historicalPrices.compactMap { $0.date }
-//                                let hours = historicalPrices.compactMap { $0.minute }
                                 LineChartView(data: prices, dates: dates, hours: nil, dragGesture: true)
                                     .padding(.bottom)
                             }
                         }
                     )
                 
+                /*
+                 Show latest news
+                 */
                 if let latestNews = company.chartData.latestNews {
                     VStack(spacing: 20) {
                         ForEach(latestNews, id: \.self) { new in
@@ -83,10 +84,10 @@
                 StatsView(keyStats: company.chartData.keyStats!)
             }
             .onAppear { self.timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect() }  // Start timer
-            .onDisappear { self.timer.upstream.connect().cancel() }  // Stop timer
+            .onDisappear { self.timer.upstream.connect().cancel() }  /// Stop timer
             .onReceive(timer) { _ in
                 let url = "https://api.lazybear.app/company/chart/symbol=\(symbol)/type=streaming"
-                company.request(url, .streaming, "chart") }  // Receive timer notification
+                company.request(url, .streaming, "chart") }  /// Receive timer notification
         } else {
             ProgressView()
                 .onAppear {
--- a/LazyBear/Views/Company/CompanyView.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Company/CompanyView.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -10,11 +10,12 @@
 
 struct CompanyView: View {
     var symbol: String
-    
     @ObservedObject var company = Company()
     @State private var showViewSelector = false
     
-    // Views
+    /*
+     Views
+     */
     @State private var showChartView = true
     @State private var showInsiderView = false
     
@@ -23,8 +24,7 @@
             VStack {
                 CompanyHeader(symbol: symbol, showViewSelector: $showViewSelector)
                     .padding(.bottom)
-                
-                // Chart View
+
                 if showChartView {
                     Chart(company: company, symbol: symbol)
                 } else if showInsiderView {
@@ -43,7 +43,7 @@
     }
     
     /*
-     Hide all views to show later the one tapped
+     Hide all views to show the one selected by user
      */
     private func resetViews() {
         showChartView = false
--- a/LazyBear/Views/Company/Helpers/InsiderList.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Company/Helpers/InsiderList.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -22,14 +22,10 @@
                 Button("See all", action: { showFullList = true })
             }
         
-            // Get total shares owned by the top 10 insiders
-            let totalPositions =  insiderSummary.map { $0.position ?? 0 }.reduce(0, +)
+            let totalPositions =  insiderSummary.map { $0.position ?? 0 }.reduce(0, +)  /// Get total shares owned by the top 10 insiders
             VStack(alignment: .leading, spacing: 20) {
                 ForEach(insiderSummary.prefix(3), id: \.self) { insider in
-                    
-                    // Compute percentage of ownership for each insider
-                    let percentage = Double(insider.position ?? 0) / Double(totalPositions)
-                    
+                    let percentage = Double(insider.position ?? 0) / Double(totalPositions)  /// Compute percentage of ownership for each insider
                     InsiderRow(percentageOfWidth: CGFloat(percentage), insiderRoster: insider)
                 }
             }
@@ -43,7 +39,13 @@
 struct InsiderList_Previews: PreviewProvider {
     static var previews: some View {
         InsiderList(insiderSummary:
-                    [InsiderRosterModel(entityName: "Dennis Concepcion", position: 1234, reportDate: 1234567)]
+            [
+                InsiderRosterModel(
+                    entityName: "Dennis Concepcion",
+                    position: 1234,
+                    reportDate: 1234567
+                )
+            ]
         )
     }
 }
@@ -55,14 +57,10 @@
     var body: some View {
         NavigationView {
             ScrollView {
-                // Get total shares owned by the top 10 insiders
-                let totalPositions =  insiderSummary.map { $0.position ?? 0 }.reduce(0, +)
+                let totalPositions =  insiderSummary.map { $0.position ?? 0 }.reduce(0, +)  /// Get total shares owned by the top 10 insiders
                 VStack(alignment: .leading, spacing: 20) {
                     ForEach(insiderSummary, id: \.self) { insider in
-                        
-                        // Compute percentage of ownership for each insider
-                        let percentage = Double(insider.position ?? 0) / Double(totalPositions)
-                        
+                        let percentage = Double(insider.position ?? 0) / Double(totalPositions)  /// Compute percentage of ownership for each insider
                         InsiderRow(percentageOfWidth: CGFloat(percentage), insiderRoster: insider)
                     }
                 }
--- a/LazyBear/Views/Company/Helpers/StatsView.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Company/Helpers/StatsView.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -9,14 +9,16 @@
 
 struct StatsView: View {
     var keyStats: KeyStatsModel
+    
     @Environment(\.presentationMode) private var presentationStatsView
+    
     let displayWords: DisplayWordsModel = parseJSON("DisplayWords.json")
     
     var body: some View {
         NavigationView {
             Form {
                 let mirror = Mirror(reflecting: keyStats)
-                ForEach(Array(mirror.children), id: \.label) { child in
+                ForEach(Array(mirror.children), id: \.label) { child in  /// Iterate over each variable within the class
                     if let unwrappedValue = unwrapAnyOptional(value: child.value) {
                         HStack {
                             let label = String(child.label!)
@@ -62,40 +64,40 @@
 struct StatsView_Previews: PreviewProvider {
     static var previews: some View {
         StatsView(keyStats:
-                    KeyStatsModel(
-                        companyName: "Apple inc",
-                        employees: 123,
-                        marketcap: 123,
-                        float: 123,
-                        sharesOutstanding: 123,
-                        beta: 123.12,
-                        peRatio: 123.4,
-                        dividendYield: 123.4,
-                        ttmDividendRate: 123.4,
-                        ttmEPS: 123.4,
-                        avg10Volume: 123,
-                        avg30Volume: 123,
-                        day50MovingAvg: 123.4,
-                        day200MovingAvg: 123.4,
-                        week52Change: 123.4,
-                        week52High: 123.4,
-                        week52Low: 123.4,
-                        week52HighSplitAdjustOnly: 123.4,
-                        week52LowSplitAdjustOnly: 123.4,
-                        maxChangePercent: 123.4,
-                        ytdChangePercent: 123.4,
-                        day5ChangePercent: 123.4,
-                        day30ChangePercent: 123.4,
-                        month1ChangePercent: 123.4,
-                        month3ChangePercent: 123.4,
-                        month6ChangePercent: 123.4,
-                        year1ChangePercent: 123.4,
-                        year2ChangePercent: 123.4,
-                        year5ChangePercent: 123.4,
-                        exDividendDate: "2020-01-01",
-                        nextDividendDate: "2020-01-01",
-                        nextEarningsDate: "2020-01-01"
-                )
+                KeyStatsModel(
+                    companyName: "Apple inc",
+                    employees: 123,
+                    marketcap: 123,
+                    float: 123,
+                    sharesOutstanding: 123,
+                    beta: 123.12,
+                    peRatio: 123.4,
+                    dividendYield: 123.4,
+                    ttmDividendRate: 123.4,
+                    ttmEPS: 123.4,
+                    avg10Volume: 123,
+                    avg30Volume: 123,
+                    day50MovingAvg: 123.4,
+                    day200MovingAvg: 123.4,
+                    week52Change: 123.4,
+                    week52High: 123.4,
+                    week52Low: 123.4,
+                    week52HighSplitAdjustOnly: 123.4,
+                    week52LowSplitAdjustOnly: 123.4,
+                    maxChangePercent: 123.4,
+                    ytdChangePercent: 123.4,
+                    day5ChangePercent: 123.4,
+                    day30ChangePercent: 123.4,
+                    month1ChangePercent: 123.4,
+                    month3ChangePercent: 123.4,
+                    month6ChangePercent: 123.4,
+                    year1ChangePercent: 123.4,
+                    year2ChangePercent: 123.4,
+                    year5ChangePercent: 123.4,
+                    exDividendDate: "2020-01-01",
+                    nextDividendDate: "2020-01-01",
+                    nextEarningsDate: "2020-01-01"
+            )
         )
     }
 }
--- a/LazyBear/Views/Company/Helpers/TransactionList.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Company/Helpers/TransactionList.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -9,6 +9,7 @@
 
 struct TransactionList: View {
     var transactions: [InsiderTransactionModel]
+    
     @State private var showFullList = false
     
     var body: some View {
@@ -38,17 +39,18 @@
     static var previews: some View {
         TransactionList(transactions:
             [
-                InsiderTransactionModel(filingDate: "2020-01-01",
-                                        fullName: "Dennis Concepcion",
-                                        postShares: 1234,
-                                        reportedTitle: "Director",
-                                        transactionCode: "S",
-                                        transactionPrice: 20.08,
-                                        transactionShares: 12345,
-                                        transactionValue: 1234567.0
+                InsiderTransactionModel(
+                    filingDate: "2020-01-01",
+                    fullName: "Dennis Concepcion",
+                    postShares: 1234,
+                    reportedTitle: "Director",
+                    transactionCode: "S",
+                    transactionPrice: 20.08,
+                    transactionShares: 12345,
+                    transactionValue: 1234567.0
                 )
             ]
-            )
+        )
     }
 }
 
--- a/LazyBear/Views/Company/Helpers/TransactionRow.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Company/Helpers/TransactionRow.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -56,14 +56,15 @@
 struct TransactionRow_Previews: PreviewProvider {
     static var previews: some View {
         TransactionRow(transaction:
-            InsiderTransactionModel(filingDate: "2020-01-01",
-                                    fullName: "Dennis Concepcion",
-                                    postShares: 1234,
-                                    reportedTitle: "Director",
-                                    transactionCode: "S",
-                                    transactionPrice: 20.08,
-                                    transactionShares: 12345,
-                                    transactionValue: 1234567.0
+            InsiderTransactionModel(
+                filingDate: "2020-01-01",
+                fullName: "Dennis Concepcion",
+                postShares: 1234,
+                reportedTitle: "Director",
+                transactionCode: "S",
+                transactionPrice: 20.08,
+                transactionShares: 12345,
+                transactionValue: 1234567.0
             )
         )
     }
--- a/LazyBear/Views/Global Helpers/Company list/ExtensiveList.swift	Wed Jun 09 20:26:28 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-//
-//  ExtensiveList.swift
-//  LazyBear
-//
-//  Created by Dennis Concepción Martín on 14/4/21.
-//
-
-import SwiftUI
-
-struct ExtensiveList: View {
-    var listName: String
-    var list: [String: QuoteModel]?
-    var intradayPrices: [String: [IntradayPriceModel]]?
-    var latestCurrencies: [String: CurrencyModel]?
-    var addOnDelete: Bool
-    
-    @Environment(\.presentationMode) private var presentationMode
-    @Environment(\.managedObjectContext) private var moc
-    @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: [])
-    var watchlistCompany: FetchedResults<WatchlistCompany>
-    
-    @State private var isEditMode: EditMode = .inactive
-    @State private var showRenameListAction = false
-    @State private var showDeleteListAlert = false
-    @State private var showSearchView = false
-    
-    var body: some View {
-        NavigationView {
-            ZStack {
-                VStack {
-                    if let list = list {
-                        List {
-                            ForEach(Array(list.keys.sorted()), id: \.self) { companySymbol in
-                                    StockItem(symbol: companySymbol,
-                                              company: list[companySymbol]!,
-                                              intradayPrices: intradayPrices?[companySymbol],
-                                              orientation: .horizontal,
-                                              hidePriceView: self.isEditMode == .active  // Hide on EditMode
-                                    )
-                                
-                            }
-                            .onDelete(perform: addOnDelete ? deleteCompany: nil)
-                        }
-                    }
-                    
-                    if let latestCurrencies = latestCurrencies {
-                        List(Array(latestCurrencies.keys.sorted()), id: \.self) { currencySymbol in
-                            CurrencyListItem(currencySymbol: currencySymbol, currency: latestCurrencies[currencySymbol]!)
-                            
-                        }
-                    }
-                }
-                
-                // Blur background
-                Color(.black)
-                    .edgesIgnoringSafeArea(.all)
-                    .opacity(showRenameListAction ? 0.2: 0)
-                    .animation(.easeInOut)
-                    .onTapGesture { showRenameListAction = false }
-                
-                // Show rename Action Sheet
-                TextfieldAlert(listName: listName, showRenameAction: $showRenameListAction, presentationMode: presentationMode)
-                    .offset(y: showRenameListAction ? 0: 700)
-                    .animation(.easeInOut)
-            }
-            // Show delete list alert
-            .alert(isPresented: $showDeleteListAlert) {
-                Alert(
-                    title: Text("Are you sure you want to delete this list?"),
-                    message: Text("This action can't be undo"),
-                    primaryButton: .destructive(Text("Delete")) { deleteList() },
-                    secondaryButton: .cancel()
-                )
-            }
-            .navigationTitle(listName)
-            .navigationBarTitleDisplayMode(.inline)
-            .toolbar {
-                ToolbarItem(placement: .cancellationAction) {
-                    if addOnDelete {
-                        EditButton()
-                    } else {
-                        Button(action: { presentationMode.wrappedValue.dismiss() }) {
-                            Image(systemName: "multiply")
-                                .imageScale(.large)
-                        }
-                    }
-                }
-                ToolbarItem(placement: .navigationBarTrailing) {
-                    if addOnDelete {
-                        ToolbarMenu(showRenameListAction: $showRenameListAction, showDeleteListAlert: $showDeleteListAlert)
-                    }
-                }
-            }
-            .environment(\.editMode, self.$isEditMode)  // Always after Toolbar
-        }
-    }
-    
-    /*
-     Delete company from watchlist
-     */
-    private func deleteCompany(at offsets: IndexSet) {
-        for index in offsets {
-            let company = watchlistCompany[index]
-            moc.delete(company)
-        }
-        do {
-            try moc.save()
-            print("Company deleted")
-        } catch {
-            print(error.localizedDescription)
-        }
-    }
-    
-    /*
-     Remove entire list if it's not the last one. It can't be zero watchlists
-     */
-    private func deleteList() {
-        let selectedWatchlist = watchlistCompany.filter({ $0.watchlist == listName })
-        for company in selectedWatchlist {
-            moc.delete(company)
-        }
-        do {
-            try moc.save()
-            print("List deleted")
-            presentationMode.wrappedValue.dismiss()  // Dismiss view
-        } catch {
-            print(error.localizedDescription)
-        }
-    }
-}
-
-struct ExtensiveList_Previews: PreviewProvider {
-    static var previews: some View {
-        ExtensiveList(listName: "List name", addOnDelete: false)
-    }
-}
--- a/LazyBear/Views/Global Helpers/Company list/Helpers/ToolbarMenu.swift	Wed Jun 09 20:26:28 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-//
-//  ToolbarMenu.swift
-//  LazyBear
-//
-//  Created by Dennis Concepción Martín on 25/4/21.
-//
-
-import SwiftUI
-
-struct ToolbarMenu: View {
-    @Binding var showRenameListAction: Bool
-    @Binding var showDeleteListAlert: Bool
-    
-    @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: [])
-    var watchlistCompany: FetchedResults<WatchlistCompany>
-    
-    var body: some View {
-        Menu {
-            Section {
-                Button(action: { showRenameListAction = true }) {
-                    Label("Rename list", systemImage: "square.and.pencil")
-                }
-            }
-            
-            // If there are only 1 watchlist -> It cannot be deleted
-            if Set(watchlistCompany.map { $0.watchlist }).count > 1 {
-                Section(header: Text("Secondary actions")) {
-                    Button(action: { showDeleteListAlert = true }) {
-                        Label("Delete list", systemImage: "trash")
-                    }
-                }
-            }
-        }
-        label: {
-            Label("Options", systemImage: "ellipsis.circle")
-                .imageScale(.large)
-        }
-    }
-}
-
-struct ToolbarMenu_Previews: PreviewProvider {
-    static var previews: some View {
-        ToolbarMenu(showRenameListAction: .constant(false), showDeleteListAlert: .constant(false))
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/Views/Global Helpers/Extensive List/ExtensiveList.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -0,0 +1,136 @@
+//
+//  ExtensiveList.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 14/4/21.
+//
+
+import SwiftUI
+
+struct ExtensiveList: View {
+    var listName: String
+    var list: [String: QuoteModel]?
+    var intradayPrices: [String: [IntradayPriceModel]]?
+    var latestCurrencies: [String: CurrencyModel]?
+    var addOnDelete: Bool
+    
+    @Environment(\.presentationMode) private var presentationMode
+    @Environment(\.managedObjectContext) private var moc
+    @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: [])
+    var watchlistCompany: FetchedResults<WatchlistCompany>
+    
+    @State private var isEditMode: EditMode = .inactive
+    @State private var showRenameListAction = false
+    @State private var showDeleteListAlert = false
+    @State private var showSearchView = false
+    
+    var body: some View {
+        NavigationView {
+            ZStack {
+                VStack {
+                    if let list = list {
+                        List {
+                            ForEach(Array(list.keys.sorted()), id: \.self) { companySymbol in
+                                    StockItem(symbol: companySymbol,
+                                              company: list[companySymbol]!,
+                                              intradayPrices: intradayPrices?[companySymbol],
+                                              orientation: .horizontal,
+                                              hidePriceView: self.isEditMode == .active  // Hide on EditMode
+                                    )
+                                
+                            }
+                            .onDelete(perform: addOnDelete ? deleteCompany: nil)
+                        }
+                    }
+                    
+                    if let latestCurrencies = latestCurrencies {
+                        List(Array(latestCurrencies.keys.sorted()), id: \.self) { currencySymbol in
+                            CurrencyListItem(currencySymbol: currencySymbol, currency: latestCurrencies[currencySymbol]!)
+                            
+                        }
+                    }
+                }
+                
+                // Blur background
+                Color(.black)
+                    .edgesIgnoringSafeArea(.all)
+                    .opacity(showRenameListAction ? 0.2: 0)
+                    .animation(.easeInOut)
+                    .onTapGesture { showRenameListAction = false }
+                
+                // Show rename Action Sheet
+                TextfieldAlert(listName: listName, showRenameAction: $showRenameListAction, presentationMode: presentationMode)
+                    .offset(y: showRenameListAction ? 0: 700)
+                    .animation(.easeInOut)
+            }
+            // Show delete list alert
+            .alert(isPresented: $showDeleteListAlert) {
+                Alert(
+                    title: Text("Are you sure you want to delete this list?"),
+                    message: Text("This action can't be undo"),
+                    primaryButton: .destructive(Text("Delete")) { deleteList() },
+                    secondaryButton: .cancel()
+                )
+            }
+            .navigationTitle(listName)
+            .navigationBarTitleDisplayMode(.inline)
+            .toolbar {
+                ToolbarItem(placement: .cancellationAction) {
+                    if addOnDelete {
+                        EditButton()
+                    } else {
+                        Button(action: { presentationMode.wrappedValue.dismiss() }) {
+                            Image(systemName: "multiply")
+                                .imageScale(.large)
+                        }
+                    }
+                }
+                ToolbarItem(placement: .navigationBarTrailing) {
+                    if addOnDelete {
+                        ToolbarMenu(showRenameListAction: $showRenameListAction, showDeleteListAlert: $showDeleteListAlert)
+                    }
+                }
+            }
+            .environment(\.editMode, self.$isEditMode)  // Always after Toolbar
+        }
+    }
+    
+    /*
+     Delete company from watchlist
+     */
+    private func deleteCompany(at offsets: IndexSet) {
+        for index in offsets {
+            let company = watchlistCompany[index]
+            moc.delete(company)
+        }
+        do {
+            try moc.save()
+            print("Company deleted")
+        } catch {
+            print(error.localizedDescription)
+        }
+    }
+    
+    /*
+     Remove entire list if it's not the last one. It can't be zero watchlists
+     */
+    private func deleteList() {
+        let selectedWatchlist = watchlistCompany.filter({ $0.watchlist == listName })
+        for company in selectedWatchlist {
+            moc.delete(company)
+        }
+        do {
+            try moc.save()
+            print("List deleted")
+            presentationMode.wrappedValue.dismiss()  // Dismiss view
+        } catch {
+            print(error.localizedDescription)
+        }
+    }
+}
+
+struct ExtensiveList_Previews: PreviewProvider {
+    static var previews: some View {
+        ExtensiveList(listName: "List name", addOnDelete: false)
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/Views/Global Helpers/Extensive List/Helpers/ToolbarMenu.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -0,0 +1,44 @@
+//
+//  ToolbarMenu.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 25/4/21.
+//
+
+import SwiftUI
+
+struct ToolbarMenu: View {
+    @Binding var showRenameListAction: Bool
+    @Binding var showDeleteListAlert: Bool
+    
+    @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: [])
+    var watchlistCompany: FetchedResults<WatchlistCompany>
+    
+    var body: some View {
+        Menu {
+            Section {
+                Button(action: { showRenameListAction = true }) {
+                    Label("Rename list", systemImage: "square.and.pencil")
+                }
+            }
+            
+            if Set(watchlistCompany.map { $0.watchlist }).count > 1 {  /// If there are only 1 watchlist -> It cannot be deleted
+                Section(header: Text("Secondary actions")) {
+                    Button(action: { showDeleteListAlert = true }) {
+                        Label("Delete list", systemImage: "trash")
+                    }
+                }
+            }
+        }
+        label: {
+            Label("Options", systemImage: "ellipsis.circle")
+                .imageScale(.large)
+        }
+    }
+}
+
+struct ToolbarMenu_Previews: PreviewProvider {
+    static var previews: some View {
+        ToolbarMenu(showRenameListAction: .constant(false), showDeleteListAlert: .constant(false))
+    }
+}
--- a/LazyBear/Views/Global Helpers/RequestType.swift	Wed Jun 09 20:26:28 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-//
-//  RequestType.swift
-//  LazyBear
-//
-//  Created by Dennis Concepción Martín on 20/5/21.
-//
-
-import SwiftUI
-
-enum RequestType {
-    case initial
-    case streaming
-    case refresh
-}
--- a/LazyBear/Views/Global Helpers/StockRow.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Global Helpers/StockRow.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -13,8 +13,9 @@
     var list: [String: QuoteModel]
     var intradayPrices: [String: [IntradayPriceModel]]?
     var addOnDelete: Bool
+
+    @State private var showExtensiveList = false
     
-    @State private var showExtensiveList = false
     @Environment(\.managedObjectContext) private var moc
     
     var body: some View {
--- a/LazyBear/Views/Home/Helpers/SectorItem.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Home/Helpers/SectorItem.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -37,8 +37,8 @@
     }
 }
 
-//struct SectorItem_Previews: PreviewProvider {
-//    static var previews: some View {
-//        SectorItem(sector: SectorPerformanceModel(name: "Technology", performance: 0.04))
-//    }
-//}
+struct SectorItem_Previews: PreviewProvider {
+    static var previews: some View {
+        SectorItem(sector: SectorPerformanceModel(name: "Technology", performance: 0.04))
+    }
+}
--- a/LazyBear/Views/Home/HomeView.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Home/HomeView.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -9,10 +9,9 @@
 
 struct HomeView: View {
     @ObservedObject var home = Home()
+    
     @State private var showTradingDates = false
-    
-    // Set recurrent price request
-    @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()
+    @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()  /// Set recurrent price request
     
     static let taskDateFormat: DateFormatter = {
         let formatter = DateFormatter()
@@ -32,17 +31,12 @@
                     }
                     
                     if let lists = home.data.lists {
-                        if let gainers = lists.gainers {
-                            StockRow(listName: "Gainers", list: gainers, intradayPrices: home.data.intradayPrices, addOnDelete: false)
-                                .listRowInsets(EdgeInsets())
-                        }
-                        if let losers = lists.losers {
-                            StockRow(listName: "Losers", list: losers, intradayPrices: home.data.intradayPrices, addOnDelete: false)
-                                .listRowInsets(EdgeInsets())
-                        }
-                        if let mostActive = lists.mostactive {
-                            StockRow(listName: "Most active", list: mostActive, intradayPrices: home.data.intradayPrices, addOnDelete: false)
-                                .listRowInsets(EdgeInsets())
+                        let mirror = Mirror(reflecting: lists)
+                        ForEach(Array(mirror.children), id: \.label) { child in
+                            if let list = child.value as? [String : QuoteModel] {
+                                StockRow(listName: "\(child.label!)", list: list, intradayPrices: home.data.intradayPrices, addOnDelete: false)
+                                    .listRowInsets(EdgeInsets())
+                            }
                         }
                     }
                     if let latestCurrencies = home.data.latestCurrencies {
@@ -50,8 +44,8 @@
                             .listRowInsets(EdgeInsets())
                     }
                 }
-                .onAppear { self.timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect() }  // Start timer
-                .onReceive(timer) { _ in home.request("https://api.lazybear.app/home/type=streaming", .streaming) }  // Receive timer notification
+                .onAppear { self.timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect() }  /// Restart timer
+                .onReceive(timer) { _ in home.request("https://api.lazybear.app/home/type=streaming", .streaming) }  /// Receive timer notification
                 .onDisappear { self.timer.upstream.connect().cancel() }  // Stop timer
                 .navigationTitle("\(dueDate, formatter: Self.taskDateFormat)")
                 .navigationBarTitleDisplayMode(.inline)
--- a/LazyBear/Views/Home/TradingDates.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Home/TradingDates.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -37,6 +37,9 @@
         }
     }
     
+    /*
+     Get array of dates to use in ForEach
+     */
     private func getArrayOfDates() -> [Date] {
         // Get array of the string dates
         let stringDates = self.dates.map { $0.date }
--- a/LazyBear/Views/Profile/Helpers/TextfieldAlert.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Profile/Helpers/TextfieldAlert.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -41,7 +41,9 @@
                     Divider()
                     
                     
-                    // Cancel and Done buttons
+                    /*
+                     Cancel and Done buttons
+                     */
                     HStack {
                         Spacer()
                         Button(action: {
@@ -72,6 +74,9 @@
         )
     }
     
+    /*
+     Rename watchlist name in Core Data
+     */
     private func renameList(_ newListName: String) {
         let selectedWatchlist = watchlistCompany.filter({ $0.watchlist == listName })
         for company in selectedWatchlist {
@@ -80,16 +85,15 @@
         do {
             try moc.save()
             print("List updated")
-            UIApplication.shared.endEditing()  // Dismiss Keyboard
-            self.showRenameAction = false  // Dismiss action rename sheet
-            self.$presentationMode.wrappedValue.dismiss()  // Dismiss Modal View
+            UIApplication.shared.endEditing()  /// Dismiss Keyboard
+            self.showRenameAction = false  /// Dismiss action rename sheet
+            self.$presentationMode.wrappedValue.dismiss()  /// Dismiss Modal View
         } catch {
             print(error.localizedDescription)
         }
     }
 }
-// Dismiss Keyboard
-extension UIApplication {
+extension UIApplication {  /// Dismiss Keyboard Extension
     func endEditing() {
         sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
     }
--- a/LazyBear/Views/Profile/Helpers/WatchlistCreator.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Profile/Helpers/WatchlistCreator.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -56,8 +56,7 @@
                     Button("Cancel", action: { self.showCancelAlert = true })
                 }
             }
-            // Show delete list alert
-            .alert(isPresented: $showCancelAlert) {
+            .alert(isPresented: $showCancelAlert) {  /// Show alert when the user tries to exit the view without saving the new watchlist
                 Alert(
                     title: Text("Your watchlist won't be saved"),
                     message: Text("This action can't be undo"),
@@ -66,8 +65,7 @@
                 )
             }
         }
-        // Show alert when watchlist name is empty
-        .alert(isPresented: $watchlistNameIsEmpty) {
+        .alert(isPresented: $watchlistNameIsEmpty) {  /// Show alert when the user tries to save the watchlist without a name
             Alert(
                 title: Text("Give a name to your new watchlist"),
                 message: Text("Try My portfolio, Favourites, ..."),
@@ -82,7 +80,7 @@
     
     /*
      Search company in array and get the index -> Delete company at
-     this index from the array
+     this index from the array (Core Data)
      */
     private func remove(_ company: SearchResponse) {
         let index = watchlistCreatorClass.companies.firstIndex(of: company)
--- a/LazyBear/Views/Profile/Helpers/WatchlistCreatorList.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Profile/Helpers/WatchlistCreatorList.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -10,6 +10,7 @@
 
 struct WatchlistCreatorList: View {
     @ObservedObject var watchlistCreatorClass: WatchlistCreatorClass
+    
     @State private var searchedCompany = String()
     @State private var companies = [SearchResponse]()
     
@@ -29,11 +30,7 @@
             .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 ?? "")")
-                }
+                encodeAndRequest(searchedCompany)
             })
             
             .toolbar {
@@ -44,12 +41,27 @@
         }
     }
     
+    /*
+     Get companies from the API that matches the searched text
+     */
     private func request(_ url: String) {
         let bazooka = Bazooka()
         bazooka.request(url: url, model: [SearchResponse].self) { response in
             self.companies = response
         }
     }
+    
+    /*
+     1) Check if searchedCompany is empty
+     2) Encode white spaces
+     3) Request API
+     */
+    private func encodeAndRequest(_ searchedCompany: String) {
+        if !searchedCompany.isEmpty {
+            let encodedSearchedCompany = searchedCompany.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
+            request("https://api.lazybear.app/search/text=\(encodedSearchedCompany ?? "")")
+        }
+    }
 }
 
 struct SearchCompanies_Previews: PreviewProvider {
--- a/LazyBear/Views/Profile/Helpers/WatchlistCreatorSearchBar.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Profile/Helpers/WatchlistCreatorSearchBar.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -13,9 +13,9 @@
     
     var body: some View {
         TextField("", text: $searchedCompany)
-        .introspectTextField { textField in
-            textField.becomeFirstResponder()
-        }
+            .introspectTextField { textField in
+                textField.becomeFirstResponder()
+            }
             .padding(10)
             .padding(.leading, 40)
             .overlay(
@@ -30,6 +30,7 @@
                     .cornerRadius(10)
             )
             .padding()
+        
     }
 }
 
--- a/LazyBear/Views/Profile/ProfileView.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Profile/ProfileView.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -15,28 +15,25 @@
     var watchlistCompanies: FetchedResults<WatchlistCompany>
 
     @State private var showCreateNewWatchlist = false
-    
-    // Set recurrent price request
-    @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()
+    @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()  /// Set recurrent price request
 
     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
-                    
+                    /*
+                     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).sorted(), id: \.self) { listName in
                         let symbols = watchlistCompanies.filter({ $0.watchlist == listName }).map { $0.symbol }
-                        
                         if let companies = profile.data.quotes {
-                            // Select from API requested companies only the ones withing the watchlist
-                            let list = companies.filter({ symbols.contains($0.key) })
+                            let list = companies.filter({ symbols.contains($0.key) })  /// From API response select the companies within the specified watchlist
                             StockRow(listName: listName, list: list, intradayPrices: profile.data.intradayPrices, addOnDelete: true)
                         }
                     }
                     .listRowInsets(EdgeInsets())
-                    .onAppear {  // Refresh API requested companies when Core Data changes
+                    .onAppear {  /// Request API again when Core Data changes to update the list
                         refreshList()
                     }
                 }
@@ -68,7 +65,7 @@
     }
     
     /*
-     Get symbols in watchlists -> Prepare url -> Request
+     Get symbols in watchlists (Core Data) -> Prepare url -> Request
      */
     private func prepareUrl(_ requestType: RequestType) {
         let symbols = watchlistCompanies.map { $0.symbol }
--- a/LazyBear/Views/Search/CompanyList.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Search/CompanyList.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -23,6 +23,34 @@
     @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")])
+        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	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Search/Helpers/SearchedCompanyItem.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -14,12 +14,12 @@
     @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: [])
     var watchlistCompany: FetchedResults<WatchlistCompany>
     
-    @State private var showingActionSheet = false
+    @State private var showingWatchlistSelector = false
     
     var body: some View {
-        let watchlistSymbols = watchlistCompany.map { $0.symbol }
         HStack {
-            Button(action: { self.showingActionSheet = true }) {
+            Button(action: { self.showingWatchlistSelector = true }) {
+                let watchlistSymbols = watchlistCompany.map { $0.symbol }
                 if watchlistSymbols.contains(company.symbol!) {
                     Image(systemName: "star.fill")
                         .foregroundColor(.yellow)
@@ -49,12 +49,15 @@
                 Text(company.region!)
             }
         }
-        .actionSheet(isPresented: $showingActionSheet) {
+        .actionSheet(isPresented: $showingWatchlistSelector) {
             ActionSheet(title: Text("Add to watchlist"), message: Text("Select"), buttons: generateButtons())
         }
     }
     
-    // Get watchlist names -> generate buttons
+    /*
+     Generate buttons for each watchlist to let the user selects to which watchlist
+     he wants to add the company
+     */
     private func generateButtons() -> [ActionSheet.Button] {
         var actionButtons = [ActionSheet.Button]()
         let watchlists = Set(watchlistCompany.map { $0.watchlist })
@@ -72,7 +75,9 @@
         return actionButtons
     }
     
-    // Add to watchlist
+    /*
+     When the user taps the watchlist -> save the company to CoreData
+     */
     private func addCompany(_ symbol: String, _ name: String, _ watchlist: String) {
         let watchlistCompany = WatchlistCompany(context: moc)
         watchlistCompany.symbol = symbol
--- a/LazyBear/Views/Search/SearchView.swift	Wed Jun 09 20:26:28 2021 +0200
+++ b/LazyBear/Views/Search/SearchView.swift	Fri Jun 11 11:37:42 2021 +0200
@@ -40,17 +40,25 @@
             .navigationBarTitleDisplayMode(.inline)
             .navigationBarSearch($searchedText)
             .onChange(of: searchedText, perform: { searchedText in
-                if !searchedText.isEmpty {
-                    // Encode string with spaces
-                    let encodedSearchedText = searchedText.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
-                    search.request("https://api.lazybear.app/search/text=\(encodedSearchedText ?? "")")
-                } else {
-                    search.showSearchList = false
-                }
+                encodeAndRequest(searchedText)
             })
         }
         .navigationViewStyle(StackNavigationViewStyle())
     }
+    
+    /*
+     1) Check if searchedText is empty
+     2) Encode white spaces
+     3) Make API request
+     */
+    private func encodeAndRequest(_ searchedText: String) {
+        if !searchedText.isEmpty {
+            let encodedSearchedText = searchedText.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
+            search.request("https://api.lazybear.app/search/text=\(encodedSearchedText ?? "")")
+        } else {
+            search.showSearchList = false
+        }
+    }
 }
 
 struct SearchView_Previews: PreviewProvider {