Commit f3e2af331aa37f8979233db17da843f3e4d9c8c6

Authored by Artem Talko
0 parents

commit1

Showing 52 changed files with 4801 additions and 0 deletions

Too many changes to show.

To preserve performance only 52 of 52+ files are displayed.

No preview for this file type
  1 +//
  2 +// ContentBlockerRequestHandler.swift
  3 +// AdBlocker
  4 +//
  5 +// Created by Artem Talko on 24.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import MobileCoreServices
  10 +
  11 +class ContentBlockerRequestHandler: NSObject, NSExtensionRequestHandling {
  12 +
  13 + func beginRequest(with context: NSExtensionContext) {
  14 + let attachment = NSItemProvider(contentsOf: Bundle.main.url(forResource: "blockerList", withExtension: "json"))!
  15 +
  16 + let item = NSExtensionItem()
  17 + item.attachments = [attachment]
  18 +
  19 + context.completeRequest(returningItems: [item], completionHandler: nil)
  20 + }
  21 +}
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>NSExtension</key>
  6 + <dict>
  7 + <key>NSExtensionPointIdentifier</key>
  8 + <string>com.apple.Safari.content-blocker</string>
  9 + <key>NSExtensionPrincipalClass</key>
  10 + <string>$(PRODUCT_MODULE_NAME).ContentBlockerRequestHandler</string>
  11 + </dict>
  12 +</dict>
  13 +</plist>
