Commit f3e2af331aa37f8979233db17da843f3e4d9c8c6

Authored by Artem Talko
0 parents

commit1

Showing 115 changed files with 6405 additions and 0 deletions
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 +}
  1 +//
  2 +// settingTableViewCell.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 26.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class SettingTableViewCell: UITableViewCell {
  11 + let settingTableViewLabel: UILabel = {
  12 + let obj = UILabel()
  13 + obj.font = FontConstants.semiboldFont_17
  14 + obj.textColor = ColorConstants.lightGray
  15 + obj.textAlignment = .center
  16 + obj.backgroundColor = ColorConstants.buttonsBackgroundColor
  17 + obj.layer.cornerRadius = 10
  18 + obj.layer.masksToBounds = true
  19 + return obj
  20 + }()
  21 +
  22 + let gradientLayer = CAGradientLayer()
  23 +
  24 + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  25 + super.init(style: style, reuseIdentifier: reuseIdentifier)
  26 + setup()
  27 + }
  28 +
  29 + required init?(coder: NSCoder) {
  30 + fatalError("init(coder:) has not been implemented")
  31 + }
  32 +
  33 + private func setup() {
  34 + contentView.addSubview(settingTableViewLabel)
  35 + setupConstraints()
  36 + }
  37 +
  38 + override func layoutSubviews() {
  39 + super.layoutSubviews()
  40 + gradientLayer.frame = self.bounds
  41 + }
  42 +
  43 + private func setupConstraints() {
  44 + settingTableViewLabel.snp.makeConstraints { make in
  45 + make.top.equalToSuperview().inset(10)
  46 + make.bottom.equalToSuperview().inset(10)
  47 + make.leading.trailing.equalToSuperview().inset(10)
  48 + }
  49 + }
  50 +}
  51 +
  52 +//MARK: Gradient
  53 +extension SettingTableViewCell {
  54 + private func gradientSetup() {
  55 + self.layer.insertSublayer(gradientLayer, at: 0)
  56 + 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]
  57 + gradientLayer.locations = [0.0, 1.0]
  58 + }
  59 +}
  1 +//
  2 +// PrivacyViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 08.11.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class PrivacyViewController: UIViewController {
  11 + private let mainView = PrivacyView()
  12 +
  13 + override func viewDidLoad() {
  14 + super.viewDidLoad()
  15 + initViewController()
  16 + }
  17 +
  18 + override func loadView() {
  19 + view = mainView
  20 + }
  21 +
  22 + init() {
  23 + super.init(nibName: nil, bundle: nil)
  24 + }
  25 +
  26 + required init?(coder: NSCoder) {
  27 + fatalError("init(coder:) has not been implemented")
  28 + }
  29 +
  30 + private func initViewController() {
  31 + addTargets()
  32 + mainView.backgroundColor = .white
  33 +
  34 + }
  35 +}
  36 +
  37 +
  38 +//MARK: Helper
  39 +extension PrivacyViewController {
  40 + func addTargets() {
  41 + mainView.privacyButton.addTarget(self, action: #selector(privacyButtonPressed), for: .touchUpInside)
  42 + }
  43 +}
  44 +
  45 +//MARK: Targets
  46 +extension PrivacyViewController {
  47 + @objc
  48 + func privacyButtonPressed() {
  49 + self.dismiss(animated: true)
  50 + }
  51 +}
  1 +//
  2 +// PrivacyView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 08.11.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +
  11 +final class PrivacyView: UIView {
  12 + private let privacyHeaderLabel: UILabel = {
  13 + let obj = UILabel()
  14 + obj.text = StringConstants.privacyHeaderText
  15 + obj.numberOfLines = 0
  16 + obj.textAlignment = .center
  17 + obj.font = FontConstants.semiboldFont_18
  18 + return obj
  19 + }()
  20 +
  21 + private let privacyMainInfoLabel: UILabel = {
  22 + let obj = UILabel()
  23 + obj.text = StringConstants.settingTerms
  24 + obj.numberOfLines = 0
  25 + obj.font = FontConstants.regularFont_18
  26 + return obj
  27 + }()
  28 +
  29 + let privacyButton: UIButton = {
  30 + let obj = UIButton()
  31 + obj.backgroundColor = .systemIndigo.withAlphaComponent(0.4)
  32 + obj.layer.cornerRadius = 10
  33 + obj.setTitle(StringConstants.settingAgreeButtonText, for: .normal)
  34 + obj.setTitleColor(.black, for: .normal)
  35 + return obj
  36 + }()
  37 +
  38 + private let privacyStackView: UIStackView = {
  39 + let obj = UIStackView()
  40 + obj.axis = .vertical
  41 + return obj
  42 + }()
  43 +
  44 + private let privacyScrollView: UIScrollView = {
  45 + let obj = UIScrollView()
  46 + obj.showsVerticalScrollIndicator = false
  47 + return obj
  48 + }()
  49 +
  50 + override init(frame: CGRect) {
  51 + super.init(frame: frame)
  52 + setup()
  53 + }
  54 +
  55 + required init?(coder: NSCoder) {
  56 + fatalError("init(coder:) has not been implemented")
  57 + }
  58 +
  59 + private func setup() {
  60 + addSubview(privacyHeaderLabel)
  61 + addSubview(privacyButton)
  62 + privacyStackView.addSubview(privacyMainInfoLabel)
  63 + privacyScrollView.addSubview(privacyStackView)
  64 + addSubview(privacyScrollView)
  65 + setupConstraints()
  66 + }
  67 +
  68 + private func setupConstraints() {
  69 + privacyHeaderLabel.snp.makeConstraints { make in
  70 + make.top.equalTo(safeAreaLayoutGuide.snp.top)
  71 + make.leading.trailing.equalToSuperview().inset(20.sizeW)
  72 + make.centerX.equalToSuperview()
  73 + }
  74 + privacyScrollView.snp.makeConstraints { make in
  75 + make.top.equalTo(privacyHeaderLabel.snp.bottom).offset(30.sizeH)
  76 + make.leading.trailing.equalToSuperview().inset(20)
  77 + make.height.equalTo(600.sizeH)
  78 + }
  79 + privacyStackView.snp.makeConstraints { make in
  80 + make.edges.equalToSuperview()
  81 + make.centerX.equalToSuperview()
  82 + }
  83 + privacyMainInfoLabel.snp.makeConstraints { make in
  84 + make.edges.equalToSuperview()
  85 + make.width.equalTo(300.sizeW)
  86 + }
  87 + privacyButton.snp.makeConstraints { make in
  88 + make.top.equalTo(privacyScrollView.snp.bottom)
  89 + make.leading.trailing.equalToSuperview().inset(20.sizeW)
  90 + make.height.equalTo(50.sizeH)
  91 + }
  92 + }
  93 +}
  1 +//
  2 +// TermsViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 08.11.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class TermsViewController: UIViewController {
  11 + private let mainView = TermsView()
  12 +
  13 + override func viewDidLoad() {
  14 + super.viewDidLoad()
  15 + initViewController()
  16 + }
  17 +
  18 + override func loadView() {
  19 + view = mainView
  20 + }
  21 +
  22 + init() {
  23 + super.init(nibName: nil, bundle: nil)
  24 + }
  25 +
  26 + required init?(coder: NSCoder) {
  27 + fatalError("init(coder:) has not been implemented")
  28 + }
  29 +
  30 + private func initViewController() {
  31 + addTargets()
  32 + mainView.backgroundColor = .white
  33 +
  34 + }
  35 +}
  36 +
  37 +
  38 +//MARK: Helper
  39 +extension TermsViewController {
  40 + func addTargets() {
  41 + mainView.termsButton.addTarget(self, action: #selector(privacyButtonPressed), for: .touchUpInside)
  42 + }
  43 +}
  44 +
  45 +//MARK: Targets
  46 +extension TermsViewController {
  47 + @objc
  48 + func privacyButtonPressed() {
  49 + self.dismiss(animated: true)
  50 + }
  51 +}
  1 +//
  2 +// TermsView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 08.11.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class TermsView: UIView {
  11 + private let termsHeaderLabel: UILabel = {
  12 + let obj = UILabel()
  13 + obj.text = StringConstants.settingHeader
  14 + obj.numberOfLines = 0
  15 + obj.textAlignment = .center
  16 + obj.font = FontConstants.semiboldFont_18
  17 + return obj
  18 + }()
  19 +
  20 + private let termsMainInfoLabel: UILabel = {
  21 + let obj = UILabel()
  22 + obj.text = StringConstants.settingTerms
  23 + obj.numberOfLines = 0
  24 + obj.font = FontConstants.regularFont_18
  25 + return obj
  26 + }()
  27 +
  28 + let termsButton: UIButton = {
  29 + let obj = UIButton()
  30 + obj.backgroundColor = .systemIndigo.withAlphaComponent(0.4)
  31 + obj.layer.cornerRadius = 10
  32 + obj.setTitle(StringConstants.settingAgreeButtonText, for: .normal)
  33 + obj.setTitleColor(.black, for: .normal)
  34 + return obj
  35 + }()
  36 +
  37 + private let termsStackView: UIStackView = {
  38 + let obj = UIStackView()
  39 + obj.axis = .vertical
  40 + return obj
  41 + }()
  42 +
  43 + private let termsScrollView: UIScrollView = {
  44 + let obj = UIScrollView()
  45 + obj.showsVerticalScrollIndicator = false
  46 + return obj
  47 + }()
  48 +
  49 + override init(frame: CGRect) {
  50 + super.init(frame: frame)
  51 + setup()
  52 + }
  53 +
  54 + required init?(coder: NSCoder) {
  55 + fatalError("init(coder:) has not been implemented")
  56 + }
  57 +
  58 + private func setup() {
  59 + addSubview(termsHeaderLabel)
  60 + addSubview(termsButton)
  61 + termsStackView.addSubview(termsMainInfoLabel)
  62 + termsScrollView.addSubview(termsStackView)
  63 + addSubview(termsScrollView)
  64 + setupConstraints()
  65 + }
  66 +
  67 + private func setupConstraints() {
  68 + termsHeaderLabel.snp.makeConstraints { make in
  69 + make.top.equalTo(safeAreaLayoutGuide.snp.top)
  70 + make.leading.trailing.equalToSuperview().inset(20.sizeW)
  71 + make.centerX.equalToSuperview()
  72 + }
  73 + termsScrollView.snp.makeConstraints { make in
  74 + make.top.equalTo(termsHeaderLabel.snp.bottom).offset(30.sizeH)
  75 + make.leading.trailing.equalToSuperview().inset(20)
  76 + make.height.equalTo(600.sizeH)
  77 + }
  78 + termsStackView.snp.makeConstraints { make in
  79 + make.edges.equalToSuperview()
  80 + make.centerX.equalToSuperview()
  81 + }
  82 + termsMainInfoLabel.snp.makeConstraints { make in
  83 + make.edges.equalToSuperview()
  84 + make.width.equalTo(300.sizeW)
  85 + }
  86 + termsButton.snp.makeConstraints { make in
  87 + make.top.equalTo(termsScrollView.snp.bottom)
  88 + make.leading.trailing.equalToSuperview().inset(20.sizeW)
  89 + make.height.equalTo(50.sizeH)
  90 + }
  91 + }
  92 +}
  1 +//
  2 +// SettingView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 26.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class SettingView: UIView {
  11 + let backButton: UIButton = {
  12 + let obj = UIButton()
  13 + obj.setImage(UIImage(systemName: "arrow.left"), for: .normal)
  14 + obj.contentMode = .scaleToFill
  15 + return obj
  16 + }()
  17 +
  18 + let settingTableView: UITableView = {
  19 + let obj = UITableView()
  20 + obj.isScrollEnabled = false
  21 + obj.separatorStyle = .none
  22 + return obj
  23 + }()
  24 +
  25 + override init(frame: CGRect) {
  26 + super.init(frame: frame)
  27 + setup()
  28 + }
  29 +
  30 + required init?(coder: NSCoder) {
  31 + fatalError("init(coder:) has not been implemented")
  32 + }
  33 +
  34 + private func setup() {
  35 + addSubview(settingTableView)
  36 + addSubview(backButton)
  37 + setupConstraints()
  38 + }
  39 +
  40 + private func setupConstraints() {
  41 + settingTableView.snp.makeConstraints { make in
  42 + make.top.equalToSuperview().offset(168.sizeH)
  43 + make.bottom.equalToSuperview().offset(-100.sizeH)
  44 + make.leading.trailing.equalToSuperview().inset(32.sizeW)
  45 + }
  46 + backButton.snp.makeConstraints { make in
  47 + make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(16.sizeH)
  48 + make.height.equalTo(24.sizeH)
  49 + make.leading.equalToSuperview().inset(16.sizeW)
  50 + }
  51 + }
  52 +}
  1 +//
  2 +// TabsViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 28.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import RealmSwift
  10 +import Realm
  11 +
  12 +
  13 +
  14 +final class TabsViewController: UIViewController {
  15 + private var tabsData: [BrowserTabDataBase] = []
  16 + var cellIndexPathForTransition: IndexPath?
  17 + let mainView = TabsView()
  18 +
  19 + override func viewDidLoad() {
  20 + super.viewDidLoad()
  21 + initViewController()
  22 + }
  23 +
  24 + private func initViewController() {
  25 + setupCollectionView()
  26 + addTargets()
  27 + view.backgroundColor = UIColor(red: 0.984, green: 0.984, blue: 0.984, alpha: 1)
  28 + }
  29 +
  30 + override func viewWillAppear(_ animated: Bool) {
  31 + super.viewWillAppear(animated)
  32 + }
  33 +
  34 + override func viewIsAppearing(_ animated: Bool) {
  35 + refreshData()
  36 + setCountOfTabs()
  37 + navigationController?.isNavigationBarHidden = true
  38 + }
  39 +
  40 + override func loadView() {
  41 + view = mainView
  42 + }
  43 +
  44 + init() {
  45 + super.init(nibName: nil, bundle: nil)
  46 + }
  47 +
  48 + required init?(coder: NSCoder) {
  49 + fatalError("init(coder:) has not been implemented")
  50 + }
  51 +}
  52 +
  53 +
  54 +//MARK: CollectionView
  55 +extension TabsViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
  56 + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  57 + return tabsData.count
  58 + }
  59 +
  60 + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  61 + let tab = tabsData[indexPath.row]
  62 + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OpenedTabsCollectionViewCell", for: indexPath) as? OpenedTabsCollectionViewCell else {
  63 + return OpenedTabsCollectionViewCell()
  64 + }
  65 + cell.model = tab
  66 + cell.delegate = self
  67 + cell.closeTabButton.addTarget(self, action: #selector(closeTab(_:)), for: .touchUpInside)
  68 + return cell
  69 + }
  70 +
  71 + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  72 + return CGSize(width: 163.sizeW, height: 184.sizeH)
  73 + }
  74 +
  75 + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  76 + cellIndexPathForTransition = indexPath
  77 + pushSelectedTab(indexPath)
  78 + }
  79 +
  80 + private func setupCollectionView() {
  81 + mainView.openedTabsCollectionView.dataSource = self
  82 + mainView.openedTabsCollectionView.delegate = self
  83 + mainView.openedTabsCollectionView.register(OpenedTabsCollectionViewCell.self, forCellWithReuseIdentifier: "OpenedTabsCollectionViewCell")
  84 + }
  85 +}
  86 +
  87 +
  88 +//MARK: - Action
  89 +extension TabsViewController {
  90 + func didTabButtonTapped(type: HistoryToolbarElementType) {
  91 + switch type {
  92 + case .add:
  93 + addNewDefaultTab()
  94 + refreshData()
  95 + let lastIndex = tabsData.endIndex - 1
  96 + let lastIndexPath = IndexPath(row: lastIndex, section: 0)
  97 + cellIndexPathForTransition = lastIndexPath
  98 + pushSelectedTab(lastIndexPath)
  99 + break
  100 + case .done:
  101 + refreshData()
  102 + let lastIndex = tabsData.endIndex - 1
  103 + let lastIndexPath = IndexPath(row: lastIndex, section: 0)
  104 + cellIndexPathForTransition = lastIndexPath
  105 + pushSelectedTab(lastIndexPath)
  106 + break
  107 +
  108 + default:
  109 + break
  110 + }
  111 + }
  112 +
  113 + @objc
  114 + private func closeTab(_ sender: TabCollectionViewCell) {}
  115 +}
  116 +
  117 +
  118 +//MARK: - Helpers
  119 +extension TabsViewController {
  120 + private func addTargets() {
  121 + addToolbarTargets()
  122 + }
  123 +
  124 + private func addToolbarTargets() {
  125 + mainView.tabsToolbarView.action = didTabButtonTapped
  126 + }
  127 +
  128 + func getCellIndex() -> IndexPath {
  129 + return cellIndexPathForTransition ?? IndexPath(row: tabsData.count - 1, section: 0)
  130 + }
  131 +
  132 + func addNewDefaultTab() {
  133 + let defaultImage = UIImage(named: "defaultImage")
  134 + TabManager.shared.saveTabWithComplition(tabTitle: "Start Page", snapshotImage: defaultImage, tabUrl: "homeUrl") { [weak self] result in
  135 + switch result {
  136 + default:
  137 + self?.refreshData()
  138 + }
  139 + }
  140 + }
  141 +
  142 + func pushSelectedTab(_ indexPath: IndexPath) {
  143 + let index = indexPath.row
  144 + if tabsData[index].TabUrl != "homeUrl" {
  145 + let browserHomeViewController = BrowserHomeViewController(url: tabsData[index].TabUrl, currentTabId: index)
  146 + browserHomeViewController.urlManagment(tabsData[index].TabUrl)
  147 + navigationController?.pushViewController(browserHomeViewController, animated: true)
  148 + } else {
  149 + let browserHomeViewController = BrowserHomeViewController(url: tabsData[index].TabUrl, currentTabId: index)
  150 + navigationController?.pushViewController(browserHomeViewController, animated: true)
  151 + }
  152 + }
  153 +
  154 + func refreshData() {
  155 + tabsData = TabManager.shared.getAllTabs()
  156 + mainView.openedTabsCollectionView.reloadData()
  157 + }
  158 +}
  159 +
  160 +//MARK: - Delete tab
  161 +extension TabsViewController: OpenedTabsCellDelegate {
  162 + func deleteTabDelegateFunc(cell: OpenedTabsCollectionViewCell) {
  163 + guard let indexPath = mainView.openedTabsCollectionView.indexPath(for: cell) else {
  164 + return
  165 + }
  166 + tabsData.remove(at: indexPath.row)
  167 + mainView.openedTabsCollectionView.performBatchUpdates({
  168 + mainView.openedTabsCollectionView.deleteItems(at: [indexPath])
  169 + }, completion: { _ in
  170 + if self.tabsData.isEmpty {
  171 + self.addNewDefaultTab()
  172 + let browserHomeViewController = BrowserHomeViewController(url: "homeUrl", currentTabId: self.tabsData.count - 1)
  173 + self.navigationController?.pushViewController(browserHomeViewController, animated: true)
  174 + self.cellIndexPathForTransition = IndexPath(row: self.tabsData.count - 1, section: 0)
  175 + }
  176 + self.setCountOfTabs()
  177 + })
  178 + }
  179 + func setCountOfTabs() {
  180 + mainView.tabsToolbarView.showTabToolbarButtonItem.title = "\(tabsData.count) Tabs"
  181 + }
  182 +}
  1 +import UIKit
  2 +import SnapKit
  3 +
  4 +protocol OpenedTabsCellDelegate: AnyObject {
  5 + func deleteTabDelegateFunc(cell: OpenedTabsCollectionViewCell)
  6 +}
  7 +
  8 +final class OpenedTabsCollectionViewCell: UICollectionViewCell {
  9 + var model: BrowserTabDataBase? {
  10 + didSet {
  11 + handleUI()
  12 + }
  13 + }
  14 +
  15 + weak var delegate: OpenedTabsCellDelegate?
  16 +
  17 + let siteNameLabel: UILabel = {
  18 + let obj = UILabel()
  19 + obj.font = FontConstants.regularFont_14
  20 + return obj
  21 + }()
  22 +
  23 + let sitePreviewImageContainer: UIView = {
  24 + let obj = UIView()
  25 + obj.clipsToBounds = true
  26 + obj.layer.cornerRadius = 10
  27 + return obj
  28 + }()
  29 +
  30 + let sitePreviewImage: UIImageView = {
  31 + let obj = UIImageView()
  32 + obj.contentMode = .scaleAspectFill
  33 + return obj
  34 + }()
  35 +
  36 + let closeTabButton: UIButton = {
  37 + let obj = UIButton()
  38 + obj.setImage(UIImage(systemName: "xmark"), for: .normal)
  39 + obj.contentMode = .scaleAspectFill
  40 + obj.tintColor = .gray
  41 + return obj
  42 + }()
  43 +
  44 + var panGestureRecognizer: UIPanGestureRecognizer!
  45 +
  46 + override init(frame: CGRect) {
  47 + super.init(frame: frame)
  48 + setup()
  49 + }
  50 +
  51 + required init?(coder: NSCoder) {
  52 + fatalError("init(coder:) has not been implemented")
  53 + }
  54 +
  55 + func setup() {
  56 + self.backgroundColor = .white
  57 + layer.cornerRadius = 10
  58 + shadowSetup()
  59 + contentView.addSubview(siteNameLabel)
  60 + contentView.addSubview(closeTabButton)
  61 + contentView.addSubview(sitePreviewImageContainer)
  62 + sitePreviewImageContainer.addSubview(sitePreviewImage)
  63 + setupConstraints()
  64 + addingTargets()
  65 + setupPanGesture()
  66 + }
  67 +
  68 + private func setupConstraints() {
  69 + closeTabButton.snp.makeConstraints { make in
  70 + make.top.equalToSuperview().offset(8)
  71 + make.trailing.equalToSuperview().offset(-8)
  72 + make.height.equalTo(14)
  73 + make.width.equalTo(14)
  74 + }
  75 +
  76 + siteNameLabel.snp.makeConstraints { make in
  77 + make.top.equalToSuperview().offset(8)
  78 + make.leading.equalToSuperview().offset(16)
  79 + make.trailing.equalTo(closeTabButton.snp.leading).offset(-2)
  80 + }
  81 +
  82 + sitePreviewImageContainer.snp.makeConstraints { make in
  83 + make.top.equalTo(closeTabButton.snp.bottom).offset(8)
  84 + make.bottom.equalToSuperview().offset(-8)
  85 + make.leading.trailing.equalToSuperview().inset(8)
  86 + }
  87 +
  88 + sitePreviewImage.snp.makeConstraints { make in
  89 + make.edges.equalToSuperview()
  90 + }
  91 + }
  92 +
  93 + override func layoutSubviews() {
  94 + super.layoutSubviews()
  95 + shadowSetup()
  96 + }
  97 +}
  98 +
  99 +
  100 +
  101 +//MARK: Helpers
  102 +extension OpenedTabsCollectionViewCell {
  103 + func setupPanGesture() {
  104 + panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
  105 + addGestureRecognizer(panGestureRecognizer)
  106 + }
  107 +
  108 + func gestureRecognizer() {
  109 + let swipeRightGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe))
  110 + swipeRightGestureRecognizer.direction = .right
  111 + addGestureRecognizer(swipeRightGestureRecognizer)
  112 + }
  113 +
  114 + private func shadowSetup() {
  115 + layer.shadowColor = UIColor.black.withAlphaComponent(0.1).cgColor
  116 + layer.shadowOpacity = 1
  117 + layer.shadowRadius = 30
  118 + layer.shadowOffset = CGSize(width: 0, height: 0)
  119 + }
  120 +
  121 + func addingTargets() {
  122 + closeTabButton.addTarget(self, action: #selector(deleteTab), for: .touchUpInside)
  123 + }
  124 +
  125 +}
  126 +
  127 +
  128 +//MARK: Handlers
  129 +extension OpenedTabsCollectionViewCell {
  130 + private func handleUI() {
  131 + siteNameLabel.text = model?.tabTitle
  132 + sitePreviewImage.image = model?.snapshotImageData?.toImage()
  133 + }
  134 +}
  135 +
  136 +
  137 +//MARK: Actions
  138 +extension OpenedTabsCollectionViewCell {
  139 + @objc
  140 + private func deleteTab() {
  141 + delegate?.deleteTabDelegateFunc(cell: self)
  142 + if let tabId = model?.tabId {
  143 + TabManager.shared.deleteTab(tabId: tabId)
  144 + }
  145 + }
  146 +
  147 + @objc
  148 + private func handleSwipe() {
  149 + deleteTab()
  150 + }
  151 +
  152 + @objc
  153 + private func handlePan(_ gesture: UIPanGestureRecognizer) {
  154 + let translation = gesture.translation(in: self)
  155 + let width = self.frame.width
  156 + let threshold = width / 2
  157 +
  158 + if gesture.state == .changed {
  159 + transform = CGAffineTransform(translationX: translation.x, y: 0)
  160 + } else if gesture.state == .ended {
  161 + if abs(translation.x) >= threshold {
  162 + deleteTab()
  163 + } else {
  164 + UIView.animate(withDuration: 0.3) {
  165 + self.transform = .identity
  166 + }
  167 + }
  168 + }
  169 + }
  170 +}
  1 +//
  2 +// Tabs.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 28.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +enum HistoryToolbarElementType {
  11 + case add
  12 + case tabs
  13 + case done
  14 +}
  15 +
  16 +final class TabsToolbarView: UIView {
  17 + var action: ((HistoryToolbarElementType) -> Void)?
  18 +
  19 + let toolbar: UIToolbar = {
  20 + let obj = UIToolbar()
  21 + obj.barTintColor = .white
  22 + return obj
  23 + }()
  24 +
  25 + let newTabToolbarButtonItem: UIBarButtonItem = {
  26 + let obj = UIBarButtonItem()
  27 + obj.image = UIImage(systemName: "plus")
  28 + obj.tintColor = .gray
  29 + return obj
  30 + }()
  31 +
  32 +
  33 + let showTabToolbarButtonItem: UIBarButtonItem = {
  34 + let obj = UIBarButtonItem()
  35 + obj.tintColor = .gray
  36 + return obj
  37 + }()
  38 +
  39 + let doneTabToolbarButtonItem: UIBarButtonItem = {
  40 + let obj = UIBarButtonItem()
  41 + obj.title = "Done"
  42 + return obj
  43 + }()
  44 +
  45 + override init(frame: CGRect) {
  46 + super.init(frame: frame)
  47 + setup()
  48 + }
  49 +
  50 + required init?(coder: NSCoder) {
  51 + fatalError("init(coder:) has not been implemented")
  52 + }
  53 +
  54 + private func setup() {
  55 + addSubview(toolbar)
  56 + let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
  57 + toolbar.items = [ newTabToolbarButtonItem,
  58 + flexibleSpace, showTabToolbarButtonItem,
  59 + flexibleSpace, doneTabToolbarButtonItem ]
  60 +
  61 + toolbar.backgroundColor = .white
  62 + initActions()
  63 + setupConstraints()
  64 + }
  65 +
  66 + private func setupConstraints() {
  67 + toolbar.snp.makeConstraints { make in
  68 + make.top.equalToSuperview()
  69 + make.leading.trailing.equalToSuperview()
  70 + make.bottom.equalTo(safeAreaLayoutGuide.snp.bottom)
  71 + }
  72 + }
  73 +}
  74 +
  75 +
  76 +// MARK: - Helpers
  77 +extension TabsToolbarView {
  78 + private func initActions() {
  79 + newTabToolbarButtonItem.target = self
  80 + newTabToolbarButtonItem.action = #selector(didItemTapped(_:))
  81 + showTabToolbarButtonItem.target = self
  82 + showTabToolbarButtonItem.action = #selector(didItemTapped(_:))
  83 + doneTabToolbarButtonItem.target = self
  84 + doneTabToolbarButtonItem.action = #selector(didItemTapped(_:))
  85 + }
  86 +}
  87 +
  88 +// MARK: - Actions
  89 +extension TabsToolbarView {
  90 + @objc
  91 + private func didItemTapped(_ sender: UIBarButtonItem) {
  92 + guard let action else {
  93 + return
  94 + }
  95 + switch sender {
  96 + case newTabToolbarButtonItem:
  97 + action(.add)
  98 + case showTabToolbarButtonItem:
  99 + action(.tabs)
  100 + case doneTabToolbarButtonItem:
  101 + action(.done)
  102 + default:
  103 + break
  104 + }
  105 + }
  106 +}
  1 +//
  2 +// TabsView.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 28.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import SnapKit
  10 +
  11 +final class TabsView: UIView {
  12 + let openedTabsCollectionView: UICollectionView = {
  13 + let obj = UICollectionViewFlowLayout()
  14 + obj.minimumInteritemSpacing = 4.sizeW
  15 + obj.sectionInset = UIEdgeInsets(top: 16.sizeH, left: 16.sizeW, bottom: 16.sizeH, right: 16.sizeW)
  16 + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: obj)
  17 + collectionView.showsVerticalScrollIndicator = false
  18 + collectionView.backgroundColor = .clear
  19 + return collectionView
  20 + }()
  21 +
  22 + let tabsToolbarView: TabsToolbarView = {
  23 + let obj = TabsToolbarView()
  24 + obj.backgroundColor = ColorConstants.lightGray
  25 + return obj
  26 + }()
  27 +
  28 + override init(frame: CGRect) {
  29 + super.init(frame: frame)
  30 + setup()
  31 + setupConstraints()
  32 + }
  33 +
  34 + required init?(coder: NSCoder) {
  35 + fatalError("init(coder:) has not been implemented")
  36 + }
  37 +
  38 + private func setup() {
  39 + addSubview(openedTabsCollectionView)
  40 + addSubview(tabsToolbarView)
  41 + }
  42 +
  43 + private func setupConstraints() {
  44 + openedTabsCollectionView.snp.makeConstraints { make in
  45 + make.top.equalTo(safeAreaLayoutGuide.snp.top)
  46 + make.leading.trailing.equalToSuperview()
  47 + make.bottom.equalTo(tabsToolbarView.snp.top)
  48 + }
  49 + tabsToolbarView.snp.makeConstraints { make in
  50 + make.leading.equalToSuperview()
  51 + make.trailing.equalToSuperview()
  52 + make.bottom.equalTo(safeAreaLayoutGuide.snp.bottom)
  53 + }
  54 + }
  55 +}
  1 +//
  2 +// NavigationControllerViewController.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 26.09.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +final class NavigationViewController: UINavigationController {
  11 + override func viewDidLoad() {
  12 + super.viewDidLoad()
  13 + initViewController()
  14 + }
  15 +
  16 + private func initViewController() {
  17 + setStartControllers()
  18 + view.backgroundColor = .blue
  19 + delegate = self
  20 + }
  21 +}
  22 +
  23 +// MARK: - Helpers
  24 +extension NavigationViewController {
  25 + private func setStartControllers() {
  26 + let tabsViewController = TabsViewController()
  27 + let browserHomeViewController = BrowserHomeViewController(url: nil, currentTabId: nil)
  28 + let payloadViewController = PayloadViewController()
  29 + let cachingManager = CachingManager.shared
  30 + if cachingManager.isFirstAppLoad == false {
  31 + setViewControllers([tabsViewController, browserHomeViewController, payloadViewController], animated: true)
  32 + cachingManager.isFirstAppLoad.toggle()
  33 + } else {
  34 + setViewControllers([tabsViewController, browserHomeViewController], animated: true)
  35 + }
  36 +
  37 + }
  38 +}
  39 +
  40 +//MARK: Navigation Controller delegate
  41 +extension NavigationViewController: UINavigationControllerDelegate {
  42 + func navigationController(_ navigationController: UINavigationController,
  43 + animationControllerFor operation: UINavigationController.Operation,
  44 + from fromVC: UIViewController,
  45 + to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
  46 + if (fromVC is BrowserHomeViewController && toVC is TabsViewController) {
  47 + return OpenTabsTransition(operation: operation)
  48 + }
  49 +
  50 + if (fromVC is TabsViewController && toVC is BrowserHomeViewController) {
  51 + return OpenTabsTransition(operation: operation)
  52 + }
  53 + return nil
  54 + }
  55 +}
  1 +//
  2 +// ColorConstants.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 19.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +struct ColorConstants {
  11 + static let lightGray = UIColor(red: 0.984, green: 0.984, blue: 0.984, alpha: 1)
  12 + static let gray = UIColor(red: 0.62, green: 0.62, blue: 0.62, alpha: 1)
  13 + static let payloadTextColor = UIColor(red: 0.121, green: 0.121, blue: 0.121, alpha: 1)
  14 + static let buttonsBackgroundColor = UIColor(red: 0.349, green: 0.565, blue: 1, alpha: 1)
  15 +}
  1 +//
  2 +// FontConstants.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 19.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +
  10 +struct FontConstants {
  11 +
  12 + //SFProText-Regular
  13 + static let regularFont_18 = UIFont(name: "SFProText-Regular", size: 18.sizeW)
  14 + static let regularFont_14 = UIFont(name: "SFProText-Regular", size: 14.sizeW)
  15 + static let regularFont_12 = UIFont(name: "SFProText-Regular", size: 12.sizeW)
  16 +
  17 + //SFProText-Semibold
  18 + static let semiboldFont_18 = UIFont(name: "SFProText-Semibold", size: 18.sizeW)
  19 + static let semiboldFont_17 = UIFont(name: "SFProText-Semibold", size: 17.sizeW)
  20 + static let semiboldFont_15 = UIFont(name: "SFProText-Semibold", size: 15.sizeW)
  21 + static let semiboldFont_14 = UIFont(name: "SFProText-Semibold", size: 14.sizeW)
  22 + static let semiboldFont_12 = UIFont(name: "SFProText-Semibold", size: 12.sizeW)
  23 +}
  1 +//
  2 +// Strings.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 19.10.2023.
  6 +//
  7 +
  8 +import Foundation
  9 +
  10 +struct StringConstants {
  11 + //static let shared = StringConstants()
  12 +
  13 + ///PayloadView
  14 + static let ourBrowser = "Our browser lets you quickly and safely access \nthe internet. You can use it to look at web \npages, find information, and chat with friends."
  15 + static let privacyLabelText = "By starting, you agree to our Terms and Condition and Privacy Policy."
  16 + static let payloadViewControllerData = ["Unlimited searching prompts", "Advert blocker activation", "Free to use"]
  17 +
  18 +
  19 + ///BrowserHomeView
  20 + static let frequentlyVisited = "Frequently visited"
  21 +
  22 + ///BrowserHomeViewController
  23 + static let browserHomeVCImages = ["Linkedin", "Opera", "Gmail", "GitHub"]
  24 + static let browserHomeVCurl = [
  25 + "https://www.linkedin.com/",
  26 + "https://www.opera.com/",
  27 + "https://mail.google.com/",
  28 + "https://github.com/" ]
  29 +
  30 + ///SettingView
  31 + static let settingViewControllerTableViewData = ["Privacy policy", "Terms and condition", "Share app", "Rate app", "Support"]
  32 + static let removeAdvertTableViewData = ["Unlimited blocks & uploads", "Enhanced User Experience", "Faster Page Load Times", "Privacy and Security"]
  33 + static let search = "Search"
  34 +
  35 +
  36 + ///RemoveAdvertView
  37 + static let yourDiscount = "You save 91% - normally US $9,99"
  38 + static let freeTrial = "3-day free trial"
  39 + static let claimOffer = "Claim your one time sing up offer"
  40 + static let price = "0.99$"
  41 + static let subscribe = "Subscribe now"
  42 + static let advertMode = "Advertblocker Mode"
  43 + static let turnOff = "Tap to turn off"
  44 + static let turnOn = "Tap to turn on"
  45 +
  46 +
  47 + ///Cell reuse identifiers
  48 + static let historyTableViewCell = "HistoryTableViewCell"
  49 + static let searchTableViewCell = "SearchingTableViewCell"
  50 + static let removeAdvertTableViewCell = "RemoveAdvertTableViewCell"
  51 + static let settingTableViewCell = "SettingTableViewCell"
  52 + static let advantagesTableViewCell = "AdvantagesTableViewCell"
  53 +
  54 + ///setting cell detail info
  55 + static let settingTerms = "Thank you for choosing VPN Proxy Master.\n\n We will collect only the minimum data required to offer you a safe and stable VPN experience. For your convenience, hereby enclosed are the bullet points of data collected by us:\n\n · Device’s System Language which we do not retain. This is for settings the in-app language.\n\n · IP address and System Country which we do not retain. Your IP information is only used to provide you with the fastest default server list.\n\n We will strictly follow our no-logs policy and relevant data privacy laws, and will try our best to protect your privacy and security.\n\n For more information, please read our Terms and Service and Privacy Policy."
  56 + static let settingHeader = "Terms\nand conditions"
  57 + static let settingAgreeButtonText = "Agree & Continue"
  58 + static let privacyHeaderText = "Your Privacy\n is our top priority"
  59 +}
  60 +
  1 +//
  2 +// URLs.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 19.10.2023.
  6 +//
  7 +
  8 +import Foundation
  9 +
  10 +
  11 +struct URLConstants {
  12 + static let baseURL = "https://suggestqueries.google.com/complete/search?output=toolbar&hl=%@&q=%@"
  13 + static let googleURL = "https://www.google.com/search?q="
  14 + static let linkedInURL = "https://www.linkedin.com/"
  15 + static let opera = "https://www.opera.com/"
  16 + static let gmail = "https://mail.google.com/"
  17 + static let github = "https://github.com/"
  18 + static let shareAppLink = "https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"
  19 +}
  1 +{
  2 + "colors" : [
  3 + {
  4 + "idiom" : "universal"
  5 + }
  6 + ],
  7 + "info" : {
  8 + "author" : "xcode",
  9 + "version" : 1
  10 + }
  11 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "'Image Resizer.png",
  5 + "idiom" : "universal",
  6 + "platform" : "ios",
  7 + "size" : "1024x1024"
  8 + }
  9 + ],
  10 + "info" : {
  11 + "author" : "xcode",
  12 + "version" : 1
  13 + }
  14 +}
  1 +{
  2 + "info" : {
  3 + "author" : "xcode",
  4 + "version" : 1
  5 + }
  6 +}
  1 +{
  2 + "info" : {
  3 + "author" : "xcode",
  4 + "version" : 1
  5 + }
  6 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Settings (1)..png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "info" : {
  3 + "author" : "xcode",
  4 + "version" : 1
  5 + }
  6 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "github.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "gmail.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "opera.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "info" : {
  3 + "author" : "xcode",
  4 + "version" : 1
  5 + }
  6 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Gotoweb 1.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + },
  16 + {
  17 + "filename" : "Gotoweb.png",
  18 + "idiom" : "iphone",
  19 + "scale" : "1x"
  20 + },
  21 + {
  22 + "idiom" : "iphone",
  23 + "scale" : "2x"
  24 + },
  25 + {
  26 + "idiom" : "iphone",
  27 + "scale" : "3x"
  28 + }
  29 + ],
  30 + "info" : {
  31 + "author" : "xcode",
  32 + "version" : 1
  33 + }
  34 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "info" : {
  3 + "author" : "xcode",
  4 + "version" : 1
  5 + }
  6 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "info" : {
  3 + "author" : "xcode",
  4 + "version" : 1
  5 + }
  6 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "Image.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "filename" : "defaultTabImage.png",
  5 + "idiom" : "universal",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "author" : "xcode",
  19 + "version" : 1
  20 + }
  21 +}
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
  3 + <device id="retina6_12" orientation="portrait" appearance="light"/>
  4 + <dependencies>
  5 + <deployment identifier="iOS"/>
  6 + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
  7 + <capability name="Safe area layout guides" minToolsVersion="9.0"/>
  8 + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
  9 + </dependencies>
  10 + <scenes>
  11 + <!--View Controller-->
  12 + <scene sceneID="EHf-IW-A2E">
  13 + <objects>
  14 + <viewController id="01J-lp-oVM" sceneMemberID="viewController">
  15 + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
  16 + <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
  17 + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  18 + <subviews>
  19 + <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="Gotoweb" translatesAutoresizingMaskIntoConstraints="NO" id="M9l-6x-NJv">
  20 + <rect key="frame" x="128" y="395" width="136" height="62"/>
  21 + <autoresizingMask key="autoresizingMask"/>
  22 + <edgeInsets key="layoutMargins" top="8" left="8" bottom="8" right="8"/>
  23 + </imageView>
  24 + </subviews>
  25 + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
  26 + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  27 + </view>
  28 + </viewController>
  29 + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
  30 + </objects>
  31 + <point key="canvasLocation" x="52.671755725190835" y="374.64788732394368"/>
  32 + </scene>
  33 + </scenes>
  34 + <resources>
  35 + <image name="Gotoweb" width="178" height="52"/>
  36 + </resources>
  37 +</document>
