From dae9ba76fceb06aef756eeefdabc07ea5a2443ce Mon Sep 17 00:00:00 2001 From: Aliaksandr Dvoineu Date: Tue, 11 Apr 2023 06:27:13 +0300 Subject: [PATCH] [KB-2177, KB-2193]: Creating a list and View the Lists, delete the list --- .../Configure Blocking/Contents.json | 6 + .../icn_create_list.imageset/Contents.json | 15 + .../icn_create_list.pdf | 145 +++++ .../icn_edit.imageset/Contents.json | 15 + .../icn_edit.imageset/icn_edit.pdf | 211 +++++++ .../icn_export_folder.imageset/Contents.json | 15 + .../icn_export_folder.pdf | 293 +++++++++ .../icn_import_list.imageset/Contents.json | 15 + .../icn_import_list.pdf | 293 +++++++++ .../icn_list_lock.imageset/Contents.json | 15 + .../icn_list_lock.imageset/icn_list_lock.pdf | 193 ++++++ .../icn_trash.imageset/Contents.json | 15 + .../icn_trash.imageset/icn_trash.pdf | 252 ++++++++ .../lightBlue.colorset/Contents.json | 20 + FirewallUtilities.swift | 54 ++ LockdowniOS.xcodeproj/project.pbxproj | 111 +++- LockdowniOS/Base.lproj/Main.storyboard | 22 +- LockdowniOS/BlockListCell.swift | 11 + .../BlockListGroupViewController.swift | 2 +- LockdowniOS/BlockListViewController.swift | 568 +++++++++++++----- LockdowniOS/CustomBlockedTableHeader.swift | 111 ++++ LockdowniOS/CustomNavigationView.swift | 14 +- LockdowniOS/EmptyListsView.swift | 94 +++ LockdowniOS/ListsSubmenuView.swift | 79 +++ LockdowniOS/StaticTableView.swift | 18 +- LockdowniOS/en.lproj/Main.strings | 4 +- Shared.swift | 1 + en.lproj/Localizable.strings | 13 +- es.lproj/Localizable.strings | 5 +- fr.lproj/Localizable.strings | 5 +- ja.lproj/Localizable.strings | 5 +- 31 files changed, 2415 insertions(+), 205 deletions(-) create mode 100644 Assets.xcassets/Configure Blocking/Contents.json create mode 100644 Assets.xcassets/Configure Blocking/icn_create_list.imageset/Contents.json create mode 100644 Assets.xcassets/Configure Blocking/icn_create_list.imageset/icn_create_list.pdf create mode 100644 Assets.xcassets/Configure Blocking/icn_edit.imageset/Contents.json create mode 100644 Assets.xcassets/Configure Blocking/icn_edit.imageset/icn_edit.pdf create mode 100644 Assets.xcassets/Configure Blocking/icn_export_folder.imageset/Contents.json create mode 100644 Assets.xcassets/Configure Blocking/icn_export_folder.imageset/icn_export_folder.pdf create mode 100644 Assets.xcassets/Configure Blocking/icn_import_list.imageset/Contents.json create mode 100644 Assets.xcassets/Configure Blocking/icn_import_list.imageset/icn_import_list.pdf create mode 100644 Assets.xcassets/Configure Blocking/icn_list_lock.imageset/Contents.json create mode 100644 Assets.xcassets/Configure Blocking/icn_list_lock.imageset/icn_list_lock.pdf create mode 100644 Assets.xcassets/Configure Blocking/icn_trash.imageset/Contents.json create mode 100644 Assets.xcassets/Configure Blocking/icn_trash.imageset/icn_trash.pdf create mode 100644 Assets.xcassets/lightBlue.colorset/Contents.json create mode 100644 LockdowniOS/CustomBlockedTableHeader.swift create mode 100644 LockdowniOS/EmptyListsView.swift create mode 100644 LockdowniOS/ListsSubmenuView.swift diff --git a/Assets.xcassets/Configure Blocking/Contents.json b/Assets.xcassets/Configure Blocking/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Assets.xcassets/Configure Blocking/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Assets.xcassets/Configure Blocking/icn_create_list.imageset/Contents.json b/Assets.xcassets/Configure Blocking/icn_create_list.imageset/Contents.json new file mode 100644 index 0000000..f36680e --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_create_list.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icn_create_list.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Assets.xcassets/Configure Blocking/icn_create_list.imageset/icn_create_list.pdf b/Assets.xcassets/Configure Blocking/icn_create_list.imageset/icn_create_list.pdf new file mode 100644 index 0000000..4f5144e --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_create_list.imageset/icn_create_list.pdf @@ -0,0 +1,145 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.000000 -1.000000 cm +0.000000 0.678431 0.905882 scn +0.000000 5.000000 m +-0.552285 5.000000 -1.000000 4.552285 -1.000000 4.000000 c +-1.000000 3.447715 -0.552285 3.000000 0.000000 3.000000 c +0.000000 5.000000 l +h +7.000000 3.000000 m +7.552285 3.000000 8.000000 3.447715 8.000000 4.000000 c +8.000000 4.552285 7.552285 5.000000 7.000000 5.000000 c +7.000000 3.000000 l +h +12.000000 6.000000 m +11.447716 6.000000 11.000000 5.552285 11.000000 5.000000 c +11.000000 4.447716 11.447715 4.000000 12.000000 4.000000 c +12.000000 6.000000 l +h +18.000000 3.999999 m +18.552284 3.999999 19.000000 4.447714 19.000000 4.999999 c +19.000000 5.552283 18.552284 5.999999 18.000000 5.999999 c +18.000000 3.999999 l +h +14.000000 2.000000 m +14.000000 1.447715 14.447715 1.000000 15.000000 1.000000 c +15.552285 1.000000 16.000000 1.447715 16.000000 2.000000 c +14.000000 2.000000 l +h +16.000000 8.000000 m +16.000000 8.552284 15.552285 9.000000 15.000000 9.000000 c +14.447715 9.000000 14.000000 8.552284 14.000000 8.000000 c +16.000000 8.000000 l +h +0.000000 10.000000 m +-0.552285 10.000000 -1.000000 9.552284 -1.000000 9.000000 c +-1.000000 8.447716 -0.552285 8.000000 0.000000 8.000000 c +0.000000 10.000000 l +h +11.000000 8.000000 m +11.552285 8.000000 12.000000 8.447716 12.000000 9.000000 c +12.000000 9.552284 11.552285 10.000000 11.000000 10.000000 c +11.000000 8.000000 l +h +0.000000 15.000000 m +-0.552285 15.000000 -1.000000 14.552285 -1.000000 14.000000 c +-1.000000 13.447715 -0.552285 13.000000 0.000000 13.000000 c +0.000000 15.000000 l +h +11.000000 13.000000 m +11.552285 13.000000 12.000000 13.447715 12.000000 14.000000 c +12.000000 14.552285 11.552285 15.000000 11.000000 15.000000 c +11.000000 13.000000 l +h +0.000000 3.000000 m +7.000000 3.000000 l +7.000000 5.000000 l +0.000000 5.000000 l +0.000000 3.000000 l +h +12.000000 4.000000 m +18.000000 3.999999 l +18.000000 5.999999 l +12.000000 6.000000 l +12.000000 4.000000 l +h +16.000000 2.000000 m +16.000000 8.000000 l +14.000000 8.000000 l +14.000000 2.000000 l +16.000000 2.000000 l +h +0.000000 8.000000 m +11.000000 8.000000 l +11.000000 10.000000 l +0.000000 10.000000 l +0.000000 8.000000 l +h +0.000000 13.000000 m +11.000000 13.000000 l +11.000000 15.000000 l +0.000000 15.000000 l +0.000000 13.000000 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 2281 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 20.000000 14.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002371 00000 n +0000002394 00000 n +0000002567 00000 n +0000002641 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2700 +%%EOF \ No newline at end of file diff --git a/Assets.xcassets/Configure Blocking/icn_edit.imageset/Contents.json b/Assets.xcassets/Configure Blocking/icn_edit.imageset/Contents.json new file mode 100644 index 0000000..a833796 --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_edit.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icn_edit.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Assets.xcassets/Configure Blocking/icn_edit.imageset/icn_edit.pdf b/Assets.xcassets/Configure Blocking/icn_edit.imageset/icn_edit.pdf new file mode 100644 index 0000000..cf55e13 --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_edit.imageset/icn_edit.pdf @@ -0,0 +1,211 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.000000 -1.032715 cm +0.000000 0.678431 0.905882 scn +0.000000 2.032844 m +-1.000000 2.032844 l +-1.000000 1.767626 -0.894642 1.513271 -0.707105 1.325735 c +-0.519567 1.138199 -0.265212 1.032843 0.000006 1.032845 c +0.000000 2.032844 l +h +0.000000 6.032844 m +-0.707108 6.739949 l +-0.894643 6.552413 -1.000000 6.298059 -1.000000 6.032844 c +0.000000 6.032844 l +h +10.868629 16.901497 m +10.161523 17.608604 l +10.161521 17.608603 l +10.868629 16.901497 l +h +13.131348 16.901497 m +12.424241 16.194389 l +12.424241 16.194389 l +13.131348 16.901497 l +h +14.868608 15.164237 m +15.575714 15.871344 l +15.575714 15.871344 l +14.868608 15.164237 l +h +14.868629 12.901496 m +14.161523 13.608603 l +14.161523 13.608603 l +14.868629 12.901496 l +h +4.000000 2.032866 m +4.000006 1.032867 l +4.265220 1.032867 4.519572 1.138226 4.707107 1.325760 c +4.000000 2.032866 l +h +15.536865 14.341839 m +16.487923 14.650856 l +16.487923 14.650856 l +15.536865 14.341839 l +h +15.536866 13.723884 m +14.585810 14.032901 l +14.585810 14.032901 l +15.536866 13.723884 l +h +11.691007 17.569710 m +11.381989 18.520765 l +11.381989 18.520765 l +11.691007 17.569710 l +h +12.309082 17.569710 m +12.618099 18.520765 l +12.618099 18.520765 l +12.309082 17.569710 l +h +8.707107 14.739950 m +8.316583 15.130474 7.683417 15.130474 7.292893 14.739950 c +6.902369 14.349426 6.902369 13.716261 7.292893 13.325737 c +8.707107 14.739950 l +h +11.292893 9.325737 m +11.683417 8.935212 12.316583 8.935212 12.707107 9.325737 c +13.097631 9.716261 13.097631 10.349426 12.707107 10.739950 c +11.292893 9.325737 l +h +1.000000 2.032844 m +1.000000 6.032844 l +-1.000000 6.032844 l +-1.000000 2.032844 l +1.000000 2.032844 l +h +0.707108 5.325738 m +11.575736 16.194389 l +10.161521 17.608603 l +-0.707108 6.739949 l +0.707108 5.325738 l +h +12.424241 16.194389 m +14.161501 14.457130 l +15.575714 15.871344 l +13.838454 17.608603 l +12.424241 16.194389 l +h +14.161523 13.608603 m +3.292893 2.739973 l +4.707107 1.325760 l +15.575736 12.194389 l +14.161523 13.608603 l +h +3.999994 3.032866 m +-0.000006 3.032844 l +0.000006 1.032845 l +4.000006 1.032867 l +3.999994 3.032866 l +h +14.161501 14.457130 m +14.371174 14.247458 14.485370 14.132161 14.561087 14.042973 c +14.629236 13.962696 14.605762 13.971414 14.585809 14.032822 c +16.487923 14.650856 l +16.393782 14.940592 16.234184 15.162500 16.085756 15.337338 c +15.944895 15.503263 15.762056 15.685001 15.575714 15.871344 c +14.161501 14.457130 l +h +15.575736 12.194389 m +15.762083 12.380735 15.944918 12.562473 16.085777 12.728401 c +16.234209 12.903247 16.393787 13.125147 16.487923 13.414867 c +14.585810 14.032901 l +14.605757 14.094292 14.629226 14.103006 14.561090 14.022745 c +14.485382 13.933565 14.371193 13.818273 14.161523 13.608603 c +15.575736 12.194389 l +h +14.585809 14.032822 m +14.585810 14.032901 l +16.487923 13.414866 l +16.618439 13.816557 16.618437 14.249172 16.487923 14.650856 c +14.585809 14.032822 l +h +11.575734 16.194387 m +11.785399 16.404053 11.900688 16.518234 11.989861 16.593933 c +12.070109 16.662056 12.061399 16.638594 12.000024 16.618652 c +11.381989 18.520765 l +11.092287 18.426636 10.870396 18.267075 10.695542 18.118643 c +10.529612 17.977785 10.347876 17.794956 10.161523 17.608604 c +11.575734 16.194387 l +h +13.838454 17.608603 m +13.652158 17.794899 13.470441 17.977737 13.304574 18.118572 c +13.129761 18.267002 12.907867 18.426615 12.618099 18.520765 c +12.000065 16.618652 l +11.938624 16.638617 11.929857 16.662127 12.010091 16.594002 c +12.099272 16.518280 12.214523 16.404106 12.424241 16.194389 c +13.838454 17.608603 l +h +12.000024 16.618652 m +12.000065 16.618652 l +12.618099 18.520765 l +12.216413 18.651281 11.783676 18.651281 11.381989 18.520765 c +12.000024 16.618652 l +h +7.292893 13.325737 m +11.292893 9.325737 l +12.707107 10.739950 l +8.707107 14.739950 l +7.292893 13.325737 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 3802 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 17.585938 17.585938 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000003892 00000 n +0000003915 00000 n +0000004088 00000 n +0000004162 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +4221 +%%EOF \ No newline at end of file diff --git a/Assets.xcassets/Configure Blocking/icn_export_folder.imageset/Contents.json b/Assets.xcassets/Configure Blocking/icn_export_folder.imageset/Contents.json new file mode 100644 index 0000000..0ee3fd3 --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_export_folder.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icn_export_folder.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Assets.xcassets/Configure Blocking/icn_export_folder.imageset/icn_export_folder.pdf b/Assets.xcassets/Configure Blocking/icn_export_folder.imageset/icn_export_folder.pdf new file mode 100644 index 0000000..dc1563a --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_export_folder.imageset/icn_export_folder.pdf @@ -0,0 +1,293 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.000000 -1.007324 cm +0.000000 0.678431 0.905882 scn +8.000000 6.007324 m +8.000000 5.455040 8.447715 5.007324 9.000000 5.007324 c +9.552284 5.007324 10.000000 5.455039 10.000000 6.007324 c +8.000000 6.007324 l +h +9.000002 12.007324 m +9.554703 12.839375 l +9.218803 13.063307 8.781201 13.063308 8.445302 12.839375 c +9.000002 12.007324 l +h +5.445300 10.839376 m +4.985771 10.533024 4.861597 9.912154 5.167949 9.452625 c +5.474302 8.993096 6.095171 8.868922 6.554700 9.175275 c +5.445300 10.839376 l +h +11.445298 9.175273 m +11.904827 8.868920 12.525696 8.993094 12.832049 9.452622 c +13.138402 9.912151 13.014228 10.533020 12.554700 10.839373 c +11.445298 9.175273 l +h +14.800198 2.007324 m +14.800198 3.007324 l +14.800198 3.007324 l +14.800198 2.007324 l +h +3.200195 2.007324 m +3.200195 1.007324 l +3.200195 1.007324 l +3.200195 2.007324 l +h +18.000216 5.207336 m +19.000216 5.207336 l +19.000216 5.207336 l +18.000216 5.207336 l +h +17.782227 3.099356 m +18.673233 2.645365 l +18.673233 2.645365 l +17.782227 3.099356 l +h +16.907787 2.225342 m +17.361778 1.334335 l +17.361778 1.334335 l +16.907787 2.225342 l +h +16.907787 15.789337 m +17.361778 16.680344 l +17.361778 16.680344 l +16.907787 15.789337 l +h +18.000214 12.807302 m +17.000214 12.807302 l +17.000214 12.807302 l +18.000214 12.807302 l +h +17.782227 14.915283 m +16.891220 14.461292 l +16.891220 14.461292 l +17.782227 14.915283 l +h +0.217987 3.099356 m +1.108994 3.553347 l +1.108993 3.553347 l +0.217987 3.099356 l +h +1.091797 2.225342 m +1.545787 3.116348 l +1.545787 3.116348 l +1.091797 2.225342 l +h +8.293136 15.300220 m +8.683660 14.909695 9.316825 14.909695 9.707349 15.300220 c +10.097874 15.690743 10.097874 16.323908 9.707349 16.714434 c +8.293136 15.300220 l +h +7.216797 17.712585 m +7.739295 18.565226 l +7.739295 18.565226 l +7.216797 17.712585 l +h +6.638752 17.952065 m +6.872197 18.924435 l +6.638752 17.952065 l +h +10.000000 6.007324 m +10.000002 12.007324 l +8.000002 12.007324 l +8.000000 6.007324 l +10.000000 6.007324 l +h +6.554700 9.175275 m +9.554702 11.175274 l +8.445302 12.839375 l +5.445300 10.839376 l +6.554700 9.175275 l +h +8.445301 11.175274 m +11.445298 9.175273 l +12.554700 10.839373 l +9.554703 12.839375 l +8.445301 11.175274 l +h +1.000000 5.207327 m +1.000000 16.007324 l +-1.000000 16.007324 l +-1.000000 5.207327 l +1.000000 5.207327 l +h +0.000000 15.007324 m +14.800002 15.007324 l +14.800002 17.007324 l +0.000000 17.007324 l +0.000000 15.007324 l +h +14.800198 3.007324 m +3.200195 3.007324 l +3.200195 1.007324 l +14.800198 1.007324 l +14.800198 3.007324 l +h +17.000216 5.207336 m +17.000216 4.630784 16.999437 4.258511 16.976288 3.975174 c +16.954092 3.703511 16.916414 3.602791 16.891220 3.553347 c +18.673233 2.645365 l +18.866026 3.023744 18.937344 3.416962 18.969645 3.812307 c +19.000992 4.195979 19.000216 4.663784 19.000216 5.207336 c +17.000216 5.207336 l +h +14.800198 1.007324 m +15.343755 1.007324 15.811479 1.006554 16.195076 1.037912 c +16.590408 1.070230 16.983469 1.141577 17.361778 1.334335 c +16.453796 3.116348 l +16.404282 3.091119 16.303600 3.053456 16.032120 3.031263 c +15.748905 3.008110 15.376745 3.007324 14.800198 3.007324 c +14.800198 1.007324 l +h +16.891220 3.553347 m +16.795576 3.365634 16.642408 3.212451 16.453796 3.116348 c +17.361778 1.334335 l +17.925814 1.621725 18.385384 2.080429 18.673233 2.645365 c +16.891220 3.553347 l +h +14.800002 15.007324 m +15.376560 15.007324 15.748776 15.006546 16.032057 14.983398 c +16.303633 14.961206 16.404325 14.923538 16.453796 14.898331 c +17.361778 16.680344 l +16.983425 16.873123 16.590279 16.944448 16.194944 16.976753 c +15.811315 17.008102 15.343550 17.007324 14.800002 17.007324 c +14.800002 15.007324 l +h +19.000214 12.807302 m +19.000214 13.350854 19.000992 13.818659 18.969645 14.202330 c +18.937344 14.597675 18.866028 14.990894 18.673233 15.369274 c +16.891220 14.461292 l +16.916412 14.411849 16.954090 14.311130 16.976286 14.039466 c +16.999435 13.756128 17.000214 13.383856 17.000214 12.807302 c +19.000214 12.807302 l +h +16.453796 14.898331 m +16.642366 14.802250 16.795555 14.649047 16.891220 14.461292 c +18.673233 15.369274 l +18.385405 15.934168 17.925856 16.392931 17.361778 16.680344 c +16.453796 14.898331 l +h +-1.000000 5.207327 m +-1.000000 4.663775 -1.000778 4.195972 -0.969431 3.812304 c +-0.937129 3.416959 -0.865813 3.023744 -0.673019 2.645365 c +1.108993 3.553347 l +1.083800 3.602792 1.046123 3.703509 1.023927 3.975168 c +1.000778 4.258503 1.000000 4.630774 1.000000 5.207327 c +-1.000000 5.207327 l +h +3.200195 3.007324 m +2.623666 3.007324 2.251269 3.008109 1.967820 3.031267 c +1.695978 3.053476 1.595188 3.091177 1.545787 3.116348 c +0.637806 1.334335 l +1.016229 1.141520 1.409586 1.070211 1.804961 1.037909 c +2.188730 1.006556 2.656620 1.007324 3.200195 1.007324 c +3.200195 3.007324 l +h +-0.673019 2.645365 m +-0.385509 2.081095 0.073104 1.622065 0.637806 1.334335 c +1.545787 3.116348 l +1.357841 3.212111 1.204977 3.364968 1.108994 3.553347 c +-0.673019 2.645365 l +h +17.000214 12.807302 m +17.000216 5.207336 l +19.000216 5.207336 l +19.000214 12.807302 l +17.000214 12.807302 l +h +9.707349 16.714434 m +8.644607 17.777176 l +7.230393 16.362961 l +8.293136 15.300220 l +9.707349 16.714434 l +h +5.674517 19.007324 m +2.000000 19.007324 l +2.000000 17.007324 l +5.674517 17.007324 l +5.674517 19.007324 l +h +2.000000 19.007324 m +0.343146 19.007324 -1.000000 17.664179 -1.000000 16.007324 c +1.000000 16.007324 l +1.000000 16.559608 1.447715 17.007324 2.000000 17.007324 c +2.000000 19.007324 l +h +8.644607 17.777176 m +8.332295 18.089487 8.065499 18.365328 7.739295 18.565226 c +6.694298 16.859945 l +6.771761 16.812477 6.850898 16.742456 7.230393 16.362961 c +8.644607 17.777176 l +h +5.674517 17.007324 m +6.211343 17.007324 6.316999 17.000895 6.405306 16.979694 c +6.872197 18.924435 l +6.500154 19.013754 6.116053 19.007324 5.674517 19.007324 c +5.674517 17.007324 l +h +7.739295 18.565226 m +7.470991 18.729643 7.178434 18.850912 6.872197 18.924435 c +6.405306 16.979694 l +6.507214 16.955229 6.604713 16.914843 6.694298 16.859945 c +7.739295 18.565226 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 5966 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 20.000000 18.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000006056 00000 n +0000006079 00000 n +0000006252 00000 n +0000006326 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +6385 +%%EOF \ No newline at end of file diff --git a/Assets.xcassets/Configure Blocking/icn_import_list.imageset/Contents.json b/Assets.xcassets/Configure Blocking/icn_import_list.imageset/Contents.json new file mode 100644 index 0000000..39d43d8 --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_import_list.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icn_import_list.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Assets.xcassets/Configure Blocking/icn_import_list.imageset/icn_import_list.pdf b/Assets.xcassets/Configure Blocking/icn_import_list.imageset/icn_import_list.pdf new file mode 100644 index 0000000..b461e4b --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_import_list.imageset/icn_import_list.pdf @@ -0,0 +1,293 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.000000 -1.007324 cm +0.000000 0.678431 0.905882 scn +10.000001 12.007324 m +10.000001 12.559608 9.552286 13.007324 9.000001 13.007324 c +8.447717 13.007324 8.000001 12.559608 8.000001 12.007324 c +10.000001 12.007324 l +h +9.000000 6.007324 m +8.445300 5.175274 l +8.781199 4.951341 9.218801 4.951341 9.554700 5.175274 c +9.000000 6.007324 l +h +12.554700 7.175274 m +13.014229 7.481627 13.138403 8.102496 12.832050 8.562024 c +12.525698 9.021553 11.904828 9.145727 11.445300 8.839375 c +12.554700 7.175274 l +h +6.554700 8.839375 m +6.095171 9.145727 5.474302 9.021553 5.167950 8.562024 c +4.861597 8.102496 4.985771 7.481627 5.445300 7.175274 c +6.554700 8.839375 l +h +14.800198 2.007324 m +14.800198 3.007324 l +14.800198 3.007324 l +14.800198 2.007324 l +h +3.200195 2.007324 m +3.200195 1.007324 l +3.200195 1.007324 l +3.200195 2.007324 l +h +18.000216 5.207336 m +19.000216 5.207336 l +19.000216 5.207336 l +18.000216 5.207336 l +h +17.782227 3.099356 m +18.673233 2.645365 l +18.673233 2.645365 l +17.782227 3.099356 l +h +16.907787 2.225342 m +17.361778 1.334335 l +17.361778 1.334335 l +16.907787 2.225342 l +h +16.907787 15.789337 m +17.361778 16.680344 l +17.361778 16.680344 l +16.907787 15.789337 l +h +18.000214 12.807302 m +17.000214 12.807302 l +17.000214 12.807302 l +18.000214 12.807302 l +h +17.782227 14.915283 m +16.891220 14.461292 l +16.891220 14.461292 l +17.782227 14.915283 l +h +0.217987 3.099356 m +1.108994 3.553347 l +1.108993 3.553347 l +0.217987 3.099356 l +h +1.091797 2.225342 m +1.545787 3.116348 l +1.545787 3.116348 l +1.091797 2.225342 l +h +8.293136 15.300220 m +8.683660 14.909695 9.316825 14.909695 9.707349 15.300220 c +10.097874 15.690743 10.097874 16.323908 9.707349 16.714434 c +8.293136 15.300220 l +h +7.216797 17.712585 m +7.739295 18.565226 l +7.739295 18.565226 l +7.216797 17.712585 l +h +6.638752 17.952065 m +6.872197 18.924435 l +6.638752 17.952065 l +h +8.000001 12.007324 m +8.000000 6.007324 l +10.000000 6.007324 l +10.000001 12.007324 l +8.000001 12.007324 l +h +11.445300 8.839375 m +8.445300 6.839375 l +9.554700 5.175274 l +12.554700 7.175274 l +11.445300 8.839375 l +h +9.554700 6.839375 m +6.554700 8.839375 l +5.445300 7.175274 l +8.445300 5.175274 l +9.554700 6.839375 l +h +1.000000 5.207327 m +1.000000 16.007324 l +-1.000000 16.007324 l +-1.000000 5.207327 l +1.000000 5.207327 l +h +0.000000 15.007324 m +14.800002 15.007324 l +14.800002 17.007324 l +0.000000 17.007324 l +0.000000 15.007324 l +h +14.800198 3.007324 m +3.200195 3.007324 l +3.200195 1.007324 l +14.800198 1.007324 l +14.800198 3.007324 l +h +17.000216 5.207336 m +17.000216 4.630784 16.999437 4.258511 16.976288 3.975174 c +16.954092 3.703511 16.916414 3.602791 16.891220 3.553347 c +18.673233 2.645365 l +18.866026 3.023744 18.937344 3.416962 18.969645 3.812307 c +19.000992 4.195979 19.000216 4.663784 19.000216 5.207336 c +17.000216 5.207336 l +h +14.800198 1.007324 m +15.343755 1.007324 15.811479 1.006554 16.195076 1.037912 c +16.590408 1.070230 16.983469 1.141577 17.361778 1.334335 c +16.453796 3.116348 l +16.404282 3.091119 16.303600 3.053456 16.032120 3.031263 c +15.748905 3.008110 15.376745 3.007324 14.800198 3.007324 c +14.800198 1.007324 l +h +16.891220 3.553347 m +16.795576 3.365634 16.642408 3.212451 16.453796 3.116348 c +17.361778 1.334335 l +17.925814 1.621725 18.385384 2.080429 18.673233 2.645365 c +16.891220 3.553347 l +h +14.800002 15.007324 m +15.376560 15.007324 15.748776 15.006546 16.032057 14.983398 c +16.303633 14.961206 16.404325 14.923538 16.453796 14.898331 c +17.361778 16.680344 l +16.983425 16.873123 16.590279 16.944448 16.194944 16.976753 c +15.811315 17.008102 15.343550 17.007324 14.800002 17.007324 c +14.800002 15.007324 l +h +19.000214 12.807302 m +19.000214 13.350854 19.000992 13.818659 18.969645 14.202330 c +18.937344 14.597675 18.866028 14.990894 18.673233 15.369274 c +16.891220 14.461292 l +16.916412 14.411849 16.954090 14.311130 16.976286 14.039466 c +16.999435 13.756128 17.000214 13.383856 17.000214 12.807302 c +19.000214 12.807302 l +h +16.453796 14.898331 m +16.642366 14.802250 16.795555 14.649047 16.891220 14.461292 c +18.673233 15.369274 l +18.385405 15.934168 17.925856 16.392931 17.361778 16.680344 c +16.453796 14.898331 l +h +-1.000000 5.207327 m +-1.000000 4.663775 -1.000778 4.195972 -0.969431 3.812304 c +-0.937129 3.416959 -0.865813 3.023744 -0.673019 2.645365 c +1.108993 3.553347 l +1.083800 3.602792 1.046123 3.703509 1.023927 3.975168 c +1.000778 4.258503 1.000000 4.630774 1.000000 5.207327 c +-1.000000 5.207327 l +h +3.200195 3.007324 m +2.623666 3.007324 2.251269 3.008109 1.967820 3.031267 c +1.695978 3.053476 1.595188 3.091177 1.545787 3.116348 c +0.637806 1.334335 l +1.016229 1.141520 1.409586 1.070211 1.804961 1.037909 c +2.188730 1.006556 2.656620 1.007324 3.200195 1.007324 c +3.200195 3.007324 l +h +-0.673019 2.645365 m +-0.385509 2.081095 0.073104 1.622065 0.637806 1.334335 c +1.545787 3.116348 l +1.357841 3.212111 1.204977 3.364968 1.108994 3.553347 c +-0.673019 2.645365 l +h +17.000214 12.807302 m +17.000216 5.207336 l +19.000216 5.207336 l +19.000214 12.807302 l +17.000214 12.807302 l +h +9.707349 16.714434 m +8.644607 17.777176 l +7.230393 16.362961 l +8.293136 15.300220 l +9.707349 16.714434 l +h +5.674517 19.007324 m +2.000000 19.007324 l +2.000000 17.007324 l +5.674517 17.007324 l +5.674517 19.007324 l +h +2.000000 19.007324 m +0.343146 19.007324 -1.000000 17.664179 -1.000000 16.007324 c +1.000000 16.007324 l +1.000000 16.559608 1.447715 17.007324 2.000000 17.007324 c +2.000000 19.007324 l +h +8.644607 17.777176 m +8.332295 18.089487 8.065499 18.365328 7.739295 18.565226 c +6.694298 16.859945 l +6.771761 16.812477 6.850898 16.742456 7.230393 16.362961 c +8.644607 17.777176 l +h +5.674517 17.007324 m +6.211343 17.007324 6.316999 17.000895 6.405306 16.979694 c +6.872197 18.924435 l +6.500154 19.013754 6.116053 19.007324 5.674517 19.007324 c +5.674517 17.007324 l +h +7.739295 18.565226 m +7.470991 18.729643 7.178434 18.850912 6.872197 18.924435 c +6.405306 16.979694 l +6.507214 16.955229 6.604713 16.914843 6.694298 16.859945 c +7.739295 18.565226 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 5958 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 20.000000 18.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000006048 00000 n +0000006071 00000 n +0000006244 00000 n +0000006318 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +6377 +%%EOF \ No newline at end of file diff --git a/Assets.xcassets/Configure Blocking/icn_list_lock.imageset/Contents.json b/Assets.xcassets/Configure Blocking/icn_list_lock.imageset/Contents.json new file mode 100644 index 0000000..b4129a9 --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_list_lock.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icn_list_lock.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Assets.xcassets/Configure Blocking/icn_list_lock.imageset/icn_list_lock.pdf b/Assets.xcassets/Configure Blocking/icn_list_lock.imageset/icn_list_lock.pdf new file mode 100644 index 0000000..e391f4a --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_list_lock.imageset/icn_list_lock.pdf @@ -0,0 +1,193 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 -0.115234 cm +0.600000 0.600000 0.600000 scn +13.355799 14.448567 m +13.355799 15.347044 14.108089 16.115234 15.085798 16.115234 c +16.063509 16.115234 16.815800 15.347045 16.815800 14.448567 c +16.815800 12.781900 l +13.355799 12.781900 l +13.355799 14.448567 l +h +18.815800 14.448568 m +18.815800 12.781900 l +19.453976 12.781900 l +19.469994 12.781900 l +19.470068 12.781900 l +19.710873 12.781902 19.895102 12.781903 20.031441 12.778576 c +20.158554 12.775473 20.318783 12.769018 20.477230 12.733616 c +20.683960 12.687425 20.825340 12.607181 20.908661 12.557057 c +20.942144 12.536773 l +20.977835 12.515055 20.995888 12.504070 21.037453 12.483383 c +21.565689 12.220476 22.000456 11.798573 22.274250 11.273685 c +22.460350 10.916920 22.527569 10.548424 22.557632 10.188303 c +22.585844 9.850403 22.585823 9.442102 22.585800 8.978066 c +22.585800 8.978024 l +22.585798 8.937500 l +22.585798 3.959723 l +22.585800 3.919319 l +22.585800 3.919185 l +22.585823 3.455129 22.585844 3.046791 22.557634 2.708854 c +22.527573 2.348729 22.460361 1.980175 22.274250 1.623386 c +22.000401 1.098391 21.565578 0.676632 21.037453 0.413780 c +20.995888 0.393093 20.977837 0.382109 20.942131 0.360380 c +20.908699 0.340124 l +20.825403 0.290012 20.684029 0.209753 20.477293 0.163548 c +20.318830 0.128130 20.158588 0.121670 20.031464 0.118565 c +19.895023 0.115232 19.710638 0.115232 19.469597 0.115234 c +19.453976 0.115234 l +10.717978 0.115234 l +10.702357 0.115234 l +10.461308 0.115232 10.276887 0.115232 10.140389 0.118565 c +10.013143 0.121670 9.852998 0.128136 9.694645 0.163469 c +9.488159 0.209541 9.346855 0.289532 9.263210 0.339779 c +9.229139 0.360394 l +9.193475 0.382071 9.175378 0.393070 9.133765 0.413780 c +8.604961 0.676970 8.171048 1.099054 7.897542 1.623386 c +7.711491 1.980061 7.644199 2.348513 7.614075 2.708692 c +7.585759 3.047248 7.585777 3.456367 7.585798 3.921459 c +7.585799 3.959723 l +7.585799 8.937500 l +7.585798 8.975773 l +7.585777 9.440857 7.585759 9.849941 7.614076 10.188466 c +7.644203 10.548641 7.711503 10.917034 7.897542 11.273685 c +8.170993 11.797913 8.604854 12.220140 9.133765 12.483382 c +9.175375 12.504091 9.193474 12.515092 9.229122 12.536757 c +9.229134 12.536764 l +9.263247 12.557402 l +9.346916 12.607658 9.488223 12.687635 9.694705 12.733694 c +9.853043 12.769012 10.013176 12.775473 10.140410 12.778576 c +10.276809 12.781903 10.461073 12.781902 10.701888 12.781900 c +10.701960 12.781900 l +10.717978 12.781900 l +11.355799 12.781900 l +11.355799 14.448567 l +11.355799 16.495609 13.048035 18.115234 15.085798 18.115234 c +17.123564 18.115234 18.815800 16.495609 18.815800 14.448568 c +h +10.717978 10.781900 m +12.565525 10.781900 l +17.605526 10.781900 l +19.453976 10.781900 l +19.714914 10.781900 19.873917 10.781825 19.982641 10.779171 c +19.985107 10.779110 l +20.028587 10.754195 20.083012 10.724394 20.146315 10.692888 c +20.302988 10.614911 20.425816 10.492844 20.500999 10.348710 c +20.513269 10.325189 20.545135 10.254660 20.564568 10.021915 c +20.585033 9.776763 20.585798 9.452318 20.585798 8.937500 c +20.585798 3.959723 l +20.585800 3.444908 20.585033 3.120418 20.564566 2.875221 c +20.545132 2.642406 20.513256 2.571858 20.500999 2.548361 c +20.425873 2.404336 20.303099 2.282308 20.146315 2.204275 c +20.082991 2.172758 20.028553 2.142953 19.985065 2.118032 c +19.982620 2.117968 l +19.873907 2.115312 19.714911 2.115234 19.453976 2.115234 c +10.717977 2.115234 l +10.457050 2.115234 10.297997 2.115312 10.189205 2.117968 c +10.186153 2.118043 l +10.142670 2.142950 10.088205 2.172770 10.024903 2.204275 c +9.868797 2.281970 9.746266 2.403675 9.670794 2.548363 c +9.658476 2.571976 9.626583 2.642624 9.607116 2.875384 c +9.586614 3.120513 9.585799 3.445012 9.585799 3.959723 c +9.585799 8.937500 l +9.585799 9.452215 9.586615 9.776669 9.607115 10.021752 c +9.626579 10.254442 9.658463 10.325073 9.670793 10.348710 c +9.746321 10.493504 9.868906 10.615247 10.024904 10.692888 c +10.088188 10.724384 10.142641 10.754193 10.186118 10.779095 c +10.189183 10.779171 l +10.297986 10.781825 10.457045 10.781900 10.717978 10.781900 c +h +6.434995 15.641798 m +6.788558 16.066074 6.731235 16.696640 6.306958 17.050203 c +5.882681 17.403769 5.252116 17.346443 4.898552 16.922167 c +2.557142 14.112475 l +1.554806 14.780700 l +1.095278 15.087051 0.474408 14.962878 0.168056 14.503349 c +-0.138296 14.043820 -0.014123 13.422951 0.445406 13.116599 c +2.195406 11.949932 l +2.620624 11.666454 3.191163 11.749201 3.518328 12.141798 c +6.434995 15.641798 l +h +6.434995 9.808607 m +6.788558 10.232883 6.731235 10.863449 6.306958 11.217012 c +5.882681 11.570577 5.252116 11.513252 4.898552 11.088976 c +2.557126 8.279264 l +1.554783 8.947453 l +1.095246 9.253792 0.474380 9.129601 0.168040 8.670063 c +-0.138299 8.210526 -0.014108 7.589661 0.445430 7.283321 c +2.195430 6.116726 l +2.620646 5.833265 3.191170 5.916018 3.518328 6.308607 c +6.434995 9.808607 l +h +6.434995 3.975132 m +6.788558 4.399409 6.731235 5.029974 6.306958 5.383537 c +5.882681 5.737102 5.252116 5.679778 4.898552 5.255501 c +2.557142 2.445809 l +1.554806 3.114033 l +1.095278 3.420385 0.474408 3.296211 0.168056 2.836682 c +-0.138297 2.377153 -0.014122 1.756285 0.445406 1.449932 c +2.195406 0.283266 l +2.620624 -0.000212 3.191163 0.082535 3.518328 0.475132 c +6.434995 3.975132 l +h +f* +n +Q + +endstream +endobj + +3 0 obj + 5259 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 22.585938 18.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000005349 00000 n +0000005372 00000 n +0000005545 00000 n +0000005619 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +5678 +%%EOF \ No newline at end of file diff --git a/Assets.xcassets/Configure Blocking/icn_trash.imageset/Contents.json b/Assets.xcassets/Configure Blocking/icn_trash.imageset/Contents.json new file mode 100644 index 0000000..795b1b0 --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_trash.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icn_trash.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Assets.xcassets/Configure Blocking/icn_trash.imageset/icn_trash.pdf b/Assets.xcassets/Configure Blocking/icn_trash.imageset/icn_trash.pdf new file mode 100644 index 0000000..1951a0c --- /dev/null +++ b/Assets.xcassets/Configure Blocking/icn_trash.imageset/icn_trash.pdf @@ -0,0 +1,252 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.000000 -1.001465 cm +0.000000 0.678431 0.905882 scn +14.000000 17.001465 m +15.000000 17.001465 l +15.000000 17.553749 14.552285 18.001465 14.000000 18.001465 c +14.000000 17.001465 l +h +2.000000 17.001465 m +2.000000 18.001465 l +1.447715 18.001465 1.000000 17.553749 1.000000 17.001465 c +2.000000 17.001465 l +h +3.091797 2.219482 m +3.545787 3.110489 l +3.545787 3.110489 l +3.091797 2.219482 l +h +2.217987 3.093435 m +1.326980 2.639444 l +1.326981 2.639444 l +2.217987 3.093435 l +h +13.782227 3.093435 m +12.891220 3.547426 l +13.782227 3.093435 l +h +12.907785 2.219482 m +12.453794 3.110489 l +12.907785 2.219482 l +h +0.000000 18.001465 m +-0.552285 18.001465 -1.000000 17.553749 -1.000000 17.001465 c +-1.000000 16.449181 -0.552285 16.001465 0.000000 16.001465 c +0.000000 18.001465 l +h +16.000000 16.001465 m +16.552284 16.001465 17.000000 16.449181 17.000000 17.001465 c +17.000000 17.553749 16.552284 18.001465 16.000000 18.001465 c +16.000000 16.001465 l +h +12.000000 17.001465 m +12.000000 16.001465 l +12.552285 16.001465 13.000000 16.449181 13.000000 17.001465 c +12.000000 17.001465 l +h +4.000000 17.001465 m +3.000000 17.001465 l +3.000000 16.449181 3.447715 16.001465 4.000000 16.001465 c +4.000000 17.001465 l +h +11.847656 18.766846 m +12.771536 19.149529 l +11.847656 18.766846 l +h +10.765368 19.849224 m +11.148051 20.773104 l +11.148051 20.773104 l +10.765368 19.849224 l +h +13.000000 17.001465 m +13.000000 5.201465 l +15.000000 5.201465 l +15.000000 17.001465 l +13.000000 17.001465 l +h +10.800196 3.001465 m +5.200195 3.001465 l +5.200195 1.001465 l +10.800196 1.001465 l +10.800196 3.001465 l +h +3.000000 5.201465 m +3.000000 17.001465 l +1.000000 17.001465 l +1.000000 5.201465 l +3.000000 5.201465 l +h +2.000000 16.001465 m +14.000000 16.001465 l +14.000000 18.001465 l +2.000000 18.001465 l +2.000000 16.001465 l +h +5.200195 3.001465 m +4.623666 3.001465 4.251269 3.002249 3.967820 3.025408 c +3.695979 3.047617 3.595189 3.085318 3.545787 3.110489 c +2.637806 1.328476 l +3.016229 1.135660 3.409585 1.064352 3.804961 1.032049 c +4.188730 1.000696 4.656620 1.001465 5.200195 1.001465 c +5.200195 3.001465 l +h +1.000000 5.201465 m +1.000000 4.657912 0.999222 4.190097 1.030569 3.806416 c +1.062869 3.411068 1.134183 3.017832 1.326980 2.639444 c +3.108994 3.547426 l +3.083804 3.596863 3.046124 3.697588 3.023927 3.969273 c +3.000778 4.252625 3.000000 4.624912 3.000000 5.201465 c +1.000000 5.201465 l +h +3.545787 3.110489 m +3.357777 3.206285 3.204944 3.359112 3.108994 3.547426 c +1.326981 2.639444 l +1.614523 2.075109 2.073169 1.616173 2.637806 1.328476 c +3.545787 3.110489 l +h +13.000000 5.201465 m +13.000000 4.624812 12.999276 4.252532 12.976167 3.969114 c +12.954009 3.697376 12.916352 3.596750 12.891220 3.547426 c +14.673233 2.639444 l +14.866088 3.017944 14.937318 3.411280 14.969550 3.806574 c +15.000831 4.190189 15.000000 4.658012 15.000000 5.201465 c +13.000000 5.201465 l +h +10.800196 1.001465 m +11.343753 1.001465 11.811477 1.000694 12.195074 1.032053 c +12.590406 1.064371 12.983468 1.135717 13.361776 1.328476 c +12.453794 3.110489 l +12.404280 3.085260 12.303599 3.047598 12.032118 3.025404 c +11.748903 3.002251 11.376743 3.001465 10.800196 3.001465 c +10.800196 1.001465 l +h +12.891220 3.547426 m +12.795609 3.359779 12.642474 3.206625 12.453794 3.110489 c +13.361776 1.328476 l +13.925745 1.615833 14.385350 2.074442 14.673233 2.639444 c +12.891220 3.547426 l +h +0.000000 16.001465 m +16.000000 16.001465 l +16.000000 18.001465 l +0.000000 18.001465 l +0.000000 16.001465 l +h +12.000000 18.001465 m +4.000000 18.001465 l +4.000000 16.001465 l +12.000000 16.001465 l +12.000000 18.001465 l +h +7.000000 19.001465 m +9.000000 19.001465 l +9.000000 21.001465 l +7.000000 21.001465 l +7.000000 19.001465 l +h +5.000000 17.001465 m +5.000000 17.481089 5.000542 17.790730 5.016711 18.027714 c +5.032267 18.255718 5.058884 18.342550 5.076120 18.384163 c +3.228361 19.149529 l +3.093356 18.823599 3.043853 18.493683 3.021349 18.163853 c +2.999458 17.843004 3.000000 17.453724 3.000000 17.001465 c +5.000000 17.001465 l +h +7.000000 21.001465 m +6.547735 21.001465 6.158405 21.002007 5.837504 20.980116 c +5.507661 20.957617 5.177657 20.908123 4.851692 20.773104 c +5.617058 18.925344 l +5.658635 18.942566 5.745502 18.969193 5.973615 18.984753 c +6.210670 19.000923 6.520382 19.001465 7.000000 19.001465 c +7.000000 21.001465 l +h +5.076120 18.384163 m +5.177706 18.629412 5.372252 18.823942 5.617058 18.925344 c +4.851692 20.773104 l +4.116386 20.468531 3.532752 19.884392 3.228361 19.149529 c +5.076120 18.384163 l +h +13.000000 17.001465 m +13.000000 17.453781 13.000516 17.843056 12.978593 18.163944 c +12.956057 18.493805 12.906512 18.823666 12.771536 19.149529 c +10.923777 18.384163 l +10.941041 18.342484 10.967669 18.255594 10.983244 18.027620 c +10.999433 17.790674 11.000000 17.481030 11.000000 17.001465 c +13.000000 17.001465 l +h +9.000000 19.001465 m +9.479624 19.001465 9.789260 19.000923 10.026240 18.984755 c +10.254239 18.969198 10.341070 18.942581 10.382684 18.925344 c +11.148051 20.773104 l +10.822123 20.908108 10.492211 20.957611 10.162383 20.980116 c +9.841536 21.002007 9.452259 21.001465 9.000000 21.001465 c +9.000000 19.001465 l +h +12.771536 19.149529 m +12.467088 19.884533 11.883216 20.468588 11.148051 20.773104 c +10.382684 18.925344 l +10.627631 18.823883 10.822249 18.629271 10.923777 18.384163 c +12.771536 19.149529 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 5310 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 18.000000 20.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000005400 00000 n +0000005423 00000 n +0000005596 00000 n +0000005670 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +5729 +%%EOF \ No newline at end of file diff --git a/Assets.xcassets/lightBlue.colorset/Contents.json b/Assets.xcassets/lightBlue.colorset/Contents.json new file mode 100644 index 0000000..8048731 --- /dev/null +++ b/Assets.xcassets/lightBlue.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.984", + "green" : "0.952", + "red" : "0.875" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirewallUtilities.swift b/FirewallUtilities.swift index 9ffa5ee..440fb82 100644 --- a/FirewallUtilities.swift +++ b/FirewallUtilities.swift @@ -14,6 +14,7 @@ import WidgetKit let kLockdownBlockedDomains = "lockdown_domains" let kUserBlockedDomains = "lockdown_domains_user" +let kUserBlockedLists = "lockdown_lists_user" // MARK: - data structures @@ -42,6 +43,21 @@ struct LockdownDefaults : Codable { var lockdownDefaults : Dictionary } +struct UserBlockListsGroup: Codable { +// var version : Int +// var internalID: String + var name: String +// var iconURL : String + var enabled : Bool + var domains : Dictionary + var ipRanges : Dictionary + var warning: String? +} + +struct UserBlockListsDefaults: Codable { + var userBlockListsDefaults: Dictionary +} + // MARK: - Block Metrics & Block Log let currentCalendar = Calendar.current @@ -385,6 +401,33 @@ func getIsCombinedBlockListEmpty() -> Bool { return (getAllBlockedDomains() + getAllWhitelistedDomains()).isEmpty } +// MARK: - User blocked lists + +func getUserBlockedList() -> Dictionary { + if let lists = defaults.dictionary(forKey: kUserBlockedLists) { + return lists + } + return Dictionary() +} + +func addUserBlockedList(list: String) { + var lists = getUserBlockedList() + lists[list] = NSNumber(value: true) + defaults.set(lists, forKey: kUserBlockedLists) +} + +func setUserBlockedList(list: String, enabled: Bool) { + var lists = getUserBlockedList() + lists[list] = NSNumber(value: enabled) + defaults.set(lists, forKey: kUserBlockedLists) +} + +func deleteUserBlockedList(list: String) { + var lists = getUserBlockedList() + lists[list] = nil + defaults.set(lists, forKey: kUserBlockedLists) +} + // MARK: - User blocked domains func getUserBlockedDomains() -> Dictionary { @@ -423,3 +466,14 @@ func getLockdownBlockedDomains() -> LockdownDefaults { } return lockdownDefaults } + +func getUserBlockedLists() -> UserBlockListsDefaults { + guard let blockListsdefaultsData = defaults.object(forKey: kUserBlockedLists) as? Data else { + return UserBlockListsDefaults(userBlockListsDefaults: [:]) + } + guard let blockListsdefaults = try? PropertyListDecoder().decode(UserBlockListsDefaults.self, from: blockListsdefaultsData) else { + return UserBlockListsDefaults(userBlockListsDefaults: [:]) + } + return blockListsdefaults +} + diff --git a/LockdowniOS.xcodeproj/project.pbxproj b/LockdowniOS.xcodeproj/project.pbxproj index 186becb..892d447 100644 --- a/LockdowniOS.xcodeproj/project.pbxproj +++ b/LockdowniOS.xcodeproj/project.pbxproj @@ -202,6 +202,10 @@ 3DF2455423A2F8A400E46613 /* EmailSignUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF2455323A2F8A400E46613 /* EmailSignUpViewController.swift */; }; 3DF2455623A306DB00E46613 /* Loader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF2455523A306DB00E46613 /* Loader.swift */; }; 3DF5D75F2633B1E100F77D79 /* amazon_trackers.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3DF5D75E2633B1E100F77D79 /* amazon_trackers.txt */; }; + 402D24B129D590F700A5AB60 /* CustomHeadersTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402D24B029D590F700A5AB60 /* CustomHeadersTableView.swift */; }; + 402D24B829D59B4400A5AB60 /* EmptyListsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402D24B729D59B4400A5AB60 /* EmptyListsView.swift */; }; + 402D24CB29D87B5A00A5AB60 /* ListsSubmenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402D24CA29D87B5A00A5AB60 /* ListsSubmenuView.swift */; }; + 402D24D429D87F4500A5AB60 /* CustomBlockedTableHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402D24D329D87F4500A5AB60 /* CustomBlockedTableHeader.swift */; }; 4A86219093026DE70A097E79 /* Pods-LockdownTests-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8DA68459884385F76BF86234 /* Pods-LockdownTests-metadata.plist */; }; 54F0B1A0273200B0002F3630 /* FirewallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCA4F4022F252720017740D /* FirewallController.swift */; }; 5647ACFEBBAB001FAE27CAF9 /* Pods-LockdownTunnel-settings-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6F089C7008AB8F59DE3EA7BD /* Pods-LockdownTunnel-settings-metadata.plist */; }; @@ -599,6 +603,10 @@ 3DF2455323A2F8A400E46613 /* EmailSignUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignUpViewController.swift; sourceTree = ""; }; 3DF2455523A306DB00E46613 /* Loader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Loader.swift; sourceTree = ""; }; 3DF5D75E2633B1E100F77D79 /* amazon_trackers.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = amazon_trackers.txt; sourceTree = ""; }; + 402D24B029D590F700A5AB60 /* CustomHeadersTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomHeadersTableView.swift; sourceTree = ""; }; + 402D24B729D59B4400A5AB60 /* EmptyListsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyListsView.swift; sourceTree = ""; }; + 402D24CA29D87B5A00A5AB60 /* ListsSubmenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListsSubmenuView.swift; sourceTree = ""; }; + 402D24D329D87F4500A5AB60 /* CustomBlockedTableHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomBlockedTableHeader.swift; sourceTree = ""; }; 4CA426CE326B009F3E4493D1 /* Pods_Lockdown.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Lockdown.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50F9BE503587CE4933CB7983 /* Pods-Lockdown-settings-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-Lockdown-settings-metadata.plist"; path = "Settings.bundle/Pods-Lockdown-settings-metadata.plist"; sourceTree = ""; }; 50FB8ADA1D444FD9486F2D44 /* Pods-Lockdown Firewall Widget-settings-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-Lockdown Firewall Widget-settings-metadata.plist"; path = "LockdowniOS/Settings.bundle/Pods-Lockdown Firewall Widget-settings-metadata.plist"; sourceTree = ""; }; @@ -1003,7 +1011,6 @@ A154A07D215C78180010FFCC /* BlockListCell.swift */, A1FCDA5E22C14EB800C928BC /* BlockListGroupCell.swift */, A1FCDA5C22C1301900C928BC /* BlockListGroupViewController.swift */, - A174CCAD22B15B1000F1B840 /* BlockListViewController.swift */, 3D970DAC22EC149D00F9CC93 /* BlockLogCell.swift */, 3D970DAE22EC15D800F9CC93 /* BlockLogViewController.swift */, ); @@ -1059,6 +1066,50 @@ name = Main; sourceTree = ""; }; + 402D24CE29D87EF300A5AB60 /* Scenes */ = { + isa = PBXGroup; + children = ( + 402D24CF29D87EF900A5AB60 /* Configure Blocking */, + ); + name = Scenes; + sourceTree = ""; + }; + 402D24CF29D87EF900A5AB60 /* Configure Blocking */ = { + isa = PBXGroup; + children = ( + 402D24D229D87F1E00A5AB60 /* Models */, + 402D24D129D87F1600A5AB60 /* Controllers */, + 402D24D029D87F0A00A5AB60 /* Views */, + ); + name = "Configure Blocking"; + sourceTree = ""; + }; + 402D24D029D87F0A00A5AB60 /* Views */ = { + isa = PBXGroup; + children = ( + 402D24CA29D87B5A00A5AB60 /* ListsSubmenuView.swift */, + 402D24D329D87F4500A5AB60 /* CustomBlockedTableHeader.swift */, + 402D24B729D59B4400A5AB60 /* EmptyListsView.swift */, + 402D24B029D590F700A5AB60 /* CustomHeadersTableView.swift */, + ); + name = Views; + sourceTree = ""; + }; + 402D24D129D87F1600A5AB60 /* Controllers */ = { + isa = PBXGroup; + children = ( + A174CCAD22B15B1000F1B840 /* BlockListViewController.swift */, + ); + name = Controllers; + sourceTree = ""; + }; + 402D24D229D87F1E00A5AB60 /* Models */ = { + isa = PBXGroup; + children = ( + ); + name = Models; + sourceTree = ""; + }; 7C0D11102473EDFD00A26E04 /* Services */ = { isa = PBXGroup; children = ( @@ -1191,6 +1242,7 @@ A1141A131F46230500F54698 /* LockdowniOS */ = { isa = PBXGroup; children = ( + 402D24CE29D87EF300A5AB60 /* Scenes */, 7C422EAC25279755007F9C22 /* Screens */, 7C422E95252796E2007F9C22 /* Views */, 7C1AE07E248028E40000A7D3 /* Extensions */, @@ -1581,7 +1633,6 @@ }; A1141A101F46230500F54698 = { CreatedOnToolsVersion = 8.3.3; - DevelopmentTeam = V8J3Z26F6Z; LastSwiftMigration = 1010; ProvisioningStyle = Automatic; SystemCapabilities = { @@ -2172,10 +2223,12 @@ 3D47CDC722F3C3F3003BD7F7 /* NVActivityIndicatorAnimationBlank.swift in Sources */, A1E7481A1F9108B6004B8021 /* SpeedTest.swift in Sources */, 3D970DAF22EC15D800F9CC93 /* BlockLogViewController.swift in Sources */, + 402D24D429D87F4500A5AB60 /* CustomBlockedTableHeader.swift in Sources */, A1EBEADB2097AE6E002B9087 /* M13CheckboxAnimationGenerator.swift in Sources */, 7CC8EFED254036050005054C /* FirewallRepair.swift in Sources */, 3D47CDD422F3C3F3003BD7F7 /* NVActivityIndicatorAnimationLineScalePulseOutRapid.swift in Sources */, 7CE91C712521D58C009D8269 /* Metrics.swift in Sources */, + 402D24B829D59B4400A5AB60 /* EmptyListsView.swift in Sources */, A12186271FB8F691007058B3 /* SignupViewController.swift in Sources */, A1EBEAD12097AE6E002B9087 /* M13Checkbox+IB.swift in Sources */, A1FCDA5F22C14EB800C928BC /* BlockListGroupCell.swift in Sources */, @@ -2189,6 +2242,7 @@ 3D47CDCC22F3C3F3003BD7F7 /* NVActivityIndicatorAnimationBallScaleMultiple.swift in Sources */, A1EBEADC2097AE6E002B9087 /* DefaultValues.swift in Sources */, A1EBEAD02097AE6E002B9087 /* M13CheckboxController.swift in Sources */, + 402D24B129D590F700A5AB60 /* CustomHeadersTableView.swift in Sources */, 3D47CDB322F3C3F3003BD7F7 /* NVActivityIndicatorView.swift in Sources */, 3D47CDBD22F3C3F3003BD7F7 /* NVActivityIndicatorAnimationBallZigZagDeflect.swift in Sources */, 3D47CDB022F3C3F3003BD7F7 /* NVActivityIndicatorPresenter.swift in Sources */, @@ -2228,6 +2282,7 @@ A1141A151F46230500F54698 /* AppDelegate.swift in Sources */, 3DBD57AE22FBE04300DE189F /* WhitelistAddCell.swift in Sources */, 3D47CDB922F3C3F3003BD7F7 /* NVActivityIndicatorAnimationBallTrianglePath.swift in Sources */, + 402D24CB29D87B5A00A5AB60 /* ListsSubmenuView.swift in Sources */, A1EBEACE2097AE6E002B9087 /* M13CheckboxExpandController.swift in Sources */, 3D5F5A0C23109ABB004C3860 /* WhatIsVpnViewController.swift in Sources */, A174CCAE22B15B1000F1B840 /* BlockListViewController.swift in Sources */, @@ -2398,7 +2453,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2413,7 +2468,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.confirmed.lockdown.Lockdown-Firewall-Today"; @@ -2435,7 +2490,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2450,7 +2505,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.confirmed.lockdown.Lockdown-Firewall-Today"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2528,7 +2583,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2542,7 +2597,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.confirmed.lockdown.LockdownFirewallWidget; @@ -2566,7 +2621,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2580,7 +2635,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.confirmed.lockdown.LockdownFirewallWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2717,7 +2772,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2735,7 +2790,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.confirmed.lockdown; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -2756,7 +2811,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2774,7 +2829,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.confirmed.lockdown; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -2801,7 +2856,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2816,7 +2871,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.confirmed.lockdown.Lockdown-VPN-Today"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -2844,7 +2899,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2859,7 +2914,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.confirmed.lockdown.Lockdown-VPN-Today"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -2880,17 +2935,17 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Lockdown Blocker/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.confirmed.lockdown.Confirmed-Blocker"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2910,17 +2965,17 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Lockdown Blocker/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.confirmed.lockdown.Confirmed-Blocker"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2942,7 +2997,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2957,7 +3012,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( @@ -2999,7 +3054,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = V8J3Z26F6Z; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3014,7 +3069,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.5.0; + MARKETING_VERSION = 2.0.0; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "$(inherited)", diff --git a/LockdowniOS/Base.lproj/Main.storyboard b/LockdowniOS/Base.lproj/Main.storyboard index b205a12..52ede15 100644 --- a/LockdowniOS/Base.lproj/Main.storyboard +++ b/LockdowniOS/Base.lproj/Main.storyboard @@ -237,7 +237,7 @@ - + @@ -967,7 +967,7 @@ - + @@ -1165,7 +1165,7 @@ - + - + - + - + @@ -1227,7 +1227,7 @@ - + @@ -3426,7 +3426,7 @@ - + @@ -3536,8 +3536,8 @@ - - + + diff --git a/LockdowniOS/BlockListCell.swift b/LockdowniOS/BlockListCell.swift index 72d69b2..c79eb5e 100644 --- a/LockdowniOS/BlockListCell.swift +++ b/LockdowniOS/BlockListCell.swift @@ -85,3 +85,14 @@ class BlockListView: UIView { } } } + +extension BlockListView.Contents { + + static func listsBlocked(listName: String, isEnabled: Bool) -> Self { + let image = UIImage(named: "icn_list_lock") + let status = isEnabled ? + NSLocalizedString("On", comment: "") : + NSLocalizedString("Off", comment: "") + return Self(image: image, title: listName, status: status) + } +} diff --git a/LockdowniOS/BlockListGroupViewController.swift b/LockdowniOS/BlockListGroupViewController.swift index f6b19f0..f253568 100644 --- a/LockdowniOS/BlockListGroupViewController.swift +++ b/LockdowniOS/BlockListGroupViewController.swift @@ -91,7 +91,7 @@ class BlockListGroupViewController: BaseViewController, UITableViewDelegate, UIT } @IBAction func dismiss() { - blockListVC?.reloadBlockLists() + blockListVC?.reloadCuratedBlockDomains() self.navigationController?.popViewController(animated: true) } } diff --git a/LockdowniOS/BlockListViewController.swift b/LockdowniOS/BlockListViewController.swift index ab10ddb..e7f1145 100644 --- a/LockdowniOS/BlockListViewController.swift +++ b/LockdowniOS/BlockListViewController.swift @@ -8,126 +8,251 @@ import UIKit import CocoaLumberjackSwift -class BlockListViewController: BaseViewController { +final class BlockListViewController: BaseViewController { + // MARK: - Properties var didMakeChange = false var lockdownBlockLists: [LockdownGroup] = [] - var userBlockedDomains: [(String, Bool)] = [] + var customBlockedDomains: [(String, Bool)] = [] + + // TODO: - change data structure [[userListBlockedDomains], Bool] + var customBlockedLists: [(String, Bool)] = [] - let blockListsTableView = StaticTableView() - let customBlocksTableView = StaticTableView() + let curatedBlockedDomainsTableView = StaticTableView() + let customBlockedListsTableView = StaticTableView() + let customBlockedDomainsTableView = StaticTableView() + + private lazy var listsSubmenuView: ListsSubmenuView = { + let view = ListsSubmenuView() + view.createNewListButton.addTarget(self, action: #selector(addList), for: .touchUpInside) + view.importBlockListButton.addTarget(self, action: #selector(importBlockList), for: .touchUpInside) + return view + }() + + private lazy var customNavigationView: CustomNavigationView = { + let view = CustomNavigationView() + view.title = NSLocalizedString("Configure Blocking", comment: "") + view.buttonTitle = NSLocalizedString("CLOSE", comment: "") + view.onButtonPressed { [unowned self] in + self.close() + } + return view + }() enum Page: CaseIterable { - case blockLists + case curated case custom var localizedTitle: String { switch self { - case .blockLists: - return NSLocalizedString("Block Lists", comment: "") + case .curated: + return NSLocalizedString("Curated", comment: "") case .custom: return NSLocalizedString("Custom", comment: "") } } } - let segmented = UISegmentedControl(items: Page.allCases.map(\.localizedTitle)) - let explanationLabel = UILabel() - - let blockListAddView = BlockListAddView() - var addDomainTextField: UITextField { - return blockListAddView.textField - } + private lazy var segmented: UISegmentedControl = { + let view = UISegmentedControl(items: Page.allCases.map(\.localizedTitle)) + view.selectedSegmentIndex = 0 + view.setTitleTextAttributes([.font: fontMedium14], for: .normal) + view.selectedSegmentTintColor = .tunnelsBlue + view.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected) + view.addTarget(self, action: #selector(segmentedControlDidChangeValue), for: .valueChanged) + return view + }() - @objc func dismissKeyboard() { - self.view.endEditing(true) - } + private let paragraphLabel: UILabel = { + let view = UILabel() + view.font = fontRegular14 + view.numberOfLines = 0 + view.text = NSLocalizedString("Block all your apps from connecting to the domains and sites below. For your convenience, Lockdown also has pre-configured suggestions.", comment: "") + return view + }() + private lazy var addNewListButton: UIButton = { + let button = UIButton(type: .system) + let symbolConfig = UIImage.SymbolConfiguration(pointSize: 14, weight: .bold, scale: .large) + button.tintColor = .tunnelsBlue + button.setImage(UIImage(systemName: "plus", withConfiguration: symbolConfig), for: .normal) + button.addTarget(self, action: #selector(showSubmenu), for: .touchUpInside) + return button + }() + + private lazy var listsLabel: UILabel = { + let label = UILabel() + label.text = NSLocalizedString("Lists", comment: "") + label.textColor = .label + label.font = fontBold18 + return label + }() + + private lazy var emptyListsView: EmptyListsView = { + let view = EmptyListsView() + view.descriptionLabel.text = NSLocalizedString("No lists yet", comment: "") + view.addButton.setTitle(NSLocalizedString("Create a list", comment: ""), for: .normal) + view.addButton.addTarget(self, action: #selector(addList), for: .touchUpInside) + return view + }() + + private lazy var domainsLabel: UILabel = { + let label = UILabel() + label.text = NSLocalizedString("Domains", comment: "") + label.textColor = .label + label.font = fontBold18 + return label + }() + + private lazy var addNewDomainButton: UIButton = { + let button = UIButton(type: .system) + let symbolConfig = UIImage.SymbolConfiguration(pointSize: 14, weight: .bold, scale: .large) + button.tintColor = .tunnelsBlue + button.setImage(UIImage(systemName: "plus", withConfiguration: symbolConfig), for: .normal) + button.addTarget(self, action: #selector(addDomain), for: .touchUpInside) + return button + }() + + private lazy var editDomainButton: UIButton = { + let button = UIButton(type: .system) + let symbolConfig = UIImage.SymbolConfiguration(pointSize: 14, weight: .bold, scale: .large) + button.tintColor = .tunnelsBlue + button.setImage(UIImage(named: "icn_edit"), for: .normal) + button.addTarget(self, action: #selector(editDomains), for: .touchUpInside) + button.isHidden = true + return button + }() + + private lazy var emptyDomainsView: EmptyListsView = { + let view = EmptyListsView() + view.descriptionLabel.text = NSLocalizedString("No custom domains yet", comment: "") + view.addButton.setTitle(NSLocalizedString("Add a domain", comment: ""), for: .normal) + view.addButton.addTarget(self, action: #selector(addDomain), for: .touchUpInside) + return view + }() + + // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() - let customNavigationView = CustomNavigationView() - customNavigationView.title = NSLocalizedString("Configure Blocking", comment: "") - customNavigationView.buttonTitle = NSLocalizedString("SAVE", comment: "") - customNavigationView.onButtonPressed { [unowned self] in - self.save() - } + view.backgroundColor = .secondarySystemBackground + + configure() + configureCuratedBlockedDomainsTableView() + configureCustomBlockedListsTableView() + configureCustomBlockedDomainsTableView() + } + + private func configure() { view.addSubview(customNavigationView) customNavigationView.anchors.leading.pin() customNavigationView.anchors.trailing.pin() customNavigationView.anchors.top.safeAreaPin() - let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) - tap.cancelsTouchesInView = false - view.addGestureRecognizer(tap) + view.addSubview(paragraphLabel) + paragraphLabel.anchors.top.spacing(0, to: customNavigationView.anchors.bottom) + paragraphLabel.anchors.leading.readableContentPin(inset: 3) + paragraphLabel.anchors.trailing.readableContentPin(inset: 3) - do { - explanationLabel.font = fontRegular14 - explanationLabel.numberOfLines = 0 - explanationLabel.text = NSLocalizedString("Block all your apps from connecting to the domains and sites below. For your convenience, Lockdown also has pre-configured suggestions.", comment: "") - - view.addSubview(explanationLabel) - explanationLabel.anchors.top.spacing(0, to: customNavigationView.anchors.bottom) - explanationLabel.anchors.leading.readableContentPin(inset: 3) - explanationLabel.anchors.trailing.readableContentPin(inset: 3) - } - - do { - view.addSubview(segmented) - segmented.selectedSegmentIndex = 0 - segmented.anchors.top.spacing(12, to: explanationLabel.anchors.bottom) - segmented.anchors.leading.readableContentPin() - segmented.anchors.trailing.readableContentPin() - segmented.setTitleTextAttributes([.font: fontMedium14], for: .normal) - if #available(iOS 13.0, *) { - segmented.selectedSegmentTintColor = .tunnelsBlue - segmented.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected) - } - - segmented.addTarget(self, action: #selector(segmentedControlDidChangeValue), for: .valueChanged) - } - - do { - addDomainTextField.addTarget(self, action: #selector(textFieldDidEndOnExit), for: .editingDidEndOnExit) - } - - do { - addTableView(blockListsTableView, layout: { tableView in - tableView.anchors.top.spacing(8, to: segmented.anchors.bottom) - tableView.anchors.leading.pin() - tableView.anchors.trailing.pin() - tableView.anchors.bottom.pin() - }) - reloadBlockLists() - - addTableView(customBlocksTableView, layout: { tableView in - tableView.anchors.top.spacing(8, to: segmented.anchors.bottom) - tableView.anchors.leading.pin() - tableView.anchors.trailing.pin() - tableView.anchors.bottom.pin() - }) - customBlocksTableView.deselectsCellsAutomatically = true - reloadUserBlockedDomains() - - transition(toPage: .blockLists) - } + view.addSubview(segmented) + segmented.anchors.top.spacing(12, to: paragraphLabel.anchors.bottom) + segmented.anchors.leading.readableContentPin() + segmented.anchors.trailing.readableContentPin() } - func reloadBlockLists() { - blockListsTableView.clear() + private func configureCuratedBlockedDomainsTableView() { + addTableView(curatedBlockedDomainsTableView, layout: { tableView in + tableView.anchors.top.spacing(8, to: segmented.anchors.bottom) + tableView.anchors.leading.pin() + tableView.anchors.trailing.pin() + }) + + reloadCuratedBlockDomains() + transition(toPage: .curated) + } + + private func configureCustomBlockedListsTableView() { + + view.addSubview(listsLabel) + listsLabel.anchors.top.spacing(24, to: segmented.anchors.bottom) + listsLabel.anchors.leading.marginsPin() + + view.addSubview(addNewListButton) + addNewListButton.anchors.centerY.equal(listsLabel.anchors.centerY) + addNewListButton.anchors.trailing.marginsPin() + + addTableView(customBlockedListsTableView, layout: { tableView in + tableView.anchors.top.spacing(0, to: listsLabel.anchors.bottom) + tableView.anchors.leading.pin() + tableView.anchors.trailing.pin() + }) + + view.addSubview(listsSubmenuView) + listsSubmenuView.anchors.trailing.marginsPin() + listsSubmenuView.anchors.top.spacing(60, to: paragraphLabel.anchors.bottom) + + customBlockedListsTableView.deselectsCellsAutomatically = true + + reloadCustomBlockedLists() + } + + private func configureCustomBlockedDomainsTableView() { + + view.addSubview(domainsLabel) + domainsLabel.anchors.top.spacing(16, to: customBlockedListsTableView.anchors.bottom) + domainsLabel.anchors.leading.marginsPin() + + view.addSubview(addNewDomainButton) + addNewDomainButton.anchors.centerY.equal(domainsLabel.anchors.centerY) + addNewDomainButton.anchors.trailing.marginsPin() + + view.addSubview(editDomainButton) + editDomainButton.anchors.centerY.equal(domainsLabel.anchors.centerY) + editDomainButton.anchors.trailing.spacing(16, to: addNewDomainButton.anchors.leading) + + addTableView(customBlockedDomainsTableView, layout: { tableView in + tableView.anchors.top.spacing(0, to: domainsLabel.anchors.bottom) + tableView.anchors.leading.pin() + tableView.anchors.trailing.pin() + }) + + customBlockedDomainsTableView.deselectsCellsAutomatically = true + + reloadCustomBlockedDomains() + } + + // Curated lists + func reloadCuratedBlockDomains() { + curatedBlockedDomainsTableView.clear() lockdownBlockLists = { let domains = getLockdownBlockedDomains().lockdownDefaults let sorted = domains.sorted(by: { $0.key < $1.key }) return Array(sorted.map(\.value)) }() - createBlockListsRows() - blockListsTableView.reloadData() + createCuratedBlockedDomainsRows() + curatedBlockedDomainsTableView.reloadData() } - func reloadUserBlockedDomains() { - customBlocksTableView.clear() - userBlockedDomains = { + func reloadCustomBlockedLists() { + customBlockedListsTableView.clear() + customBlockedLists = { + let lists = getUserBlockedList() + return lists.sorted(by: { $0.key < $1.key }).map { (key, value) -> (String, Bool) in + if let status = value as? NSNumber { + return (key, status.boolValue) + } else { + return (key, false) + } + } + }() + createCustomBlockedListsRows() + customBlockedListsTableView.reloadData() + } + + func reloadCustomBlockedDomains() { + customBlockedDomainsTableView.clear() + customBlockedDomains = { let domains = getUserBlockedDomains() return domains.sorted(by: { $0.key < $1.key }).map { (key, value) -> (String, Bool) in if let status = value as? NSNumber { @@ -137,12 +262,13 @@ class BlockListViewController: BaseViewController { } } }() - createCustomBlocksRows() - customBlocksTableView.reloadData() + createCustomBlockedDomainsRows() + customBlockedDomainsTableView.reloadData() } - func createBlockListsRows() { - let tableView = blockListsTableView + // Curated Lists + func createCuratedBlockedDomainsRows() { + let tableView = curatedBlockedDomainsTableView for lockdownGroup in lockdownBlockLists { @@ -163,15 +289,120 @@ class BlockListViewController: BaseViewController { } } - func createCustomBlocksRows() { - let tableView = customBlocksTableView + @objc + func segmentedControlDidChangeValue() { + let page = Page.allCases[segmented.selectedSegmentIndex] + transition(toPage: page) + } + + func transition(toPage page: Page) { - tableView.addRow { (contentView) in - contentView.addSubview(blockListAddView) - blockListAddView.anchors.edges.pin() + switch page { + case .curated: + customBlockedDomainsTableView.isHidden = true + customBlockedListsTableView.isHidden = true + curatedBlockedDomainsTableView.isHidden = false + listsLabel.isHidden = true + addNewListButton.isHidden = true + listsSubmenuView.isHidden = true + addNewDomainButton.isHidden = true + domainsLabel.isHidden = true + editDomainButton.isHidden = true + case .custom: + customBlockedListsTableView.isHidden = false + customBlockedDomainsTableView.isHidden = false + curatedBlockedDomainsTableView.isHidden = true + listsLabel.isHidden = false + addNewListButton.isHidden = false + addNewDomainButton.isHidden = false + domainsLabel.isHidden = false + editDomainButton.isHidden = false + } + } + + func saveNewList(userEnteredListName: String) { + DDLogInfo("Adding custom list - \(userEnteredListName)") + addUserBlockedList(list: userEnteredListName.lowercased()) + reloadCustomBlockedLists() + } + + func saveNewDomain(userEnteredDomainName: String) { + let validation = DomainNameValidator.validate(userEnteredDomainName) + + switch validation { + case .valid: + didMakeChange = true + + DDLogInfo("Adding custom domain - \(userEnteredDomainName)") + addUserBlockedDomain(domain: userEnteredDomainName.lowercased()) + reloadCustomBlockedDomains() + case .notValid(let reason): + DDLogWarn("Custom domain is not valid - \(userEnteredDomainName), reason - \(reason)") + showPopupDialog( + title: NSLocalizedString("Invalid domain", comment: ""), + message: "\"\(userEnteredDomainName)\"" + NSLocalizedString(" is not a valid entry. Please only enter the host of the domain you want to block. For example, \"google.com\" without \"https://\"", comment: ""), + acceptButton: NSLocalizedString("Okay", comment: "") + ) + } + } +} +// MARK: - Functions +extension BlockListViewController { + + func createCustomBlockedListsRows() { + let tableView = customBlockedListsTableView + let emptyList = emptyListsView + + if customBlockedLists.count == 0 { + tableView.addRow { (contentView) in + contentView.addSubview(emptyList) + emptyListsView.anchors.edges.pin() + }.onSelect { + self.addList() + } } - for (domain, isEnabled) in userBlockedDomains { + for (list, status) in customBlockedLists { +// var currentEnabledStatus = status + let blockListView = BlockListView() + blockListView.contents = .listsBlocked(listName: list, isEnabled: status) + + let cell = tableView.addRow { (contentView) in + contentView.addSubview(blockListView) + blockListView.anchors.edges.pin() + }.onSelect { [unowned blockListView, unowned self] in + self.didMakeChange = true + let storyboard = UIStoryboard.main +// let target = storyboard.instantiate(BlockListGroupViewController.self) +// target.lockdownGroup = lockdownGroup +// target.blockListVC = self +// self.navigationController?.pushViewController(target, animated: true) +// currentEnabledStatus.toggle() +// blockListView.contents = .listsBlocked(listName: list, isEnabled: currentEnabledStatus) +// setUserBlockedList(list: list, enabled: currentEnabledStatus) + }.onSwipeToDelete { [unowned self] in + self.didMakeChange = true + deleteList(list: list) + DDLogInfo("Deleting custom list - \(list)") + } + cell.accessoryType = .disclosureIndicator + } + } + + // Custom Domains + func createCustomBlockedDomainsRows() { + let tableView = customBlockedDomainsTableView + let emptyDomains = emptyDomainsView + if customBlockedDomains.count == 0 { + tableView.addRow { (contentView) in + contentView.addSubview(emptyDomains) + emptyDomains.anchors.edges.pin() + }.onSelect { [unowned self] in + self.addDomain() + } + } + + for (domain, isEnabled) in customBlockedDomains { var currentEnabledStatus = isEnabled let blockListView = BlockListView() blockListView.contents = .userBlocked(domain: domain, isEnabled: isEnabled) @@ -192,62 +423,9 @@ class BlockListViewController: BaseViewController { } } - @objc - func segmentedControlDidChangeValue() { - let page = Page.allCases[segmented.selectedSegmentIndex] - transition(toPage: page) - } - - func transition(toPage page: Page) { - dismissKeyboard() - - switch page { - case .blockLists: - customBlocksTableView.isHidden = true - blockListsTableView.isHidden = false - case .custom: - customBlocksTableView.isHidden = false - blockListsTableView.isHidden = true - } - } - - @objc - func textFieldDidEndOnExit(textField: UITextField) { - dismissKeyboard() - - guard let text = textField.text else { - DDLogError("Text is empty on add domain text field") - return - } - - saveNewDomain(userEnteredDomainName: text) - } - - func saveNewDomain(userEnteredDomainName: String) { - let validation = DomainNameValidator.validate(userEnteredDomainName) - - switch validation { - case .valid: - didMakeChange = true - - DDLogInfo("Adding custom domain - \(userEnteredDomainName)") - addUserBlockedDomain(domain: userEnteredDomainName.lowercased()) - addDomainTextField.text = "" - reloadUserBlockedDomains() - case .notValid(let reason): - DDLogWarn("Custom domain is not valid - \(userEnteredDomainName), reason - \(reason)") - showPopupDialog( - title: NSLocalizedString("Invalid domain", comment: ""), - message: "\"\(userEnteredDomainName)\"" + NSLocalizedString(" is not a valid entry. Please only enter the host of the domain you want to block. For example, \"google.com\" without \"https://\"", comment: ""), - acceptButton: NSLocalizedString("Okay", comment: "") - ) { - self.addDomainTextField.becomeFirstResponder() - } - } - } - - func save() { - self.dismiss(animated: true, completion: { + func close() { + dismiss(animated: true, completion: { [weak self] in + guard let self else { return } if (self.didMakeChange == true) { if getIsCombinedBlockListEmpty() { FirewallController.shared.setEnabled(false, isUserExplicitToggle: true) @@ -257,4 +435,96 @@ class BlockListViewController: BaseViewController { } }) } + + @objc func addList() { + let tableView = customBlockedListsTableView + let alertController = UIAlertController(title: "Create New List", message: nil, preferredStyle: .alert) + let saveAction = UIAlertAction(title: "Save", style: .default) { [weak self] (_) in + if let txtField = alertController.textFields?.first, let text = txtField.text { + guard let self else { return } + self.saveNewList(userEnteredListName: text) + if !getUserBlockedList().isEmpty { + tableView.clear() + } + self.reloadCustomBlockedLists() + self.listsSubmenuView.isHidden = true + } + } + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { [weak self] (_) in + guard let self else { return } + self.listsSubmenuView.isHidden = true + } + alertController.addTextField { (textField) in + textField.placeholder = NSLocalizedString("List Name", comment: "") + } + alertController.addAction(saveAction) + alertController.addAction(cancelAction) + self.present(alertController, animated: true, completion: nil) + } + + func deleteList(list: String) { + print("deleteDomains btn pressed ....") + let alert = UIAlertController(title: NSLocalizedString("Delete List?", comment: ""), + message: NSLocalizedString("Are you sure you want to remove this list?", comment: ""), + preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("No, Return", comment: ""), + style: UIAlertAction.Style.default, + handler: { [weak self] (_) in + guard let self else { return } + self.reloadCustomBlockedLists() + print("Return") + })) + alert.addAction(UIAlertAction(title: NSLocalizedString("Yes, Delete", comment: ""), + style: UIAlertAction.Style.destructive, + handler: { [weak self] (_) in + guard let self else { return } + deleteUserBlockedList(list: list) + self.customBlockedListsTableView.clear() + })) + self.present(alert, animated: true, completion: nil) + } + + @objc func showSubmenu() { + listsSubmenuView.isHidden = false + } + + @objc func dismissView() { + listsSubmenuView.isHidden = true + } + + @objc func importBlockList() { + listsSubmenuView.isHidden = true + print("importBlockList ....") + } + + @objc func addDomain() { + print("Alert is on") + + let tableView = customBlockedDomainsTableView + + let alertController = UIAlertController(title: "Add a Domain to Block", message: nil, preferredStyle: .alert) + let saveAction = UIAlertAction(title: "Save", style: .default) { [weak self] (_) in + if let txtField = alertController.textFields?.first, let text = txtField.text { + guard let self else { return } + self.saveNewDomain(userEnteredDomainName: text) + if !getUserBlockedDomains().isEmpty { + tableView.clear() + } + + self.reloadCustomBlockedDomains() + print("Domain==>" + text + "added") + } + } + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in } + alertController.addTextField { (textField) in + textField.placeholder = "domain-to-block URL" + } + alertController.addAction(saveAction) + alertController.addAction(cancelAction) + self.present(alertController, animated: true, completion: nil) + } + + @objc func editDomains() { + print("editDomains .....") + } } diff --git a/LockdowniOS/CustomBlockedTableHeader.swift b/LockdowniOS/CustomBlockedTableHeader.swift new file mode 100644 index 0000000..3972b4c --- /dev/null +++ b/LockdowniOS/CustomBlockedTableHeader.swift @@ -0,0 +1,111 @@ +// +// CustomTableHeader.swift +// LockdownSandbox +// +// Created by Aliaksandr Dvoineu on 24.03.23. +// + +import UIKit + +enum Section: Int, CaseIterable, CustomStringConvertible { + + case lists + case domains + + var description: String { + switch self { + case .lists: return "Lists" + case .domains: return "Domains" + } + } +} + +class CustomBlockedTableHeader: UITableViewHeaderFooterView { + static let id = "CustomBlockedTableHeader" + + private(set) var addButtonCallback: () -> () = { } + private(set) var editButtonCallback: () -> () = { } + + lazy var listsTitleLabel: UILabel = { + let label = UILabel() + label.textColor = .label + label.textAlignment = .center + label.font = fontBold18 + return label + }() + + lazy var addButton: UIButton = { + let button = UIButton(type: .system) + let symbolConfig = UIImage.SymbolConfiguration(pointSize: 14, weight: .bold, scale: .large) + button.setImage(UIImage(systemName: "plus", withConfiguration: symbolConfig), for: .normal) + button.tintColor = .tunnelsBlue + button.addTarget(self, action: #selector(addButtonDidPress), for: .touchUpInside) + return button + }() + + lazy var editButton: UIButton = { + let button = UIButton(type: .system) + let symbolConfig = UIImage.SymbolConfiguration(pointSize: 14, weight: .bold, scale: .large) + button.setImage(UIImage(named: "icn_edit"), for: .normal) + button.tintColor = .tunnelsBlue + button.addTarget(self, action: #selector(editButtonDidPress), for: .touchUpInside) + button.isHidden = true + return button + }() + + var category: Section = .lists { + didSet { + switch category { + case .lists: + listsTitleLabel.text = category.description + + case .domains: + listsTitleLabel.text = category.description + } + } + } + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + configure() + } + + func configure() { + contentView.addSubview(listsTitleLabel) + contentView.addSubview(addButton) + contentView.addSubview(editButton) + + listsTitleLabel.anchors.leading.pin() + listsTitleLabel.anchors.bottom.marginsPin() + + addButton.anchors.trailing.pin() + addButton.anchors.bottom.marginsPin() + + editButton.anchors.trailing.spacing(12, to: addButton.anchors.leading) + editButton.anchors.bottom.marginsPin() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @discardableResult + func onAddButtonPressed(_ callback: @escaping () -> ()) -> Self { + addButtonCallback = callback + return self + } + + @discardableResult + func onEditButtonPressed(_ callback: @escaping () -> ()) -> Self { + editButtonCallback = callback + return self + } + + @objc func addButtonDidPress() { + addButtonCallback() + } + + @objc func editButtonDidPress() { + editButtonCallback() + } +} diff --git a/LockdowniOS/CustomNavigationView.swift b/LockdowniOS/CustomNavigationView.swift index 29d8200..6f8310e 100644 --- a/LockdowniOS/CustomNavigationView.swift +++ b/LockdowniOS/CustomNavigationView.swift @@ -16,7 +16,7 @@ final class CustomNavigationView: UIView { } } - var buttonTitle: String = NSLocalizedString("SAVE", comment: "") { + var buttonTitle: String = NSLocalizedString("CLOSE", comment: "") { didSet { button.setTitle(buttonTitle, for: .normal) } @@ -45,26 +45,22 @@ final class CustomNavigationView: UIView { func didLoad() { addSubview(titleView) - titleView.textAlignment = .left + titleView.textAlignment = .center titleView.text = title titleView.font = fontMedium17 - titleView.anchors.leading.marginsPin(inset: 20) - titleView.anchors.width.greaterThanOrEqual(220) - titleView.anchors.height.equal(24) + titleView.anchors.centerX.align() titleView.anchors.top.pin(inset: 18) addSubview(button) button.titleLabel?.font = fontBold13 - button.contentHorizontalAlignment = .trailing + button.contentHorizontalAlignment = .leading button.tintColor = .confirmedBlue button.setTitle(buttonTitle, for: .normal) button.anchors.centerY.equal(titleView.anchors.centerY) - button.anchors.trailing.marginsPin(inset: 8) + button.anchors.leading.marginsPin(inset: 8) button.anchors.bottom.marginsPin() - button.anchors.height.equal(39) - button.anchors.width.greaterThanOrEqual(60) button.addTarget(self, action: #selector(buttonDidPress), for: .touchUpInside) } diff --git a/LockdowniOS/EmptyListsView.swift b/LockdowniOS/EmptyListsView.swift new file mode 100644 index 0000000..5d27dc3 --- /dev/null +++ b/LockdowniOS/EmptyListsView.swift @@ -0,0 +1,94 @@ +// +// NothingBlockedView.swift +// Lockdown +// +// Created by Aliaksandr Dvoineu on 21.03.23. +// Copyright © 2023 Confirmed Inc. All rights reserved. +// + +import UIKit + +final class EmptyListsView: UIView { + + var descriptionText: String = "" { + didSet { + descriptionLabel.text = descriptionText + } + } + + var buttonTitle: String = "" { + didSet { + addButton.setTitle(buttonTitle, for: .normal) + } + } + + private(set) var buttonCallback: () -> () = { } + + @discardableResult + func onButtonPressed(_ callback: @escaping () -> ()) -> Self { + buttonCallback = callback + return self + } + + // MARK: - Properties + + lazy var stackView: UIStackView = { + let stackView = UIStackView() + stackView.addArrangedSubview(descriptionLabel) + stackView.addArrangedSubview(addButton) + stackView.axis = .vertical + stackView.distribution = .fillEqually + stackView.alignment = .center + stackView.spacing = 4 + return stackView + }() + + lazy var descriptionLabel: UILabel = { + let label = UILabel() + label.textColor = .lightGray + label.textAlignment = .center + label.font = fontBold13 + label.textAlignment = .center + return label + }() + + lazy var addButton: UIButton = { + let button = UIButton(type: .system) + button.tintColor = .tunnelsBlue + button.backgroundColor = .tunnelsLightBlue + button.titleLabel?.font = fontBold13 + button.layer.cornerRadius = 8 + button.titleEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) + return button + }() + + // MARK: - Initializer + + override init(frame: CGRect) { + super.init(frame: frame) + configure() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: Configure UI + + func configure() { + addSubview(addButton) + addButton.anchors.width.greaterThanOrEqual(120) + + addSubview(stackView) + stackView.anchors.top.marginsPin() + stackView.anchors.bottom.marginsPin() + stackView.anchors.leading.marginsPin() + stackView.anchors.trailing.marginsPin() + } + + // - MARK: Functions + + @objc func buttonDidPress() { + buttonCallback() + } +} diff --git a/LockdowniOS/ListsSubmenuView.swift b/LockdowniOS/ListsSubmenuView.swift new file mode 100644 index 0000000..b750720 --- /dev/null +++ b/LockdowniOS/ListsSubmenuView.swift @@ -0,0 +1,79 @@ +// +// ListsSubmenuView.swift +// LockdownSandbox +// +// Created by Aliaksandr Dvoineu on 23.03.23. +// + +import UIKit + +final class ListsSubmenuView: UIView { + + private(set) var buttonCallback: () -> () = { } + + @discardableResult + func onButtonPressed(_ callback: @escaping () -> ()) -> Self { + buttonCallback = callback + return self + } + + // MARK: - Properties + + lazy var createNewListButton: UIButton = { + let button = UIButton(type: .system) + button.tintColor = .tunnelsBlue + button.setTitle("Create New List...", for: .normal) + button.setImage(UIImage(named: "icn_create_list"), for: .normal) + button.setTitleColor(.label, for: .normal) + button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -10, bottom: 0, right: 0) + return button + }() + + lazy var importBlockListButton: UIButton = { + let button = UIButton(type: .system) + button.tintColor = .tunnelsBlue + button.setTitle("Import Block List...", for: .normal) + button.setImage(UIImage(named: "icn_import_list"), for: .normal) + button.setTitleColor(.label, for: .normal) + button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -10, bottom: 0, right: 0) + return button + }() + + lazy var stackView: UIStackView = { + let stackView = UIStackView() + stackView.addArrangedSubview(createNewListButton) + stackView.addArrangedSubview(importBlockListButton) + stackView.axis = .vertical + stackView.distribution = .fillEqually + stackView.alignment = .leading + stackView.spacing = 12 + return stackView + }() + + // MARK: - Initializer + + override init(frame: CGRect) { + super.init(frame: frame) + configure() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Functions + + func configure() { + backgroundColor = .systemBackground + + addSubview(stackView) + stackView.anchors.top.marginsPin() + stackView.anchors.bottom.marginsPin() + stackView.anchors.leading.marginsPin(inset: 10) + stackView.anchors.trailing.marginsPin(inset: 16) + } + + @objc func buttonDidPress() { + buttonCallback() + } +} diff --git a/LockdowniOS/StaticTableView.swift b/LockdowniOS/StaticTableView.swift index 987b21d..3deefd5 100644 --- a/LockdowniOS/StaticTableView.swift +++ b/LockdowniOS/StaticTableView.swift @@ -10,11 +10,23 @@ import UIKit final class StaticTableView: UITableView { + // Resizing UITableView to fit content + override var contentSize: CGSize { + didSet { + invalidateIntrinsicContentSize() + } + } + + override var intrinsicContentSize: CGSize { + layoutIfNeeded() + return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height) + } + var rows: [SelectableTableViewCell] = [] var deselectsCellsAutomatically: Bool = false override init(frame: CGRect, style: UITableView.Style) { - super.init(frame: frame, style: style) + super.init(frame: frame, style: .insetGrouped) setup() } @@ -126,6 +138,10 @@ extension StaticTableView: UITableViewDataSource { return 1 } + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 0 + } + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return rows.count } diff --git a/LockdowniOS/en.lproj/Main.strings b/LockdowniOS/en.lproj/Main.strings index 3b9d9dc..2a80e08 100644 --- a/LockdowniOS/en.lproj/Main.strings +++ b/LockdowniOS/en.lproj/Main.strings @@ -145,8 +145,8 @@ /* Class = "UIButton"; normalTitle = "Button"; ObjectID = "O4a-yi-uRp"; */ "O4a-yi-uRp.normalTitle" = "Button"; -/* Class = "UITabBarItem"; title = "Protect"; ObjectID = "O5a-jC-Mj1"; */ -"O5a-jC-Mj1.title" = "Protect"; +/* Class = "UITabBarItem"; title = "Home"; ObjectID = "O5a-jC-Mj1"; */ +"O5a-jC-Mj1.title" = "Home"; /* Class = "UILabel"; text = "Location: 🇺🇸"; ObjectID = "O6b-GR-ijA"; */ "O6b-GR-ijA.text" = "Location: 🇺🇸"; diff --git a/Shared.swift b/Shared.swift index a4cec46..22ebada 100644 --- a/Shared.swift +++ b/Shared.swift @@ -203,6 +203,7 @@ extension UIColor { static let tunnelsBlue = UIColor(red: 0/255.0, green: 173/255.0, blue: 231/255.0, alpha: 1.0) static let tunnelsWarning = UIColor(red: 231/255.0, green: 76/255.0, blue: 68/255.0, alpha: 1.0) static let tunnelsDarkBlue = UIColor(red: 0/255.0, green: 117/255.0, blue: 157/255.0, alpha: 1.0) + static let tunnelsLightBlue = UIColor(red: 223/255.0, green: 243/255.0, blue: 251/255.0, alpha: 1.0) } extension UnicodeScalar { diff --git a/en.lproj/Localizable.strings b/en.lproj/Localizable.strings index 7e30018..1291321 100644 --- a/en.lproj/Localizable.strings +++ b/en.lproj/Localizable.strings @@ -642,7 +642,7 @@ "Block all your apps from connecting to the domains and sites below. For your convenience, Lockdown also has pre-configured suggestions." = "Block all your apps from connecting to the domains and sites below. For your convenience, Lockdown also has pre-configured suggestions."; /* No comment provided by engineer. */ -"Block Lists" = "Block Lists"; +"Curated" = "Curated"; /* No comment provided by engineer. */ "Configure Blocking" = "Configure Blocking"; @@ -653,6 +653,11 @@ /* No comment provided by engineer. */ "SAVE" = "SAVE"; +/* No comment provided by engineer. */ +"CLOSE" = "CLOSE"; + + + /* No comment provided by engineer. */ "Access to cloud service information is not allowed" = "Access to cloud service information is not allowed"; @@ -700,3 +705,9 @@ /* The title of a list of trackers */ "Dummy Domains" = "Dummy Domains"; + +// BlockListViewController +"No lists yet" = "No lists yet"; +"Create a list" = "Create a list"; +"No custom domains yet" = "No custom domains yet"; +"Add a domain" = "Add a domain"; diff --git a/es.lproj/Localizable.strings b/es.lproj/Localizable.strings index 7703f95..0aa4a1e 100644 --- a/es.lproj/Localizable.strings +++ b/es.lproj/Localizable.strings @@ -648,7 +648,7 @@ "Block all your apps from connecting to the domains and sites below. For your convenience, Lockdown also has pre-configured suggestions." = "Bloquea todas tus aplicaciones para que no se conecten a los dominios y sitios a continuación. Para su comodidad, Lockdown también tiene sugerencias preconfiguradas."; /* No comment provided by engineer. */ -"Block Lists" = "Listas De Bloqueos"; +"Curated" = "Listas De Bloqueos"; /* No comment provided by engineer. */ "Configure Blocking" = "Configurar Bloqueo"; @@ -659,6 +659,9 @@ /* No comment provided by engineer. */ "SAVE" = "GUARDAR"; +/* No comment provided by engineer. */ +"CLOSE" = "CLOSE"; + /* No comment provided by engineer. */ "Access to cloud service information is not allowed" = "Access to cloud service information is not allowed"; diff --git a/fr.lproj/Localizable.strings b/fr.lproj/Localizable.strings index 15c0a0c..5061748 100644 --- a/fr.lproj/Localizable.strings +++ b/fr.lproj/Localizable.strings @@ -648,7 +648,7 @@ "Block all your apps from connecting to the domains and sites below. For your convenience, Lockdown also has pre-configured suggestions." = "Empêche toutes vos applications de se connecter aux domaines et sites ci-dessous. Pour vous faciliter la tâche, Lockdown propose également des suggestions pré-configurées."; /* No comment provided by engineer. */ -"Block Lists" = "Listes de Blocages"; +"Curated" = "Listes de Blocages"; /* No comment provided by engineer. */ "Configure Blocking" = "Blocages"; @@ -659,6 +659,9 @@ /* No comment provided by engineer. */ "SAVE" = "SAUVEGARDER"; +/* No comment provided by engineer. */ +"CLOSE" = "CLOSE"; + /* No comment provided by engineer. */ "Access to cloud service information is not allowed" = "Access to cloud service information is not allowed"; diff --git a/ja.lproj/Localizable.strings b/ja.lproj/Localizable.strings index a7f9fb4..957fff2 100644 --- a/ja.lproj/Localizable.strings +++ b/ja.lproj/Localizable.strings @@ -648,7 +648,7 @@ "Block all your apps from connecting to the domains and sites below. For your convenience, Lockdown also has pre-configured suggestions." = "以下のドメインとサイトへの接続からすべてのアプリをブロックします。便利なように、Lockdownには事前に設定された提案もあります。"; /* No comment provided by engineer. */ -"Block Lists" = "されたブロックリスト"; +"Curated" = "されたブロックリスト"; /* No comment provided by engineer. */ "Configure Blocking" = "ブロッキングを設定する"; @@ -659,6 +659,9 @@ /* No comment provided by engineer. */ "SAVE" = "セーブ"; +/* No comment provided by engineer. */ +"CLOSE" = "CLOSE"; + /* No comment provided by engineer. */ "Access to cloud service information is not allowed" = "Access to cloud service information is not allowed";