... ...
  1 +// !$*UTF8*$!
  2 +{
  3 + archiveVersion = 1;
  4 + classes = {
  5 + };
  6 + objectVersion = 56;
  7 + objects = {
  8 +
  9 +/* Begin PBXBuildFile section */
  10 + 1904ED472AC56BDB0035DB66 /* FontsFree-Net-SFProText-Semibold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1904ED452AC56BDB0035DB66 /* FontsFree-Net-SFProText-Semibold.ttf */; };
  11 + 1904ED482AC56BDB0035DB66 /* FontsFree-Net-SFProText-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1904ED462AC56BDB0035DB66 /* FontsFree-Net-SFProText-Regular.ttf */; };
  12 + 1907D6972ADE766F00C40E9F /* HistoryDBManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1907D6962ADE766F00C40E9F /* HistoryDBManager.swift */; };
  13 + 1907D6992ADE7E9C00C40E9F /* DateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1907D6982ADE7E9C00C40E9F /* DateManager.swift */; };
  14 + 190DB9FC2AC450F6000A7BF3 /* RemoveAdvertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190DB9FB2AC450F6000A7BF3 /* RemoveAdvertViewController.swift */; };
  15 + 190DBA002AC45A3C000A7BF3 /* CachingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190DB9FF2AC45A3C000A7BF3 /* CachingManager.swift */; };
  16 + 190DBA0D2AC47701000A7BF3 /* BinaryFloatingPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190DBA0C2AC47701000A7BF3 /* BinaryFloatingPoint.swift */; };
  17 + 191BB84F2AC5A9C900A2DEB9 /* TabsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB84E2AC5A9C900A2DEB9 /* TabsView.swift */; };
  18 + 191BB8522AC5AB4600A2DEB9 /* TabsToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8512AC5AB4600A2DEB9 /* TabsToolbarView.swift */; };
  19 + 191BB8542AC5B3CD00A2DEB9 /* TabsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8532AC5B3CD00A2DEB9 /* TabsViewController.swift */; };
  20 + 191BB8572AC5B4AC00A2DEB9 /* OpenedTabsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8562AC5B4AC00A2DEB9 /* OpenedTabsCollectionViewCell.swift */; };
  21 + 191BB8622AC6A01500A2DEB9 /* SearchingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8612AC6A01500A2DEB9 /* SearchingViewController.swift */; };
  22 + 191BB8642AC6A02300A2DEB9 /* SearchingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8632AC6A02300A2DEB9 /* SearchingView.swift */; };
  23 + 191BB8692AC6A66900A2DEB9 /* SearchingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8682AC6A66900A2DEB9 /* SearchingTableViewCell.swift */; };
  24 + 191BB8772AC6B47700A2DEB9 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8762AC6B47700A2DEB9 /* HistoryView.swift */; };
  25 + 191BB8792AC6B48400A2DEB9 /* HistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8782AC6B48400A2DEB9 /* HistoryViewController.swift */; };
  26 + 191BB87C2AC6B79C00A2DEB9 /* HistoryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB87B2AC6B79C00A2DEB9 /* HistoryTableViewCell.swift */; };
  27 + 191BB87F2AC6BBBD00A2DEB9 /* HistoryToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB87E2AC6BBBD00A2DEB9 /* HistoryToolbarView.swift */; };
  28 + 191BB8812AC6FF6600A2DEB9 /* RemoveAdvertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191BB8802AC6FF6600A2DEB9 /* RemoveAdvertView.swift */; };
  29 + 1926E82F2B03BED200FEBCFB /* HistoryToolbarMenuCases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1926E82E2B03BED200FEBCFB /* HistoryToolbarMenuCases.swift */; };
  30 + 193B3B832ACAF394002161ED /* BrowserTabDataBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193B3B822ACAF394002161ED /* BrowserTabDataBase.swift */; };
  31 + 193B3B862ACAF480002161ED /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = 193B3B852ACAF480002161ED /* Realm */; };
  32 + 193B3B882ACAF480002161ED /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 193B3B872ACAF480002161ED /* RealmSwift */; };
  33 + 193B3B8A2ACAF714002161ED /* TabManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193B3B892ACAF714002161ED /* TabManager.swift */; };
  34 + 194635D62ADD738E00993D91 /* HistoryDataBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194635D52ADD738E00993D91 /* HistoryDataBase.swift */; };
  35 + 19696AF52AE80DBD00D1F8F9 /* blockerList.json in Resources */ = {isa = PBXBuildFile; fileRef = 19696AF42AE80DBD00D1F8F9 /* blockerList.json */; };
  36 + 19696AF72AE80DBD00D1F8F9 /* ContentBlockerRequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19696AF62AE80DBD00D1F8F9 /* ContentBlockerRequestHandler.swift */; };
  37 + 19696AFB2AE80DBD00D1F8F9 /* AdBlocker.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 19696AF22AE80DBC00D1F8F9 /* AdBlocker.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
  38 + 197FC3EF2AC21E1F007F429C /* PayloadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC3EE2AC21E1F007F429C /* PayloadViewController.swift */; };
  39 + 197FC3F22AC2AF9A007F429C /* AdvantagesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC3F12AC2AF9A007F429C /* AdvantagesTableViewCell.swift */; };
  40 + 197FC3F42AC2BCD7007F429C /* SearchBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC3F32AC2BCD7007F429C /* SearchBarView.swift */; };
  41 + 197FC3F92AC2FB69007F429C /* SettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC3F82AC2FB69007F429C /* SettingViewController.swift */; };
  42 + 197FC3FC2AC2FBA0007F429C /* SettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC3FB2AC2FBA0007F429C /* SettingView.swift */; };
  43 + 197FC3FF2AC30746007F429C /* SettingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC3FE2AC30746007F429C /* SettingTableViewCell.swift */; };
  44 + 197FC4012AC31D5C007F429C /* NavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC4002AC31D5C007F429C /* NavigationViewController.swift */; };
  45 + 197FC4032AC41EB7007F429C /* ToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197FC4022AC41EB7007F429C /* ToolbarView.swift */; };
  46 + 1984BF402AFB90560050F816 /* PrivacyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1984BF3F2AFB90560050F816 /* PrivacyViewController.swift */; };
  47 + 1984BF422AFB907A0050F816 /* PrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1984BF412AFB907A0050F816 /* PrivacyView.swift */; };
  48 + 1984BF582AFB970F0050F816 /* TermsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1984BF572AFB970F0050F816 /* TermsViewController.swift */; };
  49 + 1984BF5A2AFB973C0050F816 /* TermsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1984BF592AFB973C0050F816 /* TermsView.swift */; };
  50 + 1989A1602AE29D4C00292680 /* OpenTabsTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1989A15F2AE29D4B00292680 /* OpenTabsTransition.swift */; };
  51 + 1990C69C2AEFDF89004AF856 /* UICollectionViewCell+convertFrameToScreenCoordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1990C69B2AEFDF89004AF856 /* UICollectionViewCell+convertFrameToScreenCoordinates.swift */; };
  52 + 199DB1EE2AD3FCFE007E6A81 /* BrowserSearchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199DB1ED2AD3FCFE007E6A81 /* BrowserSearchService.swift */; };
  53 + 199DB1F12AD3FDEE007E6A81 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 199DB1F02AD3FDEE007E6A81 /* Alamofire */; };
  54 + 19B41DA12AD81A70002C0D31 /* SearchBarContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B41DA02AD81A70002C0D31 /* SearchBarContainer.swift */; };
  55 + 19B7396A2AE1554E0073AA59 /* URLConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B739692AE1554E0073AA59 /* URLConstants.swift */; };
  56 + 19B7396E2AE156DE0073AA59 /* StringConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B7396D2AE156DE0073AA59 /* StringConstants.swift */; };
  57 + 19B739712AE157900073AA59 /* FontConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B739702AE157900073AA59 /* FontConstants.swift */; };
  58 + 19B739732AE15B3B0073AA59 /* ColorConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B739722AE15B3B0073AA59 /* ColorConstants.swift */; };
  59 + 19B739762AE276360073AA59 /* HistoryElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B739752AE276360073AA59 /* HistoryElement.swift */; };
  60 + 19C5F0572AD9784400133BD7 /* DataExtention+toImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19C5F0562AD9784400133BD7 /* DataExtention+toImage.swift */; };
  61 + 19C7A70C2AC9EBB800B954FC /* RemoveAdvertTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19C7A70B2AC9EBB800B954FC /* RemoveAdvertTableViewCell.swift */; };
  62 + 19C7A70E2AC9F5FD00B954FC /* HistorySearchBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19C7A70D2AC9F5FD00B954FC /* HistorySearchBarView.swift */; };
  63 + 19CD89482AC719AC0035CB55 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 19CD89472AC719AC0035CB55 /* SnapKit */; };
  64 + 19D1F2E02AC1EF3200510506 /* PayloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D1F2DF2AC1EF3200510506 /* PayloadView.swift */; };
  65 + 19D8C9D62AE9169E0062D310 /* blockerList.json in Resources */ = {isa = PBXBuildFile; fileRef = 19696AF42AE80DBD00D1F8F9 /* blockerList.json */; };
  66 + 19EECA452ACED45A00094AFB /* SearchResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19EECA442ACED45A00094AFB /* SearchResultView.swift */; };
  67 + 19EECA472ACED48000094AFB /* SearchResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19EECA462ACED48000094AFB /* SearchResultViewController.swift */; };
  68 + 19FCBF222AC1727800F83A7F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19FCBF212AC1727800F83A7F /* AppDelegate.swift */; };
  69 + 19FCBF262AC1727800F83A7F /* BrowserHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19FCBF252AC1727800F83A7F /* BrowserHomeViewController.swift */; };
  70 + 19FCBF2B2AC1727900F83A7F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19FCBF2A2AC1727900F83A7F /* Assets.xcassets */; };
  71 + 19FCBF2E2AC1727900F83A7F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 19FCBF2C2AC1727900F83A7F /* LaunchScreen.storyboard */; };
  72 + 19FCBF3D2AC17AB000F83A7F /* BrowserHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19FCBF3C2AC17AB000F83A7F /* BrowserHomeView.swift */; };
  73 + 19FCBF452AC1981A00F83A7F /* TabCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19FCBF442AC1981A00F83A7F /* TabCollectionViewCell.swift */; };
  74 + 19FFD6BF2AE64A7B00D0F768 /* SnapshotService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19FFD6BE2AE64A7B00D0F768 /* SnapshotService.swift */; };
  75 +/* End PBXBuildFile section */
  76 +
  77 +/* Begin PBXContainerItemProxy section */
  78 + 19696AF92AE80DBD00D1F8F9 /* PBXContainerItemProxy */ = {
  79 + isa = PBXContainerItemProxy;
  80 + containerPortal = 19FCBF162AC1727800F83A7F /* Project object */;
  81 + proxyType = 1;
  82 + remoteGlobalIDString = 19696AF12AE80DBC00D1F8F9;
  83 + remoteInfo = AdBlocker;
  84 + };
  85 +/* End PBXContainerItemProxy section */
  86 +
  87 +/* Begin PBXCopyFilesBuildPhase section */
  88 + 19696AFC2AE80DBD00D1F8F9 /* Embed Foundation Extensions */ = {
  89 + isa = PBXCopyFilesBuildPhase;
  90 + buildActionMask = 2147483647;
  91 + dstPath = "";
  92 + dstSubfolderSpec = 13;
  93 + files = (
  94 + 19696AFB2AE80DBD00D1F8F9 /* AdBlocker.appex in Embed Foundation Extensions */,
  95 + );
  96 + name = "Embed Foundation Extensions";
  97 + runOnlyForDeploymentPostprocessing = 0;
  98 + };
  99 +/* End PBXCopyFilesBuildPhase section */
  100 +
  101 +/* Begin PBXFileReference section */
  102 + 1904ED452AC56BDB0035DB66 /* FontsFree-Net-SFProText-Semibold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FontsFree-Net-SFProText-Semibold.ttf"; sourceTree = "<group>"; };
  103 + 1904ED462AC56BDB0035DB66 /* FontsFree-Net-SFProText-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FontsFree-Net-SFProText-Regular.ttf"; sourceTree = "<group>"; };
  104 + 1907D6962ADE766F00C40E9F /* HistoryDBManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryDBManager.swift; sourceTree = "<group>"; };
  105 + 1907D6982ADE7E9C00C40E9F /* DateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateManager.swift; sourceTree = "<group>"; };
  106 + 190DB9FB2AC450F6000A7BF3 /* RemoveAdvertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdvertViewController.swift; sourceTree = "<group>"; };
  107 + 190DB9FF2AC45A3C000A7BF3 /* CachingManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachingManager.swift; sourceTree = "<group>"; };
  108 + 190DBA0C2AC47701000A7BF3 /* BinaryFloatingPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryFloatingPoint.swift; sourceTree = "<group>"; };
  109 + 191BB84E2AC5A9C900A2DEB9 /* TabsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsView.swift; sourceTree = "<group>"; };
  110 + 191BB8512AC5AB4600A2DEB9 /* TabsToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsToolbarView.swift; sourceTree = "<group>"; };
  111 + 191BB8532AC5B3CD00A2DEB9 /* TabsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsViewController.swift; sourceTree = "<group>"; };
  112 + 191BB8562AC5B4AC00A2DEB9 /* OpenedTabsCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenedTabsCollectionViewCell.swift; sourceTree = "<group>"; };
  113 + 191BB8612AC6A01500A2DEB9 /* SearchingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchingViewController.swift; sourceTree = "<group>"; };
  114 + 191BB8632AC6A02300A2DEB9 /* SearchingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchingView.swift; sourceTree = "<group>"; };
  115 + 191BB8682AC6A66900A2DEB9 /* SearchingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchingTableViewCell.swift; sourceTree = "<group>"; };
  116 + 191BB8762AC6B47700A2DEB9 /* HistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = "<group>"; };
  117 + 191BB8782AC6B48400A2DEB9 /* HistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryViewController.swift; sourceTree = "<group>"; };
  118 + 191BB87B2AC6B79C00A2DEB9 /* HistoryTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTableViewCell.swift; sourceTree = "<group>"; };
  119 + 191BB87E2AC6BBBD00A2DEB9 /* HistoryToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryToolbarView.swift; sourceTree = "<group>"; };
  120 + 191BB8802AC6FF6600A2DEB9 /* RemoveAdvertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdvertView.swift; sourceTree = "<group>"; };
  121 + 1926E82E2B03BED200FEBCFB /* HistoryToolbarMenuCases.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryToolbarMenuCases.swift; sourceTree = "<group>"; };
  122 + 193B3B822ACAF394002161ED /* BrowserTabDataBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserTabDataBase.swift; sourceTree = "<group>"; };
  123 + 193B3B892ACAF714002161ED /* TabManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabManager.swift; sourceTree = "<group>"; };
  124 + 194635D52ADD738E00993D91 /* HistoryDataBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryDataBase.swift; sourceTree = "<group>"; };
  125 + 19696AF22AE80DBC00D1F8F9 /* AdBlocker.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AdBlocker.appex; sourceTree = BUILT_PRODUCTS_DIR; };
  126 + 19696AF42AE80DBD00D1F8F9 /* blockerList.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = blockerList.json; sourceTree = "<group>"; };
  127 + 19696AF62AE80DBD00D1F8F9 /* ContentBlockerRequestHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentBlockerRequestHandler.swift; sourceTree = "<group>"; };
  128 + 19696AF82AE80DBD00D1F8F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
  129 + 197FC3EE2AC21E1F007F429C /* PayloadViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayloadViewController.swift; sourceTree = "<group>"; };
  130 + 197FC3F12AC2AF9A007F429C /* AdvantagesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvantagesTableViewCell.swift; sourceTree = "<group>"; };
  131 + 197FC3F32AC2BCD7007F429C /* SearchBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarView.swift; sourceTree = "<group>"; };
  132 + 197FC3F82AC2FB69007F429C /* SettingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingViewController.swift; sourceTree = "<group>"; };
  133 + 197FC3FB2AC2FBA0007F429C /* SettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingView.swift; sourceTree = "<group>"; };
  134 + 197FC3FE2AC30746007F429C /* SettingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingTableViewCell.swift; sourceTree = "<group>"; };
  135 + 197FC4002AC31D5C007F429C /* NavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewController.swift; sourceTree = "<group>"; };
  136 + 197FC4022AC41EB7007F429C /* ToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarView.swift; sourceTree = "<group>"; };
  137 + 1984BF3F2AFB90560050F816 /* PrivacyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyViewController.swift; sourceTree = "<group>"; };
  138 + 1984BF412AFB907A0050F816 /* PrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyView.swift; sourceTree = "<group>"; };
  139 + 1984BF572AFB970F0050F816 /* TermsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsViewController.swift; sourceTree = "<group>"; };
  140 + 1984BF592AFB973C0050F816 /* TermsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsView.swift; sourceTree = "<group>"; };
  141 + 1989A15F2AE29D4B00292680 /* OpenTabsTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTabsTransition.swift; sourceTree = "<group>"; };
  142 + 1990C69B2AEFDF89004AF856 /* UICollectionViewCell+convertFrameToScreenCoordinates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionViewCell+convertFrameToScreenCoordinates.swift"; sourceTree = "<group>"; };
  143 + 199DB1ED2AD3FCFE007E6A81 /* BrowserSearchService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserSearchService.swift; sourceTree = "<group>"; };
  144 + 19B41DA02AD81A70002C0D31 /* SearchBarContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarContainer.swift; sourceTree = "<group>"; };
  145 + 19B739692AE1554E0073AA59 /* URLConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLConstants.swift; sourceTree = "<group>"; };
  146 + 19B7396D2AE156DE0073AA59 /* StringConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringConstants.swift; sourceTree = "<group>"; };
  147 + 19B739702AE157900073AA59 /* FontConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontConstants.swift; sourceTree = "<group>"; };
  148 + 19B739722AE15B3B0073AA59 /* ColorConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorConstants.swift; sourceTree = "<group>"; };
  149 + 19B739752AE276360073AA59 /* HistoryElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryElement.swift; sourceTree = "<group>"; };
  150 + 19C5F0562AD9784400133BD7 /* DataExtention+toImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataExtention+toImage.swift"; sourceTree = "<group>"; };
  151 + 19C7A70B2AC9EBB800B954FC /* RemoveAdvertTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdvertTableViewCell.swift; sourceTree = "<group>"; };
  152 + 19C7A70D2AC9F5FD00B954FC /* HistorySearchBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistorySearchBarView.swift; sourceTree = "<group>"; };
  153 + 19D1F2DF2AC1EF3200510506 /* PayloadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayloadView.swift; sourceTree = "<group>"; };
  154 + 19EECA442ACED45A00094AFB /* SearchResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultView.swift; sourceTree = "<group>"; };
  155 + 19EECA462ACED48000094AFB /* SearchResultViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultViewController.swift; sourceTree = "<group>"; };
  156 + 19FCBF1E2AC1727800F83A7F /* browser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = browser.app; sourceTree = BUILT_PRODUCTS_DIR; };
  157 + 19FCBF212AC1727800F83A7F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
  158 + 19FCBF252AC1727800F83A7F /* BrowserHomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserHomeViewController.swift; sourceTree = "<group>"; };
  159 + 19FCBF2A2AC1727900F83A7F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
  160 + 19FCBF2D2AC1727900F83A7F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
  161 + 19FCBF2F2AC1727900F83A7F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
  162 + 19FCBF3C2AC17AB000F83A7F /* BrowserHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserHomeView.swift; sourceTree = "<group>"; };
  163 + 19FCBF442AC1981A00F83A7F /* TabCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewCell.swift; sourceTree = "<group>"; };
  164 + 19FFD6BE2AE64A7B00D0F768 /* SnapshotService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotService.swift; sourceTree = "<group>"; };
  165 +/* End PBXFileReference section */
  166 +
  167 +/* Begin PBXFrameworksBuildPhase section */
  168 + 19696AEF2AE80DBC00D1F8F9 /* Frameworks */ = {
  169 + isa = PBXFrameworksBuildPhase;
  170 + buildActionMask = 2147483647;
  171 + files = (
  172 + );
  173 + runOnlyForDeploymentPostprocessing = 0;
  174 + };
  175 + 19FCBF1B2AC1727800F83A7F /* Frameworks */ = {
  176 + isa = PBXFrameworksBuildPhase;
  177 + buildActionMask = 2147483647;
  178 + files = (
  179 + 193B3B882ACAF480002161ED /* RealmSwift in Frameworks */,
  180 + 199DB1F12AD3FDEE007E6A81 /* Alamofire in Frameworks */,
  181 + 193B3B862ACAF480002161ED /* Realm in Frameworks */,
  182 + 19CD89482AC719AC0035CB55 /* SnapKit in Frameworks */,
  183 + );
  184 + runOnlyForDeploymentPostprocessing = 0;
  185 + };
  186 +/* End PBXFrameworksBuildPhase section */
  187 +
  188 +/* Begin PBXGroup section */
  189 + 190DB9F72AC44FCA000A7BF3 /* RemoveAdvert */ = {
  190 + isa = PBXGroup;
  191 + children = (
  192 + 190DB9F82AC44FD4000A7BF3 /* View */,
  193 + 190DB9F92AC44FD8000A7BF3 /* Controller */,
  194 + );
  195 + path = RemoveAdvert;
  196 + sourceTree = "<group>";
  197 + };
  198 + 190DB9F82AC44FD4000A7BF3 /* View */ = {
  199 + isa = PBXGroup;
  200 + children = (
  201 + 19C7A70A2AC9EB9B00B954FC /* Cell */,
  202 + 191BB8802AC6FF6600A2DEB9 /* RemoveAdvertView.swift */,
  203 + );
  204 + path = View;
  205 + sourceTree = "<group>";
  206 + };
  207 + 190DB9F92AC44FD8000A7BF3 /* Controller */ = {
  208 + isa = PBXGroup;
  209 + children = (
  210 + 190DB9FB2AC450F6000A7BF3 /* RemoveAdvertViewController.swift */,
  211 + );
  212 + path = Controller;
  213 + sourceTree = "<group>";
  214 + };
  215 + 190DB9FD2AC459CD000A7BF3 /* Managers */ = {
  216 + isa = PBXGroup;
  217 + children = (
  218 + 190DB9FF2AC45A3C000A7BF3 /* CachingManager.swift */,
  219 + 193B3B892ACAF714002161ED /* TabManager.swift */,
  220 + 1907D6962ADE766F00C40E9F /* HistoryDBManager.swift */,
  221 + 1907D6982ADE7E9C00C40E9F /* DateManager.swift */,
  222 + );
  223 + path = Managers;
  224 + sourceTree = "<group>";
  225 + };
  226 + 190DBA012AC45CDA000A7BF3 /* Extentions */ = {
  227 + isa = PBXGroup;
  228 + children = (
  229 + 190DBA0C2AC47701000A7BF3 /* BinaryFloatingPoint.swift */,
  230 + 19C5F0562AD9784400133BD7 /* DataExtention+toImage.swift */,
  231 + 1990C69B2AEFDF89004AF856 /* UICollectionViewCell+convertFrameToScreenCoordinates.swift */,
  232 + );
  233 + path = Extentions;
  234 + sourceTree = "<group>";
  235 + };
  236 + 190DBA042AC474C4000A7BF3 /* Fonts */ = {
  237 + isa = PBXGroup;
  238 + children = (
  239 + 1904ED462AC56BDB0035DB66 /* FontsFree-Net-SFProText-Regular.ttf */,
  240 + 1904ED452AC56BDB0035DB66 /* FontsFree-Net-SFProText-Semibold.ttf */,
  241 + );
  242 + path = Fonts;
  243 + sourceTree = "<group>";
  244 + };
  245 + 191BB84A2AC5A8EF00A2DEB9 /* Components */ = {
  246 + isa = PBXGroup;
  247 + children = (
  248 + 197FC4022AC41EB7007F429C /* ToolbarView.swift */,
  249 + 197FC3F32AC2BCD7007F429C /* SearchBarView.swift */,
  250 + 19B41DA02AD81A70002C0D31 /* SearchBarContainer.swift */,
  251 + );
  252 + path = Components;
  253 + sourceTree = "<group>";
  254 + };
  255 + 191BB84B2AC5A9A600A2DEB9 /* Tabs */ = {
  256 + isa = PBXGroup;
  257 + children = (
  258 + 191BB84D2AC5A9B400A2DEB9 /* View */,
  259 + 191BB84C2AC5A9AD00A2DEB9 /* Controller */,
  260 + );
  261 + path = Tabs;
  262 + sourceTree = "<group>";
  263 + };
  264 + 191BB84C2AC5A9AD00A2DEB9 /* Controller */ = {
  265 + isa = PBXGroup;
  266 + children = (
  267 + 191BB8532AC5B3CD00A2DEB9 /* TabsViewController.swift */,
  268 + );
  269 + path = Controller;
  270 + sourceTree = "<group>";
  271 + };
  272 + 191BB84D2AC5A9B400A2DEB9 /* View */ = {
  273 + isa = PBXGroup;
  274 + children = (
  275 + 191BB8552AC5B48F00A2DEB9 /* Cell */,
  276 + 191BB8502AC5AB2700A2DEB9 /* Components */,
  277 + 191BB84E2AC5A9C900A2DEB9 /* TabsView.swift */,
  278 + );
  279 + path = View;
  280 + sourceTree = "<group>";
  281 + };
  282 + 191BB8502AC5AB2700A2DEB9 /* Components */ = {
  283 + isa = PBXGroup;
  284 + children = (
  285 + 191BB8512AC5AB4600A2DEB9 /* TabsToolbarView.swift */,
  286 + );
  287 + path = Components;
  288 + sourceTree = "<group>";
  289 + };
  290 + 191BB8552AC5B48F00A2DEB9 /* Cell */ = {
  291 + isa = PBXGroup;
  292 + children = (
  293 + 191BB8562AC5B4AC00A2DEB9 /* OpenedTabsCollectionViewCell.swift */,
  294 + );
  295 + path = Cell;
  296 + sourceTree = "<group>";
  297 + };
  298 + 191BB85D2AC69FC800A2DEB9 /* Searching */ = {
  299 + isa = PBXGroup;
  300 + children = (
  301 + 191BB85F2AC69FDB00A2DEB9 /* View */,
  302 + 191BB85E2AC69FCC00A2DEB9 /* Controller */,
  303 + );
  304 + path = Searching;
  305 + sourceTree = "<group>";
  306 + };
  307 + 191BB85E2AC69FCC00A2DEB9 /* Controller */ = {
  308 + isa = PBXGroup;
  309 + children = (
  310 + 191BB8612AC6A01500A2DEB9 /* SearchingViewController.swift */,
  311 + );
  312 + path = Controller;
  313 + sourceTree = "<group>";
  314 + };
  315 + 191BB85F2AC69FDB00A2DEB9 /* View */ = {
  316 + isa = PBXGroup;
  317 + children = (
  318 + 191BB8672AC6A65600A2DEB9 /* Cell */,
  319 + 191BB8632AC6A02300A2DEB9 /* SearchingView.swift */,
  320 + );
  321 + path = View;
  322 + sourceTree = "<group>";
  323 + };
  324 + 191BB8672AC6A65600A2DEB9 /* Cell */ = {
  325 + isa = PBXGroup;
  326 + children = (
  327 + 191BB8682AC6A66900A2DEB9 /* SearchingTableViewCell.swift */,
  328 + );
  329 + path = Cell;
  330 + sourceTree = "<group>";
  331 + };
  332 + 191BB8702AC6B19F00A2DEB9 /* History */ = {
  333 + isa = PBXGroup;
  334 + children = (
  335 + 191BB8722AC6B26500A2DEB9 /* View */,
  336 + 191BB8712AC6B25300A2DEB9 /* Controller */,
  337 + );
  338 + path = History;
  339 + sourceTree = "<group>";
  340 + };
  341 + 191BB8712AC6B25300A2DEB9 /* Controller */ = {
  342 + isa = PBXGroup;
  343 + children = (
  344 + 191BB8782AC6B48400A2DEB9 /* HistoryViewController.swift */,
  345 + );
  346 + path = Controller;
  347 + sourceTree = "<group>";
  348 + };
  349 + 191BB8722AC6B26500A2DEB9 /* View */ = {
  350 + isa = PBXGroup;
  351 + children = (
  352 + 191BB87A2AC6B78800A2DEB9 /* Cell */,
  353 + 191BB87D2AC6BB6600A2DEB9 /* Components */,
  354 + 191BB8762AC6B47700A2DEB9 /* HistoryView.swift */,
  355 + );
  356 + path = View;
  357 + sourceTree = "<group>";
  358 + };
  359 + 191BB87A2AC6B78800A2DEB9 /* Cell */ = {
  360 + isa = PBXGroup;
  361 + children = (
  362 + 191BB87B2AC6B79C00A2DEB9 /* HistoryTableViewCell.swift */,
  363 + );
  364 + path = Cell;
  365 + sourceTree = "<group>";
  366 + };
  367 + 191BB87D2AC6BB6600A2DEB9 /* Components */ = {
  368 + isa = PBXGroup;
  369 + children = (
  370 + 191BB87E2AC6BBBD00A2DEB9 /* HistoryToolbarView.swift */,
  371 + 19C7A70D2AC9F5FD00B954FC /* HistorySearchBarView.swift */,
  372 + );
  373 + path = Components;
  374 + sourceTree = "<group>";
  375 + };
  376 + 193B3B812ACAF36C002161ED /* DataBases */ = {
  377 + isa = PBXGroup;
  378 + children = (
  379 + 193B3B822ACAF394002161ED /* BrowserTabDataBase.swift */,
  380 + 194635D52ADD738E00993D91 /* HistoryDataBase.swift */,
  381 + );
  382 + path = DataBases;
  383 + sourceTree = "<group>";
  384 + };
  385 + 19696AF32AE80DBD00D1F8F9 /* AdBlocker */ = {
  386 + isa = PBXGroup;
  387 + children = (
  388 + 19696AF62AE80DBD00D1F8F9 /* ContentBlockerRequestHandler.swift */,
  389 + 19696AF82AE80DBD00D1F8F9 /* Info.plist */,
  390 + );
  391 + path = AdBlocker;
  392 + sourceTree = "<group>";
  393 + };
  394 + 197FC3F02AC2AF8A007F429C /* Cell */ = {
  395 + isa = PBXGroup;
  396 + children = (
  397 + 197FC3F12AC2AF9A007F429C /* AdvantagesTableViewCell.swift */,
  398 + );
  399 + path = Cell;
  400 + sourceTree = "<group>";
  401 + };
  402 + 197FC3F52AC2F9FA007F429C /* Settings */ = {
  403 + isa = PBXGroup;
  404 + children = (
  405 + 197FC3F72AC2FA0C007F429C /* View */,
  406 + 197FC3F62AC2FA06007F429C /* Controller */,
  407 + );
  408 + path = Settings;
  409 + sourceTree = "<group>";
  410 + };
  411 + 197FC3F62AC2FA06007F429C /* Controller */ = {
  412 + isa = PBXGroup;
  413 + children = (
  414 + 197FC3F82AC2FB69007F429C /* SettingViewController.swift */,
  415 + );
  416 + path = Controller;
  417 + sourceTree = "<group>";
  418 + };
  419 + 197FC3F72AC2FA0C007F429C /* View */ = {
  420 + isa = PBXGroup;
  421 + children = (
  422 + 1984BF3A2AFB8FFA0050F816 /* Components */,
  423 + 197FC3FD2AC30738007F429C /* Cell */,
  424 + 197FC3FB2AC2FBA0007F429C /* SettingView.swift */,
  425 + );
  426 + path = View;
  427 + sourceTree = "<group>";
  428 + };
  429 + 197FC3FD2AC30738007F429C /* Cell */ = {
  430 + isa = PBXGroup;
  431 + children = (
  432 + 197FC3FE2AC30746007F429C /* SettingTableViewCell.swift */,
  433 + );
  434 + path = Cell;
  435 + sourceTree = "<group>";
  436 + };
  437 + 1984BF3A2AFB8FFA0050F816 /* Components */ = {
  438 + isa = PBXGroup;
  439 + children = (
  440 + 1984BF432AFB955C0050F816 /* Terms */,
  441 + 1984BF3B2AFB902A0050F816 /* Privacy */,
  442 + );
  443 + path = Components;
  444 + sourceTree = "<group>";
  445 + };
  446 + 1984BF3B2AFB902A0050F816 /* Privacy */ = {
  447 + isa = PBXGroup;
  448 + children = (
  449 + 1984BF3E2AFB90430050F816 /* Controller */,
  450 + 1984BF3D2AFB903C0050F816 /* View */,
  451 + );
  452 + path = Privacy;
  453 + sourceTree = "<group>";
  454 + };
  455 + 1984BF3D2AFB903C0050F816 /* View */ = {
  456 + isa = PBXGroup;
  457 + children = (
  458 + 1984BF412AFB907A0050F816 /* PrivacyView.swift */,
  459 + );
  460 + path = View;
  461 + sourceTree = "<group>";
  462 + };
  463 + 1984BF3E2AFB90430050F816 /* Controller */ = {
  464 + isa = PBXGroup;
  465 + children = (
  466 + 1984BF3F2AFB90560050F816 /* PrivacyViewController.swift */,
  467 + );
  468 + path = Controller;
  469 + sourceTree = "<group>";
  470 + };
  471 + 1984BF432AFB955C0050F816 /* Terms */ = {
  472 + isa = PBXGroup;
  473 + children = (
  474 + 1984BF562AFB97030050F816 /* Controller */,
  475 + 1984BF552AFB96FE0050F816 /* View */,
  476 + );
  477 + path = Terms;
  478 + sourceTree = "<group>";
  479 + };
  480 + 1984BF552AFB96FE0050F816 /* View */ = {
  481 + isa = PBXGroup;
  482 + children = (
  483 + 1984BF592AFB973C0050F816 /* TermsView.swift */,
  484 + );
  485 + path = View;
  486 + sourceTree = "<group>";
  487 + };
  488 + 1984BF562AFB97030050F816 /* Controller */ = {
  489 + isa = PBXGroup;
  490 + children = (
  491 + 1984BF572AFB970F0050F816 /* TermsViewController.swift */,
  492 + );
  493 + path = Controller;
  494 + sourceTree = "<group>";
  495 + };
  496 + 199DB1EC2AD3FCE1007E6A81 /* Services */ = {
  497 + isa = PBXGroup;
  498 + children = (
  499 + 199DB1ED2AD3FCFE007E6A81 /* BrowserSearchService.swift */,
  500 + 19FFD6BE2AE64A7B00D0F768 /* SnapshotService.swift */,
  501 + );
  502 + path = Services;
  503 + sourceTree = "<group>";
  504 + };
  505 + 19B2D0AF2ACDEAB600D20CE8 /* SearchResult */ = {
  506 + isa = PBXGroup;
  507 + children = (
  508 + 19EECA432ACED43400094AFB /* View */,
  509 + 19B2D0B02ACDEB3500D20CE8 /* Controller */,
  510 + );
  511 + path = SearchResult;
  512 + sourceTree = "<group>";
  513 + };
  514 + 19B2D0B02ACDEB3500D20CE8 /* Controller */ = {
  515 + isa = PBXGroup;
  516 + children = (
  517 + 19EECA462ACED48000094AFB /* SearchResultViewController.swift */,
  518 + );
  519 + path = Controller;
  520 + sourceTree = "<group>";
  521 + };
  522 + 19B7396B2AE155540073AA59 /* Images */ = {
  523 + isa = PBXGroup;
  524 + children = (
  525 + 19FCBF2A2AC1727900F83A7F /* Assets.xcassets */,
  526 + );
  527 + path = Images;
  528 + sourceTree = "<group>";
  529 + };
  530 + 19B7396C2AE1555F0073AA59 /* Other */ = {
  531 + isa = PBXGroup;
  532 + children = (
  533 + 19FCBF2C2AC1727900F83A7F /* LaunchScreen.storyboard */,
  534 + );
  535 + path = Other;
  536 + sourceTree = "<group>";
  537 + };
  538 + 19B7396F2AE1573B0073AA59 /* Constants */ = {
  539 + isa = PBXGroup;
  540 + children = (
  541 + 19B739692AE1554E0073AA59 /* URLConstants.swift */,
  542 + 19B7396D2AE156DE0073AA59 /* StringConstants.swift */,
  543 + 19B739702AE157900073AA59 /* FontConstants.swift */,
  544 + 19B739722AE15B3B0073AA59 /* ColorConstants.swift */,
  545 + );
  546 + path = Constants;
  547 + sourceTree = "<group>";
  548 + };
  549 + 19B739742AE275FF0073AA59 /* Models */ = {
  550 + isa = PBXGroup;
  551 + children = (
  552 + 19B739752AE276360073AA59 /* HistoryElement.swift */,
  553 + 1926E82E2B03BED200FEBCFB /* HistoryToolbarMenuCases.swift */,
  554 + );
  555 + path = Models;
  556 + sourceTree = "<group>";
  557 + };
  558 + 19C7A70A2AC9EB9B00B954FC /* Cell */ = {
  559 + isa = PBXGroup;
  560 + children = (
  561 + 19C7A70B2AC9EBB800B954FC /* RemoveAdvertTableViewCell.swift */,
  562 + );
  563 + path = Cell;
  564 + sourceTree = "<group>";
  565 + };
  566 + 19D1F2DC2AC1EE6200510506 /* Payload */ = {
  567 + isa = PBXGroup;
  568 + children = (
  569 + 19D1F2DE2AC1EF0400510506 /* View */,
  570 + 19D1F2DD2AC1EEF800510506 /* Controller */,
  571 + );
  572 + path = Payload;
  573 + sourceTree = "<group>";
  574 + };
  575 + 19D1F2DD2AC1EEF800510506 /* Controller */ = {
  576 + isa = PBXGroup;
  577 + children = (
  578 + 197FC3EE2AC21E1F007F429C /* PayloadViewController.swift */,
  579 + );
  580 + path = Controller;
  581 + sourceTree = "<group>";
  582 + };
  583 + 19D1F2DE2AC1EF0400510506 /* View */ = {
  584 + isa = PBXGroup;
  585 + children = (
  586 + 197FC3F02AC2AF8A007F429C /* Cell */,
  587 + 19D1F2DF2AC1EF3200510506 /* PayloadView.swift */,
  588 + );
  589 + path = View;
  590 + sourceTree = "<group>";
  591 + };
  592 + 19EECA432ACED43400094AFB /* View */ = {
  593 + isa = PBXGroup;
  594 + children = (
  595 + 19EECA442ACED45A00094AFB /* SearchResultView.swift */,
  596 + );
  597 + path = View;
  598 + sourceTree = "<group>";
  599 + };
  600 + 19F65A712ACBFCB500B50F61 /* Resources */ = {
  601 + isa = PBXGroup;
  602 + children = (
  603 + 19696AF42AE80DBD00D1F8F9 /* blockerList.json */,
  604 + 19B7396F2AE1573B0073AA59 /* Constants */,
  605 + 19B7396B2AE155540073AA59 /* Images */,
  606 + 190DBA042AC474C4000A7BF3 /* Fonts */,
  607 + 19B7396C2AE1555F0073AA59 /* Other */,
  608 + );
  609 + path = Resources;
  610 + sourceTree = "<group>";
  611 + };
  612 + 19F65A722ACBFD7300B50F61 /* Common */ = {
  613 + isa = PBXGroup;
  614 + children = (
  615 + 19F65A732ACBFDD100B50F61 /* Transitions */,
  616 + );
  617 + path = Common;
  618 + sourceTree = "<group>";
  619 + };
  620 + 19F65A732ACBFDD100B50F61 /* Transitions */ = {
  621 + isa = PBXGroup;
  622 + children = (
  623 + 1989A15F2AE29D4B00292680 /* OpenTabsTransition.swift */,
  624 + );
  625 + path = Transitions;
  626 + sourceTree = "<group>";
  627 + };
  628 + 19FCBF152AC1727800F83A7F = {
  629 + isa = PBXGroup;
  630 + children = (
  631 + 19FCBF202AC1727800F83A7F /* browser */,
  632 + 19696AF32AE80DBD00D1F8F9 /* AdBlocker */,
  633 + 19FCBF1F2AC1727800F83A7F /* Products */,
  634 + );
  635 + sourceTree = "<group>";
  636 + };
  637 + 19FCBF1F2AC1727800F83A7F /* Products */ = {
  638 + isa = PBXGroup;
  639 + children = (
  640 + 19FCBF1E2AC1727800F83A7F /* browser.app */,
  641 + 19696AF22AE80DBC00D1F8F9 /* AdBlocker.appex */,
  642 + );
  643 + name = Products;
  644 + sourceTree = "<group>";
  645 + };
  646 + 19FCBF202AC1727800F83A7F /* browser */ = {
  647 + isa = PBXGroup;
  648 + children = (
  649 + 19B739742AE275FF0073AA59 /* Models */,
  650 + 19FCBF382AC17A4800F83A7F /* Modules */,
  651 + 199DB1EC2AD3FCE1007E6A81 /* Services */,
  652 + 19F65A722ACBFD7300B50F61 /* Common */,
  653 + 190DBA012AC45CDA000A7BF3 /* Extentions */,
  654 + 193B3B812ACAF36C002161ED /* DataBases */,
  655 + 19F65A712ACBFCB500B50F61 /* Resources */,
  656 + 190DB9FD2AC459CD000A7BF3 /* Managers */,
  657 + 19FCBF352AC1779800F83A7F /* Navigation */,
  658 + 19FCBF212AC1727800F83A7F /* AppDelegate.swift */,
  659 + 19FCBF2F2AC1727900F83A7F /* Info.plist */,
  660 + );
  661 + path = browser;
  662 + sourceTree = "<group>";
  663 + };
  664 + 19FCBF352AC1779800F83A7F /* Navigation */ = {
  665 + isa = PBXGroup;
  666 + children = (
  667 + 197FC4002AC31D5C007F429C /* NavigationViewController.swift */,
  668 + );
  669 + path = Navigation;
  670 + sourceTree = "<group>";
  671 + };
  672 + 19FCBF382AC17A4800F83A7F /* Modules */ = {
  673 + isa = PBXGroup;
  674 + children = (
  675 + 19B2D0AF2ACDEAB600D20CE8 /* SearchResult */,
  676 + 191BB8702AC6B19F00A2DEB9 /* History */,
  677 + 191BB85D2AC69FC800A2DEB9 /* Searching */,
  678 + 191BB84B2AC5A9A600A2DEB9 /* Tabs */,
  679 + 190DB9F72AC44FCA000A7BF3 /* RemoveAdvert */,
  680 + 197FC3F52AC2F9FA007F429C /* Settings */,
  681 + 19D1F2DC2AC1EE6200510506 /* Payload */,
  682 + 19FCBF392AC17A6600F83A7F /* Home */,
  683 + );
  684 + path = Modules;
  685 + sourceTree = "<group>";
  686 + };
  687 + 19FCBF392AC17A6600F83A7F /* Home */ = {
  688 + isa = PBXGroup;
  689 + children = (
  690 + 19FCBF3B2AC17A8400F83A7F /* View */,
  691 + 19FCBF3A2AC17A7800F83A7F /* Controller */,
  692 + );
  693 + path = Home;
  694 + sourceTree = "<group>";
  695 + };
  696 + 19FCBF3A2AC17A7800F83A7F /* Controller */ = {
  697 + isa = PBXGroup;
  698 + children = (
  699 + 19FCBF252AC1727800F83A7F /* BrowserHomeViewController.swift */,
  700 + );
  701 + path = Controller;
  702 + sourceTree = "<group>";
  703 + };
  704 + 19FCBF3B2AC17A8400F83A7F /* View */ = {
  705 + isa = PBXGroup;
  706 + children = (
  707 + 19FCBF432AC197FD00F83A7F /* Cell */,
  708 + 191BB84A2AC5A8EF00A2DEB9 /* Components */,
  709 + 19FCBF3C2AC17AB000F83A7F /* BrowserHomeView.swift */,
  710 + );
  711 + path = View;
  712 + sourceTree = "<group>";
  713 + };
  714 + 19FCBF432AC197FD00F83A7F /* Cell */ = {
  715 + isa = PBXGroup;
  716 + children = (
  717 + 19FCBF442AC1981A00F83A7F /* TabCollectionViewCell.swift */,
  718 + );
  719 + path = Cell;
  720 + sourceTree = "<group>";
  721 + };
  722 +/* End PBXGroup section */
  723 +
  724 +/* Begin PBXNativeTarget section */
  725 + 19696AF12AE80DBC00D1F8F9 /* AdBlocker */ = {
  726 + isa = PBXNativeTarget;
  727 + buildConfigurationList = 19696AFF2AE80DBD00D1F8F9 /* Build configuration list for PBXNativeTarget "AdBlocker" */;
  728 + buildPhases = (
  729 + 19696AEE2AE80DBC00D1F8F9 /* Sources */,
  730 + 19696AEF2AE80DBC00D1F8F9 /* Frameworks */,
  731 + 19696AF02AE80DBC00D1F8F9 /* Resources */,
  732 + );
  733 + buildRules = (
  734 + );
  735 + dependencies = (
  736 + );
  737 + name = AdBlocker;
  738 + productName = AdBlocker;
  739 + productReference = 19696AF22AE80DBC00D1F8F9 /* AdBlocker.appex */;
  740 + productType = "com.apple.product-type.app-extension";
  741 + };
  742 + 19FCBF1D2AC1727800F83A7F /* browser */ = {
  743 + isa = PBXNativeTarget;
  744 + buildConfigurationList = 19FCBF322AC1727900F83A7F /* Build configuration list for PBXNativeTarget "browser" */;
  745 + buildPhases = (
  746 + 19FCBF1A2AC1727800F83A7F /* Sources */,
  747 + 19FCBF1B2AC1727800F83A7F /* Frameworks */,
  748 + 19FCBF1C2AC1727800F83A7F /* Resources */,
  749 + 19696AFC2AE80DBD00D1F8F9 /* Embed Foundation Extensions */,
  750 + );
  751 + buildRules = (
  752 + );
  753 + dependencies = (
  754 + 19696AFA2AE80DBD00D1F8F9 /* PBXTargetDependency */,
  755 + );
  756 + name = browser;
  757 + packageProductDependencies = (
  758 + 19CD89472AC719AC0035CB55 /* SnapKit */,
  759 + 193B3B852ACAF480002161ED /* Realm */,
  760 + 193B3B872ACAF480002161ED /* RealmSwift */,
  761 + 199DB1F02AD3FDEE007E6A81 /* Alamofire */,
  762 + );
  763 + productName = browser;
  764 + productReference = 19FCBF1E2AC1727800F83A7F /* browser.app */;
  765 + productType = "com.apple.product-type.application";
  766 + };
  767 +/* End PBXNativeTarget section */
  768 +
  769 +/* Begin PBXProject section */
  770 + 19FCBF162AC1727800F83A7F /* Project object */ = {
  771 + isa = PBXProject;
  772 + attributes = {
  773 + BuildIndependentTargetsInParallel = 1;
  774 + LastSwiftUpdateCheck = 1500;
  775 + LastUpgradeCheck = 1500;
  776 + TargetAttributes = {
  777 + 19696AF12AE80DBC00D1F8F9 = {
  778 + CreatedOnToolsVersion = 15.0.1;
  779 + };
  780 + 19FCBF1D2AC1727800F83A7F = {
  781 + CreatedOnToolsVersion = 15.0;
  782 + };
  783 + };
  784 + };
  785 + buildConfigurationList = 19FCBF192AC1727800F83A7F /* Build configuration list for PBXProject "browser" */;
  786 + compatibilityVersion = "Xcode 14.0";
  787 + developmentRegion = en;
  788 + hasScannedForEncodings = 0;
  789 + knownRegions = (
  790 + en,
  791 + Base,
  792 + );
  793 + mainGroup = 19FCBF152AC1727800F83A7F;
  794 + packageReferences = (
  795 + 19CD89462AC719AB0035CB55 /* XCRemoteSwiftPackageReference "SnapKit" */,
  796 + 193B3B842ACAF480002161ED /* XCRemoteSwiftPackageReference "realm-swift" */,
  797 + 199DB1EF2AD3FDEE007E6A81 /* XCRemoteSwiftPackageReference "Alamofire" */,
  798 + );
  799 + productRefGroup = 19FCBF1F2AC1727800F83A7F /* Products */;
  800 + projectDirPath = "";
  801 + projectRoot = "";
  802 + targets = (
  803 + 19FCBF1D2AC1727800F83A7F /* browser */,
  804 + 19696AF12AE80DBC00D1F8F9 /* AdBlocker */,
  805 + );
  806 + };
  807 +/* End PBXProject section */
  808 +
  809 +/* Begin PBXResourcesBuildPhase section */
  810 + 19696AF02AE80DBC00D1F8F9 /* Resources */ = {
  811 + isa = PBXResourcesBuildPhase;
  812 + buildActionMask = 2147483647;
  813 + files = (
  814 + 19696AF52AE80DBD00D1F8F9 /* blockerList.json in Resources */,
  815 + );
  816 + runOnlyForDeploymentPostprocessing = 0;
  817 + };
  818 + 19FCBF1C2AC1727800F83A7F /* Resources */ = {
  819 + isa = PBXResourcesBuildPhase;
  820 + buildActionMask = 2147483647;
  821 + files = (
  822 + 1904ED472AC56BDB0035DB66 /* FontsFree-Net-SFProText-Semibold.ttf in Resources */,
  823 + 19FCBF2E2AC1727900F83A7F /* LaunchScreen.storyboard in Resources */,
  824 + 1904ED482AC56BDB0035DB66 /* FontsFree-Net-SFProText-Regular.ttf in Resources */,
  825 + 19FCBF2B2AC1727900F83A7F /* Assets.xcassets in Resources */,
  826 + 19D8C9D62AE9169E0062D310 /* blockerList.json in Resources */,
  827 + );
  828 + runOnlyForDeploymentPostprocessing = 0;
  829 + };
  830 +/* End PBXResourcesBuildPhase section */
  831 +
  832 +/* Begin PBXSourcesBuildPhase section */
  833 + 19696AEE2AE80DBC00D1F8F9 /* Sources */ = {
  834 + isa = PBXSourcesBuildPhase;
  835 + buildActionMask = 2147483647;
  836 + files = (
  837 + 19696AF72AE80DBD00D1F8F9 /* ContentBlockerRequestHandler.swift in Sources */,
  838 + );
  839 + runOnlyForDeploymentPostprocessing = 0;
  840 + };
  841 + 19FCBF1A2AC1727800F83A7F /* Sources */ = {
  842 + isa = PBXSourcesBuildPhase;
  843 + buildActionMask = 2147483647;
  844 + files = (
  845 + 19B739712AE157900073AA59 /* FontConstants.swift in Sources */,
  846 + 191BB8812AC6FF6600A2DEB9 /* RemoveAdvertView.swift in Sources */,
  847 + 191BB8792AC6B48400A2DEB9 /* HistoryViewController.swift in Sources */,
  848 + 197FC3F42AC2BCD7007F429C /* SearchBarView.swift in Sources */,
  849 + 19B739732AE15B3B0073AA59 /* ColorConstants.swift in Sources */,
  850 + 19FCBF262AC1727800F83A7F /* BrowserHomeViewController.swift in Sources */,
  851 + 197FC3FF2AC30746007F429C /* SettingTableViewCell.swift in Sources */,
  852 + 19B41DA12AD81A70002C0D31 /* SearchBarContainer.swift in Sources */,
  853 + 19EECA452ACED45A00094AFB /* SearchResultView.swift in Sources */,
  854 + 1907D6972ADE766F00C40E9F /* HistoryDBManager.swift in Sources */,
  855 + 19B739762AE276360073AA59 /* HistoryElement.swift in Sources */,
  856 + 197FC4032AC41EB7007F429C /* ToolbarView.swift in Sources */,
  857 + 19B7396A2AE1554E0073AA59 /* URLConstants.swift in Sources */,
  858 + 19EECA472ACED48000094AFB /* SearchResultViewController.swift in Sources */,
  859 + 191BB8572AC5B4AC00A2DEB9 /* OpenedTabsCollectionViewCell.swift in Sources */,
  860 + 190DB9FC2AC450F6000A7BF3 /* RemoveAdvertViewController.swift in Sources */,
  861 + 193B3B832ACAF394002161ED /* BrowserTabDataBase.swift in Sources */,
  862 + 1984BF402AFB90560050F816 /* PrivacyViewController.swift in Sources */,
  863 + 199DB1EE2AD3FCFE007E6A81 /* BrowserSearchService.swift in Sources */,
  864 + 1907D6992ADE7E9C00C40E9F /* DateManager.swift in Sources */,
  865 + 191BB8522AC5AB4600A2DEB9 /* TabsToolbarView.swift in Sources */,
  866 + 191BB84F2AC5A9C900A2DEB9 /* TabsView.swift in Sources */,
  867 + 19FCBF452AC1981A00F83A7F /* TabCollectionViewCell.swift in Sources */,
  868 + 19B7396E2AE156DE0073AA59 /* StringConstants.swift in Sources */,
  869 + 191BB8542AC5B3CD00A2DEB9 /* TabsViewController.swift in Sources */,
  870 + 194635D62ADD738E00993D91 /* HistoryDataBase.swift in Sources */,
  871 + 197FC3F22AC2AF9A007F429C /* AdvantagesTableViewCell.swift in Sources */,
  872 + 191BB8642AC6A02300A2DEB9 /* SearchingView.swift in Sources */,
  873 + 190DBA002AC45A3C000A7BF3 /* CachingManager.swift in Sources */,
  874 + 1984BF422AFB907A0050F816 /* PrivacyView.swift in Sources */,
  875 + 191BB8692AC6A66900A2DEB9 /* SearchingTableViewCell.swift in Sources */,
  876 + 1990C69C2AEFDF89004AF856 /* UICollectionViewCell+convertFrameToScreenCoordinates.swift in Sources */,
  877 + 19FCBF222AC1727800F83A7F /* AppDelegate.swift in Sources */,
  878 + 19C7A70C2AC9EBB800B954FC /* RemoveAdvertTableViewCell.swift in Sources */,
  879 + 19D1F2E02AC1EF3200510506 /* PayloadView.swift in Sources */,
  880 + 19FFD6BF2AE64A7B00D0F768 /* SnapshotService.swift in Sources */,
  881 + 190DBA0D2AC47701000A7BF3 /* BinaryFloatingPoint.swift in Sources */,
  882 + 191BB8772AC6B47700A2DEB9 /* HistoryView.swift in Sources */,
  883 + 19FCBF3D2AC17AB000F83A7F /* BrowserHomeView.swift in Sources */,
  884 + 191BB87F2AC6BBBD00A2DEB9 /* HistoryToolbarView.swift in Sources */,
  885 + 1984BF582AFB970F0050F816 /* TermsViewController.swift in Sources */,
  886 + 193B3B8A2ACAF714002161ED /* TabManager.swift in Sources */,
  887 + 191BB87C2AC6B79C00A2DEB9 /* HistoryTableViewCell.swift in Sources */,
  888 + 1926E82F2B03BED200FEBCFB /* HistoryToolbarMenuCases.swift in Sources */,
  889 + 197FC3F92AC2FB69007F429C /* SettingViewController.swift in Sources */,
  890 + 1984BF5A2AFB973C0050F816 /* TermsView.swift in Sources */,
  891 + 197FC3FC2AC2FBA0007F429C /* SettingView.swift in Sources */,
  892 + 191BB8622AC6A01500A2DEB9 /* SearchingViewController.swift in Sources */,
  893 + 197FC4012AC31D5C007F429C /* NavigationViewController.swift in Sources */,
  894 + 19C5F0572AD9784400133BD7 /* DataExtention+toImage.swift in Sources */,
  895 + 1989A1602AE29D4C00292680 /* OpenTabsTransition.swift in Sources */,
  896 + 197FC3EF2AC21E1F007F429C /* PayloadViewController.swift in Sources */,
  897 + 19C7A70E2AC9F5FD00B954FC /* HistorySearchBarView.swift in Sources */,
  898 + );
  899 + runOnlyForDeploymentPostprocessing = 0;
  900 + };
  901 +/* End PBXSourcesBuildPhase section */
  902 +
  903 +/* Begin PBXTargetDependency section */
  904 + 19696AFA2AE80DBD00D1F8F9 /* PBXTargetDependency */ = {
  905 + isa = PBXTargetDependency;
  906 + target = 19696AF12AE80DBC00D1F8F9 /* AdBlocker */;
  907 + targetProxy = 19696AF92AE80DBD00D1F8F9 /* PBXContainerItemProxy */;
  908 + };
  909 +/* End PBXTargetDependency section */
  910 +
  911 +/* Begin PBXVariantGroup section */
  912 + 19FCBF2C2AC1727900F83A7F /* LaunchScreen.storyboard */ = {
  913 + isa = PBXVariantGroup;
  914 + children = (
  915 + 19FCBF2D2AC1727900F83A7F /* Base */,
  916 + );
  917 + name = LaunchScreen.storyboard;
  918 + sourceTree = "<group>";
  919 + };
  920 +/* End PBXVariantGroup section */
  921 +
  922 +/* Begin XCBuildConfiguration section */
  923 + 19696AFD2AE80DBD00D1F8F9 /* Debug */ = {
  924 + isa = XCBuildConfiguration;
  925 + buildSettings = {
  926 + ARCHS = "$(ARCHS_STANDARD_64_BIT)";
  927 + CODE_SIGN_STYLE = Automatic;
  928 + CURRENT_PROJECT_VERSION = 1;
  929 + DEVELOPMENT_TEAM = 6Y97YM76EY;
  930 + GENERATE_INFOPLIST_FILE = YES;
  931 + INFOPLIST_FILE = AdBlocker/Info.plist;
  932 + INFOPLIST_KEY_CFBundleDisplayName = AdBlocker;
  933 + INFOPLIST_KEY_NSHumanReadableCopyright = "";
  934 + IPHONEOS_DEPLOYMENT_TARGET = 15.0;
  935 + LD_RUNPATH_SEARCH_PATHS = (
  936 + "$(inherited)",
  937 + "@executable_path/Frameworks",
  938 + "@executable_path/../../Frameworks",
  939 + );
  940 + MARKETING_VERSION = 1.0;
  941 + PRODUCT_BUNDLE_IDENTIFIER = "com.4k-soft.browser.AdBlock";
  942 + PRODUCT_NAME = "$(TARGET_NAME)";
  943 + SKIP_INSTALL = YES;
  944 + SWIFT_EMIT_LOC_STRINGS = YES;
  945 + SWIFT_VERSION = 5.0;
  946 + TARGETED_DEVICE_FAMILY = "1,2";
  947 + };
  948 + name = Debug;
  949 + };
  950 + 19696AFE2AE80DBD00D1F8F9 /* Release */ = {
  951 + isa = XCBuildConfiguration;
  952 + buildSettings = {
  953 + ARCHS = "$(ARCHS_STANDARD_64_BIT)";
  954 + CODE_SIGN_STYLE = Automatic;
  955 + CURRENT_PROJECT_VERSION = 1;
  956 + DEVELOPMENT_TEAM = 6Y97YM76EY;
  957 + GENERATE_INFOPLIST_FILE = YES;
  958 + INFOPLIST_FILE = AdBlocker/Info.plist;
  959 + INFOPLIST_KEY_CFBundleDisplayName = AdBlocker;
  960 + INFOPLIST_KEY_NSHumanReadableCopyright = "";
  961 + IPHONEOS_DEPLOYMENT_TARGET = 15.0;
  962 + LD_RUNPATH_SEARCH_PATHS = (
  963 + "$(inherited)",
  964 + "@executable_path/Frameworks",
  965 + "@executable_path/../../Frameworks",
  966 + );
  967 + MARKETING_VERSION = 1.0;
  968 + PRODUCT_BUNDLE_IDENTIFIER = "com.4k-soft.browser.AdBlock";
  969 + PRODUCT_NAME = "$(TARGET_NAME)";
  970 + SKIP_INSTALL = YES;
  971 + SWIFT_EMIT_LOC_STRINGS = YES;
  972 + SWIFT_VERSION = 5.0;
  973 + TARGETED_DEVICE_FAMILY = "1,2";
  974 + };
  975 + name = Release;
  976 + };
  977 + 19FCBF302AC1727900F83A7F /* Debug */ = {
  978 + isa = XCBuildConfiguration;
  979 + buildSettings = {
  980 + ALWAYS_SEARCH_USER_PATHS = NO;
  981 + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
  982 + CLANG_ANALYZER_NONNULL = YES;
  983 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
  984 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
  985 + CLANG_ENABLE_MODULES = YES;
  986 + CLANG_ENABLE_OBJC_ARC = YES;
  987 + CLANG_ENABLE_OBJC_WEAK = YES;
  988 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
  989 + CLANG_WARN_BOOL_CONVERSION = YES;
  990 + CLANG_WARN_COMMA = YES;
  991 + CLANG_WARN_CONSTANT_CONVERSION = YES;
  992 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
  993 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
  994 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
  995 + CLANG_WARN_EMPTY_BODY = YES;
  996 + CLANG_WARN_ENUM_CONVERSION = YES;
  997 + CLANG_WARN_INFINITE_RECURSION = YES;
  998 + CLANG_WARN_INT_CONVERSION = YES;
  999 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
  1000 + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
  1001 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
  1002 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
  1003 + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
  1004 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
  1005 + CLANG_WARN_STRICT_PROTOTYPES = YES;
  1006 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
  1007 + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
  1008 + CLANG_WARN_UNREACHABLE_CODE = YES;
  1009 + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
  1010 + COPY_PHASE_STRIP = NO;
  1011 + DEBUG_INFORMATION_FORMAT = dwarf;
  1012 + ENABLE_STRICT_OBJC_MSGSEND = YES;
  1013 + ENABLE_TESTABILITY = YES;
  1014 + ENABLE_USER_SCRIPT_SANDBOXING = YES;
  1015 + GCC_C_LANGUAGE_STANDARD = gnu17;
  1016 + GCC_DYNAMIC_NO_PIC = NO;
  1017 + GCC_NO_COMMON_BLOCKS = YES;
  1018 + GCC_OPTIMIZATION_LEVEL = 0;
  1019 + GCC_PREPROCESSOR_DEFINITIONS = (
  1020 + "DEBUG=1",
  1021 + "$(inherited)",
  1022 + );
  1023 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
  1024 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
  1025 + GCC_WARN_UNDECLARED_SELECTOR = YES;
  1026 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
  1027 + GCC_WARN_UNUSED_FUNCTION = YES;
  1028 + GCC_WARN_UNUSED_VARIABLE = YES;
  1029 + IPHONEOS_DEPLOYMENT_TARGET = 15.0;
  1030 + LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
  1031 + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
  1032 + MTL_FAST_MATH = YES;
  1033 + ONLY_ACTIVE_ARCH = YES;
  1034 + SDKROOT = iphoneos;
  1035 + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
  1036 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
  1037 + };
  1038 + name = Debug;
  1039 + };
  1040 + 19FCBF312AC1727900F83A7F /* Release */ = {
  1041 + isa = XCBuildConfiguration;
  1042 + buildSettings = {
  1043 + ALWAYS_SEARCH_USER_PATHS = NO;
  1044 + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
  1045 + CLANG_ANALYZER_NONNULL = YES;
  1046 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
  1047 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
  1048 + CLANG_ENABLE_MODULES = YES;
  1049 + CLANG_ENABLE_OBJC_ARC = YES;
  1050 + CLANG_ENABLE_OBJC_WEAK = YES;
  1051 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
  1052 + CLANG_WARN_BOOL_CONVERSION = YES;
  1053 + CLANG_WARN_COMMA = YES;
  1054 + CLANG_WARN_CONSTANT_CONVERSION = YES;
  1055 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
  1056 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
  1057 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
  1058 + CLANG_WARN_EMPTY_BODY = YES;
  1059 + CLANG_WARN_ENUM_CONVERSION = YES;
  1060 + CLANG_WARN_INFINITE_RECURSION = YES;
  1061 + CLANG_WARN_INT_CONVERSION = YES;
  1062 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
  1063 + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
  1064 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
  1065 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
  1066 + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
  1067 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
  1068 + CLANG_WARN_STRICT_PROTOTYPES = YES;
  1069 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
  1070 + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
  1071 + CLANG_WARN_UNREACHABLE_CODE = YES;
  1072 + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
  1073 + COPY_PHASE_STRIP = NO;
  1074 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
  1075 + ENABLE_NS_ASSERTIONS = NO;
  1076 + ENABLE_STRICT_OBJC_MSGSEND = YES;
  1077 + ENABLE_USER_SCRIPT_SANDBOXING = YES;
  1078 + GCC_C_LANGUAGE_STANDARD = gnu17;
  1079 + GCC_NO_COMMON_BLOCKS = YES;
  1080 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
  1081 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
  1082 + GCC_WARN_UNDECLARED_SELECTOR = YES;
  1083 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
  1084 + GCC_WARN_UNUSED_FUNCTION = YES;
  1085 + GCC_WARN_UNUSED_VARIABLE = YES;
  1086 + IPHONEOS_DEPLOYMENT_TARGET = 15.0;
  1087 + LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
  1088 + MTL_ENABLE_DEBUG_INFO = NO;
  1089 + MTL_FAST_MATH = YES;
  1090 + SDKROOT = iphoneos;
  1091 + SWIFT_COMPILATION_MODE = wholemodule;
  1092 + VALIDATE_PRODUCT = YES;
  1093 + };
  1094 + name = Release;
  1095 + };
  1096 + 19FCBF332AC1727900F83A7F /* Debug */ = {
  1097 + isa = XCBuildConfiguration;
  1098 + buildSettings = {
  1099 + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
  1100 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
  1101 + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
  1102 + CODE_SIGN_STYLE = Automatic;
  1103 + CURRENT_PROJECT_VERSION = 1;
  1104 + DEVELOPMENT_TEAM = 6Y97YM76EY;
  1105 + GENERATE_INFOPLIST_FILE = YES;
  1106 + INFOPLIST_FILE = browser/Info.plist;
  1107 + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
  1108 + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
  1109 + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
  1110 + INFOPLIST_KEY_UIUserInterfaceStyle = Light;
  1111 + IPHONEOS_DEPLOYMENT_TARGET = 15.0;
  1112 + LD_RUNPATH_SEARCH_PATHS = (
  1113 + "$(inherited)",
  1114 + "@executable_path/Frameworks",
  1115 + );
  1116 + MARKETING_VERSION = 1.0;
  1117 + PRODUCT_BUNDLE_IDENTIFIER = "com.4k-soft.browser";
  1118 + PRODUCT_NAME = "$(TARGET_NAME)";
  1119 + SWIFT_EMIT_LOC_STRINGS = YES;
  1120 + SWIFT_VERSION = 5.0;
  1121 + TARGETED_DEVICE_FAMILY = "1,2";
  1122 + };
  1123 + name = Debug;
  1124 + };
  1125 + 19FCBF342AC1727900F83A7F /* Release */ = {
  1126 + isa = XCBuildConfiguration;
  1127 + buildSettings = {
  1128 + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
  1129 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
  1130 + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
  1131 + CODE_SIGN_STYLE = Automatic;
  1132 + CURRENT_PROJECT_VERSION = 1;
  1133 + DEVELOPMENT_TEAM = 6Y97YM76EY;
  1134 + GENERATE_INFOPLIST_FILE = YES;
  1135 + INFOPLIST_FILE = browser/Info.plist;
  1136 + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
  1137 + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
  1138 + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
  1139 + INFOPLIST_KEY_UIUserInterfaceStyle = Light;
  1140 + IPHONEOS_DEPLOYMENT_TARGET = 15.0;
  1141 + LD_RUNPATH_SEARCH_PATHS = (
  1142 + "$(inherited)",
  1143 + "@executable_path/Frameworks",
  1144 + );
  1145 + MARKETING_VERSION = 1.0;
  1146 + PRODUCT_BUNDLE_IDENTIFIER = "com.4k-soft.browser";
  1147 + PRODUCT_NAME = "$(TARGET_NAME)";
  1148 + SWIFT_EMIT_LOC_STRINGS = YES;
  1149 + SWIFT_VERSION = 5.0;
  1150 + TARGETED_DEVICE_FAMILY = "1,2";
  1151 + };
  1152 + name = Release;
  1153 + };
  1154 +/* End XCBuildConfiguration section */
  1155 +
  1156 +/* Begin XCConfigurationList section */
  1157 + 19696AFF2AE80DBD00D1F8F9 /* Build configuration list for PBXNativeTarget "AdBlocker" */ = {
  1158 + isa = XCConfigurationList;
  1159 + buildConfigurations = (
  1160 + 19696AFD2AE80DBD00D1F8F9 /* Debug */,
  1161 + 19696AFE2AE80DBD00D1F8F9 /* Release */,
  1162 + );
  1163 + defaultConfigurationIsVisible = 0;
  1164 + defaultConfigurationName = Release;
  1165 + };
  1166 + 19FCBF192AC1727800F83A7F /* Build configuration list for PBXProject "browser" */ = {
  1167 + isa = XCConfigurationList;
  1168 + buildConfigurations = (
  1169 + 19FCBF302AC1727900F83A7F /* Debug */,
  1170 + 19FCBF312AC1727900F83A7F /* Release */,
  1171 + );
  1172 + defaultConfigurationIsVisible = 0;
  1173 + defaultConfigurationName = Release;
  1174 + };
  1175 + 19FCBF322AC1727900F83A7F /* Build configuration list for PBXNativeTarget "browser" */ = {
  1176 + isa = XCConfigurationList;
  1177 + buildConfigurations = (
  1178 + 19FCBF332AC1727900F83A7F /* Debug */,
  1179 + 19FCBF342AC1727900F83A7F /* Release */,
  1180 + );
  1181 + defaultConfigurationIsVisible = 0;
  1182 + defaultConfigurationName = Release;
  1183 + };
  1184 +/* End XCConfigurationList section */
  1185 +
  1186 +/* Begin XCRemoteSwiftPackageReference section */
  1187 + 193B3B842ACAF480002161ED /* XCRemoteSwiftPackageReference "realm-swift" */ = {
  1188 + isa = XCRemoteSwiftPackageReference;
  1189 + repositoryURL = "https://github.com/realm/realm-swift.git";
  1190 + requirement = {
  1191 + branch = master;
  1192 + kind = branch;
  1193 + };
  1194 + };
  1195 + 199DB1EF2AD3FDEE007E6A81 /* XCRemoteSwiftPackageReference "Alamofire" */ = {
  1196 + isa = XCRemoteSwiftPackageReference;
  1197 + repositoryURL = "https://github.com/Alamofire/Alamofire.git";
  1198 + requirement = {
  1199 + kind = upToNextMajorVersion;
  1200 + minimumVersion = 5.8.0;
  1201 + };
  1202 + };
  1203 + 19CD89462AC719AB0035CB55 /* XCRemoteSwiftPackageReference "SnapKit" */ = {
  1204 + isa = XCRemoteSwiftPackageReference;
  1205 + repositoryURL = "https://github.com/SnapKit/SnapKit.git";
  1206 + requirement = {
  1207 + kind = upToNextMajorVersion;
  1208 + minimumVersion = 5.6.0;
  1209 + };
  1210 + };
  1211 +/* End XCRemoteSwiftPackageReference section */
  1212 +
  1213 +/* Begin XCSwiftPackageProductDependency section */
  1214 + 193B3B852ACAF480002161ED /* Realm */ = {
  1215 + isa = XCSwiftPackageProductDependency;
  1216 + package = 193B3B842ACAF480002161ED /* XCRemoteSwiftPackageReference "realm-swift" */;
  1217 + productName = Realm;
  1218 + };
  1219 + 193B3B872ACAF480002161ED /* RealmSwift */ = {
  1220 + isa = XCSwiftPackageProductDependency;
  1221 + package = 193B3B842ACAF480002161ED /* XCRemoteSwiftPackageReference "realm-swift" */;
  1222 + productName = RealmSwift;
  1223 + };
  1224 + 199DB1F02AD3FDEE007E6A81 /* Alamofire */ = {
  1225 + isa = XCSwiftPackageProductDependency;
  1226 + package = 199DB1EF2AD3FDEE007E6A81 /* XCRemoteSwiftPackageReference "Alamofire" */;
  1227 + productName = Alamofire;
  1228 + };
  1229 + 19CD89472AC719AC0035CB55 /* SnapKit */ = {
  1230 + isa = XCSwiftPackageProductDependency;
  1231 + package = 19CD89462AC719AB0035CB55 /* XCRemoteSwiftPackageReference "SnapKit" */;
  1232 + productName = SnapKit;
  1233 + };
  1234 +/* End XCSwiftPackageProductDependency section */
  1235 + };
  1236 + rootObject = 19FCBF162AC1727800F83A7F /* Project object */;
  1237 +}
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<Workspace
  3 + version = "1.0">
  4 + <FileRef
  5 + location = "self:">
  6 + </FileRef>
  7 +</Workspace>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>IDEDidComputeMac32BitWarning</key>
  6 + <true/>
  7 +</dict>
  8 +</plist>