This diff could not be displayed because it is too large.
  1 +//
  2 +// BrowserSearchService.swift
  3 +// Pro Seecurity VPN
  4 +//
  5 +// Created by Leyter on 30.05.2023.
  6 +//
  7 +
  8 +import Foundation
  9 +import Alamofire
  10 +
  11 +class BrowserSearchService {
  12 + private let baseUrl = "https://suggestqueries.google.com/complete/search?output=toolbar&hl=%@&q=%@"
  13 +
  14 + func searchSuggest(_ query: String) async -> [String] {
  15 + let url = String(format: baseUrl, Locale.current.languageCode ?? "", query.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "")
  16 +
  17 + guard let xmlResponse = await AF.request(url, method: .get).serializingString().response.value?.data(using: .utf8) else {
  18 + return []
  19 + }
  20 + let parser = XMLParser(data: xmlResponse)
  21 + let delegate = XMLParserSearchResponseDelegate()
  22 + parser.delegate = delegate
  23 + parser.parse()
  24 +
  25 + return delegate.dataNames
  26 + }
  27 +}
  28 +
  29 +// MARK: parser
  30 +extension BrowserSearchService {
  31 + class XMLParserSearchResponseDelegate: NSObject, XMLParserDelegate {
  32 + var dataNames: [String] = []
  33 +
  34 + func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
  35 + if elementName == "suggestion", let data = attributeDict["data"] {
  36 + dataNames.append(data)
  37 + }
  38 + }
  39 + }
  40 +}
  1 +//
  2 +// SnapshotService.swift
  3 +// browser
  4 +//
  5 +// Created by Artem Talko on 23.10.2023.
  6 +//
  7 +
  8 +import UIKit
  9 +import WebKit
  10 +
  11 +
  12 +final class SnapshotService {
  13 + static let shared = SnapshotService()
  14 + let snapshotConfiguration = WKSnapshotConfiguration()
  15 +
  16 + func makeSnapshot(_ viewForSnap: UIView) -> UIImage {
  17 + let renderer = UIGraphicsImageRenderer(size: viewForSnap.bounds.size)
  18 + let siteSnapshotImage = renderer.image { (context) in
  19 + viewForSnap.layer.render(in: context.cgContext)
  20 + }
  21 + return siteSnapshotImage
  22 + }
  23 +
  24 + func makeWKWebViewSnapshot(_ wkWV: WKWebView?, completion: @escaping (UIImage?) -> Void) {
  25 + wkWV?.takeSnapshot(with: snapshotConfiguration) { (image, error) in
  26 + if let snaphotIMG = image {
  27 + completion(snaphotIMG)
  28 + } else if let error = error {
  29 + print(error)
  30 + completion(nil)
  31 + }
  32 + }
  33 + }
  34 +}
Please register or login to post a comment