... ...
  1 +{
  2 + "pins" : [
  3 + {
  4 + "identity" : "alamofire",
  5 + "kind" : "remoteSourceControl",
  6 + "location" : "https://github.com/Alamofire/Alamofire.git",
  7 + "state" : {
  8 + "revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad",
  9 + "version" : "5.8.1"
  10 + }
  11 + },
  12 + {
  13 + "identity" : "realm-core",
  14 + "kind" : "remoteSourceControl",
  15 + "location" : "https://github.com/realm/realm-core.git",
  16 + "state" : {
  17 + "revision" : "c569bec4d04da84030d94f376437bc4efda3686b",
  18 + "version" : "13.23.1"
  19 + }
  20 + },
  21 + {
  22 + "identity" : "realm-swift",
  23 + "kind" : "remoteSourceControl",
  24 + "location" : "https://github.com/realm/realm-swift.git",
  25 + "state" : {
  26 + "branch" : "master",
  27 + "revision" : "6b992e508b1fab07d47775f2fd7485fd5f110893"
  28 + }
  29 + },
  30 + {
  31 + "identity" : "snapkit",
  32 + "kind" : "remoteSourceControl",
  33 + "location" : "https://github.com/SnapKit/SnapKit.git",
  34 + "state" : {
  35 + "revision" : "f222cbdf325885926566172f6f5f06af95473158",
  36 + "version" : "5.6.0"
  37 + }
  38 + }
  39 + ],
  40 + "version" : 2
  41 +}
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>top-level-items</key>
  6 + <array>
  7 + <dict>
  8 + <key>destination</key>
  9 + <dict>
  10 + <key>rebasable-url</key>
  11 + <dict>
  12 + <key>base</key>
  13 + <string>workspace</string>
  14 + <key>payload</key>
  15 + <dict>
  16 + <key>relative-path</key>
  17 + <string>browser/Modules/History/Controller/HistoryViewController.swift</string>
  18 + </dict>
  19 + </dict>
  20 + <key>type</key>
  21 + <string>DVTDocumentLocation</string>
  22 + </dict>
  23 + <key>type</key>
  24 + <string>bookmark</string>
  25 + </dict>
  26 + </array>
  27 +</dict>
  28 +</plist>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<Bucket
  3 + uuid = "7D2BF3CE-0152-4175-98D9-E41B0FA9C333"
  4 + type = "1"
  5 + version = "2.0">
  6 + <Breakpoints>
  7 + <BreakpointProxy
  8 + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
  9 + <BreakpointContent
  10 + uuid = "F889FE98-5ADA-45D9-9094-5319F398E5D0"
  11 + shouldBeEnabled = "Yes"
  12 + ignoreCount = "0"
  13 + continueAfterRunningActions = "No"
  14 + filePath = "browser/Models/HistoryToolbarMenuCases.swift"
  15 + startingColumnNumber = "9223372036854775807"
  16 + endingColumnNumber = "9223372036854775807"
  17 + startingLineNumber = "21"
  18 + endingLineNumber = "21"
  19 + landmarkName = "action"
  20 + landmarkType = "24">
  21 + </BreakpointContent>
  22 + </BreakpointProxy>
  23 + <BreakpointProxy
  24 + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
  25 + <BreakpointContent
  26 + uuid = "2E2EC010-6906-4B8A-9667-CF365A133EA9"
  27 + shouldBeEnabled = "No"
  28 + ignoreCount = "0"
  29 + continueAfterRunningActions = "No"
  30 + filePath = "browser/Modules/SearchResult/View/SearchResultView.swift"
  31 + startingColumnNumber = "9223372036854775807"
  32 + endingColumnNumber = "9223372036854775807"
  33 + startingLineNumber = "20"
  34 + endingLineNumber = "20"
  35 + landmarkName = "searchResultView"
  36 + landmarkType = "24">
  37 + </BreakpointContent>
  38 + </BreakpointProxy>
  39 + <BreakpointProxy
  40 + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
  41 + <BreakpointContent
  42 + uuid = "AF29D2F2-0DE8-426B-B8C0-6E69F97CA3CA"
  43 + shouldBeEnabled = "No"
  44 + ignoreCount = "0"
  45 + continueAfterRunningActions = "No"
  46 + filePath = "browser/Modules/RemoveAdvert/Controller/RemoveAdvertViewController.swift"
  47 + startingColumnNumber = "9223372036854775807"
  48 + endingColumnNumber = "9223372036854775807"
  49 + startingLineNumber = "82"
  50 + endingLineNumber = "82"
  51 + landmarkName = "shieldButtonTapped(_:)"
  52 + landmarkType = "7">
  53 + </BreakpointContent>
  54 + </BreakpointProxy>
  55 + <BreakpointProxy
  56 + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
  57 + <BreakpointContent
  58 + uuid = "2F610807-91FB-4B53-BAE6-77E3D9664161"
  59 + shouldBeEnabled = "No"
  60 + ignoreCount = "0"
  61 + continueAfterRunningActions = "No"
  62 + filePath = "browser/Modules/RemoveAdvert/Controller/RemoveAdvertViewController.swift"
  63 + startingColumnNumber = "9223372036854775807"
  64 + endingColumnNumber = "9223372036854775807"
  65 + startingLineNumber = "86"
  66 + endingLineNumber = "86"
  67 + landmarkName = "shieldButtonTapped(_:)"
  68 + landmarkType = "7">
  69 + </BreakpointContent>
  70 + </BreakpointProxy>
  71 + <BreakpointProxy
  72 + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
  73 + <BreakpointContent
  74 + uuid = "2DAFEA73-1A5C-412B-9CAB-F119AA59AC98"
  75 + shouldBeEnabled = "No"
  76 + ignoreCount = "0"
  77 + continueAfterRunningActions = "No"
  78 + filePath = "browser/Modules/SearchResult/Controller/SearchResultViewController.swift"
  79 + startingColumnNumber = "9223372036854775807"
  80 + endingColumnNumber = "9223372036854775807"
  81 + startingLineNumber = "55"
  82 + endingLineNumber = "55"
  83 + landmarkName = "setupAdBlocker()"
  84 + landmarkType = "7">
  85 + </BreakpointContent>
  86 + </BreakpointProxy>
  87 + <BreakpointProxy
  88 + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
  89 + <BreakpointContent
  90 + uuid = "3D9602FE-229B-4486-9E84-86F3385737CB"
  91 + shouldBeEnabled = "No"
  92 + ignoreCount = "0"
  93 + continueAfterRunningActions = "No"
  94 + filePath = "browser/Modules/Home/Controller/BrowserHomeViewController.swift"
  95 + startingColumnNumber = "9223372036854775807"
  96 + endingColumnNumber = "9223372036854775807"
  97 + startingLineNumber = "236"
  98 + endingLineNumber = "236"
  99 + landmarkName = "tabsButtonHandler()"
  100 + landmarkType = "7">
  101 + </BreakpointContent>
  102 + </BreakpointProxy>
  103 + <BreakpointProxy
  104 + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
  105 + <BreakpointContent
  106 + uuid = "890732EB-28CC-4180-BED8-D29D0A5F9C6A"
  107 + shouldBeEnabled = "No"
  108 + ignoreCount = "0"
  109 + continueAfterRunningActions = "No"
  110 + filePath = "browser/Modules/Home/Controller/BrowserHomeViewController.swift"
  111 + startingColumnNumber = "9223372036854775807"
  112 + endingColumnNumber = "9223372036854775807"
  113 + startingLineNumber = "235"
  114 + endingLineNumber = "235"
  115 + landmarkName = "tabsButtonHandler()"
  116 + landmarkType = "7">
  117 + </BreakpointContent>
  118 + </BreakpointProxy>
  119 + </Breakpoints>
  120 +</Bucket>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>SchemeUserState</key>
  6 + <dict>
  7 + <key>AdBlocker.xcscheme_^#shared#^_</key>
  8 + <dict>
  9 + <key>orderHint</key>
  10 + <integer>0</integer>
  11 + </dict>
  12 + <key>GettingStarted (Playground) 1.xcscheme</key>
  13 + <dict>
  14 + <key>isShown</key>
  15 + <false/>
  16 + <key>orderHint</key>
  17 + <integer>5</integer>
  18 + </dict>
  19 + <key>GettingStarted (Playground) 2.xcscheme</key>
  20 + <dict>
  21 + <key>isShown</key>
  22 + <false/>
  23 + <key>orderHint</key>
  24 + <integer>6</integer>
  25 + </dict>
  26 + <key>GettingStarted (Playground).xcscheme</key>
  27 + <dict>
  28 + <key>isShown</key>
  29 + <false/>
  30 + <key>orderHint</key>
  31 + <integer>2</integer>
  32 + </dict>
  33 + <key>SnapKitPlayground (Playground) 1.xcscheme</key>
  34 + <dict>
  35 + <key>isShown</key>
  36 + <false/>
  37 + <key>orderHint</key>
  38 + <integer>3</integer>
  39 + </dict>
  40 + <key>SnapKitPlayground (Playground) 2.xcscheme</key>
  41 + <dict>
  42 + <key>isShown</key>
  43 + <false/>
  44 + <key>orderHint</key>
  45 + <integer>4</integer>
  46 + </dict>
  47 + <key>SnapKitPlayground (Playground) 3.xcscheme</key>
  48 + <dict>
  49 + <key>isShown</key>
  50 + <false/>
  51 + <key>orderHint</key>
  52 + <integer>0</integer>
  53 + </dict>
  54 + <key>SnapKitPlayground (Playground) 4.xcscheme</key>
  55 + <dict>
  56 + <key>isShown</key>
  57 + <false/>
  58 + <key>orderHint</key>
  59 + <integer>5</integer>
  60 + </dict>
  61 + <key>SnapKitPlayground (Playground) 5.xcscheme</key>
  62 + <dict>
  63 + <key>isShown</key>
  64 + <false/>
  65 + <key>orderHint</key>
  66 + <integer>6</integer>
  67 + </dict>
  68 + <key>SnapKitPlayground (Playground).xcscheme</key>
  69 + <dict>
  70 + <key>isShown</key>
  71 + <false/>
  72 + <key>orderHint</key>
  73 + <integer>1</integer>
  74 + </dict>
  75 + <key>browser.xcscheme_^#shared#^_</key>
  76 + <dict>
  77 + <key>orderHint</key>
  78 + <integer>1</integer>
  79 + </dict>
  80 + </dict>
  81 +</dict>
  82 +</plist>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<Bucket
  3 + uuid = "F63F5695-7576-4143-8985-9EE894842229"
  4 + type = "1"
  5 + version = "2.0">
  6 +</Bucket>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>SchemeUserState</key>
  6 + <dict>
  7 + <key>AdBlocker.xcscheme_^#shared#^_</key>
  8 + <dict>
  9 + <key>orderHint</key>
  10 + <integer>1</integer>
  11 + </dict>
  12 + <key>GettingStarted (Playground) 1.xcscheme</key>
  13 + <dict>
  14 + <key>isShown</key>
  15 + <false/>
  16 + <key>orderHint</key>
  17 + <integer>6</integer>
  18 + </dict>
  19 + <key>GettingStarted (Playground) 2.xcscheme</key>
  20 + <dict>
  21 + <key>isShown</key>
  22 + <false/>
  23 + <key>orderHint</key>
  24 + <integer>7</integer>
  25 + </dict>
  26 + <key>GettingStarted (Playground).xcscheme</key>
  27 + <dict>
  28 + <key>isShown</key>
  29 + <false/>
  30 + <key>orderHint</key>
  31 + <integer>5</integer>
  32 + </dict>
  33 + <key>SnapKitPlayground (Playground) 1.xcscheme</key>
  34 + <dict>
  35 + <key>isShown</key>
  36 + <false/>
  37 + <key>orderHint</key>
  38 + <integer>3</integer>
  39 + </dict>
  40 + <key>SnapKitPlayground (Playground) 2.xcscheme</key>
  41 + <dict>
  42 + <key>isShown</key>
  43 + <false/>
  44 + <key>orderHint</key>
  45 + <integer>4</integer>
  46 + </dict>
  47 + <key>SnapKitPlayground (Playground).xcscheme</key>
  48 + <dict>
  49 + <key>isShown</key>
  50 + <false/>
  51 + <key>orderHint</key>
  52 + <integer>2</integer>
  53 + </dict>
  54 + <key>browser.xcscheme_^#shared#^_</key>
  55 + <dict>
  56 + <key>orderHint</key>
  57 + <integer>0</integer>
  58 + </dict>
  59 + </dict>
  60 +</dict>
  61 +</plist>
... ...
No preview for this file type
  1 +import UIKit
  2 +
  3 +@main
  4 + class AppDelegate: UIResponder, UIApplicationDelegate {
  5 + var window: UIWindow?
  6 +
  7 + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  8 +
  9 + let screenRect = UIScreen.main.bounds
  10 + window = UIWindow(frame: screenRect)
  11 +
  12 + if let window = window {
  13 + let navigationViewController = NavigationViewController()
  14 + window.rootViewController = navigationViewController
  15 + window.makeKeyAndVisible()
  16 + }
  17 + return true
  18 + }
  19 +}
... ...
  1 +//  Transition.swift
  2 +//  browser
  3 +//
  4 +//  Created by Artem Talko on 23.11.2023.
  5 +//
  6 +
  7 +import UIKit
  8 +
  9 +
  10 +final class OpenTabsTransition: NSObject, UIViewControllerAnimatedTransitioning {
  11 + private var operation: UINavigationController.Operation
  12 +
  13 + init( operation: UINavigationController.Operation ) {
  14 + self.operation = operation
  15 + super.init()
  16 + }
  17 +
  18 + func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
  19 + return 0.4
  20 + }
  21 +
  22 + func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
  23 + guard let toController = transitionContext.viewController(forKey: .to),
  24 + let fromController = transitionContext.viewController(forKey: .from) else {
  25 + transitionContext.completeTransition(true)
  26 + return
  27 + }
  28 + switch operation {
  29 + case .push :
  30 + pushController(fromController: fromController, toController: toController, transitionContext: transitionContext)
  31 + case .pop:
  32 + popController(fromController: fromController, toController: toController, transitionContext: transitionContext)
  33 + case .none:
  34 + transitionContext.completeTransition(true)
  35 + return
  36 + @unknown default:
  37 + break
  38 + }
  39 + }
  40 +}
  41 +
  42 +
  43 +//MARK: animation handlers
  44 +extension OpenTabsTransition {
  45 + private func pushController(fromController: UIViewController, toController: UIViewController, transitionContext: UIViewControllerContextTransitioning) {
  46 + let container = transitionContext.containerView
  47 + guard let tabsController = fromController as? TabsViewController else {
  48 + transitionContext.completeTransition(true)
  49 + return
  50 + }
  51 + guard let browserHomeController = toController as? BrowserHomeViewController else {
  52 + transitionContext.completeTransition(true)
  53 + return
  54 + }
  55 + let cellIndexPathForTransition = tabsController.getCellIndex()
  56 +
  57 + container.insertSubview(browserHomeController.mainView, at: 0)
  58 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
  59 + let tabsCollectionView = tabsController.mainView.openedTabsCollectionView
  60 + tabsCollectionView.scrollToItem(at: cellIndexPathForTransition, at: .bottom, animated: false)
  61 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
  62 + let cell = tabsController.mainView.openedTabsCollectionView.cellForItem(at: cellIndexPathForTransition)
  63 + let browserHomeImage = UIImageView()
  64 + browserHomeImage.image = SnapshotService.shared.makeSnapshot(browserHomeController.mainView)
  65 +
  66 + guard let lastTab = cell as? OpenedTabsCollectionViewCell else {
  67 + return
  68 + }
  69 + lastTab.isHidden = true
  70 +
  71 + container.addSubview(browserHomeImage)
  72 + browserHomeImage.frame = lastTab.frame
  73 + UIView.animate(withDuration: 0.2) {
  74 + browserHomeImage.frame = UIScreen.main.bounds
  75 + } completion: { _ in
  76 + browserHomeImage.removeFromSuperview()
  77 + lastTab.isHidden = false
  78 + transitionContext.completeTransition(true)
  79 + }
  80 + }
  81 + }
  82 + }
  83 +
  84 + private func popController(fromController: UIViewController, toController: UIViewController, transitionContext: UIViewControllerContextTransitioning) {
  85 + let container = transitionContext.containerView
  86 + guard let tabsController = toController as? TabsViewController else {
  87 + transitionContext.completeTransition(true)
  88 + return
  89 + }
  90 + guard let browserHomeController = fromController as? BrowserHomeViewController else {
  91 + transitionContext.completeTransition(true)
  92 + return
  93 + }
  94 + let cellIndexPathForTransition = tabsController.getCellIndex()
  95 +
  96 + container.insertSubview(tabsController.mainView, at: 0)
  97 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
  98 + let tabsCollectionView = tabsController.mainView.openedTabsCollectionView
  99 + tabsCollectionView.scrollToItem(at: cellIndexPathForTransition, at: .bottom, animated: false)
  100 + let lastItemIndex = tabsController.getCellIndex()
  101 +
  102 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
  103 + let cell = tabsController.mainView.openedTabsCollectionView.cellForItem(at: lastItemIndex)
  104 + let browserHomeImage = UIImageView()
  105 + browserHomeImage.image = SnapshotService.shared.makeSnapshot(browserHomeController.mainView)
  106 +
  107 + guard let lastTab = cell as? OpenedTabsCollectionViewCell else {
  108 + return
  109 + }
  110 + lastTab.isHidden = true
  111 +
  112 + container.addSubview(browserHomeImage)
  113 + browserHomeImage.frame = browserHomeController.mainView.frame
  114 + UIView.animate(withDuration: 0.2) {
  115 + fromController.view.isHidden = true
  116 + browserHomeImage.frame = lastTab.convertFrameToScreenCoordinates() ?? CGRect()
  117 + } completion: { _ in
  118 + browserHomeImage.removeFromSuperview()
  119 + lastTab.isHidden = false
  120 + transitionContext.completeTransition(true)
  121 + }
  122 + }
  123 + }
  124 + }
  125 +}
  126 +
... ...
  1 +//
  2 +// BrowserTab.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 02.10.2023.
  6 +//
  7 +
  8 +
  9 +import UIKit
  10 +import Realm
  11 +import RealmSwift
  12 +
  13 +class BrowserTabDataBase: Object {
  14 + @Persisted(primaryKey: true) var tabId: String = UUID().uuidString
  15 + @Persisted var tabTitle: String
  16 + @Persisted var TabUrl: String
  17 + @Persisted var snapshotImageData: Data?
  18 +
  19 + convenience init(tabTitle: String, snapshotImage: UIImage?, tabUrl: String) {
  20 + self.init()
  21 + self.tabTitle = tabTitle
  22 + self.TabUrl = tabUrl
  23 + if let image = snapshotImage {
  24 + self.snapshotImageData = image.pngData()
  25 + }
  26 + }
  27 +}
... ...
  1 +//
  2 +// HistoryDataBase.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 16.10.2023.
  6 +//
  7 +
  8 +
  9 +import UIKit
  10 +import Realm
  11 +import RealmSwift
  12 +
  13 +class HistoryDataBase: Object {
  14 + @Persisted(primaryKey: true) var historyCellId: String = UUID().uuidString
  15 + @Persisted var siteTitle: String
  16 + @Persisted var siteUrl: String
  17 + @Persisted var lastVisit: Date
  18 +
  19 + convenience init(siteTitle: String, siteUrl: String, lastVisit: Date) {
  20 + self.init()
  21 + self.siteTitle = siteTitle
  22 + self.siteUrl = siteUrl
  23 + self.lastVisit = lastVisit
  24 + }
  25 +}
  26 +
... ...
  1 +//
  2 +// File.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 27.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +
  11 +extension BinaryFloatingPoint {
  12 + private var size: CGSize {
  13 + return CGSize(width: 375, height: 812)
  14 + }
  15 +
  16 + var sizeW: CGFloat {
  17 + (CGFloat(self) * UIScreen.main.bounds.width / size.width)
  18 + }
  19 +
  20 + var sizeH: CGFloat {
  21 + (CGFloat(self) * UIScreen.main.bounds.height / size.height)
  22 + }
  23 +
  24 + var lessThanOrEqualToSizeW: CGFloat {
  25 + UIScreen.main.bounds.width < size.width ? self.sizeW : CGFloat(self)
  26 + }
  27 +
  28 + var lessThanOrEqualToSizeH: CGFloat {
  29 + UIScreen.main.bounds.height < size.height ? self.sizeH : CGFloat(self)
  30 + }
  31 +}
  32 +
  33 +extension BinaryInteger {
  34 + var sizeW: CGFloat {
  35 + CGFloat(self).sizeW
  36 + }
  37 +
  38 + var sizeH: CGFloat {
  39 + CGFloat(self).sizeH
  40 + }
  41 +
  42 + var lessThanOrEqualToSizeW: CGFloat {
  43 + CGFloat(self).lessThanOrEqualToSizeW
  44 + }
  45 +
  46 + var lessThanOrEqualToSizeH: CGFloat {
  47 + CGFloat(self).lessThanOrEqualToSizeH
  48 + }
  49 +}
... ...
  1 +//
  2 +// DataExtention.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 13.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +extension Data {
  11 + func toImage() -> UIImage? {
  12 + return UIImage(data: self)
  13 + }
  14 +}
... ...
  1 +//
  2 +// UIView+convertFrameToScreenCoordinates.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 30.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +extension UICollectionViewCell {
  11 + func convertFrameToScreenCoordinates() -> CGRect? {
  12 + guard let rootView = UIApplication.shared.keyWindow?.rootViewController?.view else {
  13 + return nil
  14 + }
  15 +
  16 + let convertedOrigin = convert(bounds.origin, to: rootView)
  17 + return CGRect(origin: convertedOrigin, size: bounds.size)
  18 + }
  19 +
  20 + func convertRectToFullScreen(_ rect: CGRect) -> CGRect? {
  21 + guard let window = UIApplication.shared.windows.first else {
  22 + return nil
  23 + }
  24 +
  25 + let rectInWindow = convert(rect, to: window)
  26 + let fullScreenRect = window.convert(rectInWindow, to: UIScreen.main.coordinateSpace)
  27 +
  28 + return fullScreenRect
  29 + }
  30 +}
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>NSAppTransportSecurity</key>
  6 + <dict>
  7 + <key>NSAllowsArbitraryLoads</key>
  8 + <true/>
  9 + <key>NSAllowsArbitraryLoadsForMedia</key>
  10 + <true/>
  11 + </dict>
  12 + <key>UIAppFonts</key>
  13 + <array>
  14 + <string>FontsFree-Net-SFProText-Semibold.ttf</string>
  15 + <string>FontsFree-Net-SFProText-Regular.ttf</string>
  16 + </array>
  17 +</dict>
  18 +</plist>
... ...
  1 +//
  2 +// FirstTimeOpen.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 27.09.2023.
  6 +//
  7 +
  8 +import Foundation
  9 +
  10 +final class CachingManager {
  11 + private enum Keys {
  12 + static let isFirstAppLoad = "IsFirstAppLoad"
  13 + static let isAdBlocking = "IsAdBlocking"
  14 + }
  15 +
  16 + static let shared = CachingManager()
  17 + private let userDefaults = UserDefaults.standard
  18 +
  19 + var isFirstAppLoad: Bool {
  20 + get { return userDefaults.bool(forKey: Keys.isFirstAppLoad) }
  21 + set { userDefaults.set(newValue, forKey: Keys.isFirstAppLoad) }
  22 + }
  23 + var isAdBlocking: Bool {
  24 + get { return userDefaults.bool(forKey: Keys.isAdBlocking) }
  25 + set { userDefaults.set(newValue, forKey: Keys.isAdBlocking) }
  26 + }
  27 +}
... ...
  1 +//
  2 +// DateManager.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 17.10.2023.
  6 +//
  7 +
  8 +import Foundation
  9 +
  10 +
  11 +final class DateManager {
  12 + static let shared = DateManager()
  13 +
  14 + func getTimeFromDB(_ date: Date?) -> String {
  15 + let timeFormatter = DateFormatter()
  16 + timeFormatter.dateFormat = "h:mm a"
  17 + return timeFormatter.string(from: date ?? Date())
  18 + }
  19 +
  20 + var dateFormatter: DateFormatter{
  21 + let obj = DateFormatter()
  22 + obj.dateFormat = "EEEE, d MMM"
  23 + return obj
  24 + }
  25 +
  26 + var currentDate: Date {
  27 + let obj = Date()
  28 + return obj
  29 + }
  30 +}
  31 +
  32 +
  33 +
... ...
  1 +//
  2 +// HistoryDBManager.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 17.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import Realm
  10 +import RealmSwift
  11 +
  12 +class HistoryDBManager {
  13 + static let shared = HistoryDBManager()
  14 + private let realm: Realm
  15 +
  16 +
  17 +
  18 + private init() {
  19 + do {
  20 + self.realm = try Realm()
  21 + } catch {
  22 + fatalError("Error initializing Realm: \(error.localizedDescription)")
  23 + }
  24 + }
  25 +
  26 + //MARK: ADDING
  27 + func saveToHistory(siteTitle: String, siteUrl: String, lastVisit: Date) {
  28 + let historyCell = HistoryDataBase(siteTitle: siteTitle, siteUrl: siteUrl, lastVisit: lastVisit)
  29 + do {
  30 + try realm.write {
  31 + realm.add(historyCell)
  32 + }
  33 +
  34 + } catch {
  35 + print("Error adding new tab: \(error.localizedDescription)")
  36 + }
  37 + }
  38 +
  39 + //MARK: GETTING
  40 + func getHistory(sorted: Bool = false) -> [HistoryDataBase] {
  41 + if sorted {
  42 + let history = realm.objects(HistoryDataBase.self).sorted(byKeyPath: "lastVisit", ascending: false)
  43 + return Array(history)
  44 + } else {
  45 + let history = realm.objects(HistoryDataBase.self)
  46 + return Array(history)
  47 + }
  48 + }
  49 +
  50 + func getHistoryDataForTableView() -> ([HistoryElement]) {
  51 + let stories = getHistory(sorted: true)
  52 + return createHistoryData(elements: Array(stories))
  53 + }
  54 +
  55 + func createHistoryData(elements: [HistoryDataBase]) -> ([HistoryElement]) {
  56 + var groupedData: [String: [HistoryDataBase]] = [:]
  57 + let dateFormatter = DateManager.shared.dateFormatter
  58 +
  59 + for data in elements {
  60 + let formattedDate = dateFormatter.string(from: data.lastVisit)
  61 + if groupedData[formattedDate] == nil {
  62 + groupedData[formattedDate] = []
  63 + }
  64 + groupedData[formattedDate]?.append(data)
  65 + }
  66 +
  67 + let result = groupedData.map({ HistoryElement( name: $0.key, stories: $0.value )})
  68 +
  69 + return result
  70 + }
  71 +
  72 + func getFilteredHistory(filter: String) -> ([HistoryElement]) {
  73 + let lowercasedFilter = filter.lowercased()
  74 + let history = getHistory(sorted: true)
  75 + let filteredHistory = history.filter({ $0.siteTitle.lowercased().contains(lowercasedFilter) || $0.siteUrl.lowercased().contains(lowercasedFilter)})
  76 + return createHistoryData(elements: filteredHistory)
  77 + }
  78 +
  79 + //MARK: DELETING
  80 + func cleanHistory() {
  81 + do {
  82 + let history = realm.objects(HistoryDataBase.self)
  83 + try realm.write {
  84 + realm.delete(history)
  85 + }
  86 +
  87 + } catch {
  88 + print("Error cleaning history: \(error.localizedDescription)")
  89 + }
  90 + }
  91 +
  92 + func deleteHistoryInRange(startDate: Date) {
  93 + do {
  94 + let history = realm.objects(HistoryDataBase.self).filter("lastVisit >= %@", startDate)
  95 + try realm.write {
  96 + realm.delete(history)
  97 + }
  98 +
  99 + } catch {
  100 + print("Error deleting history within the specified time range: \(error.localizedDescription)")
  101 + }
  102 + }
  103 +
  104 + func deleteHistoryCell(tabId: String) {
  105 + if let historyCellToDelete = realm.object(ofType: HistoryDataBase.self, forPrimaryKey: tabId) {
  106 + do {
  107 + try realm.write {
  108 + realm.delete(historyCellToDelete)
  109 + }
  110 +
  111 + } catch {
  112 + print("Error deleting history cell: \(error.localizedDescription)")
  113 + }
  114 + }
  115 + }
  116 +
  117 +
  118 +}
  119 +
... ...
  1 +//
  2 +// DataBaseManager.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 02.10.2023.
  6 +//
  7 +
  8 +import Realm
  9 +import RealmSwift
  10 +import Alamofire
  11 +import UIKit
  12 +
  13 +final class TabManager {
  14 + static let shared = TabManager()
  15 + private let realm: Realm
  16 +
  17 +
  18 + private init() {
  19 + do {
  20 + self.realm = try Realm()
  21 + } catch {
  22 + fatalError("Error initializing Realm: \(error.localizedDescription)")
  23 + }
  24 + }
  25 +
  26 +
  27 + func saveTabWithComplition(tabTitle: String, snapshotImage: UIImage?, tabUrl: String, completion: (Result<Void,Error>) -> Void) {
  28 + let newTab = BrowserTabDataBase(tabTitle: tabTitle, snapshotImage: snapshotImage, tabUrl: tabUrl)
  29 +
  30 + do {
  31 + try realm.write {
  32 + realm.add(newTab)
  33 + completion(.success(()))
  34 + }
  35 + } catch {
  36 + print("Error adding new tab: \(error.localizedDescription)")
  37 + completion(.failure(error))
  38 + }
  39 + }
  40 +
  41 + func saveTab(tabTitle: String, snapshotImage: UIImage?, tabUrl: String) {
  42 + let newTab = BrowserTabDataBase(tabTitle: tabTitle, snapshotImage: snapshotImage, tabUrl: tabUrl)
  43 +
  44 + do {
  45 + try realm.write {
  46 + realm.add(newTab)
  47 + }
  48 + } catch {
  49 + print("Error adding new tab: \(error.localizedDescription)")
  50 + }
  51 + }
  52 +
  53 + func updateTab(tabId: String, newTabTitle: String, newSnapshotImage: UIImage?, newTabUrl: String, completion: (Result<Void, Error>) -> Void) {
  54 + if let tabToUpdate = realm.object(ofType: BrowserTabDataBase.self, forPrimaryKey: tabId) {
  55 + do {
  56 + try realm.write {
  57 + tabToUpdate.tabTitle = newTabTitle
  58 + tabToUpdate.TabUrl = newTabUrl
  59 + if let image = newSnapshotImage {
  60 + tabToUpdate.snapshotImageData = image.pngData()
  61 + }
  62 + completion(.success(()))
  63 + }
  64 + } catch {
  65 + print("Error updating tab: \(error.localizedDescription)")
  66 + completion(.failure(error))
  67 + }
  68 + } else {
  69 + let error = NSError(domain: "Error", code: 404, userInfo: [NSLocalizedDescriptionKey: "Tab not found"])
  70 + completion(.failure(error))
  71 + }
  72 + }
  73 +
  74 + func getAllTabs() -> [BrowserTabDataBase] {
  75 + let savedTabs = realm.objects(BrowserTabDataBase.self)
  76 + return Array(savedTabs)
  77 + }
  78 +
  79 + func deleteTab(tabId: String) {
  80 + if let tabToDelete = realm.object(ofType: BrowserTabDataBase.self, forPrimaryKey: tabId) {
  81 + do {
  82 + try realm.write {
  83 + realm.delete(tabToDelete)
  84 + }
  85 + } catch {
  86 + print("Error deleting tab: \(error.localizedDescription)")
  87 + }
  88 + }
  89 + }
  90 +}
  91 +
... ...
  1 +//
  2 +// HistoryElement.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 20.10.2023.
  6 +//
  7 +
  8 +import Foundation
  9 +
  10 +struct HistoryElement {
  11 + var name: String
  12 + var stories: [HistoryDataBase]
  13 +}
... ...
  1 +//
  2 +// HistoryToolbar.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 14.11.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +enum menuCases: CaseIterable {
  11 + case allTime
  12 + case lastMonth
  13 + case todayAndYesterday
  14 + case today
  15 + case lastHour
  16 + //MARK: todo
  17 + var action: UIAction {
  18 + switch self {
  19 + case .allTime:
  20 + return UIAction(title: "All time") { _ in
  21 + HistoryDBManager.shared.cleanHistory()
  22 +
  23 + }
  24 + case .lastMonth:
  25 + return UIAction(title: "The last 30 days") { _ in
  26 + let lastMonth = Calendar.current.date(byAdding: .day, value: -30, to: Date()) ?? Date()
  27 + HistoryDBManager.shared.deleteHistoryInRange(startDate: lastMonth)
  28 + }
  29 + case .todayAndYesterday:
  30 + return UIAction(title: "Today and yesterday") { _ in
  31 + let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date()) ?? Date()
  32 + HistoryDBManager.shared.deleteHistoryInRange(startDate: yesterday)
  33 + }
  34 + case .today:
  35 + return UIAction(title: "Today") { _ in
  36 + let startOfToday = Calendar.current.startOfDay(for: Date())
  37 + HistoryDBManager.shared.deleteHistoryInRange(startDate: startOfToday)
  38 + }
  39 + case .lastHour:
  40 + return UIAction(title: "The last hour") { _ in
  41 + let lastHour = Calendar.current.date(byAdding: .hour, value: -1, to: Date()) ?? Date()
  42 + HistoryDBManager.shared.deleteHistoryInRange(startDate: lastHour)
  43 + }
  44 + }
  45 + }
  46 +}
... ...
  1 +//
  2 +// HistoryViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import RealmSwift
  10 +
  11 +final class HistoryViewController: UIViewController {
  12 + private let mainView = HistoryView()
  13 +
  14 + private var objectNotificationToken: NotificationToken?
  15 +
  16 + private var historyData: [HistoryElement] = [] {
  17 + didSet {
  18 + filteredData = historyData
  19 + }
  20 + }
  21 + private var filteredData: [HistoryElement] = [] {
  22 + didSet {
  23 + mainView.historyTabsTableView.reloadData()
  24 + }
  25 + }
  26 +
  27 + override func viewWillAppear(_ animated: Bool) {
  28 + super.viewWillAppear(animated)
  29 + navigationController?.isNavigationBarHidden = false
  30 + navigationItem.title = "History"
  31 + }
  32 +
  33 + override func viewDidLoad() {
  34 + super.viewDidLoad()
  35 + initViewController()
  36 + }
  37 +
  38 + private func initViewController() {
  39 + setupTableView()
  40 + addTargets()
  41 + setupSearchBar()
  42 + historyData = HistoryDBManager.shared.getHistoryDataForTableView()
  43 + historyChangesObserve()
  44 + }
  45 +
  46 + override func loadView() {
  47 + view = mainView
  48 + view.backgroundColor = .white
  49 + navigationController?.isNavigationBarHidden = false
  50 + navigationItem.title = "History"
  51 + // historyChangesObserve()
  52 + }
  53 +
  54 + init() {
  55 + super.init(nibName: nil, bundle: nil)
  56 + }
  57 +
  58 + required init?(coder: NSCoder) {
  59 + fatalError("init(coder:) has not been implemented")
  60 + }
  61 +}
  62 +
  63 +//MARK: - TableView Extention
  64 +extension HistoryViewController: UITableViewDelegate, UITableViewDataSource {
  65 +
  66 + func numberOfSections(in tableView: UITableView) -> Int {
  67 + return filteredData.count
  68 + }
  69 +
  70 + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
  71 + return filteredData[section].name
  72 + }
  73 +
  74 + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  75 + return filteredData[section].stories.count
  76 + }
  77 +
  78 + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  79 + guard let cell = tableView.dequeueReusableCell(withIdentifier: "HistoryTableViewCell", for: indexPath) as? HistoryTableViewCell else {
  80 + return HistoryTableViewCell()
  81 + }
  82 + let row = indexPath.row
  83 + let section = indexPath.section
  84 +
  85 + cell.model = filteredData[section].stories[row]
  86 +
  87 + return cell
  88 + }
  89 +
  90 + private func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
  91 + return true
  92 + }
  93 +
  94 + func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
  95 + if (editingStyle == .delete) {
  96 + let row = indexPath.row
  97 + let section = indexPath.section
  98 + let historyCellData = filteredData[section].stories[row]
  99 + let tabId = historyCellData.historyCellId
  100 + HistoryDBManager.shared.deleteHistoryCell(tabId: tabId)
  101 + filteredData[section].stories.remove(at: row)
  102 + mainView.historyTabsTableView.reloadData()
  103 + }
  104 + }
  105 +
  106 + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  107 + let section = indexPath.section
  108 + let index = indexPath.row
  109 + let urlForFunc = historyData[section].stories[index].siteUrl
  110 + if let navigationController = presentingViewController as? NavigationViewController {
  111 + for viewController in navigationController.viewControllers {
  112 + if let browserHomeViewController = viewController as? BrowserHomeViewController {
  113 + browserHomeViewController.urlManagment(urlForFunc)
  114 + }
  115 + }
  116 + dismiss(animated: true)
  117 + }
  118 + }
  119 +
  120 + func setupTableView() {
  121 + mainView.historyTabsTableView.dataSource = self
  122 + mainView.historyTabsTableView.delegate = self
  123 + mainView.historyTabsTableView.register(HistoryTableViewCell.self, forCellReuseIdentifier: StringConstants.historyTableViewCell)
  124 + }
  125 +}
  126 +
  127 +
  128 +
  129 +//MARK: Helper
  130 +extension HistoryViewController {
  131 + private func addTargets() {
  132 + mainView.historySearchBar.searchTextFieldView.addTarget(self, action: #selector(searchBarTextChanged), for: .editingChanged)
  133 + addToolbarTargets()
  134 + }
  135 +
  136 + private func addToolbarTargets() {
  137 + mainView.historyToolbarView.action = didTabButtonTapped
  138 + }
  139 +}
  140 +
  141 +
  142 +//MARK: Targets
  143 +extension HistoryViewController {
  144 + func didTabButtonTapped(type: historyToolbarElementType) {
  145 + if type == .clean {
  146 + HistoryDBManager.shared.cleanHistory()
  147 + historyData.removeAll()
  148 + mainView.historyTabsTableView.reloadData()
  149 + }
  150 + }
  151 +}
  152 +
  153 +
  154 +//MARK: Action
  155 +extension HistoryViewController {
  156 + @objc
  157 + private func searchResultAction() {
  158 + mainView.historySearchBar.searchTextFieldView.text = nil
  159 + filteredData = historyData
  160 + }
  161 +
  162 + @objc private func searchBarTextChanged() {
  163 + if let text = mainView.historySearchBar.searchTextFieldView.text {
  164 + if text.isEmpty {
  165 + filteredData = historyData
  166 + } else {
  167 + filteredData = HistoryDBManager.shared.getFilteredHistory(filter: text)
  168 + }
  169 + }
  170 + }
  171 +}
  172 +
  173 +
  174 +//MARK: SearchBar
  175 +extension HistoryViewController: UITextFieldDelegate {
  176 + func textFieldDidBeginEditing(_ textField: UITextField) {
  177 + mainView.historySearchBar.searchTextFieldView.text = nil
  178 + mainView.historySearchBar.searchTextFieldView.textColor = .black
  179 + }
  180 +
  181 + func setupSearchBar() {
  182 + mainView.historySearchBar.searchTextFieldView.delegate = self
  183 + }
  184 +}
  185 +
  186 +//MARK: History DB observe
  187 +extension HistoryViewController {
  188 + func historyChangesObserve() {
  189 + let historyObjects = HistoryDBManager.shared.getHistory()
  190 + for historyObject in historyObjects {
  191 + objectNotificationToken = historyObject.observe { [self] changes in
  192 + switch changes {
  193 + case .error(let error):
  194 + print("Error observing changes in Realm: \(error)")
  195 + case .change(_, _):
  196 + break
  197 + case .deleted:
  198 + print("Object deleted in Realm")
  199 + self.historyData = HistoryDBManager.shared.getHistoryDataForTableView()
  200 + self.mainView.historyTabsTableView.reloadData()
  201 + }
  202 + }
  203 + }
  204 + }
  205 +}
... ...
  1 +//
  2 +// HistoryTableViewCell.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import SnapKit
  10 +
  11 +class HistoryTableViewCell: UITableViewCell {
  12 + var model: HistoryDataBase? {
  13 + didSet {
  14 + handleUI()
  15 + }
  16 + }
  17 +
  18 + let searchImageLogo: UIImageView = {
  19 + let obj = UIImageView()
  20 + obj.image = UIImage(systemName: "magnifyingglass")
  21 + obj.tintColor = .gray
  22 + obj.contentMode = .scaleAspectFit
  23 + return obj
  24 + }()
  25 +
  26 + let lastVisitSiteLabel: UILabel = {
  27 + let obj = UILabel()
  28 + obj.font = FontConstants.regularFont_14
  29 + return obj
  30 + }()
  31 +
  32 + let lastVisitSiteUrlLabel: UILabel = {
  33 + let obj = UILabel()
  34 + obj.textColor = .gray
  35 + obj.font = FontConstants.regularFont_12
  36 + return obj
  37 + }()
  38 +
  39 + let lastVisitDateLabel: UILabel = {
  40 + let obj = UILabel()
  41 + obj.font = FontConstants.regularFont_12
  42 + obj.textColor = .gray
  43 + return obj
  44 + }()
  45 +
  46 + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  47 + super.init(style: style, reuseIdentifier: reuseIdentifier)
  48 + setup()
  49 + }
  50 +
  51 + required init?(coder: NSCoder) {
  52 + fatalError("init(coder:) has not been implemented")
  53 + }
  54 +
  55 + private func setup() {
  56 + contentView.addSubview(searchImageLogo)
  57 + contentView.addSubview(lastVisitSiteLabel)
  58 + contentView.addSubview(lastVisitSiteUrlLabel)
  59 + contentView.addSubview(lastVisitDateLabel)
  60 + setupConstraints()
  61 + }
  62 +
  63 + private func setupConstraints() {
  64 + searchImageLogo.snp.makeConstraints { make in
  65 + make.leading.equalToSuperview().inset(8.sizeW)
  66 + make.top.equalToSuperview().inset(8.sizeH)
  67 + make.height.equalTo(18.sizeW)
  68 + make.width.equalTo(18.sizeW)
  69 + }
  70 + lastVisitSiteLabel.snp.makeConstraints { make in
  71 + make.leading.equalTo(searchImageLogo.snp.trailing).offset(8.sizeW)
  72 + make.trailing.equalTo(lastVisitDateLabel.snp.leading).offset(-8.sizeW)
  73 + make.top.equalToSuperview().inset(8.sizeH)
  74 + }
  75 + lastVisitDateLabel.snp.makeConstraints { make in
  76 + make.trailing.equalToSuperview().inset(8.sizeW)
  77 + make.top.equalToSuperview().inset(8.sizeH)
  78 + }
  79 + lastVisitSiteUrlLabel.snp.makeConstraints { make in
  80 + make.leading.equalToSuperview().offset(34.sizeW)
  81 + make.top.equalTo(lastVisitSiteLabel.snp.bottom).offset(4.sizeH)
  82 + make.bottom.equalToSuperview().inset(8.sizeH)
  83 + make.trailing.equalToSuperview().inset(61.sizeW)
  84 + }
  85 + }
  86 +}
  87 +
  88 +extension HistoryTableViewCell {
  89 + private func handleUI() {
  90 + let dateForLabel = DateManager.shared.getTimeFromDB(model?.lastVisit)
  91 + lastVisitDateLabel.text = dateForLabel
  92 + lastVisitSiteLabel.text = model?.siteTitle
  93 + lastVisitSiteUrlLabel.text = model?.siteUrl
  94 + }
  95 +}
  96 +
... ...
  1 +//
  2 +// HistorySearchBarView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 01.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class HistorySearchBarView: UIView {
  11 + let searchImageView: UIImageView = {
  12 + let obj = UIImageView()
  13 + let magnifyImage = UIImage(systemName: "magnifyingglass")?.withTintColor(.gray, renderingMode: .alwaysOriginal)
  14 + obj.image = magnifyImage
  15 + obj.contentMode = .scaleAspectFit
  16 + return obj
  17 + }()
  18 +
  19 + let searchTextFieldView: UITextField = {
  20 + let obj = UITextField()
  21 + obj.text = StringConstants.search
  22 + obj.textColor = ColorConstants.gray
  23 + return obj
  24 + }()
  25 +
  26 + override init(frame: CGRect) {
  27 + super.init(frame: frame)
  28 + setup()
  29 + setupConstraints()
  30 + }
  31 +
  32 + required init?(coder: NSCoder) {
  33 + fatalError("init(coder:) has not been implemented")
  34 + }
  35 +
  36 + private func setup() {
  37 + addSubview(searchImageView)
  38 + addSubview(searchTextFieldView)
  39 + }
  40 +
  41 + private func setupConstraints() {
  42 + searchImageView.snp.makeConstraints { make in
  43 + make.leading.equalToSuperview().offset(16.sizeW)
  44 + make.top.bottom.equalToSuperview().inset(8.sizeH)
  45 + make.height.equalTo(16.sizeH)
  46 + }
  47 + searchTextFieldView.snp.makeConstraints { make in
  48 + make.leading.equalTo(searchImageView).offset(32.sizeW)
  49 + make.trailing.equalToSuperview().offset(-16.sizeW)
  50 + make.top.bottom.equalToSuperview().inset(8.sizeH)
  51 + }
  52 + }
  53 +}
  54 +
... ...
  1 +//
  2 +// ToolbarView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +enum historyToolbarElementType {
  11 + case clean
  12 +}
  13 +
  14 +final class HistoryToolbarView: UIView {
  15 + var action: ((historyToolbarElementType) -> Void)?
  16 +
  17 + let cleanHistoryButton: UIButton = {
  18 + let obj = UIButton()
  19 + obj.setTitle("Clean", for: .normal)
  20 + obj.setTitleColor(.systemBlue, for: .normal)
  21 + let menuItems: [UIMenuElement] = menuCases.allCases.map { $0.action }
  22 + obj.menu = UIMenu(title: "Clearing will remove history, cookies and other browsing data. History will be cleared from devices signed into your iCloud Account. Clear from:", children: menuItems)
  23 + obj.showsMenuAsPrimaryAction = true
  24 + return obj
  25 + }()
  26 +
  27 + override init(frame: CGRect) {
  28 + super.init(frame: frame)
  29 + setup()
  30 + setupConstraints()
  31 + }
  32 +
  33 + required init?(coder: NSCoder) {
  34 + fatalError("init(coder:) has not been implemented")
  35 + }
  36 +
  37 + private func setup() {
  38 + backgroundColor = .white
  39 + addSubview(cleanHistoryButton)
  40 + }
  41 +
  42 + private func setupConstraints() {
  43 + cleanHistoryButton.snp.makeConstraints { make in
  44 + make.trailing.equalToSuperview().inset(20.sizeW)
  45 + make.height.equalTo(20.sizeH)
  46 + make.top.bottom.equalToSuperview()
  47 + }
  48 + }
  49 +}
  50 +
... ...
  1 +//
  2 +// HistoryView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class HistoryView: UIView {
  11 + let historySearchBar: HistorySearchBarView = {
  12 + let obj = HistorySearchBarView()
  13 + obj.layer.cornerRadius = 10
  14 + obj.backgroundColor = UIColor(red: 0.913, green: 0.913, blue: 0.947, alpha: 1)
  15 + return obj
  16 + }()
  17 +
  18 + let historyTabsTableView: UITableView = {
  19 + let obj = UITableView()
  20 + obj.separatorStyle = .none
  21 + return obj
  22 + }()
  23 +
  24 + let historyToolbarView: HistoryToolbarView = {
  25 + let obj = HistoryToolbarView()
  26 + return obj
  27 + }()
  28 +
  29 + override init(frame: CGRect) {
  30 + super.init(frame: frame)
  31 + setup()
  32 + }
  33 +
  34 + required init?(coder: NSCoder) {
  35 + fatalError("init(coder:) has not been implemented")
  36 + }
  37 +
  38 + private func setup() {
  39 + backgroundColor = .gray.withAlphaComponent(0.1)
  40 + addSubview(historySearchBar)
  41 + addSubview(historyTabsTableView)
  42 + addSubview(historyToolbarView)
  43 + setupConstraints()
  44 + }
  45 +
  46 + private func setupConstraints() {
  47 + historySearchBar.snp.makeConstraints { make in
  48 + make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(16.sizeH)
  49 + make.leading.trailing.equalToSuperview().inset(16.sizeW)
  50 + }
  51 +
  52 + historyTabsTableView.snp.makeConstraints { make in
  53 + make.top.equalTo(historySearchBar.snp.bottom).offset(32.sizeH)
  54 + make.bottom.equalTo(historyToolbarView.snp.top).inset(7.sizeH)
  55 + make.leading.trailing.equalToSuperview().inset(16.sizeW)
  56 + make.height.equalTo(600.sizeH)
  57 + }
  58 + historyToolbarView.snp.makeConstraints { make in
  59 + make.bottom.equalTo(safeAreaLayoutGuide.snp.bottom)
  60 + make.leading.trailing.equalToSuperview()
  61 + }
  62 + }
  63 +}
  64 +
  65 +//MARK: - Helpers
  66 +extension HistoryView: UITextFieldDelegate {
  67 + func textFieldDidBeginEditing(_ textField: UITextField) {
  68 + historySearchBar.searchTextFieldView.text = ""
  69 + }
  70 +}
  71 +
  72 +
... ...
  1 +//
  2 +// ViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 25.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import SnapKit
  10 +import WebKit
  11 +import Combine
  12 +import Realm
  13 +
  14 +final class BrowserHomeViewController: UIViewController {
  15 + private let images = StringConstants.browserHomeVCImages
  16 + private let searchingViewController = SearchingViewController(dataForReq: [])
  17 + private let searchResultViewController = SearchResultViewController(searchLink: String())
  18 + private var subscriptions: Set<AnyCancellable> = []
  19 + private var finalSearchRequest = URLConstants.googleURL
  20 + private let tabsViewController = TabsViewController()
  21 + private var currentTabId: Int?
  22 +
  23 + let mainView = BrowserHomeView()
  24 +
  25 + private var url: String? {
  26 + didSet {
  27 + finalSearchRequest = url ?? String()
  28 + openSearchResult()
  29 + }
  30 + }
  31 +
  32 + override func viewDidLoad() {
  33 + super.viewDidLoad()
  34 + view.backgroundColor = ColorConstants.lightGray
  35 + initViewController()
  36 + }
  37 +
  38 + override func viewWillAppear(_ animated: Bool) {
  39 + keyboardObserver()
  40 + }
  41 +
  42 + private func initViewController() {
  43 + setupCollectionView()
  44 + addTargets()
  45 + setupSearchBarComponentsAction()
  46 + setupSearchingViewController()
  47 + progressObserver()
  48 + }
  49 +
  50 + override func viewIsAppearing(_ animated: Bool) {
  51 + navigationController?.isNavigationBarHidden = true
  52 + }
  53 +
  54 + override func loadView() {
  55 + view = mainView
  56 + }
  57 +
  58 + init(url: String?, currentTabId: Int?) {
  59 + super.init(nibName: nil, bundle: nil)
  60 + self.url = url
  61 + self.currentTabId = currentTabId
  62 + }
  63 +
  64 + required init?(coder: NSCoder) {
  65 + fatalError("init(coder:) has not been implemented")
  66 + }
  67 +
  68 + override func viewWillDisappear(_ animated: Bool) {
  69 + super.viewWillDisappear(animated)
  70 + NotificationCenter.default.removeObserver(self)
  71 + }
  72 +}
  73 +
  74 +
  75 +//MARK: CollectionView Setup
  76 +extension BrowserHomeViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
  77 + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  78 + images.count
  79 + }
  80 +
  81 + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  82 + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TabCollectionViewCell", for: indexPath) as? TabCollectionViewCell else {
  83 + return TabCollectionViewCell()
  84 + }
  85 + let finalCell = setupCellForCollectionView(cell, indexPath)
  86 + return finalCell
  87 + }
  88 +
  89 + private func setupCellForCollectionView(_ cell: TabCollectionViewCell, _ indexPath: IndexPath) -> TabCollectionViewCell {
  90 + let imageName = images[indexPath.item]
  91 + cell.tabCellImage.image = UIImage(named: imageName)
  92 + cell.tabCellLabel.text = imageName
  93 + cell.backgroundColor = .white
  94 + return cell
  95 + }
  96 +
  97 + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  98 + return CGSize(width: 72.sizeW, height: 94.sizeH)
  99 + }
  100 +
  101 + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  102 + finalSearchRequest = StringConstants.browserHomeVCurl[indexPath.row]
  103 + openSearchResult()
  104 + }
  105 +
  106 + private func setupCollectionView() {
  107 + mainView.frequentlyVisitedCollectionView.dataSource = self
  108 + mainView.frequentlyVisitedCollectionView.delegate = self
  109 + mainView.frequentlyVisitedCollectionView.register(TabCollectionViewCell.self, forCellWithReuseIdentifier: "TabCollectionViewCell")
  110 + }
  111 +}
  112 +
  113 +
  114 +//MARK: - Keyboard extention
  115 +extension BrowserHomeViewController {
  116 + func keyboardObserver() {
  117 + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: UIResponder.keyboardWillHideNotification, object: nil)
  118 + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
  119 + }
  120 +}
  121 +
  122 +
  123 +//MARK: - Action
  124 +extension BrowserHomeViewController {
  125 + @objc private func searchResultAction() {
  126 + removeChildViewController()
  127 + mainView.searchBarContainer.searchBarView.searchTextFieldView.text = nil
  128 + mainView.searchBarContainer.searchBarView.cleanTextFieldButton.isHidden = true
  129 + }
  130 +
  131 + func searchAndReloadTableView() async {
  132 + let sitesFromSearch: [String] = await BrowserSearchService().searchSuggest(finalSearchRequest)
  133 + if !sitesFromSearch.isEmpty {
  134 + searchingViewController.dataForReq = sitesFromSearch
  135 + }
  136 + addingSearchingViewController(searchingViewController)
  137 + }
  138 +
  139 + @objc
  140 + func keyboardWillShow(_ notification: Notification) {
  141 + guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
  142 + let keyboardHeight = keyboardFrame.height
  143 + self.mainView.animateSearchBar(keyboardHeight)
  144 + }
  145 +
  146 + @objc
  147 + func keyboardWillDisappear() {
  148 + mainView.animateSearchBarDismiss()
  149 + }
  150 +
  151 + @objc
  152 + private func settingButtonTapped(_ sender: UIButton) {
  153 + let settingViewController = SettingViewController()
  154 + openAdditionViewController(settingViewController)
  155 + }
  156 +
  157 + @objc
  158 + private func removeAdButtonTapped(_ sender: UIButton) {
  159 + let removeAdViewController = RemoveAdvertViewController()
  160 + openAdditionViewController(removeAdViewController)
  161 + }
  162 +
  163 + @objc
  164 + private func removeSearchingViewController(_ sender: UIButton) {
  165 + searchResultAction()
  166 + }
  167 +
  168 + func didTabButtonTapped(type: ToolbarElementType) {
  169 + switch type {
  170 + case .history:
  171 + let historyViewController = HistoryViewController()
  172 + present(historyViewController, animated: true, completion: nil)
  173 + break
  174 + case .tabs:
  175 + tabsButtonHandler()
  176 + break
  177 + case .back:
  178 + searchResultViewController.mainView.searchResultView.goBack()
  179 + break
  180 + case .forward:
  181 + searchResultViewController.mainView.searchResultView.goForward()
  182 + break
  183 + case .share:
  184 + let items = [URL(string: finalSearchRequest)]
  185 + let shareView = UIActivityViewController(activityItems: items as [Any], applicationActivities: nil)
  186 + present(shareView, animated: true)
  187 + break
  188 + }
  189 + }
  190 +}
  191 +
  192 +
  193 +//MARK: - Helpers
  194 +extension BrowserHomeViewController {
  195 + private func addTargets() {
  196 + mainView.settingButton.addTarget(self, action: #selector(settingButtonTapped(_ :)), for: .touchUpInside)
  197 + mainView.removeAddButton.addTarget(self, action: #selector(removeAdButtonTapped(_ :)), for: .touchUpInside)
  198 + mainView.searchBarContainer.searchBarView.searchTextFieldView.addTarget(self, action: #selector(searchBarTextChanged), for: .editingChanged)
  199 + searchingViewController.mainView.searchingButton.addTarget(self, action: #selector(removeSearchingViewController(_ :)), for: .touchUpInside)
  200 + addToolbarTargets()
  201 + }
  202 +
  203 + private func addToolbarTargets() {
  204 + mainView.toolbarView.action = didTabButtonTapped
  205 + }
  206 +
  207 + private func openAdditionViewController(_ viewController: UIViewController) {
  208 + viewController.modalPresentationStyle = .fullScreen
  209 + present(viewController, animated: true, completion: nil)
  210 + }
  211 +
  212 + private func setupSearchingViewController() {
  213 + searchingViewController.searchCell = { [self] cell in
  214 + guard let cell = cell as? SearchingTableViewCell else {
  215 + return
  216 + }
  217 + finalSearchRequest = "https://www.google.com/search?q=" + (cell.searchLabel.text ?? "")
  218 + openSearchResult()
  219 + mainView.searchBarContainer.searchBarView.searchTextFieldView.endEditing(true)
  220 + }
  221 + }
  222 +
  223 + private func openSearchResult() {
  224 + let finalSearchRequest = finalSearchRequest.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
  225 + searchResultViewController.searchLink = finalSearchRequest ?? ""
  226 + if let localUrl = URL(string: finalSearchRequest ?? "") {
  227 + let request = URLRequest(url: localUrl)
  228 + print(request)
  229 + searchResultViewController.mainView.searchResultView.load(request)
  230 + }
  231 + addingSearchingViewController(searchResultViewController)
  232 + }
  233 +
  234 + private func tabsButtonHandler() {
  235 + if currentTabId == nil {
  236 + addNewTab()
  237 + navigationController?.popViewController(animated: true)
  238 + } else {
  239 + updateCurrentTab()
  240 + }
  241 + }
  242 +
  243 + private func addNewTab() {
  244 + if let childViewController = self.children.first as? SearchResultViewController {
  245 + guard let siteTitle = childViewController.mainView.searchResultView.title else {
  246 + return
  247 + }
  248 + guard let siteUrl = childViewController.mainView.searchResultView.url else {
  249 + return
  250 + }
  251 + let finalUrl = siteUrl.absoluteString
  252 + let lastVisit = DateManager.shared.currentDate
  253 + let wkWVForSnapshot = childViewController.mainView.searchResultView
  254 +
  255 + SnapshotService.shared.makeWKWebViewSnapshot(wkWVForSnapshot) { snapshotForDB in
  256 + TabManager.shared.saveTab(tabTitle: siteTitle, snapshotImage: snapshotForDB, tabUrl: finalUrl)
  257 + }
  258 + HistoryDBManager.shared.saveToHistory(siteTitle: siteTitle, siteUrl: finalUrl, lastVisit: lastVisit)
  259 + } else {
  260 + let homeViewSnapshot = SnapshotService.shared.makeSnapshot(mainView)
  261 + TabManager.shared.saveTab(tabTitle: "Start Page", snapshotImage: homeViewSnapshot, tabUrl: "homeUrl")
  262 + currentTabId = tabsViewController.getCellIndex().row
  263 + }
  264 + }
  265 +
  266 + private func updateCurrentTab() {
  267 + let allTabs = TabManager.shared.getAllTabs()
  268 + let chosenTab = allTabs[self.currentTabId ?? Int()]
  269 + let gottedCellId = chosenTab.tabId
  270 + let imageForUpdatedTab = SnapshotService.shared.makeSnapshot(self.mainView)
  271 + if let childViewController = self.children.first as? SearchResultViewController {
  272 + guard let siteTitle = childViewController.mainView.searchResultView.title else {
  273 + return
  274 + }
  275 + guard let siteUrl = childViewController.mainView.searchResultView.url?.absoluteString else {
  276 + return
  277 + }
  278 + let lastDate = DateManager.shared.currentDate
  279 +
  280 + TabManager.shared.updateTab(tabId: gottedCellId, newTabTitle: siteTitle, newSnapshotImage: imageForUpdatedTab, newTabUrl: siteUrl) { result in
  281 + self.navigationController?.popViewController(animated: true)
  282 + }
  283 + HistoryDBManager.shared.saveToHistory(siteTitle: siteTitle, siteUrl: siteUrl, lastVisit: lastDate)
  284 + } else {
  285 + TabManager.shared.updateTab(tabId: gottedCellId, newTabTitle: "Start Page", newSnapshotImage: imageForUpdatedTab, newTabUrl: "homeUrl") { result in
  286 + self.navigationController?.popViewController(animated: true)
  287 + }
  288 + }
  289 + }
  290 +}
  291 +
  292 +
  293 +//MARK: - ChildVC actions
  294 +extension BrowserHomeViewController {
  295 + func addingSearchingViewController(_ childViewController: UIViewController) {
  296 + if self.children.isEmpty {
  297 + addNewChildViewController(childViewController)
  298 + } else {
  299 + removeChildViewController()
  300 + addNewChildViewController(childViewController)
  301 + }
  302 + }
  303 +
  304 + func addNewChildViewController(_ child: UIViewController) {
  305 + addChild(child)
  306 + mainView.addSearchView(child.view)
  307 + child.didMove(toParent: self)
  308 + }
  309 +
  310 + func removeChildViewController() {
  311 + if let childViewController = self.children.first as? SearchingViewController {
  312 + childViewController.view.removeFromSuperview()
  313 + childViewController.willMove(toParent: nil)
  314 + childViewController.removeFromParent()
  315 + }
  316 + if let childViewController = self.children.first as? SearchResultViewController {
  317 + childViewController.view.removeFromSuperview()
  318 + childViewController.willMove(toParent: nil)
  319 + childViewController.removeFromParent()
  320 + }
  321 + }
  322 +}
  323 +
  324 +
  325 +//MARK: - SearchBar extention
  326 +extension BrowserHomeViewController: UITextFieldDelegate {
  327 + @objc
  328 + func searchBarTextChanged() {
  329 + if let text = mainView.searchBarContainer.searchBarView.searchTextFieldView.text {
  330 + finalSearchRequest = text
  331 + mainView.searchBarContainer.searchBarView.cleanTextFieldButton.isHidden = false
  332 + if finalSearchRequest.isEmpty {
  333 + searchResultAction()
  334 + } else {
  335 + Task {
  336 + await searchAndReloadTableView()
  337 + }
  338 + }
  339 + }
  340 + }
  341 +
  342 + func textFieldDidBeginEditing(_ textField: UITextField) {
  343 + mainView.searchBarContainer.searchBarView.searchTextFieldView.text = nil
  344 + mainView.searchBarContainer.searchBarView.searchTextFieldView.textColor = .black
  345 + }
  346 +
  347 + func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  348 + finalSearchRequest = "https://www.google.com/search?q=" + (textField.text ?? "")
  349 + openSearchResult()
  350 + textField.resignFirstResponder()
  351 + return true
  352 + }
  353 +
  354 + func setupSearchBarComponentsAction() {
  355 + mainView.searchBarContainer.searchBarView.searchTextFieldView.autocorrectionType = .no
  356 + isButtonClickable()
  357 + mainView.searchBarContainer.searchBarView.searchTextFieldView.delegate = self
  358 + mainView.searchBarContainer.searchBarView.cleanTextFieldButton.addTarget(self, action: #selector(searchResultAction), for: .touchUpInside)
  359 + }
  360 +}
  361 +
  362 +
  363 +//MARK: - WebView extention
  364 +extension BrowserHomeViewController {
  365 + func isButtonClickable() {
  366 + searchResultViewController.mainView.searchResultView
  367 + .publisher(for: \.canGoBack)
  368 + .sink { [weak self] canGoBack in
  369 + self?.mainView.toolbarView.backBarButtonItem.isEnabled = canGoBack
  370 + }
  371 + .store(in: &subscriptions)
  372 +
  373 + searchResultViewController.mainView.searchResultView
  374 + .publisher(for: \.canGoForward)
  375 + .sink { [weak self] canGoForward in
  376 + self?.mainView.toolbarView.forwardBarButtonItem.isEnabled = canGoForward
  377 + }
  378 + .store(in: &subscriptions)
  379 +
  380 + searchResultViewController.mainView.searchResultView
  381 + .publisher(for: \.isLoading)
  382 + .sink { [weak self] isLoading in
  383 + guard let self = self else { return }
  384 + if let url = self.searchResultViewController.mainView.searchResultView.url {
  385 + self.finalSearchRequest = url.absoluteString
  386 + }
  387 + }
  388 + .store(in: &subscriptions)
  389 + }
  390 +
  391 + private func progressObserver() {
  392 + searchResultViewController.mainView.searchResultView
  393 + .publisher(for: \.estimatedProgress)
  394 + .sink { [weak self] progress in
  395 + guard let self = self else { return }
  396 + self.mainView.searchBarContainer.searchBarView.progressBar.progress = Float(progress)
  397 + if progress == 1 {
  398 + self.mainView.searchBarContainer.searchBarView.progressBar.isHidden = true
  399 + self.mainView.toolbarView.shareBarButtonItem.isEnabled = true
  400 + } else if progress == 0 {
  401 + self.mainView.searchBarContainer.searchBarView.progressBar.isHidden = true
  402 + } else {
  403 + self.mainView.searchBarContainer.searchBarView.progressBar.isHidden = false
  404 + self.mainView.toolbarView.shareBarButtonItem.isEnabled = false
  405 + }
  406 + }
  407 + .store(in: &subscriptions)
  408 + }
  409 + }
  410 +
  411 +extension BrowserHomeViewController {
  412 + func urlManagment(_ url: String) {
  413 + finalSearchRequest = url
  414 + openSearchResult()
  415 + }
  416 +}
... ...
  1 +//
  2 +// MainView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 25.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import SnapKit
  10 +
  11 +final class BrowserHomeView: UIView {
  12 + let removeAddButton: UIButton = {
  13 + let obj = UIButton()
  14 + obj.backgroundColor = ColorConstants.buttonsBackgroundColor
  15 + obj.setTitle("Remove advert", for: .normal)
  16 + obj.titleLabel?.font = FontConstants.semiboldFont_15
  17 + obj.translatesAutoresizingMaskIntoConstraints = false
  18 + obj.setTitleColor(.white, for: .normal)
  19 + obj.setImage(UIImage(systemName: "shield.lefthalf.filled")?.withTintColor(.white, renderingMode: .alwaysOriginal), for: .normal)
  20 + obj.layer.cornerRadius = 10
  21 + obj.contentEdgeInsets = UIEdgeInsets(top: 10.sizeW, left: 10.sizeW, bottom: 10.sizeW, right: 10.sizeW)
  22 + obj.clipsToBounds = true
  23 + obj.layer.masksToBounds = false
  24 + return obj
  25 + }()
  26 +
  27 + let settingButton: UIButton = {
  28 + let obj = UIButton()
  29 + obj.setImage(UIImage(named: "Settings")?.withTintColor(.systemBlue), for: .normal)
  30 + return obj
  31 + }()
  32 +
  33 + let titleLabel: UILabel = {
  34 + let obj = UILabel()
  35 + obj.text = StringConstants.frequentlyVisited
  36 + obj.font = FontConstants.semiboldFont_18
  37 + return obj
  38 + }()
  39 +
  40 + let frequentlyVisitedCollectionView: UICollectionView = {
  41 + let obj = UICollectionViewFlowLayout()
  42 + obj.minimumInteritemSpacing = 12.sizeW
  43 + obj.scrollDirection = .horizontal
  44 + obj.sectionInset = UIEdgeInsets(top: 4.sizeH, left: 4.sizeW, bottom: 4.sizeH, right: 4.sizeW)
  45 +
  46 + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: obj)
  47 + collectionView.backgroundColor = .clear
  48 + collectionView.showsHorizontalScrollIndicator = false
  49 + return collectionView
  50 + }()
  51 +
  52 + let toolbarView: ToolbarView = {
  53 + let obj = ToolbarView()
  54 + return obj
  55 + }()
  56 +
  57 + let searchBarContainer: SearchBarContainer = {
  58 + let obj = SearchBarContainer()
  59 + obj.backgroundColor = .clear
  60 + return obj
  61 + }()
  62 +
  63 + override init(frame: CGRect) {
  64 + super.init(frame: frame)
  65 + setup()
  66 + setupConstraints()
  67 + }
  68 +
  69 + required init?(coder: NSCoder) {
  70 + fatalError("init(coder:) has not been implemented")
  71 + }
  72 +
  73 + private func setup() {
  74 + addSubview(titleLabel)
  75 + addSubview(frequentlyVisitedCollectionView)
  76 + addSubview(removeAddButton)
  77 + addSubview(settingButton)
  78 + addSubview(searchBarContainer)
  79 + addSubview(toolbarView)
  80 + }
  81 +
  82 + private func setupConstraints() {
  83 + removeAddButton.snp.makeConstraints { make in
  84 + make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(16.sizeH)
  85 + make.leading.equalTo(safeAreaLayoutGuide.snp.leading).offset(20.sizeW)
  86 + make.trailing.equalToSuperview().offset(-158.sizeW)
  87 + }
  88 + settingButton.snp.makeConstraints { make in
  89 + make.centerY.equalTo(removeAddButton)
  90 + make.height.equalTo(24.sizeH)
  91 + make.width.equalTo(24.sizeH)
  92 + make.trailing.equalToSuperview().offset(-16.sizeW)
  93 + }
  94 + titleLabel.snp.makeConstraints { make in
  95 + make.top.equalTo(removeAddButton.snp.bottom).offset(64.sizeH)
  96 + make.leading.equalTo(safeAreaLayoutGuide.snp.leading).offset(16.sizeW)
  97 + }
  98 + frequentlyVisitedCollectionView.snp.makeConstraints { make in
  99 + make.leading.trailing.equalToSuperview().inset(24.sizeW)
  100 + make.height.equalTo(120.sizeH)
  101 + make.top.equalTo(titleLabel.snp.bottom).offset(8.sizeH)
  102 + }
  103 + toolbarView.snp.makeConstraints { make in
  104 + make.leading.equalToSuperview()
  105 + make.trailing.equalToSuperview()
  106 + make.bottom.equalTo(safeAreaLayoutGuide.snp.bottom)
  107 + }
  108 + searchBarContainer.snp.makeConstraints { make in
  109 + make.leading.equalToSuperview()
  110 + make.trailing.equalToSuperview()
  111 + make.bottom.equalToSuperview().offset(-90.sizeH)
  112 + }
  113 + }
  114 +}
  115 +
  116 +//MARK: - childView extension
  117 +extension BrowserHomeView {
  118 + func addSearchView(_ childView: UIView){
  119 + addSubview(childView)
  120 + childView.snp.makeConstraints { make in
  121 + make.top.equalToSuperview()
  122 + make.leading.trailing.equalToSuperview()
  123 + make.bottom.equalTo(searchBarContainer.snp.top).offset(-2.sizeH)
  124 + }
  125 + }
  126 +}
  127 +
  128 +//MARK: - Search bar extention
  129 +extension BrowserHomeView {
  130 + func animateSearchBar(_ keyboardHeight: CGFloat) {
  131 + UIView.animate(withDuration: 0.3) {
  132 + self.searchBarContainer.backgroundColor = UIColor(red: 0.808, green: 0.823, blue: 0.85, alpha: 0.9)
  133 + self.searchBarContainer.snp.updateConstraints { make in
  134 + make.leading.equalToSuperview()
  135 + make.trailing.equalToSuperview()
  136 + make.bottom.equalToSuperview().offset(-keyboardHeight)
  137 + }
  138 + self.layoutIfNeeded()
  139 + }
  140 + }
  141 +
  142 + func animateSearchBarDismiss() {
  143 + BrowserHomeView.animate(withDuration: 0.3) {
  144 + self.searchBarContainer.backgroundColor = .clear
  145 + self.searchBarContainer.snp.updateConstraints { make in
  146 + make.leading.equalToSuperview()
  147 + make.trailing.equalToSuperview()
  148 + make.bottom.equalToSuperview().offset(-90.sizeH)
  149 + }
  150 + }
  151 + self.layoutIfNeeded()
  152 + }
  153 +}
... ...
  1 +//
  2 +// tabCell.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 25.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class TabCollectionViewCell: UICollectionViewCell {
  11 + let tabCellImage: UIImageView = {
  12 + let obj = UIImageView()
  13 + obj.contentMode = .scaleToFill
  14 + return obj
  15 + }()
  16 +
  17 + let tabCellLabel: UILabel = {
  18 + let obj = UILabel()
  19 + obj.textColor = .black
  20 + obj.font = FontConstants.regularFont_14
  21 + return obj
  22 + }()
  23 +
  24 + override init(frame: CGRect) {
  25 + super.init(frame: frame)
  26 + setup()
  27 + }
  28 +
  29 + required init?(coder: NSCoder) {
  30 + fatalError("init(coder:) has not been implemented")
  31 + }
  32 +
  33 + func setup() {
  34 +
  35 + layer.cornerRadius = 10
  36 + contentView.backgroundColor = UIColor(red: 0.867, green: 0.867, blue: 0.863, alpha: 0.4)
  37 + contentView.layer.cornerRadius = 10
  38 + contentView.addSubview(tabCellImage)
  39 + contentView.addSubview(tabCellLabel)
  40 + setupConstraints()
  41 + }
  42 +
  43 + private func setupConstraints() {
  44 + tabCellImage.snp.makeConstraints { make in
  45 + make.top.equalToSuperview().offset(14.sizeH)
  46 + make.leading.trailing.equalToSuperview().inset(9.sizeW)
  47 + make.height.equalTo(50.sizeW)
  48 + }
  49 +
  50 + tabCellLabel.snp.makeConstraints { make in
  51 + make.centerX.equalToSuperview()
  52 + make.top.equalTo(tabCellImage.snp.bottom).offset(8.sizeH)
  53 + }
  54 + }
  55 +
  56 + override func layoutSubviews() {
  57 + super.layoutSubviews()
  58 + shadowSetup()
  59 + }
  60 +}
  61 +
  62 +//MARK: - Shadows
  63 +extension TabCollectionViewCell {
  64 + private func shadowSetup() {
  65 + layer.shadowColor = UIColor.gray.cgColor
  66 + layer.shadowOpacity = 0.2
  67 + layer.shadowRadius = 3
  68 + layer.shadowOffset = CGSize(width: 2, height: 2)
  69 + }
  70 +}
... ...
  1 +//
  2 +// SearchBarSpace.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 12.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class SearchBarContainer: UIView {
  11 + let searchBarView: SearchBarView = {
  12 + let obj = SearchBarView()
  13 + obj.backgroundColor = .white
  14 + obj.layer.cornerRadius = 10
  15 + obj.layer.shadowColor = UIColor.black.withAlphaComponent(0.1).cgColor
  16 + obj.layer.shadowOpacity = 1
  17 + obj.layer.shadowRadius = 10
  18 + obj.layer.shadowOffset = CGSize(width: 0, height: 4.sizeW)
  19 + return obj
  20 + }()
  21 +
  22 + override init(frame: CGRect) {
  23 + super.init(frame: frame)
  24 + setup()
  25 + setupConstraints()
  26 + }
  27 +
  28 + required init?(coder: NSCoder) {
  29 + fatalError("init(coder:) has not been implemented")
  30 + }
  31 +
  32 + private func setup() {
  33 + addSubview(searchBarView)
  34 + }
  35 +
  36 + private func setupConstraints() {
  37 + searchBarView.snp.makeConstraints { make in
  38 + make.top.equalToSuperview().offset(4.sizeH)
  39 + make.leading.equalToSuperview().offset(16.sizeW)
  40 + make.trailing.equalToSuperview().offset(-16.sizeW)
  41 + make.bottom.equalToSuperview().offset(-6.sizeH)
  42 + }
  43 + }
  44 +}
... ...
  1 +//
  2 +// SearchBarView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 26.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class SearchBarView: UIView {
  11 + let searchImageView: UIImageView = {
  12 + let obj = UIImageView()
  13 + let magnifyImage = UIImage(systemName: "magnifyingglass")?.withTintColor(.gray, renderingMode: .alwaysOriginal)
  14 + obj.image = magnifyImage
  15 + return obj
  16 + }()
  17 +
  18 + let searchTextFieldView: UITextField = {
  19 + let obj = UITextField()
  20 + obj.text = "Search"
  21 + obj.textColor = ColorConstants.gray
  22 + return obj
  23 + }()
  24 +
  25 + let cleanTextFieldButton: UIButton = {
  26 + let obj = UIButton()
  27 + obj.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal)
  28 + obj.tintColor = .black
  29 + obj.isHidden = true
  30 + return obj
  31 + }()
  32 +
  33 + let progressBar: UIProgressView = {
  34 + let obj = UIProgressView(progressViewStyle: .default)
  35 + obj.progressTintColor = .systemIndigo
  36 + obj.progress = 0
  37 + obj.translatesAutoresizingMaskIntoConstraints = false
  38 + return obj
  39 + }()
  40 +
  41 + override init(frame: CGRect) {
  42 + super.init(frame: frame)
  43 + setup()
  44 + setupConstraints()
  45 + }
  46 +
  47 + required init?(coder: NSCoder) {
  48 + fatalError("init(coder:) has not been implemented")
  49 + }
  50 +
  51 + private func setup() {
  52 + addSubview(progressBar)
  53 + addSubview(searchImageView)
  54 + addSubview(searchTextFieldView)
  55 + addSubview(cleanTextFieldButton)
  56 + }
  57 +
  58 + private func setupConstraints() {
  59 + searchImageView.snp.makeConstraints { make in
  60 + make.leading.equalToSuperview().offset(16.sizeW)
  61 + make.top.bottom.equalToSuperview().inset(8.sizeH)
  62 + }
  63 + searchTextFieldView.snp.makeConstraints { make in
  64 + make.leading.equalTo(searchImageView).offset(32.sizeW)
  65 + make.trailing.equalToSuperview().offset(-16.sizeW)
  66 + make.top.bottom.equalToSuperview().inset(8.sizeH)
  67 + }
  68 + cleanTextFieldButton.snp.makeConstraints { make in
  69 + make.trailing.equalToSuperview().offset(-16.sizeW)
  70 + make.top.bottom.equalToSuperview().inset(8.sizeH)
  71 + }
  72 + progressBar.snp.makeConstraints { make in
  73 + make.bottom.equalToSuperview().inset(2.sizeH)
  74 + make.leading.trailing.equalToSuperview()
  75 + make.height.equalTo(2)
  76 + }
  77 + }
  78 +}
... ...
  1 +//
  2 +// UINavigationToolbar.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 27.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +enum ToolbarElementType {
  11 + case back
  12 + case forward
  13 + case share
  14 + case history
  15 + case tabs
  16 +}
  17 +
  18 +final class ToolbarView: UIView {
  19 + var action: ((ToolbarElementType) -> Void)?
  20 +
  21 + let toolbar: UIToolbar = {
  22 + let obj = UIToolbar()
  23 + obj.sizeToFit()
  24 + obj.barTintColor = ColorConstants.lightGray
  25 + obj.clipsToBounds = true
  26 + return obj
  27 + }()
  28 +
  29 + let backBarButtonItem: UIBarButtonItem = {
  30 + let obj = UIBarButtonItem()
  31 + obj.isEnabled = false
  32 + obj.image = UIImage(systemName: "chevron.backward")
  33 + return obj
  34 + }()
  35 +
  36 + let forwardBarButtonItem: UIBarButtonItem = {
  37 + let obj = UIBarButtonItem()
  38 + obj.isEnabled = false
  39 + obj.image = UIImage(systemName: "chevron.forward")
  40 + return obj
  41 + }()
  42 +
  43 + let shareBarButtonItem: UIBarButtonItem = {
  44 + let obj = UIBarButtonItem()
  45 + obj.isEnabled = false
  46 + obj.image = UIImage(systemName: "square.and.arrow.up")
  47 + return obj
  48 + }()
  49 +
  50 + let historyBarButtonItem: UIBarButtonItem = {
  51 + let obj = UIBarButtonItem()
  52 + obj.image = UIImage(systemName: "book")
  53 + return obj
  54 + }()
  55 +
  56 + let tabsBarButtonItem: UIBarButtonItem = {
  57 + let obj = UIBarButtonItem()
  58 + obj.image = UIImage(systemName: "square.on.square")
  59 + return obj
  60 + }()
  61 +
  62 + override init(frame: CGRect) {
  63 + super.init(frame: frame)
  64 + setup()
  65 + }
  66 +
  67 + required init?(coder: NSCoder) {
  68 + fatalError("init(coder:) has not been implemented")
  69 + }
  70 +
  71 + private func setup() {
  72 + addSubview(toolbar)
  73 + let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
  74 + toolbar.items = [
  75 + backBarButtonItem,
  76 + flexibleSpace,
  77 + forwardBarButtonItem,
  78 + flexibleSpace,
  79 + shareBarButtonItem,
  80 + flexibleSpace,
  81 + historyBarButtonItem,
  82 + flexibleSpace,
  83 + tabsBarButtonItem,
  84 + ]
  85 + initActions()
  86 + setupConstraints()
  87 + }
  88 +
  89 + private func setupConstraints() {
  90 + toolbar.snp.makeConstraints { make in
  91 + make.top.equalToSuperview()
  92 + make.leading.trailing.equalToSuperview()
  93 + make.bottom.equalTo(safeAreaLayoutGuide.snp.bottom)
  94 + }
  95 + }
  96 +}
  97 +
  98 +// MARK: - Helpers
  99 +extension ToolbarView {
  100 + private func initActions() {
  101 + backBarButtonItem.action = #selector(didItemTapped(_:))
  102 + backBarButtonItem.target = self
  103 + forwardBarButtonItem.action = #selector(didItemTapped(_:))
  104 + forwardBarButtonItem.target = self
  105 + shareBarButtonItem.action = #selector(didItemTapped(_:))
  106 + shareBarButtonItem.target = self
  107 + historyBarButtonItem.action = #selector(didItemTapped(_:))
  108 + historyBarButtonItem.target = self
  109 + tabsBarButtonItem.action = #selector(didItemTapped(_:))
  110 + tabsBarButtonItem.target = self
  111 + }
  112 +}
  113 +
  114 +// MARK: - Actions
  115 +extension ToolbarView {
  116 + @objc
  117 + private func didItemTapped(_ sender: UIBarButtonItem) {
  118 + guard let action else {
  119 + return
  120 + }
  121 + switch sender {
  122 + case backBarButtonItem:
  123 + action(.back)
  124 + case forwardBarButtonItem:
  125 + action(.forward)
  126 + case shareBarButtonItem:
  127 + action(.share)
  128 + case historyBarButtonItem:
  129 + action(.history)
  130 + case tabsBarButtonItem:
  131 + action(.tabs)
  132 + default:
  133 + break
  134 + }
  135 + }
  136 +}
... ...
  1 +//
  2 +// PayloadViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 25.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class PayloadViewController: UIViewController {
  11 + private let mainView = PayloadView()
  12 + private let data = StringConstants.payloadViewControllerData
  13 +
  14 + override func viewDidLoad() {
  15 + super.viewDidLoad()
  16 + view.backgroundColor = ColorConstants.lightGray
  17 + initViewController()
  18 + }
  19 +
  20 + private func initViewController() {
  21 + setupTableView()
  22 + addTargets()
  23 + navigationController?.isNavigationBarHidden = true
  24 + }
  25 +
  26 + override func loadView() {
  27 + view = mainView
  28 + }
  29 +
  30 + init(){
  31 + super.init(nibName: nil, bundle: nil)
  32 + }
  33 + required init?(coder: NSCoder) {
  34 + fatalError("init(coder:) has not been implemented")
  35 + }
  36 +
  37 + override func viewWillDisappear(_ animated: Bool) {
  38 + super.viewWillDisappear(animated)
  39 + NotificationCenter.default.removeObserver(self)
  40 + }
  41 +}
  42 +
  43 +extension PayloadViewController: UITableViewDelegate, UITableViewDataSource {
  44 + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  45 + return data.count
  46 + }
  47 +
  48 + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  49 + guard let cell = tableView.dequeueReusableCell(withIdentifier: "AdvantagesTableViewCell") as?
  50 + AdvantagesTableViewCell else {
  51 + return UITableViewCell() }
  52 + cell.advantagesCellLabel.text = data[indexPath.row]
  53 + cell.selectionStyle = .none
  54 + return cell
  55 + }
  56 +
  57 + private func setupTableView() {
  58 + mainView.advantagesTableView.dataSource = self
  59 + mainView.advantagesTableView.delegate = self
  60 + mainView.advantagesTableView.register(AdvantagesTableViewCell.self, forCellReuseIdentifier: StringConstants.advantagesTableViewCell)
  61 + }
  62 +}
  63 +
  64 +
  65 +//MARK: - Action
  66 +extension PayloadViewController {
  67 + @objc
  68 + private func getStartedButtonTapped(_ sender: UIButton) {
  69 + navigationController?.popViewController(animated: false)
  70 + }
  71 +
  72 + @objc
  73 + private func textPressed(_ sender: UITapGestureRecognizer) {
  74 + // navigationController?.popViewController(animated: false)
  75 + let termsViewController = TermsViewController()
  76 + termsViewController.modalPresentationStyle = .fullScreen
  77 + present(termsViewController, animated: true)
  78 + }
  79 +
  80 + private func addTargets() {
  81 + mainView.getStartedButton.addTarget(self, action: #selector(getStartedButtonTapped(_ :)), for: .touchUpInside)
  82 + mainView.privacyLabelView.isUserInteractionEnabled = true
  83 + mainView.privacyLabelView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(textPressed(_:))))
  84 +
  85 + GestureSetup()
  86 + }
  87 +
  88 + private func GestureSetup() {
  89 + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textPressed(_ :)))
  90 + mainView.infoLabel.addGestureRecognizer(tapGesture)
  91 + }
  92 +}
  93 +
  94 +
... ...
  1 +//
  2 +// AdvantagesTableViewCell.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 26.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class AdvantagesTableViewCell: UITableViewCell {
  11 + let advantagesCellLabel: UILabel = {
  12 + let obj = UILabel()
  13 + obj.font = FontConstants.semiboldFont_14
  14 + return obj
  15 + }()
  16 +
  17 + let advantagesCellImage: UIImageView = {
  18 + let obj = UIImageView()
  19 + let checkmarkImg = UIImage(systemName: "checkmark")?.withTintColor(.blue, renderingMode: .alwaysOriginal)
  20 + obj.image = checkmarkImg
  21 + obj.contentMode = .scaleToFill
  22 + return obj
  23 + }()
  24 +
  25 + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  26 + super.init(style: style, reuseIdentifier: reuseIdentifier)
  27 + setup()
  28 +
  29 + }
  30 +
  31 + required init?(coder: NSCoder) {
  32 + fatalError("init(coder:) has not been implemented")
  33 + }
  34 +
  35 +
  36 +
  37 + func setup() {
  38 + contentView.addSubview(advantagesCellLabel)
  39 + contentView.addSubview(advantagesCellImage)
  40 + setupConstraints()
  41 + backgroundColor = .clear
  42 + }
  43 +
  44 + private func setupConstraints() {
  45 + advantagesCellImage.snp.makeConstraints { make in
  46 + make.top.equalToSuperview().inset(5.sizeH)
  47 + make.bottom.equalToSuperview().inset(5.sizeH)
  48 + make.leading.equalToSuperview()
  49 + make.trailing.equalTo(advantagesCellLabel.snp.leading).offset(-8.sizeW)
  50 + }
  51 + advantagesCellLabel.snp.makeConstraints { make in
  52 + make.top.equalToSuperview().inset(5.sizeH)
  53 + make.bottom.equalToSuperview().inset(5.sizeH)
  54 + make.leading.equalTo(advantagesCellImage.snp.trailing)
  55 + make.trailing.equalToSuperview()
  56 + }
  57 + }
  58 +}
... ...
  1 +//
  2 +// PayloadView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 25.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class PayloadView: UIView {
  11 +
  12 + let logoImageView: UIImageView = {
  13 + let obj = UIImageView()
  14 + obj.image = UIImage(named: "Gotoweb")
  15 + obj.contentMode = .scaleAspectFit
  16 + return obj
  17 + }()
  18 +
  19 + let phoneImageView: UIImageView = {
  20 + let obj = UIImageView()
  21 + obj.image = UIImage(named: "Phone")
  22 + obj.contentMode = .scaleAspectFit
  23 + return obj
  24 + }()
  25 +
  26 + let zoomedTabImageView: UIImageView = {
  27 + let obj = UIImageView()
  28 + obj.image = UIImage(named: "ZoomedTab")
  29 + obj.contentMode = .scaleAspectFit
  30 + return obj
  31 + }()
  32 +
  33 + let infoLabel: UILabel = {
  34 + let obj = UILabel()
  35 + obj.text = StringConstants.ourBrowser
  36 + obj.font = FontConstants.regularFont_12
  37 + obj.numberOfLines = 0
  38 + return obj
  39 + }()
  40 +
  41 + let advantagesTableView: UITableView = {
  42 + let obj = UITableView()
  43 + obj.backgroundColor = .clear
  44 + obj.isScrollEnabled = false
  45 + obj.separatorStyle = .none
  46 + return obj
  47 + }()
  48 +
  49 + let gradientLayer = CAGradientLayer()
  50 +
  51 + let getStartedButton: UIButton = {
  52 + let obj = UIButton()
  53 + obj.setTitle("Get started", for: .normal)
  54 + obj.titleLabel?.font = FontConstants.semiboldFont_17
  55 + obj.setTitleColor(.white, for: .normal)
  56 + obj.layer.cornerRadius = 10
  57 + obj.layer.masksToBounds = true
  58 + return obj
  59 + }()
  60 +
  61 + let privacyLabelView: UILabel = {
  62 + let obj = UILabel()
  63 + obj.textAlignment = .center
  64 +
  65 + let fullText = "By starting, you agree to our Terms and Condition and Privacy Policy."
  66 + let attributedText = NSMutableAttributedString(string: fullText)
  67 + attributedText.addAttribute(.foregroundColor, value: UIColor(red: 0.349, green: 0.565, blue: 1, alpha: 1).cgColor, range: NSRange(location: fullText.range(of: "Terms and Condition")?.lowerBound.utf16Offset(in: fullText) ?? 0, length: "Terms and Condition".count))
  68 + attributedText.addAttribute(.foregroundColor, value: UIColor(red: 0.349, green: 0.565, blue: 1, alpha: 1).cgColor, range: NSRange(location: fullText.range(of: "Privacy Policy")?.lowerBound.utf16Offset(in: fullText) ?? 0, length: "Privacy Policy".count))
  69 + obj.attributedText = attributedText
  70 + obj.font = FontConstants.regularFont_12
  71 + obj.numberOfLines = 0
  72 + obj.isUserInteractionEnabled = true
  73 + return obj
  74 + }()
  75 +
  76 + override init (frame: CGRect) {
  77 + super.init(frame: frame)
  78 + setup()
  79 + }
  80 +
  81 + required init?(coder: NSCoder) {
  82 + fatalError("init(coder:) has not been implemented")
  83 + }
  84 +
  85 + override func layoutSubviews() {
  86 + super.layoutSubviews()
  87 + gradientLayer.frame = getStartedButton.bounds
  88 + }
  89 +
  90 + private func setup() {
  91 + addSubview(logoImageView)
  92 + addSubview(phoneImageView)
  93 + addSubview(zoomedTabImageView)
  94 + addSubview(infoLabel)
  95 + addSubview(advantagesTableView)
  96 + addSubview(getStartedButton)
  97 + addSubview(privacyLabelView)
  98 + setupConstraints()
  99 + gradientSetup()
  100 + }
  101 +
  102 + func setupConstraints() {
  103 + logoImageView.snp.makeConstraints { make in
  104 + make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(16.sizeH)
  105 + make.leading.trailing.equalToSuperview().inset(143.sizeW)
  106 + make.height.equalTo(26.sizeH)
  107 + }
  108 +
  109 + phoneImageView.snp.makeConstraints { make in
  110 + make.top.equalTo(logoImageView.snp.bottom).offset(16.sizeH)
  111 + make.leading.trailing.equalToSuperview().inset(90.sizeW)
  112 + make.height.equalTo(355.sizeH)
  113 + }
  114 +
  115 + zoomedTabImageView.snp.makeConstraints { make in
  116 + make.top.equalTo(phoneImageView.snp.top).offset(119.sizeH)
  117 + make.leading.equalTo(phoneImageView.snp.leading).offset(91.sizeW)
  118 + make.trailing.equalToSuperview().offset(-71)
  119 + make.bottom.equalTo(phoneImageView.snp.bottom).offset(-104.sizeH)
  120 + }
  121 +
  122 + infoLabel.snp.makeConstraints { make in
  123 + make.top.equalTo(phoneImageView.snp.bottom).offset(16.sizeH)
  124 + make.leading.trailing.equalToSuperview().inset(55.sizeW)
  125 + }
  126 +
  127 + advantagesTableView.snp.makeConstraints { make in
  128 + make.top.equalTo(infoLabel.snp.bottom).offset(16.sizeH)
  129 + make.leading.equalToSuperview().offset(55.sizeW)
  130 + make.trailing.equalToSuperview().offset(-92.sizeW)
  131 + make.bottom.equalTo(getStartedButton.snp.top).offset(-38.sizeH)
  132 + }
  133 +
  134 + getStartedButton.snp.makeConstraints { make in
  135 + make.top.equalTo(advantagesTableView.snp.bottom).offset(24.sizeH)
  136 + make.leading.trailing.equalToSuperview().inset(32.sizeW)
  137 + make.height.equalTo(40.sizeH)
  138 + }
  139 +
  140 + privacyLabelView.snp.makeConstraints { make in
  141 + make.top.equalTo(getStartedButton.snp.bottom).offset(16.sizeH)
  142 + make.leading.trailing.equalToSuperview().inset(32.sizeW)
  143 + make.bottom.equalTo(safeAreaLayoutGuide).offset(-16.sizeH)
  144 + }
  145 +
  146 + }
  147 +}
  148 +
  149 +//MARK: Gradient
  150 +extension PayloadView {
  151 + private func gradientSetup() {
  152 + getStartedButton.layer.insertSublayer(gradientLayer, at: 0)
  153 + gradientLayer.colors = [UIColor(red: 0.349, green: 0.565, blue: 1, alpha: 1).cgColor, UIColor(red: 0.349, green: 0.565, blue: 1, alpha: 0.7).cgColor]
  154 + gradientLayer.locations = [0.0, 1.0]
  155 + }
  156 +}
... ...
  1 +//
  2 +// RemoveAdvertViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 27.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class RemoveAdvertViewController: UIViewController {
  11 +
  12 + private let mainView = RemoveAdvertView()
  13 + let data = StringConstants.removeAdvertTableViewData
  14 +
  15 + override func viewDidLoad() {
  16 + super.viewDidLoad()
  17 + view.backgroundColor = ColorConstants.lightGray
  18 + initViewController()
  19 + }
  20 +
  21 + private func initViewController() {
  22 + setupTableView()
  23 + addTargets()
  24 + }
  25 +
  26 + override func loadView() {
  27 + view = mainView
  28 + }
  29 +
  30 + init(){
  31 + super.init(nibName: nil, bundle: nil)
  32 + }
  33 +
  34 + required init?(coder: NSCoder) {
  35 + fatalError("init(coder:) has not been implemented")
  36 + }
  37 +}
  38 +
  39 +
  40 +//MARK: - Table View
  41 +extension RemoveAdvertViewController: UITableViewDelegate, UITableViewDataSource {
  42 + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  43 + return data.count
  44 + }
  45 +
  46 + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  47 + guard let cell = tableView.dequeueReusableCell(withIdentifier: "RemoveAdvertTableViewCell") as?
  48 + RemoveAdvertTableViewCell else {
  49 + return UITableViewCell() }
  50 +
  51 + cell.advantagesCellLabel.text = data[indexPath.row]
  52 + cell.selectionStyle = .none
  53 +
  54 + return cell
  55 + }
  56 +
  57 + private func setupTableView() {
  58 + mainView.advantagesTableView.dataSource = self
  59 + mainView.advantagesTableView.delegate = self
  60 + mainView.advantagesTableView.register(RemoveAdvertTableViewCell.self, forCellReuseIdentifier: StringConstants.removeAdvertTableViewCell)
  61 + }
  62 +}
  63 +
  64 +
  65 +//MARK: - Action
  66 +extension RemoveAdvertViewController {
  67 + private func addTargets() {
  68 + mainView.shieldView.addTarget(self, action: #selector(shieldButtonTapped(_ :)), for: .touchUpInside)
  69 + mainView.closeButton.addTarget(self, action: #selector(closeViewController(_ :)), for: .touchUpInside)
  70 + }
  71 +
  72 + @objc
  73 + private func shieldButtonTapped(_ sender: UIButton) {
  74 + UIView.animate(withDuration: 0.2) {
  75 + sender.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
  76 + sender.alpha = 0.7
  77 + }
  78 + let userDefaultsAdBlockerValue = CachingManager.shared.isAdBlocking
  79 + if userDefaultsAdBlockerValue {
  80 + mainView.shieldView.setImage(.shieldInactive, for: .normal)
  81 + mainView.tapActionLabel.text = StringConstants.turnOff
  82 + CachingManager.shared.isAdBlocking = false
  83 + } else {
  84 + mainView.shieldView.setImage(.shieldActive, for: .normal)
  85 + mainView.tapActionLabel.text = StringConstants.turnOn
  86 + CachingManager.shared.isAdBlocking = true
  87 + }
  88 + UIView.animate(withDuration: 0.2, delay: 0.2) {
  89 + sender.transform = .identity
  90 + sender.alpha = 1.0
  91 + }
  92 + }
  93 +
  94 + @objc
  95 + private func closeViewController(_ sender: UIButton) {
  96 + dismiss(animated: true, completion: nil)
  97 + }
  98 +}
... ...
  1 +//
  2 +// RemoveAdvertTableViewCell.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 01.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +
  11 +final class RemoveAdvertTableViewCell: UITableViewCell {
  12 + let advantagesCellLabel: UILabel = {
  13 + let obj = UILabel()
  14 + obj.font = FontConstants.regularFont_14
  15 + return obj
  16 + }()
  17 +
  18 + let advantagesCellImage: UIImageView = {
  19 + let obj = UIImageView()
  20 + let checkmarkImg = UIImage(systemName: "checkmark")?.withTintColor(.blue, renderingMode: .alwaysOriginal)
  21 + obj.image = checkmarkImg
  22 + obj.contentMode = .scaleToFill
  23 + return obj
  24 + }()
  25 +
  26 + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  27 + super.init(style: style, reuseIdentifier: reuseIdentifier)
  28 + setup()
  29 +
  30 + }
  31 +
  32 + required init?(coder: NSCoder) {
  33 + fatalError("init(coder:) has not been implemented")
  34 + }
  35 +
  36 + func setup() {
  37 + contentView.addSubview(advantagesCellLabel)
  38 + contentView.addSubview(advantagesCellImage)
  39 + backgroundColor = .clear
  40 + setupConstraints()
  41 + }
  42 +
  43 + private func setupConstraints() {
  44 + advantagesCellImage.snp.makeConstraints { make in
  45 + make.top.equalToSuperview().inset(5.sizeH)
  46 + make.bottom.equalToSuperview().inset(5.sizeH)
  47 + make.leading.equalToSuperview()
  48 + make.trailing.equalTo(advantagesCellLabel.snp.leading).offset(-8.sizeW)
  49 + }
  50 + advantagesCellLabel.snp.makeConstraints { make in
  51 + make.top.equalToSuperview().inset(5.sizeH)
  52 + make.bottom.equalToSuperview().inset(5.sizeH)
  53 + make.leading.equalTo(advantagesCellImage.snp.trailing)
  54 + make.trailing.equalToSuperview()
  55 + }
  56 + }
  57 +}
... ...
  1 +//
  2 +// RemoveAdvertView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import SnapKit
  10 +
  11 +final class RemoveAdvertView: UIView {
  12 +
  13 + let closeButton: UIButton = {
  14 + let obj = UIButton()
  15 + obj.setImage(UIImage(systemName: "xmark"), for: .normal)
  16 + obj.contentMode = .scaleToFill
  17 + obj.tintColor = .gray
  18 + return obj
  19 + }()
  20 +
  21 + let shieldView: UIButton = {
  22 + let obj = UIButton()
  23 + let userDefaultsValue = CachingManager.shared.isAdBlocking
  24 +
  25 + if userDefaultsValue {
  26 + obj.setImage(UIImage(named: "ShieldActive"), for: .normal)
  27 + print(userDefaultsValue)
  28 + } else {
  29 + obj.setImage(UIImage(named: "ShieldInactive"), for: .normal)
  30 + print(userDefaultsValue)
  31 + }
  32 +
  33 + obj.contentMode = .scaleAspectFit
  34 + return obj
  35 + }()
  36 +
  37 + let gradientLayer = CAGradientLayer()
  38 +
  39 + let abvertBlockerModeLabel: UILabel = {
  40 + let obj = UILabel()
  41 + obj.text = StringConstants.advertMode
  42 + obj.font = FontConstants.semiboldFont_18
  43 + return obj
  44 + }()
  45 +
  46 + let tapActionLabel: UILabel = {
  47 + let obj = UILabel()
  48 + obj.text = StringConstants.turnOff
  49 + obj.font = FontConstants.semiboldFont_14
  50 + return obj
  51 + }()
  52 +
  53 + let advantagesTableView: UITableView = {
  54 + let obj = UITableView()
  55 + obj.backgroundColor = .clear
  56 + obj.isScrollEnabled = false
  57 + obj.separatorStyle = .none
  58 + return obj
  59 + }()
  60 +
  61 + let claimOfferLabel: UILabel = {
  62 + let obj = UILabel()
  63 + obj.text = StringConstants.claimOffer
  64 + obj.font = FontConstants.regularFont_12
  65 + return obj
  66 + }()
  67 +
  68 + let priceLabel: UILabel = {
  69 + let obj = UILabel()
  70 + obj.text = StringConstants.price
  71 + obj.font = FontConstants.regularFont_18
  72 + return obj
  73 + }()
  74 +
  75 + let subscribeButton: UIButton = {
  76 + let obj = UIButton()
  77 + obj.backgroundColor = .systemIndigo
  78 + obj.setTitle(StringConstants.subscribe, for: .normal)
  79 + obj.titleLabel?.font = FontConstants.semiboldFont_17
  80 + obj.setTitleColor(.white, for: .normal)
  81 + obj.layer.cornerRadius = 10
  82 + obj.layer.masksToBounds = true
  83 + return obj
  84 + }()
  85 +
  86 + let freeTrialLabel: UILabel = {
  87 + let obj = UILabel()
  88 + obj.textAlignment = .center
  89 + obj.font = FontConstants.semiboldFont_12
  90 + obj.text = StringConstants.freeTrial
  91 + return obj
  92 + }()
  93 +
  94 + let discountLabel: UILabel = {
  95 + let obj = UILabel()
  96 + obj.textAlignment = .center
  97 + obj.text = StringConstants.yourDiscount
  98 + obj.font = FontConstants.regularFont_12
  99 + return obj
  100 + }()
  101 +
  102 + override init (frame: CGRect) {
  103 + super.init(frame: frame)
  104 + setup()
  105 + }
  106 +
  107 + override func layoutSubviews() {
  108 + super.layoutSubviews()
  109 + gradientLayer.frame = subscribeButton.bounds
  110 + }
  111 +
  112 + required init?(coder: NSCoder) {
  113 + fatalError("init(coder:) has not been implemented")
  114 + }
  115 +
  116 + private func setup() {
  117 + addSubview(closeButton)
  118 + addSubview(shieldView)
  119 + addSubview(abvertBlockerModeLabel)
  120 + addSubview(tapActionLabel)
  121 + addSubview(advantagesTableView)
  122 + addSubview(claimOfferLabel)
  123 + addSubview(priceLabel)
  124 + addSubview(subscribeButton)
  125 + addSubview(freeTrialLabel)
  126 + addSubview(discountLabel)
  127 + setupConstraints()
  128 + gradientSetup()
  129 + }
  130 +
  131 + func setupConstraints() {
  132 + closeButton.snp.makeConstraints { make in
  133 + make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(16.sizeH)
  134 + make.height.equalTo(24.sizeH)
  135 + make.trailing.equalToSuperview().inset(16.sizeW)
  136 + }
  137 +
  138 + shieldView.snp.makeConstraints { make in
  139 + make.top.equalTo(closeButton.snp.top).offset(8.sizeH)
  140 + make.height.equalTo(280.sizeH)
  141 + make.leading.trailing.equalToSuperview().inset(47.sizeW)
  142 + }
  143 + abvertBlockerModeLabel.snp.makeConstraints { make in
  144 + make.top.equalTo(shieldView.snp.bottom).offset(16.sizeH)
  145 + make.centerX.equalToSuperview()
  146 + }
  147 + tapActionLabel.snp.makeConstraints { make in
  148 + make.top.equalTo(abvertBlockerModeLabel.snp.bottom).offset(8.sizeH)
  149 + make.centerX.equalToSuperview()
  150 + }
  151 + advantagesTableView.snp.makeConstraints { make in
  152 + make.top.equalTo(tapActionLabel.snp.bottom).offset(26.sizeH)
  153 + make.bottom.equalTo(claimOfferLabel.snp.top).offset(-24.sizeH)
  154 + make.leading.equalToSuperview().offset(80.sizeW)
  155 + make.trailing.equalToSuperview().offset(-86.sizeW)
  156 + }
  157 + claimOfferLabel.snp.makeConstraints { make in
  158 + make.bottom.equalTo(priceLabel.snp.top).offset(-4.sizeH)
  159 + make.centerX.equalToSuperview()
  160 + }
  161 + priceLabel.snp.makeConstraints { make in
  162 + make.bottom.equalTo(subscribeButton.snp.top).offset(-16.sizeH)
  163 + make.centerX.equalToSuperview()
  164 + }
  165 + subscribeButton.snp.makeConstraints { make in
  166 + make.bottom.equalTo(freeTrialLabel.snp.top).offset(-16.sizeH)
  167 + make.leading.trailing.equalToSuperview().inset(32.sizeW)
  168 + make.height.equalTo(40.sizeH)
  169 + }
  170 + freeTrialLabel.snp.makeConstraints { make in
  171 + make.bottom.equalTo(discountLabel.snp.top).offset(-8.sizeH)
  172 + make.centerX.equalToSuperview()
  173 + }
  174 + discountLabel.snp.makeConstraints { make in
  175 + make.centerX.equalToSuperview()
  176 + make.bottom.equalTo(safeAreaLayoutGuide.snp.bottom).offset(-24.sizeH)
  177 + }
  178 + }
  179 +}
  180 +
  181 +//MARK: gradient
  182 +extension RemoveAdvertView {
  183 + private func gradientSetup() {
  184 + subscribeButton.layer.insertSublayer(gradientLayer, at: 0)
  185 + gradientLayer.colors = [UIColor(red: 0.349, green: 0.565, blue: 1, alpha: 1).cgColor, UIColor(red: 0.349, green: 0.565, blue: 1, alpha: 0.7).cgColor]
  186 + gradientLayer.locations = [0.0, 1.0]
  187 + }
  188 +}
... ...
  1 +//
  2 +// SearchResultViewColroller.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 05.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import WebKit
  10 +
  11 +final class SearchResultViewController: UIViewController {
  12 + let mainView = SearchResultView()
  13 + var searchLink: String
  14 +
  15 + init(searchLink: String) {
  16 + self.searchLink = searchLink
  17 + super.init(nibName: nil, bundle: nil)
  18 + }
  19 +
  20 + required init?(coder: NSCoder) {
  21 + fatalError("init(coder:) has not been implemented")
  22 + }
  23 +
  24 + override func loadView() {
  25 + view = mainView
  26 + }
  27 +
  28 + override func viewDidLoad() {
  29 + super.viewDidLoad()
  30 + initViewController()
  31 + }
  32 +
  33 + private func initViewController() {
  34 + view.backgroundColor = ColorConstants.lightGray
  35 + urlChecker(searchLink)
  36 + setupAdBlocker()
  37 + }
  38 +
  39 + override func viewIsAppearing(_ animated: Bool) {
  40 + navigationController?.isNavigationBarHidden = true
  41 + }
  42 +}
  43 +
  44 +extension SearchResultViewController {
  45 + func urlChecker(_ url: String) {
  46 + let request = URLRequest(url: URL(string: url) ?? URL(fileURLWithPath: ""))
  47 + mainView.searchResultView.load(request)
  48 + }
  49 +}
  50 +
  51 +
  52 +//MARK: AdBlocker
  53 +extension SearchResultViewController {
  54 + func setupAdBlocker() {
  55 + let userDefaultsValue = CachingManager.shared.isAdBlocking
  56 + if userDefaultsValue {
  57 + WKContentRuleListStore.default().getAvailableContentRuleListIdentifiers { res in
  58 +// if res?.isEmpty ?? true {
  59 + if let url = Bundle.main.url(forResource: "blockerList", withExtension: "json"),
  60 + let str = try? String(contentsOf: url) {
  61 + WKContentRuleListStore.default().compileContentRuleList(forIdentifier: "blockerList", encodedContentRuleList: str) { list, error in
  62 + if let list {
  63 + self.mainView.searchResultView.configuration.userContentController.add(list)
  64 + }
  65 + }
  66 + }
  67 +// }
  68 + }
  69 + } else {
  70 + WKContentRuleListStore.default().getAvailableContentRuleListIdentifiers { res in
  71 + if res != nil {
  72 + WKContentRuleListStore.default().removeContentRuleList(forIdentifier: "blockerList") { error in
  73 + if let error {
  74 + print(error)
  75 + }
  76 + }
  77 + }
  78 + }
  79 + }
  80 + }
  81 +}
... ...
  1 +//
  2 +// SearchResultView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 05.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import WebKit
  10 +
  11 +final class SearchResultView: UIView {
  12 + let searchResultView: WKWebView = {
  13 +// let userDefaultsValue = CachingManager.shared.isAdBlocking
  14 +// if userDefaultsValue {
  15 +// let configuration = WKWebViewConfiguration()
  16 +// let contentController = WKUserContentController()
  17 +// let url = Bundle.main.url(forResource: "blockerList", withExtension: "json")?.absoluteString ?? ""
  18 +// contentController.addUserScript(WKUserScript(source: url, injectionTime: .atDocumentStart, forMainFrameOnly: false))
  19 +// configuration.userContentController = contentController
  20 +// let obj = WKWebView(frame: .zero, configuration: configuration)
  21 +// obj.allowsBackForwardNavigationGestures = true
  22 +// obj.allowsLinkPreview = true
  23 +// return obj
  24 +// } else {
  25 + let obj = WKWebView()
  26 + obj.allowsBackForwardNavigationGestures = true
  27 + obj.allowsLinkPreview = true
  28 + return obj
  29 + // }
  30 + }()
  31 +
  32 + override init(frame: CGRect) {
  33 + super.init(frame: frame)
  34 + setup()
  35 + }
  36 +
  37 +
  38 + required init?(coder: NSCoder) {
  39 + fatalError("init(coder:) has not been implemented")
  40 + }
  41 +
  42 + private func setup() {
  43 + addSubview(searchResultView)
  44 + setupConstaraints()
  45 + backgroundColor = .white
  46 + }
  47 +
  48 + private func setupConstaraints() {
  49 + searchResultView.snp.makeConstraints { make in
  50 + make.top.equalTo(safeAreaLayoutGuide.snp.top)
  51 + make.leading.trailing.equalToSuperview()
  52 + make.bottom.equalToSuperview()
  53 + }
  54 + }
  55 +}
  56 +
... ...
  1 +//
  2 +// SearchingViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class SearchingViewController: UIViewController {
  11 + let mainView = SearchingView()
  12 + var dataForReq: [String] {
  13 + didSet {
  14 + mainView.searchTableView.reloadData()
  15 + }
  16 + }
  17 + var searchCell: ((UITableViewCell) -> Void)?
  18 +
  19 + init(dataForReq: [String]) {
  20 + self.dataForReq = dataForReq
  21 + super.init(nibName: nil, bundle: nil)
  22 + }
  23 +
  24 + required init?(coder: NSCoder) {
  25 + fatalError("init(coder:) has not been implemented")
  26 + }
  27 +
  28 + override func loadView() {
  29 + view = mainView
  30 + }
  31 +
  32 + override func viewDidLoad() {
  33 + super.viewDidLoad()
  34 + view.backgroundColor = ColorConstants.lightGray
  35 + initViewController()
  36 + }
  37 +
  38 + private func initViewController() {
  39 + setupTableView()
  40 + }
  41 +}
  42 +
  43 +extension SearchingViewController: UITableViewDelegate, UITableViewDataSource {
  44 + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  45 + return dataForReq.count
  46 + }
  47 +
  48 + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  49 + guard let cell = tableView.dequeueReusableCell(withIdentifier: "SearchingTableViewCell", for: indexPath) as? SearchingTableViewCell else {
  50 + return SearchingTableViewCell()
  51 + }
  52 + let searchCellData = dataForReq[indexPath.row]
  53 + cell.model = searchCellData
  54 + return cell
  55 + }
  56 +
  57 + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  58 + guard let tappedCell = tableView.cellForRow(at: indexPath) else { return }
  59 + searchCell?(tappedCell)
  60 + }
  61 +
  62 + func setupTableView() {
  63 + mainView.searchTableView.dataSource = self
  64 + mainView.searchTableView.delegate = self
  65 + mainView.searchTableView.register(SearchingTableViewCell.self, forCellReuseIdentifier: StringConstants.searchTableViewCell)
  66 + }
  67 +}
  68 +
... ...
  1 +//
  2 +// SearchingTableViewCell.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +class SearchingTableViewCell: UITableViewCell {
  11 + var model: String? {
  12 + didSet {
  13 + handleUI()
  14 + }
  15 + }
  16 +
  17 + var searchImage: UIImageView = {
  18 + let obj = UIImageView()
  19 + obj.image = UIImage(systemName: "magnifyingglass")
  20 + obj.tintColor = .gray
  21 + return obj
  22 + }()
  23 +
  24 + var searchLabel: UILabel = {
  25 + let obj = UILabel()
  26 + obj.font = FontConstants.regularFont_14
  27 + return obj
  28 + }()
  29 +
  30 + var siteLogoImage: UIImageView = {
  31 + let obj = UIImageView()
  32 + return obj
  33 + }()
  34 +
  35 + var linkImage: UIImageView = {
  36 + let obj = UIImageView()
  37 + obj.image = UIImage(systemName: "arrow.up.left")
  38 + obj.tintColor = .gray
  39 + return obj
  40 + }()
  41 +
  42 +
  43 + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  44 + super.init(style: style, reuseIdentifier: reuseIdentifier)
  45 + setup()
  46 + }
  47 +
  48 + required init?(coder: NSCoder) {
  49 + fatalError("init(coder:) has not been implemented")
  50 + }
  51 +
  52 + func setup() {
  53 + contentView.addSubview(searchImage)
  54 + contentView.addSubview(searchLabel)
  55 + contentView.addSubview(siteLogoImage)
  56 + contentView.addSubview(linkImage)
  57 + setupConstraints()
  58 + }
  59 +
  60 + private func setupConstraints() {
  61 + searchImage.snp.makeConstraints { make in
  62 + make.top.equalToSuperview().offset(8.sizeH)
  63 + make.leading.equalToSuperview().offset(8.sizeW)
  64 + make.bottom.equalToSuperview().offset(-8.sizeH)
  65 + }
  66 + searchLabel.snp.makeConstraints { make in
  67 + make.top.equalToSuperview().inset(8.sizeH)
  68 + make.leading.equalTo(searchImage.snp.trailing).offset(8.sizeW)
  69 + }
  70 + siteLogoImage.snp.makeConstraints { make in
  71 + make.top.equalToSuperview().inset(8.sizeH)
  72 + make.height.width.equalTo(18.sizeH)
  73 + }
  74 + linkImage.snp.makeConstraints { make in
  75 + make.top.equalToSuperview().inset(8.sizeH)
  76 + make.leading.equalTo(siteLogoImage.snp.trailing).offset(8.sizeW)
  77 + make.trailing.equalToSuperview().inset(8.sizeW)
  78 + }
  79 + }
  80 +}
  81 +
  82 +extension SearchingTableViewCell {
  83 + private func handleUI() {
  84 + searchLabel.text = model
  85 +// if model?.siteLogo != UIImage() {
  86 +// siteLogoImage.image = model?.siteLogo
  87 +// } else {
  88 +// siteLogoImage.image = UIImage()
  89 +// }
  90 + }
  91 +}
... ...
  1 +//
  2 +// SearchingView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 29.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class SearchingView: UIView, UITextFieldDelegate {
  11 + let searchingButton: UIButton = {
  12 + let obj = UIButton()
  13 + obj.setImage(UIImage(systemName: "arrow.left"), for: .normal)
  14 + return obj
  15 + }()
  16 +
  17 + let searchingLabel: UILabel = {
  18 + let obj = UILabel()
  19 + obj.text = "Searching"
  20 + obj.font = FontConstants.semiboldFont_18
  21 + return obj
  22 + }()
  23 +
  24 + let searchTableView: UITableView = {
  25 + let obj = UITableView()
  26 + obj.backgroundColor = .clear
  27 + obj.separatorStyle = .none
  28 + return obj
  29 + }()
  30 +
  31 + override init(frame: CGRect) {
  32 + super.init(frame: frame)
  33 + setup()
  34 + }
  35 +
  36 + required init?(coder: NSCoder) {
  37 + fatalError("init(coder:) has not been implemented")
  38 + }
  39 +
  40 + private func setup() {
  41 + addSubview(searchingButton)
  42 + addSubview(searchingLabel)
  43 + addSubview(searchTableView)
  44 + setupConstaraints()
  45 + backgroundColor = .white
  46 + }
  47 +
  48 + private func setupConstaraints() {
  49 + searchingButton.snp.makeConstraints { make in
  50 + make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(16.sizeH)
  51 + make.leading.equalToSuperview().offset(16.sizeW)
  52 + make.height.equalTo(24.sizeH)
  53 + }
  54 +
  55 + searchingLabel.snp.makeConstraints { make in
  56 + make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(16.sizeH)
  57 + make.leading.equalTo(searchingButton.snp.trailing).offset(109.sizeW)
  58 + make.trailing.equalToSuperview().offset(-138.sizeW)
  59 + }
  60 +
  61 + searchTableView.snp.makeConstraints { make in
  62 + make.top.equalTo(searchingLabel.snp.bottom).offset(16.sizeH)
  63 + make.leading.trailing.equalToSuperview().inset(16.sizeW)
  64 + make.bottom.equalToSuperview()/*.offset(-16.sizeH)*/
  65 + }
  66 + }
  67 +}
  68 +
... ...
  1 +//
  2 +// SettingController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 26.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import MessageUI
  10 +
  11 +final class SettingViewController: UIViewController {
  12 + private let mainView = SettingView()
  13 + private let param = StringConstants.settingViewControllerTableViewData
  14 + init() {
  15 + super.init(nibName: nil, bundle: nil)
  16 + }
  17 +
  18 + required init?(coder: NSCoder) {
  19 + fatalError("init(coder:) has not been implemented")
  20 + }
  21 +
  22 + override func loadView() {
  23 + view = mainView
  24 + }
  25 +
  26 + override func viewDidLoad() {
  27 + super.viewDidLoad()
  28 + view.backgroundColor = .white
  29 + initViewController()
  30 + }
  31 +
  32 + private func initViewController() {
  33 + navigationController?.isNavigationBarHidden = false
  34 + setupSettingTableView()
  35 + addTargets()
  36 + }
  37 +}
  38 +
  39 +
  40 +//MARK: SettingTableView
  41 +extension SettingViewController: UITableViewDelegate, UITableViewDataSource {
  42 + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  43 + return param.count
  44 + }
  45 +
  46 + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  47 + guard let cell = tableView.dequeueReusableCell(withIdentifier: "SettingTableViewCell", for: indexPath) as? SettingTableViewCell
  48 + else { return UITableViewCell() }
  49 + let info = param[indexPath.item]
  50 + cell.settingTableViewLabel.text = info
  51 + cell.selectionStyle = .none
  52 + return cell
  53 + }
  54 +
  55 + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  56 + return 60.0
  57 + }
  58 +
  59 + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  60 + let index = indexPath.row
  61 + cellPresshandler(index)
  62 + }
  63 +}
  64 +
  65 +
  66 +//MARK: - Helpers
  67 +extension SettingViewController {
  68 + private func setupSettingTableView() {
  69 + mainView.settingTableView.delegate = self
  70 + mainView.settingTableView.dataSource = self
  71 + mainView.settingTableView.register(SettingTableViewCell.self, forCellReuseIdentifier: StringConstants.settingTableViewCell)
  72 + }
  73 +
  74 + private func setupMessage() {
  75 + guard MFMailComposeViewController.canSendMail() else {
  76 + return
  77 + }
  78 + let composer = MFMailComposeViewController()
  79 + composer.mailComposeDelegate = self
  80 + composer.setToRecipients(["test@gmail.com"])
  81 + composer.setSubject("Browser")
  82 + present(composer, animated: true, completion: nil)
  83 + }
  84 +
  85 + private func cellPresshandler(_ index: Int) {
  86 + switch index {
  87 + case 0:
  88 + let privacyViewController = PrivacyViewController()
  89 + presentViewController(privacyViewController)
  90 + case 1:
  91 + let termsViewController = TermsViewController()
  92 + presentViewController(termsViewController)
  93 + case 2:
  94 + shareButtonPressed()
  95 + case 3:
  96 + break
  97 + case 4:
  98 + setupMessage()
  99 + default:
  100 + break
  101 + }
  102 + }
  103 +}
  104 +
  105 +//MARK: - Action
  106 +extension SettingViewController {
  107 + func addTargets() {
  108 + mainView.backButton.addTarget(self, action: #selector(closeViewController(_ :)), for: .touchUpInside)
  109 + }
  110 +
  111 + @objc
  112 + private func closeViewController(_ sender: UIButton) {
  113 + dismiss(animated: true, completion: nil)
  114 + }
  115 +
  116 + private func shareButtonPressed() {
  117 + let items = [URL(string: URLConstants.shareAppLink)]
  118 + let shareView = UIActivityViewController(activityItems: items as [Any], applicationActivities: nil)
  119 + present(shareView, animated: true)
  120 + }
  121 +
  122 + private func presentViewController(_ viewController: UIViewController) {
  123 + viewController.modalPresentationStyle = .fullScreen
  124 + present(viewController, animated: true)
  125 + }
  126 +
  127 +}
  128 +
  129 +//MARK: Mail helper
  130 +extension SettingViewController: MFMailComposeViewControllerDelegate {
  131 + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
  132 + if let _ = error {
  133 + controller.dismiss(animated: true)
  134 + }
  135 + switch result {
  136 + case .cancelled:
  137 + print("cancelled")
  138 + case .saved:
  139 + print("saved")
  140 + case .sent:
  141 + print("send")
  142 + case .failed:
  143 + print("fail")
  144 + @unknown default:
  145 + print("error!")
  146 + }
  147 +
  148 + controller.dismiss(animated: true)
  149 + }
  150 +}
... ...
Please register or login to post a comment