Showing
221 changed files
with
5519 additions
and
3 deletions
InterQR-Internship/Assets.xcassets/Genegal Views/InterQR.imageset/Group 33497-2.png
deleted
100644 → 0
3.84 KB
InterQR-Internship/Assets.xcassets/Genegal Views/InterQR.imageset/Group 33497-3.png
deleted
100644 → 0
6.25 KB
1.83 KB
TheButler/AppDelegate.swift
0 → 100644
| 1 | +// | |
| 2 | +// AppDelegate.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 30.05.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +@main | |
| 11 | +class AppDelegate: UIResponder, UIApplicationDelegate { | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { | |
| 16 | + // Override point for customization after application launch. | |
| 17 | + return true | |
| 18 | + } | |
| 19 | + | |
| 20 | + // MARK: UISceneSession Lifecycle | |
| 21 | + | |
| 22 | + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { | |
| 23 | + // Called when a new scene session is being created. | |
| 24 | + // Use this method to select a configuration to create the new scene with. | |
| 25 | + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) | |
| 26 | + } | |
| 27 | + | |
| 28 | + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { | |
| 29 | + // Called when the user discards a scene session. | |
| 30 | + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. | |
| 31 | + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. | |
| 32 | + } | |
| 33 | + | |
| 34 | + | |
| 35 | +} | |
| 36 | + | ... | ... |
2.13 KB
3.57 KB
966 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "3Users.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "3 User@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "3 User@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "EmptySquere.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Rectangle 8@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Rectangle 8@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
317 Bytes
523 Bytes
782 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "FullSquere.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 33542@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 33542@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
750 Bytes
1.84 KB
3.72 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "iphone", | |
| 5 | + "scale" : "2x", | |
| 6 | + "size" : "20x20" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "idiom" : "iphone", | |
| 10 | + "scale" : "3x", | |
| 11 | + "size" : "20x20" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "idiom" : "iphone", | |
| 15 | + "scale" : "2x", | |
| 16 | + "size" : "29x29" | |
| 17 | + }, | |
| 18 | + { | |
| 19 | + "idiom" : "iphone", | |
| 20 | + "scale" : "3x", | |
| 21 | + "size" : "29x29" | |
| 22 | + }, | |
| 23 | + { | |
| 24 | + "idiom" : "iphone", | |
| 25 | + "scale" : "2x", | |
| 26 | + "size" : "40x40" | |
| 27 | + }, | |
| 28 | + { | |
| 29 | + "idiom" : "iphone", | |
| 30 | + "scale" : "3x", | |
| 31 | + "size" : "40x40" | |
| 32 | + }, | |
| 33 | + { | |
| 34 | + "idiom" : "iphone", | |
| 35 | + "scale" : "2x", | |
| 36 | + "size" : "60x60" | |
| 37 | + }, | |
| 38 | + { | |
| 39 | + "idiom" : "iphone", | |
| 40 | + "scale" : "3x", | |
| 41 | + "size" : "60x60" | |
| 42 | + }, | |
| 43 | + { | |
| 44 | + "idiom" : "ipad", | |
| 45 | + "scale" : "1x", | |
| 46 | + "size" : "20x20" | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + "idiom" : "ipad", | |
| 50 | + "scale" : "2x", | |
| 51 | + "size" : "20x20" | |
| 52 | + }, | |
| 53 | + { | |
| 54 | + "idiom" : "ipad", | |
| 55 | + "scale" : "1x", | |
| 56 | + "size" : "29x29" | |
| 57 | + }, | |
| 58 | + { | |
| 59 | + "idiom" : "ipad", | |
| 60 | + "scale" : "2x", | |
| 61 | + "size" : "29x29" | |
| 62 | + }, | |
| 63 | + { | |
| 64 | + "idiom" : "ipad", | |
| 65 | + "scale" : "1x", | |
| 66 | + "size" : "40x40" | |
| 67 | + }, | |
| 68 | + { | |
| 69 | + "idiom" : "ipad", | |
| 70 | + "scale" : "2x", | |
| 71 | + "size" : "40x40" | |
| 72 | + }, | |
| 73 | + { | |
| 74 | + "idiom" : "ipad", | |
| 75 | + "scale" : "1x", | |
| 76 | + "size" : "76x76" | |
| 77 | + }, | |
| 78 | + { | |
| 79 | + "idiom" : "ipad", | |
| 80 | + "scale" : "2x", | |
| 81 | + "size" : "76x76" | |
| 82 | + }, | |
| 83 | + { | |
| 84 | + "idiom" : "ipad", | |
| 85 | + "scale" : "2x", | |
| 86 | + "size" : "83.5x83.5" | |
| 87 | + }, | |
| 88 | + { | |
| 89 | + "idiom" : "ios-marketing", | |
| 90 | + "scale" : "1x", | |
| 91 | + "size" : "1024x1024" | |
| 92 | + } | |
| 93 | + ], | |
| 94 | + "info" : { | |
| 95 | + "author" : "xcode", | |
| 96 | + "version" : 1 | |
| 97 | + } | |
| 98 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Apartman.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 33613@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 33613@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
26 KB
51.7 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Mask.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Mask Group@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Mask Group@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
63.8 KB
19.4 KB
TheButler/Assets.xcassets/Contents.json
0 → 100644
14.9 KB
| 1 | 1 | { |
| 2 | 2 | "images" : [ |
| 3 | 3 | { |
| 4 | - "filename" : "InterQR.png", | |
| 4 | + "filename" : "AUS.png", | |
| 5 | 5 | "idiom" : "universal", |
| 6 | 6 | "scale" : "1x" |
| 7 | 7 | }, |
| 8 | 8 | { |
| 9 | - "filename" : "Group 33497-2.png", | |
| 10 | 9 | "idiom" : "universal", |
| 11 | 10 | "scale" : "2x" |
| 12 | 11 | }, |
| 13 | 12 | { |
| 14 | - "filename" : "Group 33497-3.png", | |
| 15 | 13 | "idiom" : "universal", |
| 16 | 14 | "scale" : "3x" |
| 17 | 15 | } | ... | ... |
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "GB.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "icons8-великобритания-48.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "icons8-великобритания-96.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
871 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "USA.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Icons@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Icons@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
2.14 KB
3.18 KB
1.02 KB
414 Bytes
580 Bytes
239 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "BackPointer.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Arrow - Left 2@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Arrow - Left 2@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
377 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Close.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 33489@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 33489@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
562 Bytes
752 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "FlagPointer.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Stroke 1@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Stroke 1@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
251 Bytes
287 Bytes
343 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "NextPointer.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Stroke 3@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Stroke 3@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
221 Bytes
343 Bytes
450 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Gradient.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Rectangle 6@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Rectangle 6@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
6.77 KB
28.6 KB
54.8 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Home.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Home@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Home@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
19.2 KB
62 KB
126 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "LeftBlue.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 33668@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 33668@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
13.3 KB
2.41 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "RightBlue.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 33606@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 33606@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
3.99 KB
1.78 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "RightYellow.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 33607@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 33607@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
1.15 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Setting.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Setting@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Setting@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
701 Bytes
1.34 KB
1.87 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Lock.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Lock@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Lock@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
21.5 KB
71.8 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Tick.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Stroke 3@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Stroke 3@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
309 Bytes
404 Bytes
237 Bytes
543 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Bin.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Delete@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Delete@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
1.02 KB
1.62 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Edit.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Edit@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Edit@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
649 Bytes
1.33 KB
2.2 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Heart.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Heart@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Heart@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
647 Bytes
1.13 KB
1.64 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "HeartRed.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Heart@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Heart@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
725 Bytes
990 Bytes
421 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Plus.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 33489@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 33489@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
371 Bytes
466 Bytes
278 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Gear.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Setting@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Setting@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
14.5 KB
45.5 KB
92.2 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Notification.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Notification@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Notification@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
638 Bytes
1.25 KB
2.15 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Password.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Password@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Password@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
569 Bytes
1.05 KB
1.57 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Profile.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Profile@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Profile@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
646 Bytes
1.44 KB
2.31 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Volume.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Volume Up@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Volume Up@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
1.58 KB
2.47 KB
724 Bytes
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "234", | |
| 9 | + "green" : "234", | |
| 10 | + "red" : "227" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.180", | |
| 9 | + "green" : "0.000", | |
| 10 | + "red" : "1.000" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
TheButler/Assets.xcassets/UIColors/BorderColor/LightBlueBorderColor.colorset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.545", | |
| 9 | + "green" : "0.267", | |
| 10 | + "red" : "0.000" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
TheButler/Assets.xcassets/UIColors/BorderColor/LightGreyBorderColor.colorset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.910", | |
| 9 | + "green" : "0.910", | |
| 10 | + "red" : "0.882" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.545", | |
| 9 | + "green" : "0.257", | |
| 10 | + "red" : "0.000" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.827", | |
| 9 | + "green" : "0.561", | |
| 10 | + "red" : "0.000" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.333", | |
| 9 | + "green" : "0.216", | |
| 10 | + "red" : "0.196" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "iphone" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "iphone" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + }, | |
| 38 | + "properties" : { | |
| 39 | + "localizable" : true | |
| 40 | + } | |
| 41 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.725", | |
| 9 | + "green" : "0.725", | |
| 10 | + "red" : "0.725" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "0.980", | |
| 8 | + "blue" : "0.180", | |
| 9 | + "green" : "0.000", | |
| 10 | + "red" : "1.000" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.942", | |
| 9 | + "green" : "0.929", | |
| 10 | + "red" : "1.000" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
TheButler/Assets.xcassets/UIColors/TextFieldColor/GeneralTextField.colorset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "colors" : [ | |
| 3 | + { | |
| 4 | + "color" : { | |
| 5 | + "color-space" : "srgb", | |
| 6 | + "components" : { | |
| 7 | + "alpha" : "1.000", | |
| 8 | + "blue" : "0.954", | |
| 9 | + "green" : "0.954", | |
| 10 | + "red" : "0.954" | |
| 11 | + } | |
| 12 | + }, | |
| 13 | + "idiom" : "universal" | |
| 14 | + }, | |
| 15 | + { | |
| 16 | + "appearances" : [ | |
| 17 | + { | |
| 18 | + "appearance" : "luminosity", | |
| 19 | + "value" : "dark" | |
| 20 | + } | |
| 21 | + ], | |
| 22 | + "color" : { | |
| 23 | + "color-space" : "srgb", | |
| 24 | + "components" : { | |
| 25 | + "alpha" : "1.000", | |
| 26 | + "blue" : "1.000", | |
| 27 | + "green" : "1.000", | |
| 28 | + "red" : "1.000" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "idiom" : "universal" | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "info" : { | |
| 35 | + "author" : "xcode", | |
| 36 | + "version" : 1 | |
| 37 | + } | |
| 38 | +} | ... | ... |
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "OffIndicator.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Ellipse 1@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Ellipse 1@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
1.23 KB
1.75 KB
602 Bytes
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "OnIndicator.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Group 1@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Group 1@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
1.01 KB
1.43 KB
567 Bytes
TheButler/Assets.xcassets/Verification Screen/Pointer.imageset/Arrow - Right Circle@2x.png
0 → 100644
756 Bytes
TheButler/Assets.xcassets/Verification Screen/Pointer.imageset/Arrow - Right Circle@3x.png
0 → 100644
1.14 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Pointer.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Arrow - Right Circle@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Arrow - Right Circle@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
417 Bytes
2.97 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "8D57D412-3800-4D7C-922A-FF392EC0594E_4_5005_c.jpeg", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Rectangle@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Rectangle@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
82.5 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "RectangleWithShadow.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Rectangle@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Rectangle@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
TheButler/Assets.xcassets/Verification Screen/RectangleWithShadow.imageset/Rectangle@2x.png
0 → 100644
108 KB
TheButler/Assets.xcassets/Verification Screen/RectangleWithShadow.imageset/Rectangle@3x.png
0 → 100644
211 KB
TheButler/Assets.xcassets/Verification Screen/RectangleWithShadow.imageset/RectangleWithShadow.png
0 → 100644
34.6 KB
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "filename" : "Shield.png", | |
| 5 | + "idiom" : "universal", | |
| 6 | + "scale" : "1x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "filename" : "Mask Group@2x.png", | |
| 10 | + "idiom" : "universal", | |
| 11 | + "scale" : "2x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "filename" : "Mask Group@3x.png", | |
| 15 | + "idiom" : "universal", | |
| 16 | + "scale" : "3x" | |
| 17 | + } | |
| 18 | + ], | |
| 19 | + "info" : { | |
| 20 | + "author" : "xcode", | |
| 21 | + "version" : 1 | |
| 22 | + } | |
| 23 | +} | ... | ... |
22.8 KB
TheButler/AuthService/AuthService.swift
0 → 100644
| 1 | +// | |
| 2 | +// NetworkManager.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 25.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import Alamofire | |
| 10 | + | |
| 11 | +class AuthService { | |
| 12 | + static let shared = AuthService() | |
| 13 | + | |
| 14 | + private init() { | |
| 15 | + } | |
| 16 | + | |
| 17 | + var networkToken: String? { | |
| 18 | + get { | |
| 19 | + return UserDefaults.standard.string(forKey: "NETWORK_TOKEN") | |
| 20 | + } | |
| 21 | + | |
| 22 | + set (newValue) { | |
| 23 | + UserDefaults.standard.set(newValue, forKey: "NETWORK_TOKEN") | |
| 24 | + } | |
| 25 | + } | |
| 26 | + | |
| 27 | + typealias InitWebServiceResponse = (InitResponseModel) -> Void | |
| 28 | + typealias StartWebServiceResponse = (StartResponseModel) -> Void | |
| 29 | + typealias VerifyWebServiceResponse = (VerifyResponseModel) -> Void | |
| 30 | + typealias LoginWebServiceResponse = (LoginResponseModel) -> Void | |
| 31 | + typealias LogoutWebServiceResponse = (LogoutResponseModel) -> Void | |
| 32 | + | |
| 33 | + typealias FailedHandler = (Error) -> Void | |
| 34 | + | |
| 35 | + func initRequest(model: InitRequestModel, completion: @escaping InitWebServiceResponse, fail: @escaping FailedHandler) { | |
| 36 | + | |
| 37 | + let params = ["device_uuid": model.deviceUUID, | |
| 38 | + "manufacturer": model.manufacturer, | |
| 39 | + "model": model.model, | |
| 40 | + "platform": model.platform, | |
| 41 | + "os_version": model.osVersion, | |
| 42 | + "app_version": model.appVersion] as [String: Any] | |
| 43 | + | |
| 44 | + AF.request(Constants.baseURL + APIRoutes.initURL.urlString, method: .post, parameters: params, encoding: JSONEncoding.default).responseDecodable(of: InitResponseModel.self ) { response in | |
| 45 | + | |
| 46 | + if let error = response.error { | |
| 47 | + fail(error) | |
| 48 | + } else { | |
| 49 | + if let res = response.value { | |
| 50 | + completion(res) | |
| 51 | + } | |
| 52 | + } | |
| 53 | + } | |
| 54 | + } | |
| 55 | + | |
| 56 | + func startRequest(model: StartRequestModel, completion: @escaping StartWebServiceResponse, fail: @escaping FailedHandler) { | |
| 57 | + | |
| 58 | + let params = ["email_or_number": model.emailOrNumber] as [String: Any] | |
| 59 | + | |
| 60 | + AF.request(Constants.baseURL + APIRoutes.startURL.urlString, method: .post, parameters: params, encoding: JSONEncoding.default).responseDecodable(of: StartResponseModel.self ) { response in | |
| 61 | + | |
| 62 | + if let error = response.error { | |
| 63 | + fail(error) | |
| 64 | + } else { | |
| 65 | + if let res = response.value { | |
| 66 | + completion(res) | |
| 67 | + } | |
| 68 | + } | |
| 69 | + } | |
| 70 | + } | |
| 71 | + | |
| 72 | + func verifyRequest(model: VerifyRequestModel, completion: @escaping VerifyWebServiceResponse, fail: @escaping FailedHandler) { | |
| 73 | + | |
| 74 | + let params = ["email_or_number": model.emailOrNumber, | |
| 75 | + "code": model.code, | |
| 76 | + "second_auth_token": model.secondAuthToken] as [String: Any] | |
| 77 | + | |
| 78 | + AF.request(Constants.baseURL + APIRoutes.verifyURL.urlString, method: .post, parameters: params, encoding: JSONEncoding.default).responseDecodable(of: VerifyResponseModel.self ) { response in | |
| 79 | + | |
| 80 | + if let error = response.error { | |
| 81 | + fail(error) | |
| 82 | + } else { | |
| 83 | + if let res = response.value { | |
| 84 | + self.networkToken = res.data.token | |
| 85 | + completion(res) | |
| 86 | + } | |
| 87 | + } | |
| 88 | + } | |
| 89 | + } | |
| 90 | + | |
| 91 | + func loginRequest(model: LoginRequestModel, success: @escaping LoginWebServiceResponse, fail: @escaping FailedHandler) { | |
| 92 | + let interceptor = InterQrRequestInterceptor() | |
| 93 | + | |
| 94 | + let params = ["device_uuid": model.deviceUUID] as [String: Any] | |
| 95 | + | |
| 96 | + AF.request(Constants.baseURL + APIRoutes.loginURL.urlString, method: .post, parameters: params, encoding: JSONEncoding.default, interceptor: interceptor).responseDecodable(of: LoginResponseModel.self ) { response in | |
| 97 | + | |
| 98 | + switch response.result { | |
| 99 | + case .failure(let error) : | |
| 100 | + fail(error) | |
| 101 | + case .success(let res) : | |
| 102 | + success(res) | |
| 103 | + } | |
| 104 | + } | |
| 105 | + } | |
| 106 | + | |
| 107 | + func logoutRequest(model: LogoutRequestModel, completion: @escaping LogoutWebServiceResponse, fail: @escaping FailedHandler) { | |
| 108 | + let interceptor = InterQrRequestInterceptor() | |
| 109 | + let params = ["device_uuid": model.deviceUUID] as [String: Any] | |
| 110 | + | |
| 111 | + AF.request(Constants.baseURL + APIRoutes.logoutURL.urlString, method: .post, parameters: params, encoding: JSONEncoding.default, interceptor: interceptor).responseDecodable(of: LogoutResponseModel.self ) { response in | |
| 112 | + guard let successCode = response.response?.statusCode else { return } | |
| 113 | + if let error = response.error { | |
| 114 | + fail(error) | |
| 115 | + } else { | |
| 116 | + if successCode == 200 { | |
| 117 | + guard let res = response.value else { return } | |
| 118 | + completion(res) | |
| 119 | + } | |
| 120 | + } | |
| 121 | + } | |
| 122 | + } | |
| 123 | +} | |
| 124 | + | |
| 125 | +class InterQrRequestInterceptor: RequestInterceptor { | |
| 126 | + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) { | |
| 127 | + var urlRequest = urlRequest | |
| 128 | +// let headers = ["Authorization": "Bearer \(self.networkToken ?? "")"] | |
| 129 | +// let params = ["device_uuid": model.deviceUUID] as [String: Any] | |
| 130 | + if let token = AuthService.shared.networkToken { | |
| 131 | + urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") | |
| 132 | + } | |
| 133 | +// if let deviceUUID = | |
| 134 | + completion(.success(urlRequest)) | |
| 135 | + } | |
| 136 | +} | ... | ... |
TheButler/Base.lproj/LaunchScreen.storyboard
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
| 2 | +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> | |
| 3 | + <dependencies> | |
| 4 | + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> | |
| 5 | + <capability name="Safe area layout guides" minToolsVersion="9.0"/> | |
| 6 | + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | |
| 7 | + </dependencies> | |
| 8 | + <scenes> | |
| 9 | + <!--View Controller--> | |
| 10 | + <scene sceneID="EHf-IW-A2E"> | |
| 11 | + <objects> | |
| 12 | + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> | |
| 13 | + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> | |
| 14 | + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> | |
| 15 | + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |
| 16 | + <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> | |
| 17 | + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> | |
| 18 | + </view> | |
| 19 | + </viewController> | |
| 20 | + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> | |
| 21 | + </objects> | |
| 22 | + <point key="canvasLocation" x="53" y="375"/> | |
| 23 | + </scene> | |
| 24 | + </scenes> | |
| 25 | +</document> | ... | ... |
| 1 | +// | |
| 2 | +// Checkbox.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 07.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | +class Checkbox: UIButton { | |
| 11 | + private let checkboxImageView: UIImageView = { | |
| 12 | + let obj = UIImageView() | |
| 13 | + return obj | |
| 14 | + }() | |
| 15 | + | |
| 16 | + private let checkBoxLabel: UILabel = { | |
| 17 | + let obj = UILabel() | |
| 18 | + obj.font = .skModernist(type: .regular, ofSize: 15) | |
| 19 | + return obj | |
| 20 | + }() | |
| 21 | + | |
| 22 | + override var isSelected: Bool { | |
| 23 | + didSet { | |
| 24 | + checkBoxLabel.textColor = isSelected ? | |
| 25 | + .TextColor.darkBlue : | |
| 26 | + .TextColor.lightGrey | |
| 27 | + checkboxImageView.image = isSelected ? | |
| 28 | + UIImage(named: .Image.onIndicator) : | |
| 29 | + UIImage(named: .Image.offIndicator) | |
| 30 | + } | |
| 31 | + } | |
| 32 | + | |
| 33 | + var checkboxTitle: String = "" { | |
| 34 | + didSet { | |
| 35 | + checkBoxLabel.text = checkboxTitle | |
| 36 | + } | |
| 37 | + } | |
| 38 | + | |
| 39 | + override init(frame: CGRect) { | |
| 40 | + super.init(frame: frame) | |
| 41 | + setup() | |
| 42 | + } | |
| 43 | + | |
| 44 | + required init?(coder: NSCoder) { | |
| 45 | + super.init(coder: coder) | |
| 46 | + setup() | |
| 47 | + } | |
| 48 | + | |
| 49 | + private func setup() { | |
| 50 | + isSelected = false | |
| 51 | + | |
| 52 | + addSubview(checkboxImageView) | |
| 53 | + addSubview(checkBoxLabel) | |
| 54 | + | |
| 55 | + checkboxImageView.snp.makeConstraints { make in | |
| 56 | + make.leading.equalToSuperview() | |
| 57 | + make.top.bottom.equalToSuperview() | |
| 58 | + } | |
| 59 | + | |
| 60 | + checkBoxLabel.snp.makeConstraints { make in | |
| 61 | + make.top.bottom.equalToSuperview() | |
| 62 | + make.trailing.equalToSuperview() | |
| 63 | + make.leading.equalTo(checkboxImageView.snp.trailing).offset(5) | |
| 64 | + } | |
| 65 | + } | |
| 66 | +} | ... | ... |
| 1 | +// | |
| 2 | +// SquereCheckBox.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 17.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | +class SquereCheckbox: UIButton { | |
| 10 | + private let checkboxImageView: UIImageView = { | |
| 11 | + let obj = UIImageView() | |
| 12 | + return obj | |
| 13 | + }() | |
| 14 | + | |
| 15 | + private let checkBoxLabel: UILabel = { | |
| 16 | + let obj = UILabel() | |
| 17 | + obj.font = .skModernist(type: .regular, ofSize: 12) | |
| 18 | + return obj | |
| 19 | + }() | |
| 20 | + | |
| 21 | + override var isSelected: Bool { | |
| 22 | + didSet { | |
| 23 | + checkBoxLabel.textColor = isSelected ? | |
| 24 | + .TextColor.darkBlue : | |
| 25 | + .TextColor.lightGrey | |
| 26 | + checkboxImageView.image = isSelected ? | |
| 27 | + UIImage(named: .Image.fullSquere) : | |
| 28 | + UIImage(named: .Image.emptySquere) | |
| 29 | + } | |
| 30 | + } | |
| 31 | + | |
| 32 | + var checkboxTitle: String = "" { | |
| 33 | + didSet { | |
| 34 | + checkBoxLabel.text = checkboxTitle | |
| 35 | + } | |
| 36 | + } | |
| 37 | + | |
| 38 | + override init(frame: CGRect) { | |
| 39 | + super.init(frame: frame) | |
| 40 | + setup() | |
| 41 | + } | |
| 42 | + | |
| 43 | + required init?(coder: NSCoder) { | |
| 44 | + super.init(coder: coder) | |
| 45 | + setup() | |
| 46 | + } | |
| 47 | + | |
| 48 | + private func setup() { | |
| 49 | + isSelected = false | |
| 50 | + | |
| 51 | + addSubview(checkboxImageView) | |
| 52 | + addSubview(checkBoxLabel) | |
| 53 | + | |
| 54 | + checkboxImageView.snp.makeConstraints { make in | |
| 55 | + make.leading.equalToSuperview() | |
| 56 | + make.top.bottom.equalToSuperview() | |
| 57 | + } | |
| 58 | + | |
| 59 | + checkBoxLabel.snp.makeConstraints { make in | |
| 60 | + make.top.bottom.equalToSuperview() | |
| 61 | + make.trailing.equalToSuperview() | |
| 62 | + make.leading.equalTo(checkboxImageView.snp.trailing).offset(10) | |
| 63 | + } | |
| 64 | + } | |
| 65 | +} | ... | ... |
| 1 | +// | |
| 2 | +// TextFieldWithPadding.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 01.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class TextFieldWithPadding: UITextField { | |
| 11 | + var textPadding = UIEdgeInsets( | |
| 12 | + top: 0, | |
| 13 | + left: 0, | |
| 14 | + bottom: 0, | |
| 15 | + right: 0) | |
| 16 | + | |
| 17 | + override func textRect(forBounds bounds: CGRect) -> CGRect { | |
| 18 | + let rect = super.textRect(forBounds: bounds) | |
| 19 | + return rect.inset(by: textPadding) | |
| 20 | + } | |
| 21 | + | |
| 22 | + override func editingRect(forBounds bounds: CGRect) -> CGRect { | |
| 23 | + let rect = super.editingRect(forBounds: bounds) | |
| 24 | + return rect.inset(by: textPadding) | |
| 25 | + } | |
| 26 | +} | ... | ... |
TheButler/Constants.swift
0 → 100644
| 1 | +// | |
| 2 | +// Constant.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 25.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | + | |
| 10 | +struct Constants { | |
| 11 | + static let baseURL = "" | |
| 12 | +} | |
| 13 | + | |
| 14 | +enum APIRoutes { | |
| 15 | + case initURL | |
| 16 | + case startURL | |
| 17 | + case verifyURL | |
| 18 | + case loginURL | |
| 19 | + case logoutURL | |
| 20 | + | |
| 21 | + var urlString: String { | |
| 22 | + switch self { | |
| 23 | + | |
| 24 | + case .initURL: | |
| 25 | + return "" | |
| 26 | + case .startURL: | |
| 27 | + return "" | |
| 28 | + case .verifyURL: | |
| 29 | + return "" | |
| 30 | + case .loginURL: | |
| 31 | + return "" | |
| 32 | + case .logoutURL: | |
| 33 | + return "" | |
| 34 | + } | |
| 35 | + } | |
| 36 | +} | |
| 37 | + | ... | ... |
| 1 | +// | |
| 2 | +// Colors + extension.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 19.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | + | |
| 11 | +extension UIColor { | |
| 12 | + enum TextColor { | |
| 13 | + static let darkBlue = UIColor(named: "DarkBlueText") | |
| 14 | + static let lightGrey = UIColor(named: "LightGreyText") | |
| 15 | + static let redError = UIColor(named: "RedErrorText") | |
| 16 | + } | |
| 17 | + | |
| 18 | + enum TextFieldColor { | |
| 19 | + static let general = UIColor(named: "GeneralTextField") | |
| 20 | + static let error = UIColor(named: "ErrorTextField") | |
| 21 | + } | |
| 22 | + | |
| 23 | + enum Background { | |
| 24 | + static let lightGrey = UIColor(named: "LightGreyBackground") | |
| 25 | + static let lightRed = UIColor(named: "LightRedBackgroud") | |
| 26 | + } | |
| 27 | + | |
| 28 | + enum GradientBlue { | |
| 29 | + static let left = UIColor(named: "Left")?.cgColor | |
| 30 | + static let right = UIColor(named: "Right")?.cgColor | |
| 31 | + } | |
| 32 | + | |
| 33 | +} | |
| 34 | +extension CGColor { | |
| 35 | + enum BorderColor { | |
| 36 | + static let lightGrey = UIColor(named: "LightGreyBorderColor")?.cgColor | |
| 37 | + static let lightBlue = UIColor(named: "LightBlueBorderColor")?.cgColor | |
| 38 | + } | |
| 39 | + | |
| 40 | + enum GradientBlue { | |
| 41 | + static let left = UIColor(named: "Left")?.cgColor | |
| 42 | + static let right = UIColor(named: "Right")?.cgColor | |
| 43 | + } | |
| 44 | +} | |
| 45 | + | |
| 46 | +extension CAGradientLayer { | |
| 47 | + enum GradientBlue { | |
| 48 | + static let left = UIColor(named: "Left")?.cgColor | |
| 49 | + static let right = UIColor(named: "Right")?.cgColor | |
| 50 | + } | |
| 51 | +} | ... | ... |
| 1 | +// | |
| 2 | +// Strings + Extension.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 02.07.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | + | |
| 11 | +extension String { | |
| 12 | + enum Text { | |
| 13 | + static let addResident = "Add resident" | |
| 14 | + static let residentName = "Resident name" | |
| 15 | + static let enterResidentName = "Enter resident name" | |
| 16 | + static let mobileNumber = "Mobile number" | |
| 17 | + static let enterResidentNumber = "Enter resident number" | |
| 18 | + static let manager = "Manager" | |
| 19 | + static let hidden = "Hidden" | |
| 20 | + static let enterYourVerificationCode = "Enter your\nverification code" | |
| 21 | + static let pleaseEnterValidCode = "Please, enter valid verification code" | |
| 22 | + static let verify = "Verify" | |
| 23 | + static let myApartName = "My apart name" | |
| 24 | + static let residents = "Residents" | |
| 25 | + static let chooseApartment = "Choose\napartman" | |
| 26 | + static let settings = "Settings" | |
| 27 | + static let logout = "Logout" | |
| 28 | + static let yourDisplayName = "Your display name" | |
| 29 | + static let nameWillBeDisplay = "This name will be displayed everywhere" | |
| 30 | + static let editResidents = "Edit residents" | |
| 31 | + static let editResidentsAndInfo = "Edit the residents and their information" | |
| 32 | + static let doNotDisturb = "Do not disturb" | |
| 33 | + static let youWillNotBeNotified = "You will not be notified of any calls for one day. Auto reset at midnight" | |
| 34 | + static let welcome = "Welcome" | |
| 35 | + static let myDoors = "My doors" | |
| 36 | + static let locked = "Locked" | |
| 37 | + static let home = "Home" | |
| 38 | + static let frontDoor = "Front Door" | |
| 39 | + static let selectYourCountry = "Select your country" | |
| 40 | + static let select = "Select" | |
| 41 | + static let hello = "Hello" | |
| 42 | + static let letsVerifyYourAccount = "Lets verify your \naccount" | |
| 43 | + static let chooseWhatToStartWith = "Choose what to start with" | |
| 44 | + static let email = "Email" | |
| 45 | + static let phoneNumber = "Phone Number" | |
| 46 | + static let enterYourEmailAddress = "Enter your email address" | |
| 47 | + static let exampleEmail = "Example: john.doe@gmail.com" | |
| 48 | + static let plusOne = "+1" | |
| 49 | + static let verificationCodeWillBeSentToYourEmail = "Verification code will be sent to your e-mail" | |
| 50 | + static let continueText = "Continue" | |
| 51 | + static let johnDoe = "John Doe" | |
| 52 | + static let userCode = "503331651" | |
| 53 | + static let enterYourPhoneNumber = "Enter your phone number" | |
| 54 | + static let verificationCodeWillBeSentToYourNumber = "Verification code will be sent to\nyour phone number" | |
| 55 | + static let apple = "Apple" | |
| 56 | + } | |
| 57 | + | |
| 58 | + enum Image { | |
| 59 | + static let close = "Close" | |
| 60 | + static let threeUsers = "3Users" | |
| 61 | + static let heart = "Heart" | |
| 62 | + static let heartRed = "HeartRed" | |
| 63 | + static let backPointer = "BackPointer" | |
| 64 | + static let interQR = "InterQR" | |
| 65 | + static let lock = "Lock" | |
| 66 | + static let RectangleWithShadow = "RectangleWithShadow" | |
| 67 | + static let tick = "Tick" | |
| 68 | + static let edit = "Edit" | |
| 69 | + static let bin = "Bin" | |
| 70 | + static let mask = "Mask" | |
| 71 | + static let apartman = "Apartman" | |
| 72 | + static let nextPointer = "NextPointer" | |
| 73 | + static let gear = "Gear" | |
| 74 | + static let profile = "Profile" | |
| 75 | + static let notification = "Notification" | |
| 76 | + static let setting = "Setting" | |
| 77 | + static let home = "Home" | |
| 78 | + static let gradient = "Gradient" | |
| 79 | + static let password = "Password" | |
| 80 | + static let rightStatus = "RightBlue" | |
| 81 | + static let leftBlue = "LeftBlue" | |
| 82 | + static let shield = "Shield" | |
| 83 | + static let USA = "USA" | |
| 84 | + static let flagPointer = "FlagPointer" | |
| 85 | + static let fullSquere = "FullSquere" | |
| 86 | + static let emptySquere = "EmptySquere" | |
| 87 | + static let pointer = "Pointer" | |
| 88 | + static let onIndicator = "OnIndicator" | |
| 89 | + static let offIndicator = "OffIndicator" | |
| 90 | + } | |
| 91 | +} | ... | ... |
TheButler/Info.plist
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| 3 | +<plist version="1.0"> | |
| 4 | +<dict> | |
| 5 | + <key>UIAppFonts</key> | |
| 6 | + <array> | |
| 7 | + <string>Sk-Modernist-Bold.otf</string> | |
| 8 | + <string>Sk-Modernist-Mono.otf</string> | |
| 9 | + <string>Sk-Modernist-Regular.otf</string> | |
| 10 | + </array> | |
| 11 | + <key>UIApplicationSceneManifest</key> | |
| 12 | + <dict> | |
| 13 | + <key>UIApplicationSupportsMultipleScenes</key> | |
| 14 | + <false/> | |
| 15 | + <key>UISceneConfigurations</key> | |
| 16 | + <dict> | |
| 17 | + <key>UIWindowSceneSessionRoleApplication</key> | |
| 18 | + <array> | |
| 19 | + <dict> | |
| 20 | + <key>UISceneConfigurationName</key> | |
| 21 | + <string>Default Configuration</string> | |
| 22 | + <key>UISceneDelegateClassName</key> | |
| 23 | + <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string> | |
| 24 | + </dict> | |
| 25 | + </array> | |
| 26 | + </dict> | |
| 27 | + </dict> | |
| 28 | +</dict> | |
| 29 | +</plist> | ... | ... |
TheButler/Models/Auth Model/AuthModel.swift
0 → 100644
| 1 | +// | |
| 2 | +// AuthModel.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 25.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | + | |
| 10 | +//MARK: - Init collection | |
| 11 | +struct InitRequestModel: Codable { | |
| 12 | + var deviceUUID: String | |
| 13 | + var manufacturer: String | |
| 14 | + var model: String | |
| 15 | + var platform: String | |
| 16 | + var osVersion: String | |
| 17 | + var appVersion: String | |
| 18 | +} | |
| 19 | + | |
| 20 | +struct InitResponseModel: Decodable { | |
| 21 | + var message: String | |
| 22 | +} | |
| 23 | + | |
| 24 | +//MARK: - Start2fa collection | |
| 25 | +struct StartRequestModel: Codable { | |
| 26 | + var emailOrNumber: String | |
| 27 | + | |
| 28 | + enum CodingKeys: String, CodingKey { | |
| 29 | + case emailOrNumber = "email_or_number" | |
| 30 | + } | |
| 31 | +} | |
| 32 | + | |
| 33 | +struct StartResponseModel: Decodable { | |
| 34 | + var message: String | |
| 35 | +} | |
| 36 | + | |
| 37 | +//MARK: - Verify2fa collection | |
| 38 | +struct VerifyRequestModel: Codable { | |
| 39 | + var emailOrNumber: String | |
| 40 | + var code: String | |
| 41 | + var secondAuthToken: String | |
| 42 | + | |
| 43 | + enum CodingKeys: String, CodingKey { | |
| 44 | + case emailOrNumber = "email_or_number" | |
| 45 | + case code | |
| 46 | + case secondAuthToken = "second_auth_token" | |
| 47 | + } | |
| 48 | +} | |
| 49 | + | |
| 50 | +struct VerifyResponseModel: Decodable { | |
| 51 | + var data: VerifyData | |
| 52 | + var message: String | |
| 53 | +} | |
| 54 | + | |
| 55 | +struct VerifyData: Decodable { | |
| 56 | + var token: String | |
| 57 | + var uuid: String | |
| 58 | +} | |
| 59 | + | |
| 60 | +//MARK: - Login collection | |
| 61 | +struct LoginRequestModel: Codable { | |
| 62 | + var deviceUUID: String | |
| 63 | + | |
| 64 | + enum CodingKeys: String, CodingKey { | |
| 65 | + case deviceUUID = "device_uuid" | |
| 66 | + } | |
| 67 | +} | |
| 68 | + | |
| 69 | +struct LoginResponseModel: Decodable { | |
| 70 | + var message: String? | |
| 71 | +} | |
| 72 | + | |
| 73 | +//MARK: - Logout collection | |
| 74 | + | |
| 75 | +struct LogoutRequestModel: Codable { | |
| 76 | + var deviceUUID: String | |
| 77 | + | |
| 78 | + enum CodingKeys: String, CodingKey { | |
| 79 | + case deviceUUID = "device_uuid" | |
| 80 | + } | |
| 81 | +} | |
| 82 | + | |
| 83 | +struct LogoutResponseModel: Decodable { | |
| 84 | + var message: String? | |
| 85 | +} | ... | ... |
| 1 | +// | |
| 2 | +// PhonePickerModel.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 31.05.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | + | |
| 11 | +struct PhonePickerModel { | |
| 12 | + let code: String | |
| 13 | + let countryCode: String | |
| 14 | + let title: String | |
| 15 | + let icon: UIImage | |
| 16 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ResidentModel.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 18.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +struct ResidentModel { | |
| 11 | + var name: String | |
| 12 | + var mobileNumber: String | |
| 13 | + var manager = false | |
| 14 | + var hidden = false | |
| 15 | + var heart = false | |
| 16 | +} | ... | ... |
| 1 | +// | |
| 2 | +// AddResidentsView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 14.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class AddResidentsView: UIView { | |
| 11 | + var isShow: Bool = false | |
| 12 | + | |
| 13 | + let blurEffect: UIVisualEffectView = { | |
| 14 | + let blur = UIBlurEffect(style: UIBlurEffect.Style.systemMaterialDark) | |
| 15 | + let obj = UIVisualEffectView(effect: blur) | |
| 16 | + obj.autoresizingMask = [.flexibleWidth, .flexibleHeight] | |
| 17 | + obj.alpha = 0.9 | |
| 18 | + obj.isUserInteractionEnabled = true | |
| 19 | + return obj | |
| 20 | + }() | |
| 21 | + | |
| 22 | + let transparentView: UIView = { | |
| 23 | + var obj = UIView() | |
| 24 | + obj.isUserInteractionEnabled = true | |
| 25 | + obj.backgroundColor = .black | |
| 26 | + obj.alpha = 0.5 | |
| 27 | + return obj | |
| 28 | + }() | |
| 29 | + | |
| 30 | + var containerView: UIView = { | |
| 31 | + var obj = UIView() | |
| 32 | + obj.clipsToBounds = true | |
| 33 | + obj.layer.cornerRadius = 15 | |
| 34 | + obj.backgroundColor = .white | |
| 35 | + return obj | |
| 36 | + }() | |
| 37 | + | |
| 38 | + var addResidentLabeL: UILabel = { | |
| 39 | + var obj = UILabel() | |
| 40 | + obj.text = .Text.addResident | |
| 41 | + obj.textColor = .TextColor.darkBlue | |
| 42 | + obj.font = .skModernist(type: .bold, ofSize: 24) | |
| 43 | + return obj | |
| 44 | + }() | |
| 45 | + | |
| 46 | + var closeButton: UIButton = { | |
| 47 | + var obj = UIButton() | |
| 48 | + obj.layer.cornerRadius = 13 | |
| 49 | + obj.layer.borderWidth = 1 | |
| 50 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 51 | + obj.setImage(UIImage(named: .Image.close), for: .normal) | |
| 52 | + return obj | |
| 53 | + }() | |
| 54 | + | |
| 55 | + var dividingLineView: UIView = { | |
| 56 | + var view = UIView() | |
| 57 | + view.backgroundColor = .Background.lightGrey | |
| 58 | + return view | |
| 59 | + }() | |
| 60 | + | |
| 61 | + var residentNameLabel: UILabel = { | |
| 62 | + var obj = UILabel() | |
| 63 | + obj.text = .Text.residentName | |
| 64 | + obj.font = .skModernist(type: .bold, ofSize: 14) | |
| 65 | + obj.textColor = .TextColor.darkBlue | |
| 66 | + return obj | |
| 67 | + }() | |
| 68 | + | |
| 69 | + var nameTextField: TextFieldWithPadding = { | |
| 70 | + var obj = TextFieldWithPadding() | |
| 71 | + obj.backgroundColor = .TextFieldColor.general | |
| 72 | + obj.textAlignment = .left | |
| 73 | + obj.layer.cornerRadius = 15 | |
| 74 | + obj.placeholder = .Text.enterResidentName | |
| 75 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 76 | + obj.textPadding = UIEdgeInsets(top: 0, left: 22, bottom: 0, right: 22) | |
| 77 | + obj.returnKeyType = .done | |
| 78 | + return obj | |
| 79 | + }() | |
| 80 | + | |
| 81 | + var mobileNumberLabel: UILabel = { | |
| 82 | + var obj = UILabel() | |
| 83 | + obj.text = .Text.mobileNumber | |
| 84 | + obj.font = .skModernist(type: .bold, ofSize: 14) | |
| 85 | + obj.textColor = .TextColor.darkBlue | |
| 86 | + return obj | |
| 87 | + }() | |
| 88 | + | |
| 89 | + var mobileNumberTextField: TextFieldWithPadding = { | |
| 90 | + var obj = TextFieldWithPadding() | |
| 91 | + obj.backgroundColor = .TextFieldColor.general | |
| 92 | + obj.textAlignment = .left | |
| 93 | + obj.layer.cornerRadius = 15 | |
| 94 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 95 | + obj.textPadding = UIEdgeInsets(top: 0, left: 22, bottom: 0, right: 45) | |
| 96 | + obj.placeholder = .Text.enterResidentNumber | |
| 97 | + obj.keyboardType = .phonePad | |
| 98 | + return obj | |
| 99 | + }() | |
| 100 | + | |
| 101 | + let contactListButton: UIButton = { | |
| 102 | + let obj = UIButton() | |
| 103 | + obj.setImage(UIImage(named: .Image.threeUsers), for: .normal) | |
| 104 | + return obj | |
| 105 | + }() | |
| 106 | + | |
| 107 | + var managerButton: SquereCheckbox = { | |
| 108 | + var obj = SquereCheckbox() | |
| 109 | + obj.checkboxTitle = .Text.manager | |
| 110 | + return obj | |
| 111 | + }() | |
| 112 | + | |
| 113 | + var hiddenButton: SquereCheckbox = { | |
| 114 | + var obj = SquereCheckbox() | |
| 115 | + obj.checkboxTitle = .Text.hidden | |
| 116 | + return obj | |
| 117 | + }() | |
| 118 | + | |
| 119 | + var heartButton: UIButton = { | |
| 120 | + var obj = UIButton() | |
| 121 | + obj.setImage(UIImage(named: .Image.heart), for: .normal) | |
| 122 | + obj.setImage(UIImage(named: .Image.heartRed), for: .selected) | |
| 123 | + return obj | |
| 124 | + }() | |
| 125 | + | |
| 126 | + var gradientBG: CAGradientLayer = { | |
| 127 | + let obj = CAGradientLayer() | |
| 128 | + var leftColor = CGColor.GradientBlue.left | |
| 129 | + var rightColor = CGColor.GradientBlue.right | |
| 130 | + obj.colors = [leftColor, rightColor] | |
| 131 | + obj.startPoint = CGPoint(x: 0, y: 0.5) | |
| 132 | + obj.endPoint = CGPoint(x: 1, y: 0.5) | |
| 133 | + return obj | |
| 134 | + }() | |
| 135 | + | |
| 136 | + var addResidentButton: UIButton = { | |
| 137 | + var obj = UIButton() | |
| 138 | + obj.setTitle(.Text.addResident, for: .normal) | |
| 139 | + obj.setTitleColor(.white, for: .normal) | |
| 140 | + obj.titleLabel?.font = .skModernist(type: .bold, ofSize: 16) | |
| 141 | + obj.clipsToBounds = true | |
| 142 | + obj.layer.masksToBounds = true | |
| 143 | + return obj | |
| 144 | + }() | |
| 145 | + | |
| 146 | + override init(frame: CGRect) { | |
| 147 | + super.init(frame: frame) | |
| 148 | + layout() | |
| 149 | + backgroundColor = .clear | |
| 150 | + } | |
| 151 | + | |
| 152 | + required init?(coder: NSCoder) { | |
| 153 | + fatalError("init(coder:) has not been implemented") | |
| 154 | + } | |
| 155 | + | |
| 156 | + func layout() { | |
| 157 | + isUserInteractionEnabled = true | |
| 158 | + addResidentButton.layer.insertSublayer(gradientBG, at: 0) | |
| 159 | + | |
| 160 | + addSubview(transparentView) | |
| 161 | + transparentView.addSubview(blurEffect) | |
| 162 | + | |
| 163 | + addSubview(containerView) | |
| 164 | + containerView.addSubview(addResidentLabeL) | |
| 165 | + containerView.addSubview(closeButton) | |
| 166 | + containerView.addSubview(dividingLineView) | |
| 167 | + containerView.addSubview(residentNameLabel) | |
| 168 | + containerView.addSubview(nameTextField) | |
| 169 | + containerView.addSubview(mobileNumberLabel) | |
| 170 | + containerView.addSubview(mobileNumberTextField) | |
| 171 | + mobileNumberTextField.addSubview(contactListButton) | |
| 172 | + | |
| 173 | + containerView.addSubview(managerButton) | |
| 174 | + containerView.addSubview(hiddenButton) | |
| 175 | + containerView.addSubview(heartButton) | |
| 176 | + containerView.addSubview(addResidentButton) | |
| 177 | + | |
| 178 | + transparentView.snp.makeConstraints { | |
| 179 | + $0.leading.top.trailing.bottom.equalToSuperview() | |
| 180 | + } | |
| 181 | + | |
| 182 | + containerView.snp.makeConstraints { | |
| 183 | + $0.leading.trailing.equalToSuperview().inset(25) | |
| 184 | + $0.centerY.equalTo(transparentView.snp.centerY) | |
| 185 | + } | |
| 186 | + | |
| 187 | + addResidentLabeL.snp.makeConstraints { | |
| 188 | + $0.top.equalToSuperview().offset(34) | |
| 189 | + $0.leading.equalToSuperview().offset(28) | |
| 190 | + } | |
| 191 | + | |
| 192 | + closeButton.snp.makeConstraints { | |
| 193 | + $0.centerY.equalTo(addResidentLabeL) | |
| 194 | + $0.trailing.equalToSuperview().offset(-30) | |
| 195 | + $0.height.width.equalTo(45) | |
| 196 | + } | |
| 197 | + | |
| 198 | + dividingLineView.snp.makeConstraints { | |
| 199 | + $0.trailing.leading.equalToSuperview() | |
| 200 | + $0.height.equalTo(1) | |
| 201 | + $0.top.equalTo(addResidentLabeL.snp.bottom).offset(34) | |
| 202 | + } | |
| 203 | + | |
| 204 | + residentNameLabel.snp.makeConstraints { | |
| 205 | + $0.top.equalTo(dividingLineView.snp.bottom).offset(24) | |
| 206 | + $0.leading.equalToSuperview().offset(44) | |
| 207 | + } | |
| 208 | + | |
| 209 | + nameTextField.snp.makeConstraints { | |
| 210 | + $0.leading.trailing.equalToSuperview().inset(30) | |
| 211 | + $0.top.equalTo(residentNameLabel.snp.bottom).offset(10) | |
| 212 | + $0.height.equalTo(47) | |
| 213 | + } | |
| 214 | + | |
| 215 | + mobileNumberLabel.snp.makeConstraints { | |
| 216 | + $0.leading.equalTo(residentNameLabel.snp.leading) | |
| 217 | + $0.top.equalTo(nameTextField.snp.bottom).offset(15) | |
| 218 | + } | |
| 219 | + | |
| 220 | + mobileNumberTextField.snp.makeConstraints { | |
| 221 | + $0.leading.trailing.equalToSuperview().inset(30) | |
| 222 | + $0.top.equalTo(mobileNumberLabel.snp.bottom).offset(10) | |
| 223 | + $0.height.equalTo(47) | |
| 224 | + } | |
| 225 | + | |
| 226 | + contactListButton.snp.makeConstraints { | |
| 227 | + $0.height.width.equalTo(24) | |
| 228 | + $0.centerY.equalToSuperview() | |
| 229 | + $0.trailing.equalToSuperview().offset(-19) | |
| 230 | + } | |
| 231 | + | |
| 232 | + managerButton.snp.makeConstraints { | |
| 233 | + $0.leading.equalToSuperview().offset(29) | |
| 234 | + $0.top.equalTo(mobileNumberTextField.snp.bottom).offset(30) | |
| 235 | + $0.height.equalTo(20) | |
| 236 | + } | |
| 237 | + | |
| 238 | + hiddenButton.snp.makeConstraints { | |
| 239 | + $0.top.equalTo(managerButton) | |
| 240 | + $0.leading.equalTo(managerButton.snp.trailing).offset(24) | |
| 241 | + $0.height.equalTo(20) | |
| 242 | + } | |
| 243 | + | |
| 244 | + heartButton.snp.makeConstraints { | |
| 245 | + $0.top.equalTo(managerButton) | |
| 246 | + $0.trailing.equalToSuperview().offset(-32.5) | |
| 247 | + } | |
| 248 | + | |
| 249 | + addResidentButton.snp.makeConstraints { | |
| 250 | + $0.top.equalTo(managerButton.snp.bottom).offset(43) | |
| 251 | + $0.leading.trailing.bottom.equalToSuperview() | |
| 252 | + $0.height.equalTo(64) | |
| 253 | + } | |
| 254 | + } | |
| 255 | + | |
| 256 | + override func layoutSubviews() { | |
| 257 | + super.layoutSubviews() | |
| 258 | + gradientBG.frame = addResidentButton.bounds | |
| 259 | + blurEffect.frame = transparentView.bounds | |
| 260 | + } | |
| 261 | +} | ... | ... |
| 1 | +// | |
| 2 | +// AddResidentViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 14.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | +import ContactsUI | |
| 10 | + | |
| 11 | +class AddResidentsViewController: UIViewController { | |
| 12 | + var isKeyboardAppear = false | |
| 13 | + | |
| 14 | + var mainView = AddResidentsView() | |
| 15 | + weak var delegate: ResidentSavable? | |
| 16 | + var closeTap: UITapGestureRecognizer? | |
| 17 | + | |
| 18 | + override func loadView() { | |
| 19 | + view = mainView | |
| 20 | + } | |
| 21 | + | |
| 22 | + override func viewDidLoad() { | |
| 23 | + super.viewDidLoad() | |
| 24 | + initViewController() | |
| 25 | + } | |
| 26 | + | |
| 27 | + func initViewController() { | |
| 28 | + self.closeTap = UITapGestureRecognizer(target: self, action: #selector(didTapCloseButton)) | |
| 29 | + if let closeTap = self.closeTap { | |
| 30 | + mainView.transparentView.addGestureRecognizer(closeTap) | |
| 31 | + } | |
| 32 | + addDoneButtonOnKeyboard() | |
| 33 | + | |
| 34 | + mainView.nameTextField.delegate = self | |
| 35 | + mainView.mobileNumberTextField.delegate = self | |
| 36 | + | |
| 37 | + mainView.closeButton.addTarget(self, action: #selector(didTapCloseButton), for: .touchUpInside) | |
| 38 | + mainView.managerButton.addTarget(self, action: #selector(didTapOnChangeableButtons(_:)), for: .touchUpInside) | |
| 39 | + mainView.hiddenButton.addTarget(self, action: #selector(didTapOnChangeableButtons(_:)), for: .touchUpInside) | |
| 40 | + mainView.heartButton.addTarget(self, action: #selector(didTapOnChangeableButtons(_:)), for: .touchUpInside) | |
| 41 | + mainView.addResidentButton.addTarget(self, action: #selector(didTapResidentButton), for: .touchUpInside) | |
| 42 | + mainView.contactListButton.addTarget(self, action: #selector(didTapContactListButton), for: .touchUpInside) | |
| 43 | + | |
| 44 | + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) | |
| 45 | + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) | |
| 46 | + } | |
| 47 | + | |
| 48 | + deinit { | |
| 49 | + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) | |
| 50 | + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) | |
| 51 | + } | |
| 52 | + | |
| 53 | + func addDoneButtonOnKeyboard() { | |
| 54 | + let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50)) | |
| 55 | + doneToolbar.barStyle = .default | |
| 56 | + | |
| 57 | + let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) | |
| 58 | + let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction)) | |
| 59 | + | |
| 60 | + let items = [flexSpace, done] | |
| 61 | + doneToolbar.items = items | |
| 62 | + doneToolbar.sizeToFit() | |
| 63 | + | |
| 64 | + mainView.mobileNumberTextField.inputAccessoryView = doneToolbar | |
| 65 | + } | |
| 66 | + | |
| 67 | + @objc func doneButtonAction(){ | |
| 68 | + mainView.mobileNumberTextField.resignFirstResponder() | |
| 69 | + | |
| 70 | + } | |
| 71 | + | |
| 72 | + func reloadView() { | |
| 73 | + mainView.mobileNumberTextField.reloadInputViews() | |
| 74 | + } | |
| 75 | + | |
| 76 | + @objc private func didTapCloseButton() { | |
| 77 | + dismiss(animated: true, completion: nil) | |
| 78 | + } | |
| 79 | + | |
| 80 | + @objc private func didTapResidentButton() { | |
| 81 | + if mainView.nameTextField.text == "" { | |
| 82 | + let alert = UIAlertController(title: "Enter name field", message: "", preferredStyle: .alert) | |
| 83 | + alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) | |
| 84 | + present(alert, animated: true, completion: nil) | |
| 85 | + } else { | |
| 86 | + if mainView.mobileNumberTextField.text == "" { | |
| 87 | + let alert = UIAlertController(title: "Enter phone number field", message: "", preferredStyle: .alert) | |
| 88 | + alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) | |
| 89 | + present(alert, animated: true, completion: nil) | |
| 90 | + } else { | |
| 91 | + didReceiveData() | |
| 92 | + dismiss(animated: true, completion: nil) | |
| 93 | + } | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + func didReceiveData() { | |
| 98 | + guard let name = mainView.nameTextField.text, | |
| 99 | + let mobileNumber = mainView.mobileNumberTextField.text | |
| 100 | + else { | |
| 101 | + return | |
| 102 | + } | |
| 103 | + let model = ResidentModel(name: name, | |
| 104 | + mobileNumber: mobileNumber, | |
| 105 | + manager: mainView.managerButton.isSelected, | |
| 106 | + hidden: mainView.hiddenButton.isSelected, | |
| 107 | + heart: mainView.heartButton.isSelected) | |
| 108 | + delegate?.save(model) | |
| 109 | + } | |
| 110 | + | |
| 111 | + @objc private func didTapOnChangeableButtons(_ sender: SquereCheckbox) { | |
| 112 | + switch sender { | |
| 113 | + case mainView.managerButton : | |
| 114 | + if mainView.managerButton.isSelected == true { | |
| 115 | + mainView.managerButton.isSelected = false | |
| 116 | + } else { | |
| 117 | + mainView.managerButton.isSelected = true | |
| 118 | + } | |
| 119 | + case mainView.hiddenButton : | |
| 120 | + if mainView.hiddenButton.isSelected == true { | |
| 121 | + mainView.hiddenButton.isSelected = false | |
| 122 | + } else { | |
| 123 | + mainView.hiddenButton.isSelected = true | |
| 124 | + } | |
| 125 | + case mainView.heartButton : | |
| 126 | + if mainView.heartButton.isSelected == true { | |
| 127 | + mainView.heartButton.isSelected = false | |
| 128 | + } else { | |
| 129 | + mainView.heartButton.isSelected = true | |
| 130 | + } | |
| 131 | + default: | |
| 132 | + return | |
| 133 | + } | |
| 134 | + } | |
| 135 | + | |
| 136 | + @objc private func didTapContactListButton() { | |
| 137 | + presentContactPickerVC() | |
| 138 | + } | |
| 139 | + | |
| 140 | + func presentContactPickerVC() { | |
| 141 | + let viewController = ContactPickerViewController() | |
| 142 | + viewController.delegate = self | |
| 143 | + present(viewController, animated: true) | |
| 144 | + } | |
| 145 | +} | |
| 146 | + | |
| 147 | +//MARK: - Keyboard observer | |
| 148 | +extension AddResidentsViewController { | |
| 149 | + @objc private func keyboardWillShow(notification: NSNotification) { | |
| 150 | + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double | |
| 151 | + | |
| 152 | + if !isKeyboardAppear { | |
| 153 | + | |
| 154 | + UIView.animate(withDuration: duration ?? 0) { | |
| 155 | + self.mainView.containerView.snp.updateConstraints { make in | |
| 156 | + make.centerY.equalTo(self.mainView.transparentView.snp.centerY).offset(-150) | |
| 157 | + } | |
| 158 | + self.mainView.layoutIfNeeded() | |
| 159 | + } | |
| 160 | + isKeyboardAppear = true | |
| 161 | + } | |
| 162 | + } | |
| 163 | + | |
| 164 | + @objc private func keyboardWillHide(notification: NSNotification) { | |
| 165 | + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double | |
| 166 | + | |
| 167 | + if isKeyboardAppear { | |
| 168 | + | |
| 169 | + UIView.animate(withDuration: duration ?? 0) { | |
| 170 | + self.mainView.containerView.snp.updateConstraints { make in | |
| 171 | + make.centerY.equalTo(self.mainView.transparentView.snp.centerY) | |
| 172 | + } | |
| 173 | + self.mainView.layoutIfNeeded() | |
| 174 | + } | |
| 175 | + isKeyboardAppear = false | |
| 176 | + } | |
| 177 | + } | |
| 178 | +} | |
| 179 | +//MARK: - Contact picker delegate | |
| 180 | +extension AddResidentsViewController: CNContactPickerDelegate { | |
| 181 | + func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) { | |
| 182 | + let userPhoneNumbers:[CNLabeledValue<CNPhoneNumber>] = contact.phoneNumbers | |
| 183 | + let firstPhoneNumber:CNPhoneNumber = userPhoneNumbers[0].value | |
| 184 | + | |
| 185 | + mainView.mobileNumberTextField.text = firstPhoneNumber.stringValue | |
| 186 | + } | |
| 187 | +} | |
| 188 | +//MARK: - TextField delegate | |
| 189 | +extension AddResidentsViewController: UITextFieldDelegate { | |
| 190 | + func textFieldShouldReturn(_ textField: UITextField) -> Bool { | |
| 191 | + guard let text = mainView.nameTextField.text else { return true } | |
| 192 | + if text.isEmpty{ | |
| 193 | + let alert = UIAlertController(title: "Enter name field", message: "", preferredStyle: .alert) | |
| 194 | + alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) | |
| 195 | + present(alert, animated: true, completion: nil) | |
| 196 | + } else { | |
| 197 | + mainView.mobileNumberTextField.becomeFirstResponder() | |
| 198 | + } | |
| 199 | + return true | |
| 200 | + } | |
| 201 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ChooseApartmentsTableViewCell.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 14.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class ChooseApartmentsTableViewCell: UITableViewCell { | |
| 11 | + static let id = String(describing: ChooseApartmentsTableViewCell.self) | |
| 12 | + | |
| 13 | + var apartmanImage: UIImageView = { | |
| 14 | + var obj = UIImageView() | |
| 15 | + obj.image = UIImage(named: .Image.apartman) | |
| 16 | + return obj | |
| 17 | + }() | |
| 18 | + | |
| 19 | + var clientNameLabel: UILabel = { | |
| 20 | + var obj = UILabel() | |
| 21 | + obj.text = "Bares Family" | |
| 22 | + obj.textColor = .TextColor.darkBlue | |
| 23 | + obj.font = .skModernist(type: .bold, ofSize: 16) | |
| 24 | + return obj | |
| 25 | + }() | |
| 26 | + | |
| 27 | + var adressLabel: UILabel = { | |
| 28 | + var obj = UILabel() | |
| 29 | + obj.text = "200 5th Ave" | |
| 30 | + obj.textColor = .TextColor.lightGrey | |
| 31 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 32 | + return obj | |
| 33 | + }() | |
| 34 | + | |
| 35 | + var nextPointerImage: UIImageView = { | |
| 36 | + var obj = UIImageView() | |
| 37 | + obj.image = UIImage(named: .Image.nextPointer) | |
| 38 | + return obj | |
| 39 | + }() | |
| 40 | + | |
| 41 | + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { | |
| 42 | + super.init(style: style, reuseIdentifier: reuseIdentifier) | |
| 43 | + setup() | |
| 44 | + } | |
| 45 | + | |
| 46 | + required init?(coder: NSCoder) { | |
| 47 | + fatalError("init(coder:) has not been implemented") | |
| 48 | + } | |
| 49 | + | |
| 50 | + func setup() { | |
| 51 | + selectionStyle = .none | |
| 52 | + contentView.addSubview(apartmanImage) | |
| 53 | + contentView.addSubview(clientNameLabel) | |
| 54 | + contentView.addSubview(adressLabel) | |
| 55 | + contentView.addSubview(nextPointerImage) | |
| 56 | + | |
| 57 | + apartmanImage.snp.makeConstraints { | |
| 58 | + $0.top.equalToSuperview().offset(8) | |
| 59 | + $0.leading.equalToSuperview() | |
| 60 | + } | |
| 61 | + clientNameLabel.snp.makeConstraints { | |
| 62 | + $0.top.equalToSuperview().offset(20) | |
| 63 | + $0.leading.equalTo(apartmanImage.snp.trailing).offset(18) | |
| 64 | + } | |
| 65 | + adressLabel.snp.makeConstraints { | |
| 66 | + $0.top.equalTo(clientNameLabel.snp.bottom).offset(5) | |
| 67 | + $0.leading.equalTo(clientNameLabel.snp.leading) | |
| 68 | + } | |
| 69 | + nextPointerImage.snp.makeConstraints { | |
| 70 | + $0.centerY.equalToSuperview() | |
| 71 | + $0.trailing.equalToSuperview().offset(-26) | |
| 72 | + } | |
| 73 | + } | |
| 74 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ChooseApartmentsView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 14.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class ChooseApartmentView: UIView { | |
| 11 | + | |
| 12 | + var backButton: UIButton = { | |
| 13 | + var obj = UIButton() | |
| 14 | + obj.setImage(UIImage(named: .Image.backPointer), for: .normal) | |
| 15 | + obj.backgroundColor = .white | |
| 16 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 17 | + obj.layer.cornerRadius = 13 | |
| 18 | + obj.layer.borderWidth = 1 | |
| 19 | + return obj | |
| 20 | + }() | |
| 21 | + | |
| 22 | + var logoImage: UIImageView = { | |
| 23 | + var obj = UIImageView() | |
| 24 | + obj.image = UIImage(named: .Image.USA) | |
| 25 | + return obj | |
| 26 | + }() | |
| 27 | + | |
| 28 | + var tickImage: UIImageView = { | |
| 29 | + var obj = UIImageView() | |
| 30 | + obj.image = UIImage(named: .Image.mask) | |
| 31 | + return obj | |
| 32 | + }() | |
| 33 | + | |
| 34 | + let apartmentsLabel: UILabel = { | |
| 35 | + var obj = UILabel() | |
| 36 | + obj.font = .skModernist(type: .bold, ofSize: 35) | |
| 37 | + obj.text = .Text.chooseApartment | |
| 38 | + obj.numberOfLines = 0 | |
| 39 | + return obj | |
| 40 | + }() | |
| 41 | + | |
| 42 | + var tableView: UITableView = { | |
| 43 | + var obj = UITableView() | |
| 44 | + obj.showsVerticalScrollIndicator = false | |
| 45 | + return obj | |
| 46 | + }() | |
| 47 | + | |
| 48 | + override init(frame: CGRect) { | |
| 49 | + super.init(frame: frame) | |
| 50 | + backgroundColor = .white | |
| 51 | + layout() | |
| 52 | + } | |
| 53 | + | |
| 54 | + required init?(coder: NSCoder) { | |
| 55 | + fatalError("init(coder:) has not been implemented") | |
| 56 | + } | |
| 57 | + | |
| 58 | + func layout() { | |
| 59 | + addSubview(backButton) | |
| 60 | + addSubview(logoImage) | |
| 61 | + addSubview(tickImage) | |
| 62 | + addSubview(apartmentsLabel) | |
| 63 | + addSubview(tableView) | |
| 64 | + | |
| 65 | + backButton.snp.makeConstraints { | |
| 66 | + $0.top.equalTo(snp.top).offset(66) | |
| 67 | + $0.leading.equalTo(snp.leading).offset(25) | |
| 68 | + $0.height.width.equalTo(45) | |
| 69 | + } | |
| 70 | + logoImage.snp.makeConstraints { | |
| 71 | + $0.leading.equalTo(backButton.snp.trailing).offset(20) | |
| 72 | + $0.top.equalTo(snp.top).offset(79) | |
| 73 | + } | |
| 74 | + tickImage.snp.makeConstraints { | |
| 75 | + $0.trailing.equalTo(snp.trailing) | |
| 76 | + $0.top.equalTo(snp.top).offset(106) | |
| 77 | + } | |
| 78 | + apartmentsLabel.snp.makeConstraints { | |
| 79 | + $0.leading.equalTo(backButton.snp.leading) | |
| 80 | + $0.top.equalTo(backButton.snp.bottom).offset(46) | |
| 81 | + } | |
| 82 | + | |
| 83 | + tableView.snp.makeConstraints { make in | |
| 84 | + make.leading.trailing.equalToSuperview() | |
| 85 | + make.top.equalTo(apartmentsLabel.snp.bottom).offset(85) | |
| 86 | + make.bottom.equalToSuperview() | |
| 87 | + } | |
| 88 | + } | |
| 89 | +} | ... | ... |
TheButler/Modules/ChooseApartmentsScreen/ViewController/ChooseApartmentsViewController.swift
0 → 100644
| 1 | +// | |
| 2 | +// ChooseApartmentsViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 14.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class ChooseApartmentsViewController: UIViewController { | |
| 11 | + | |
| 12 | + var mainView = ChooseApartmentView() | |
| 13 | + | |
| 14 | + override func loadView() { | |
| 15 | + view = mainView | |
| 16 | + } | |
| 17 | + | |
| 18 | + override func viewDidLoad() { | |
| 19 | + super.viewDidLoad() | |
| 20 | + initViewController() | |
| 21 | + } | |
| 22 | + | |
| 23 | + func initViewController() { | |
| 24 | + mainView.tableView.delegate = self | |
| 25 | + mainView.tableView.dataSource = self | |
| 26 | + mainView.backButton.addTarget(self, action: #selector(backToSettingsVC), for: .touchUpInside) | |
| 27 | + mainView.tableView.register(ChooseApartmentsTableViewCell.self, forCellReuseIdentifier: ChooseApartmentsTableViewCell.id) | |
| 28 | + } | |
| 29 | + | |
| 30 | + @objc func backToSettingsVC() { | |
| 31 | + navigationController?.popViewController(animated: true) | |
| 32 | + } | |
| 33 | +} | |
| 34 | +extension ChooseApartmentsViewController: UITableViewDelegate, UITableViewDataSource { | |
| 35 | + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
| 36 | + 3 | |
| 37 | + } | |
| 38 | + | |
| 39 | + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
| 40 | + guard let cell = tableView.dequeueReusableCell(withIdentifier: ChooseApartmentsTableViewCell.id, for: indexPath) as? ChooseApartmentsTableViewCell else { return UITableViewCell() } | |
| 41 | +// cell.configureWithItem(doors[indexPath.row]) | |
| 42 | + return cell | |
| 43 | + } | |
| 44 | + | |
| 45 | + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { | |
| 46 | + 87 | |
| 47 | + } | |
| 48 | + | |
| 49 | + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | |
| 50 | + let vc = ResidentsViewController() | |
| 51 | + navigationController?.pushViewController(vc, animated: true) | |
| 52 | + } | |
| 53 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ContactPickerViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 17.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | +import ContactsUI | |
| 11 | + | |
| 12 | +class ContactPickerViewController: CNContactPickerViewController { | |
| 13 | + var phoneNumber = "" | |
| 14 | +} | |
| 15 | + | |
| 16 | +//MARK: - Contact picker delegate | |
| 17 | +extension ContactPickerViewController: CNContactPickerDelegate { | |
| 18 | + func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) { | |
| 19 | + phoneNumber = "\(contact.phoneNumbers)" | |
| 20 | + | |
| 21 | + } | |
| 22 | +} | ... | ... |
| 1 | +// | |
| 2 | +// HomeTableViewCell.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 08.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class HomeTableViewCell: UITableViewCell { | |
| 11 | + static let id = String(describing: HomeTableViewCell.self) | |
| 12 | + | |
| 13 | + var containerView: UIView = { | |
| 14 | + var obj = UIView() | |
| 15 | + obj.layer.cornerRadius = 15 | |
| 16 | + obj.layer.borderWidth = 1 | |
| 17 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 18 | + return obj | |
| 19 | + }() | |
| 20 | + | |
| 21 | + var leftStatusImage: UIImageView = { | |
| 22 | + var obj = UIImageView() | |
| 23 | + obj.image = UIImage(named: .Image.leftBlue) | |
| 24 | + obj.contentMode = .scaleAspectFill | |
| 25 | + return obj | |
| 26 | + }() | |
| 27 | + | |
| 28 | + var doorNameLabel: UILabel = { | |
| 29 | + var obj = UILabel() | |
| 30 | + obj.font = .skModernist(type: .bold, ofSize: 16) | |
| 31 | + obj.textColor = .TextColor.darkBlue | |
| 32 | + obj.text = .Text.frontDoor | |
| 33 | + return obj | |
| 34 | + }() | |
| 35 | + | |
| 36 | + var doorLocationLabel: UILabel = { | |
| 37 | + var obj = UILabel() | |
| 38 | + obj.textColor = .TextColor.lightGrey | |
| 39 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 40 | + obj.text = .Text.home | |
| 41 | + return obj | |
| 42 | + }() | |
| 43 | + | |
| 44 | + var lockStatusLabel: UILabel = { | |
| 45 | + var obj = UILabel() | |
| 46 | + obj.textColor = .TextColor.darkBlue | |
| 47 | + obj.font = .skModernist(type: .bold, ofSize: 15) | |
| 48 | + obj.text = .Text.locked | |
| 49 | + return obj | |
| 50 | + }() | |
| 51 | + | |
| 52 | + var rightStatusImage: UIImageView = { | |
| 53 | + var obj = UIImageView() | |
| 54 | + obj.image = UIImage(named: .Image.rightStatus) | |
| 55 | + return obj | |
| 56 | + }() | |
| 57 | + | |
| 58 | + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { | |
| 59 | + super.init(style: style, reuseIdentifier: reuseIdentifier) | |
| 60 | + setup() | |
| 61 | + } | |
| 62 | + | |
| 63 | + required init?(coder: NSCoder) { | |
| 64 | + fatalError("init(coder:) has not been implemented") | |
| 65 | + } | |
| 66 | + | |
| 67 | + func setup() { | |
| 68 | + selectionStyle = .none | |
| 69 | + | |
| 70 | + addSubview(containerView) | |
| 71 | + containerView.addSubview(leftStatusImage) | |
| 72 | + containerView.addSubview(doorNameLabel) | |
| 73 | + containerView.addSubview(doorLocationLabel) | |
| 74 | + containerView.addSubview(lockStatusLabel) | |
| 75 | + containerView.addSubview(rightStatusImage) | |
| 76 | + | |
| 77 | + containerView.snp.makeConstraints { | |
| 78 | + $0.leading.trailing.equalToSuperview() | |
| 79 | + $0.bottom.equalToSuperview().offset(-8) | |
| 80 | + $0.top.equalToSuperview().offset(8) | |
| 81 | + } | |
| 82 | + | |
| 83 | + leftStatusImage.snp.makeConstraints { | |
| 84 | + $0.top.equalTo(containerView.snp.top).offset(19) | |
| 85 | + $0.leading.equalTo(containerView.snp.leading).offset(23) | |
| 86 | + $0.height.width.equalTo(41) | |
| 87 | + } | |
| 88 | + | |
| 89 | + doorNameLabel.snp.makeConstraints { | |
| 90 | + $0.top.equalTo(snp.top).offset(22) | |
| 91 | + $0.leading.equalTo(leftStatusImage.snp.trailing).offset(14) | |
| 92 | + } | |
| 93 | + | |
| 94 | + doorLocationLabel.snp.makeConstraints { | |
| 95 | + $0.top.equalTo(doorNameLabel.snp.bottom) | |
| 96 | + $0.leading.equalTo(doorNameLabel.snp.leading) | |
| 97 | + } | |
| 98 | + | |
| 99 | + lockStatusLabel.snp.makeConstraints { | |
| 100 | + $0.bottom.equalTo(snp.bottom).offset(-15) | |
| 101 | + $0.centerX.equalTo(snp.centerX) | |
| 102 | + } | |
| 103 | + | |
| 104 | + rightStatusImage.snp.makeConstraints { | |
| 105 | + $0.trailing.equalTo(snp.trailing).offset(-16) | |
| 106 | + $0.top.equalTo(snp.top).offset(19) | |
| 107 | + } | |
| 108 | + } | |
| 109 | +} | |
| 110 | + | ... | ... |
| 1 | +// | |
| 2 | +// HomeView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 07.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class HomeView: UIView { | |
| 11 | + var logoView: UIImageView = { | |
| 12 | + var obj = UIImageView() | |
| 13 | + obj.image = UIImage(named: .Image.USA) | |
| 14 | + return obj | |
| 15 | + }() | |
| 16 | + | |
| 17 | + var settingsButton: UIButton = { | |
| 18 | + var obj = UIButton() | |
| 19 | + obj.setImage(UIImage(named: .Image.setting), for: .normal) | |
| 20 | + obj.layer.borderWidth = 1 | |
| 21 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 22 | + obj.layer.cornerRadius = 13 | |
| 23 | + return obj | |
| 24 | + }() | |
| 25 | + | |
| 26 | + var homeImage: UIImageView = { | |
| 27 | + var obj = UIImageView() | |
| 28 | + obj.image = UIImage(named: .Image.home) | |
| 29 | + return obj | |
| 30 | + }() | |
| 31 | + | |
| 32 | + var welcomeLabel: UILabel = { | |
| 33 | + var obj = UILabel() | |
| 34 | + obj.font = .skModernist(type: .bold, ofSize: 35) | |
| 35 | + obj.text = .Text.welcome | |
| 36 | + return obj | |
| 37 | + }() | |
| 38 | + | |
| 39 | + var doorsLabel: UILabel = { | |
| 40 | + var obj = UILabel() | |
| 41 | + obj.font = .skModernist(type: .bold, ofSize: 20) | |
| 42 | + obj.text = .Text.myDoors | |
| 43 | + return obj | |
| 44 | + }() | |
| 45 | + | |
| 46 | + var tableView: UITableView = { | |
| 47 | + var obj = UITableView() | |
| 48 | + obj.separatorStyle = .none | |
| 49 | + obj.showsVerticalScrollIndicator = false | |
| 50 | + return obj | |
| 51 | + }() | |
| 52 | + | |
| 53 | + var gradientView: UIImageView = { | |
| 54 | + var obj = UIImageView() | |
| 55 | + obj.image = UIImage(named: .Image.gradient) | |
| 56 | + return obj | |
| 57 | + }() | |
| 58 | + | |
| 59 | + var passwordButton: UIButton = { | |
| 60 | + var obj = UIButton() | |
| 61 | + obj.setImage(UIImage(named: .Image.password), for: .normal) | |
| 62 | + return obj | |
| 63 | + }() | |
| 64 | + | |
| 65 | + override init(frame: CGRect) { | |
| 66 | + super.init(frame: frame) | |
| 67 | + backgroundColor = .white | |
| 68 | + setup() | |
| 69 | + } | |
| 70 | + | |
| 71 | + required init?(coder: NSCoder) { | |
| 72 | + fatalError("init(coder:) has not been implemented") | |
| 73 | + } | |
| 74 | + | |
| 75 | + func setup() { | |
| 76 | + addSubview(logoView) | |
| 77 | + addSubview(settingsButton) | |
| 78 | + addSubview(welcomeLabel) | |
| 79 | + addSubview(homeImage) | |
| 80 | + addSubview(doorsLabel) | |
| 81 | + addSubview(tableView) | |
| 82 | + addSubview(gradientView) | |
| 83 | + gradientView.addSubview(passwordButton) | |
| 84 | + | |
| 85 | + logoView.snp.makeConstraints { | |
| 86 | + $0.top.equalTo(77) | |
| 87 | + $0.leading.equalTo(24) | |
| 88 | + } | |
| 89 | + | |
| 90 | + settingsButton.snp.makeConstraints { | |
| 91 | + $0.top.equalTo(snp.top).offset(63) | |
| 92 | + $0.trailing.equalTo(snp.trailing).offset(-27) | |
| 93 | + $0.height.width.equalTo(45) | |
| 94 | + } | |
| 95 | + | |
| 96 | + welcomeLabel.snp.makeConstraints { | |
| 97 | + $0.top.equalTo(logoView.snp.bottom).offset(63) | |
| 98 | + $0.leading.equalTo(logoView.snp.leading) | |
| 99 | + } | |
| 100 | + | |
| 101 | + homeImage.snp.makeConstraints { | |
| 102 | + $0.top.equalTo(settingsButton.snp.bottom) | |
| 103 | + $0.trailing.equalTo(snp.trailing).offset(5) | |
| 104 | + } | |
| 105 | + | |
| 106 | + doorsLabel.snp.makeConstraints { | |
| 107 | + $0.top.equalTo(homeImage.snp.bottom).offset(31) | |
| 108 | + $0.leading.equalTo(logoView.snp.leading) | |
| 109 | + } | |
| 110 | + | |
| 111 | + tableView.snp.makeConstraints { | |
| 112 | + $0.top.equalTo(doorsLabel.snp.bottom).offset(28) | |
| 113 | + $0.leading.equalTo(snp.leading).offset(20) | |
| 114 | + $0.trailing.equalTo(snp.trailing).offset(-27) | |
| 115 | + $0.bottom.equalToSuperview() | |
| 116 | + } | |
| 117 | + | |
| 118 | + gradientView.snp.makeConstraints { | |
| 119 | + $0.leading.trailing.bottom.equalToSuperview() | |
| 120 | + $0.height.equalTo(75) | |
| 121 | + } | |
| 122 | + | |
| 123 | + passwordButton.snp.makeConstraints { | |
| 124 | + $0.trailing.equalTo(gradientView.snp.trailing).offset(-48) | |
| 125 | + $0.bottom.equalTo(gradientView.snp.bottom).offset(-18) | |
| 126 | + $0.height.width.equalTo(18.5) | |
| 127 | + } | |
| 128 | + } | |
| 129 | +} | ... | ... |
| 1 | +// | |
| 2 | +// HomeViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 07.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class HomeViewController: UIViewController { | |
| 11 | + var mainView = HomeView() | |
| 12 | + | |
| 13 | + override func loadView() { | |
| 14 | + view = mainView | |
| 15 | + } | |
| 16 | + | |
| 17 | + override func viewDidLoad() { | |
| 18 | + initViewController() | |
| 19 | + } | |
| 20 | + | |
| 21 | + private func initViewController() { | |
| 22 | + mainView.tableView.delegate = self | |
| 23 | + mainView.tableView.dataSource = self | |
| 24 | + mainView.tableView.register(HomeTableViewCell.self, forCellReuseIdentifier: HomeTableViewCell.id) | |
| 25 | + mainView.settingsButton.addTarget(self, action: #selector(didShowSettingsVC), for: .touchUpInside) | |
| 26 | + } | |
| 27 | +} | |
| 28 | + | |
| 29 | +extension HomeViewController { | |
| 30 | + @objc private func didShowSettingsVC() { | |
| 31 | + let vc = SettingsViewController() | |
| 32 | + navigationController?.pushViewController(vc, animated: true) | |
| 33 | + } | |
| 34 | +} | |
| 35 | + | |
| 36 | +extension HomeViewController: UITableViewDelegate, UITableViewDataSource { | |
| 37 | + | |
| 38 | + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
| 39 | + 5 | |
| 40 | + } | |
| 41 | + | |
| 42 | + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
| 43 | + guard let cell = tableView.dequeueReusableCell(withIdentifier: HomeTableViewCell.id, for: indexPath) as? HomeTableViewCell else { return UITableViewCell() } | |
| 44 | + return cell | |
| 45 | + } | |
| 46 | + | |
| 47 | + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { | |
| 48 | + 120 | |
| 49 | + } | |
| 50 | + | |
| 51 | + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | |
| 52 | + print("✅") | |
| 53 | + } | |
| 54 | + | |
| 55 | + | |
| 56 | +} | ... | ... |
| 1 | +// | |
| 2 | +// CodeVerificationView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 03.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class CodeVerificationView: UIView { | |
| 11 | + var containerView: UIView = { | |
| 12 | + var obj = UIView() | |
| 13 | + return obj | |
| 14 | + }() | |
| 15 | + | |
| 16 | + var backButton: UIButton = { | |
| 17 | + var obj = UIButton() | |
| 18 | + obj.setImage(UIImage(named: .Image.backPointer), for: .normal) | |
| 19 | + obj.backgroundColor = .white | |
| 20 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 21 | + obj.layer.cornerRadius = 13 | |
| 22 | + obj.layer.borderWidth = 1 | |
| 23 | + return obj | |
| 24 | + }() | |
| 25 | + | |
| 26 | + var logoImage: UIImageView = { | |
| 27 | + var obj = UIImageView() | |
| 28 | + obj.image = UIImage(named: .Image.USA) | |
| 29 | + return obj | |
| 30 | + }() | |
| 31 | + | |
| 32 | + var shieldImage: UIImageView = { | |
| 33 | + var obj = UIImageView() | |
| 34 | + obj.image = UIImage(named: .Image.lock) | |
| 35 | + return obj | |
| 36 | + }() | |
| 37 | + | |
| 38 | + var descriptionLabel: UILabel = { | |
| 39 | + var obj = UILabel() | |
| 40 | + obj.font = .skModernist(type: .bold, ofSize: 35) | |
| 41 | + obj.text = .Text.enterYourVerificationCode | |
| 42 | + obj.numberOfLines = 2 | |
| 43 | + return obj | |
| 44 | + }() | |
| 45 | + | |
| 46 | + let otpView: OTPView = { | |
| 47 | + let obj = OTPView() | |
| 48 | + return obj | |
| 49 | + }() | |
| 50 | + | |
| 51 | + var errorAlertLabel: UILabel = { | |
| 52 | + var obj = UILabel() | |
| 53 | + obj.text = .Text.pleaseEnterValidCode | |
| 54 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 55 | + obj.textColor = UIColor(red: 255/255, green: 0/255, blue: 46/255, alpha: 1) | |
| 56 | + obj.isHidden = true | |
| 57 | + return obj | |
| 58 | + }() | |
| 59 | + | |
| 60 | + var verifyButton: UIButton = { | |
| 61 | + var obj = UIButton() | |
| 62 | + obj.setImage(UIImage(named: .Image.RectangleWithShadow), for: .normal) | |
| 63 | + return obj | |
| 64 | + }() | |
| 65 | + | |
| 66 | + var verifyLabel: UILabel = { | |
| 67 | + var obj = UILabel() | |
| 68 | + obj.font = UIFont(name: SkModernistFontType.bold.rawValue, size: 16) | |
| 69 | + obj.textColor = .white | |
| 70 | + obj.text = .Text.verify | |
| 71 | + return obj | |
| 72 | + }() | |
| 73 | + | |
| 74 | + var tickImage: UIImageView = { | |
| 75 | + var obj = UIImageView() | |
| 76 | + obj.image = UIImage(named: .Image.tick) | |
| 77 | + return obj | |
| 78 | + }() | |
| 79 | + | |
| 80 | + let spinner: UIActivityIndicatorView = { | |
| 81 | + var obj = UIActivityIndicatorView(style: .large) | |
| 82 | + obj.hidesWhenStopped = true | |
| 83 | + return obj | |
| 84 | + }() | |
| 85 | + | |
| 86 | + let loadingView: UIView = { | |
| 87 | + var obj = UIView() | |
| 88 | + obj.alpha = 0.25 | |
| 89 | + obj.backgroundColor = .black | |
| 90 | + obj.clipsToBounds = true | |
| 91 | + obj.layer.cornerRadius = 13 | |
| 92 | + return obj | |
| 93 | + }() | |
| 94 | + | |
| 95 | + override init(frame: CGRect) { | |
| 96 | + super.init(frame: frame) | |
| 97 | + setup() | |
| 98 | + } | |
| 99 | + | |
| 100 | + required init?(coder: NSCoder) { | |
| 101 | + fatalError("init(coder:) has not been implemented") | |
| 102 | + } | |
| 103 | + | |
| 104 | + func setup() { | |
| 105 | + backgroundColor = .white | |
| 106 | + | |
| 107 | + addSubview(backButton) | |
| 108 | + addSubview(logoImage) | |
| 109 | + addSubview(shieldImage) | |
| 110 | + addSubview(containerView) | |
| 111 | + addSubview(spinner) | |
| 112 | + spinner.addSubview(loadingView) | |
| 113 | + | |
| 114 | + containerView.addSubview(descriptionLabel) | |
| 115 | + containerView.addSubview(otpView) | |
| 116 | + containerView.addSubview(errorAlertLabel) | |
| 117 | + | |
| 118 | + containerView.addSubview(verifyButton) | |
| 119 | + verifyButton.addSubview(verifyLabel) | |
| 120 | + verifyButton.addSubview(tickImage) | |
| 121 | + | |
| 122 | + backButton.snp.makeConstraints { | |
| 123 | + $0.top.equalTo(snp.top).offset(66) | |
| 124 | + $0.leading.equalTo(snp.leading).offset(22) | |
| 125 | + $0.height.width.equalTo(45) | |
| 126 | + } | |
| 127 | + | |
| 128 | + logoImage.snp.makeConstraints { | |
| 129 | + $0.leading.equalTo(backButton.snp.trailing).offset(20) | |
| 130 | + $0.centerY.equalTo(backButton) | |
| 131 | + } | |
| 132 | + | |
| 133 | + shieldImage.snp.makeConstraints { | |
| 134 | + $0.top.equalTo(backButton.snp.bottom).offset(25) | |
| 135 | + $0.right.equalTo(snp.right).offset(-101) | |
| 136 | + } | |
| 137 | + | |
| 138 | + containerView.snp.makeConstraints { | |
| 139 | + $0.top.equalTo(backButton.snp.bottom).offset(227) | |
| 140 | + $0.leading.trailing.equalToSuperview() | |
| 141 | + $0.height.equalTo(300) | |
| 142 | + } | |
| 143 | + | |
| 144 | + descriptionLabel.snp.makeConstraints { | |
| 145 | + $0.leading.equalTo(containerView.snp.leading).offset(20) | |
| 146 | + $0.top.equalTo(containerView.snp.top) | |
| 147 | + } | |
| 148 | + | |
| 149 | + otpView.snp.makeConstraints { make in | |
| 150 | + make.leading.trailing.equalToSuperview().inset(25) | |
| 151 | + make.top.equalTo(descriptionLabel.snp.bottom).offset(28) | |
| 152 | + make.height.equalTo(55) | |
| 153 | + } | |
| 154 | + | |
| 155 | + errorAlertLabel.snp.makeConstraints { | |
| 156 | + $0.top.equalTo(otpView.snp.bottom).offset(8) | |
| 157 | + $0.leading.equalTo(otpView.snp.leading) | |
| 158 | + } | |
| 159 | + | |
| 160 | + verifyButton.snp.makeConstraints { | |
| 161 | + $0.top.equalTo(otpView.snp.bottom).offset(67) | |
| 162 | + $0.left.right.equalToSuperview() | |
| 163 | + } | |
| 164 | + | |
| 165 | + verifyLabel.snp.makeConstraints { | |
| 166 | + $0.left.equalToSuperview().offset(49) | |
| 167 | + $0.top.equalToSuperview().offset(22) | |
| 168 | + } | |
| 169 | + | |
| 170 | + tickImage.snp.makeConstraints { | |
| 171 | + $0.right.equalToSuperview().offset(-47) | |
| 172 | + $0.centerY.equalTo(verifyLabel) | |
| 173 | + } | |
| 174 | + spinner.snp.makeConstraints { make in | |
| 175 | + make.centerX.centerY.equalToSuperview() | |
| 176 | + } | |
| 177 | + loadingView.snp.makeConstraints { make in | |
| 178 | + make.edges.equalTo(snp.edges) | |
| 179 | + } | |
| 180 | + } | |
| 181 | +} | |
| 182 | + | ... | ... |
| 1 | +// | |
| 2 | +// OTPView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 02.07.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | +protocol OTPViewDelegate: AnyObject { | |
| 11 | + func didFullCodeCompletion(_ otpView: OTPView) | |
| 12 | +} | |
| 13 | + | |
| 14 | +class OTPView: UIView { | |
| 15 | + weak var delegate: OTPViewDelegate? | |
| 16 | + | |
| 17 | + var digitViews: [UILabel] = [] | |
| 18 | + | |
| 19 | + var code: String? { | |
| 20 | + return textField.text | |
| 21 | + } | |
| 22 | + | |
| 23 | + var isError: Bool = false { | |
| 24 | + didSet { | |
| 25 | + handleErrorUI(isError) | |
| 26 | + } | |
| 27 | + } | |
| 28 | + | |
| 29 | + let textField: UITextField = { | |
| 30 | + let obj = UITextField() | |
| 31 | + obj.isHidden = true | |
| 32 | + obj.keyboardType = .numberPad | |
| 33 | + return obj | |
| 34 | + }() | |
| 35 | + | |
| 36 | + private lazy var stackView: UIStackView = { | |
| 37 | + let obj = UIStackView(arrangedSubviews: digitViews) | |
| 38 | + obj.axis = .horizontal | |
| 39 | + obj.spacing = 11 | |
| 40 | + obj.distribution = .fillEqually | |
| 41 | + obj.semanticContentAttribute = .forceLeftToRight | |
| 42 | + return obj | |
| 43 | + }() | |
| 44 | + | |
| 45 | + override init(frame: CGRect) { | |
| 46 | + super.init(frame: frame) | |
| 47 | + initDigits() | |
| 48 | + setup() | |
| 49 | + } | |
| 50 | + | |
| 51 | + required init?(coder: NSCoder) { | |
| 52 | + super.init(coder: coder) | |
| 53 | + setup() | |
| 54 | + } | |
| 55 | + | |
| 56 | + private func initDigits() { | |
| 57 | + for i in 0...3 { | |
| 58 | + digitViews.append(initLabel()) | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | + private func initLabel() -> UILabel { | |
| 63 | + let obj = UILabel() | |
| 64 | + obj.font = .skModernist(type: .bold, ofSize: 16) | |
| 65 | + obj.textColor = .black | |
| 66 | + obj.textAlignment = .center | |
| 67 | + obj.backgroundColor = .TextFieldColor.general | |
| 68 | + obj.layer.cornerRadius = 15 | |
| 69 | + obj.clipsToBounds = true | |
| 70 | + return obj | |
| 71 | + } | |
| 72 | + | |
| 73 | + private func setup() { | |
| 74 | + addSubview(textField) | |
| 75 | + addSubview(stackView) | |
| 76 | + | |
| 77 | + stackView.snp.makeConstraints { make in | |
| 78 | + make.edges.equalToSuperview() | |
| 79 | + } | |
| 80 | + | |
| 81 | + textField.addTarget(self, action: #selector(didTextFieldChanged(_:)), for: .editingChanged) | |
| 82 | + } | |
| 83 | + | |
| 84 | + override func addSubview(_ view: UIView) { | |
| 85 | + super.addSubview(view) | |
| 86 | + textField.becomeFirstResponder() | |
| 87 | + } | |
| 88 | + | |
| 89 | + @objc func didTextFieldChanged(_ sender: UITextField) { | |
| 90 | + guard var code = sender.text else { | |
| 91 | + return | |
| 92 | + } | |
| 93 | + if code.count == 0 { | |
| 94 | + delegate?.didFullCodeCompletion(self) | |
| 95 | + } else if code.count > 4 { | |
| 96 | + code.removeLast() | |
| 97 | + } else { | |
| 98 | + if code.count == 4 { | |
| 99 | + delegate?.didFullCodeCompletion(self) | |
| 100 | + textField.resignFirstResponder() | |
| 101 | + } | |
| 102 | + } | |
| 103 | + digitViews.enumerated().forEach { index, item in | |
| 104 | + item.text = (code.count-1 >= index ? String(code[code.index(code.startIndex, offsetBy: index)]) : "") | |
| 105 | + } | |
| 106 | + } | |
| 107 | + | |
| 108 | + private func handleErrorUI(_ isError: Bool) { | |
| 109 | + colorСhanger() | |
| 110 | + } | |
| 111 | + | |
| 112 | + private func colorСhanger() { | |
| 113 | + digitViews.self.forEach { label in | |
| 114 | + label.backgroundColor = .TextFieldColor.error | |
| 115 | + label.textColor = .TextColor.redError | |
| 116 | + } | |
| 117 | + } | |
| 118 | +} | ... | ... |
TheButler/Modules/OneTimePasswordScreen/ViewController/CodeVerificationViewController.swift
0 → 100644
| 1 | +// | |
| 2 | +// CodeVerificationViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 03.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class CodeVerificationViewController: UIViewController { | |
| 11 | + var isKeyboardAppear = false | |
| 12 | + var verifyMessage: String? | |
| 13 | + private let mainView = CodeVerificationView() | |
| 14 | + | |
| 15 | + override func loadView() { | |
| 16 | + view = mainView | |
| 17 | + } | |
| 18 | + | |
| 19 | + override func viewDidLoad() { | |
| 20 | + initViewController() | |
| 21 | + } | |
| 22 | + | |
| 23 | + private func initViewController() { | |
| 24 | + mainView.otpView.delegate = self | |
| 25 | + mainView.backButton.addTarget(self, action: #selector(didTapBackButton), for: .touchUpInside) | |
| 26 | + mainView.verifyButton.addTarget(self, action: #selector(didTapVerifyButton), for: .touchUpInside) | |
| 27 | + | |
| 28 | + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) | |
| 29 | + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) | |
| 30 | + } | |
| 31 | + | |
| 32 | + deinit { | |
| 33 | + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) | |
| 34 | + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) | |
| 35 | + } | |
| 36 | + | |
| 37 | + func verificationRequestProcessing() { | |
| 38 | + self.mainView.spinner.startAnimating() | |
| 39 | + guard let verifyModel = getVerifyModel() else { return } | |
| 40 | + AuthService.shared.verifyRequest(model: verifyModel) { response in | |
| 41 | + print("3️⃣✅\(response.data)") | |
| 42 | + print("\(response.message)✅") | |
| 43 | + self.loginRequestProcessing() | |
| 44 | + } fail: { error in | |
| 45 | + self.mainView.spinner.stopAnimating() | |
| 46 | + print("3️⃣\(error)") | |
| 47 | + self.errorProcessing() | |
| 48 | + } | |
| 49 | + } | |
| 50 | + | |
| 51 | + func loginRequestProcessing() { | |
| 52 | + guard let loginModel = getLoginModel() else { return } | |
| 53 | + AuthService.shared.loginRequest(model: loginModel) { response in | |
| 54 | + print("4️⃣\(String(describing: response.message))4️⃣") | |
| 55 | + self.verifyMessage = response.message | |
| 56 | + self.loginDataProcessing() | |
| 57 | + } fail: { error in | |
| 58 | + self.mainView.spinner.stopAnimating() | |
| 59 | + self.errorProcessing() | |
| 60 | + print("4️⃣⛔️\(error)⛔️") | |
| 61 | + } | |
| 62 | + } | |
| 63 | + | |
| 64 | + func getVerifyModel() -> VerifyRequestModel? { | |
| 65 | + let email = "" | |
| 66 | + guard let code = mainView.otpView.code else { return nil } | |
| 67 | + return VerifyRequestModel(emailOrNumber: email, code: code, secondAuthToken: "asdas") | |
| 68 | + } | |
| 69 | + | |
| 70 | + func getLoginModel() -> LoginRequestModel? { | |
| 71 | + guard let deviceUUID = UIDevice.current.identifierForVendor?.uuidString else { | |
| 72 | + return nil | |
| 73 | + } | |
| 74 | + return LoginRequestModel(deviceUUID: deviceUUID) | |
| 75 | + } | |
| 76 | +} | |
| 77 | +//MARK: - Targets | |
| 78 | +extension CodeVerificationViewController { | |
| 79 | + @objc private func didTapVerifyButton() { | |
| 80 | + verificationRequestProcessing() | |
| 81 | + } | |
| 82 | + | |
| 83 | + private func showHomeVC() { | |
| 84 | + let viewController = HomeViewController() | |
| 85 | + navigationController?.pushViewController(viewController, animated: true) | |
| 86 | + } | |
| 87 | + | |
| 88 | + private func loginDataProcessing() { | |
| 89 | + self.mainView.spinner.stopAnimating() | |
| 90 | + self.showHomeVC() | |
| 91 | + } | |
| 92 | + | |
| 93 | + private func errorProcessing() { | |
| 94 | + guard let code = mainView.otpView.code else { return } | |
| 95 | + | |
| 96 | + if code.count < 4 { | |
| 97 | + let alert = UIAlertController(title: "❌", message: "Enter all fields", preferredStyle: .alert) | |
| 98 | + alert.addAction(UIAlertAction(title: "Close", style: .cancel, handler: nil)) | |
| 99 | + present(alert, animated: true, completion: nil) | |
| 100 | + } else if verifyMessage != "OK" { | |
| 101 | + let alert = UIAlertController(title: "Wrong password", message: "", preferredStyle: .alert) | |
| 102 | + alert.addAction(UIAlertAction(title: "Try again", style: .cancel, handler: { action in | |
| 103 | + self.mainView.otpView.isError.toggle() | |
| 104 | + self.mainView.errorAlertLabel.isHidden = false | |
| 105 | + self.mainView.otpView.textField.becomeFirstResponder() | |
| 106 | + })) | |
| 107 | + present(alert, animated: true, completion: nil) | |
| 108 | + } else { | |
| 109 | + let alert = UIAlertController(title: "Network technical issues", message: "", preferredStyle: .alert) | |
| 110 | + alert.addAction(UIAlertAction(title: "Reload", style: .cancel, handler: { action in | |
| 111 | + self.didTapBackButton() | |
| 112 | + })) | |
| 113 | + present(alert, animated: true, completion: nil) | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + @objc private func didTapBackButton() { | |
| 118 | + navigationController?.popViewController(animated: true) | |
| 119 | + } | |
| 120 | + | |
| 121 | + @objc private func keyboardWillShow(notification: NSNotification) { | |
| 122 | + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double | |
| 123 | + | |
| 124 | + if !isKeyboardAppear { | |
| 125 | + UIView.animate(withDuration: duration ?? 0) { | |
| 126 | + self.mainView.containerView.snp.updateConstraints { make in | |
| 127 | + make.top.equalTo(self.mainView.backButton.snp.bottom).offset(97) | |
| 128 | + } | |
| 129 | + self.mainView.shieldImage.snp.updateConstraints { | |
| 130 | + $0.right.equalTo(self.mainView.snp.right).offset(-6) | |
| 131 | + } | |
| 132 | + self.mainView.layoutIfNeeded() | |
| 133 | + } | |
| 134 | + isKeyboardAppear = true | |
| 135 | + } | |
| 136 | + } | |
| 137 | + | |
| 138 | + @objc private func keyboardWillHide(notification: NSNotification) { | |
| 139 | + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double | |
| 140 | + | |
| 141 | + if isKeyboardAppear { | |
| 142 | + UIView.animate(withDuration: duration ?? 0) { | |
| 143 | + self.mainView.containerView.snp.updateConstraints { make in | |
| 144 | + make.top.equalTo(self.mainView.backButton.snp.bottom).offset(227) | |
| 145 | + } | |
| 146 | + self.mainView.shieldImage.snp.updateConstraints { | |
| 147 | + $0.right.equalTo(self.mainView.snp.right).offset(-101) | |
| 148 | + } | |
| 149 | + self.mainView.layoutIfNeeded() | |
| 150 | + } | |
| 151 | + isKeyboardAppear = false | |
| 152 | + } | |
| 153 | + } | |
| 154 | +} | |
| 155 | + | |
| 156 | +//MARK: - OTPView delegate | |
| 157 | +extension CodeVerificationViewController: OTPViewDelegate { | |
| 158 | + | |
| 159 | + func didFullCodeCompletion(_ otpView: OTPView) { | |
| 160 | + print("code -> \(String(describing: otpView.code))") | |
| 161 | + } | |
| 162 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ResidentTableViewCell.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 21.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +protocol ResidentTableViewCellDelegate: AnyObject { | |
| 11 | + func didRemoveButtonTapped(cell: ResidentTableViewCell) | |
| 12 | + func didManagerButtonTapped(cell: ResidentTableViewCell) | |
| 13 | + func didHiddenButtonTapped(cell: ResidentTableViewCell) | |
| 14 | + func didHeardButtonTapped(cell: ResidentTableViewCell) | |
| 15 | +} | |
| 16 | + | |
| 17 | +class ResidentTableViewCell: UITableViewCell { | |
| 18 | + var model: ResidentModel? { | |
| 19 | + didSet { | |
| 20 | + if let model = model { | |
| 21 | + nameLabel.text = model.name | |
| 22 | + phoneNumberLabel.text = model.mobileNumber | |
| 23 | + managerButton.isSelected = model.manager | |
| 24 | + hiddenButton.isSelected = model.hidden | |
| 25 | + heartButton.isSelected = model.heart | |
| 26 | + } | |
| 27 | + } | |
| 28 | + } | |
| 29 | + | |
| 30 | + weak var delegate: ResidentTableViewCellDelegate? | |
| 31 | + | |
| 32 | + static let id = String(describing: ResidentTableViewCell.self) | |
| 33 | + | |
| 34 | + var containerView: UIView = { | |
| 35 | + var obj = UIView() | |
| 36 | + obj.layer.cornerRadius = 15 | |
| 37 | + obj.layer.borderWidth = 1 | |
| 38 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 39 | + return obj | |
| 40 | + }() | |
| 41 | + | |
| 42 | + var serialNumberView: UIImageView = { | |
| 43 | + let obj = UIImageView() | |
| 44 | + obj.clipsToBounds = true | |
| 45 | + obj.layer.cornerRadius = 21.5 | |
| 46 | + return obj | |
| 47 | + }() | |
| 48 | + | |
| 49 | + var serialNumberLabel: UILabel = { | |
| 50 | + let obj = UILabel() | |
| 51 | + obj.font = .skModernist(type: .bold, ofSize: 14) | |
| 52 | + obj.textColor = .white | |
| 53 | + return obj | |
| 54 | + }() | |
| 55 | + | |
| 56 | + var nameLabel: UILabel = { | |
| 57 | + var obj = UILabel() | |
| 58 | + obj.textColor = .TextColor.darkBlue | |
| 59 | + obj.font = .skModernist(type: .bold, ofSize: 16) | |
| 60 | + obj.text = "John Doe" | |
| 61 | + return obj | |
| 62 | + }() | |
| 63 | + | |
| 64 | + var phoneNumberLabel: UILabel = { | |
| 65 | + var obj = UILabel() | |
| 66 | + obj.textColor = .TextColor.lightGrey | |
| 67 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 68 | + obj.text = "+38095" | |
| 69 | + return obj | |
| 70 | + }() | |
| 71 | + | |
| 72 | + var managerButton: SquereCheckbox = { | |
| 73 | + var obj = SquereCheckbox() | |
| 74 | + obj.checkboxTitle = .Text.manager | |
| 75 | + obj.setTitleColor(.TextColor.lightGrey, for: .normal) | |
| 76 | + obj.setTitleColor(.TextColor.darkBlue, for: .selected) | |
| 77 | + obj.isSelected = false | |
| 78 | + return obj | |
| 79 | + }() | |
| 80 | + | |
| 81 | + var hiddenButton: SquereCheckbox = { | |
| 82 | + var obj = SquereCheckbox() | |
| 83 | + obj.checkboxTitle = .Text.hidden | |
| 84 | + obj.setTitleColor(.TextColor.lightGrey, for: .normal) | |
| 85 | + obj.setTitleColor(.TextColor.darkBlue, for: .selected) | |
| 86 | + obj.isSelected = false | |
| 87 | + return obj | |
| 88 | + }() | |
| 89 | + | |
| 90 | + var heartButton: UIButton = { | |
| 91 | + var obj = UIButton() | |
| 92 | + obj.setImage(UIImage(named: .Image.heart), for: .normal) | |
| 93 | + obj.setImage(UIImage(named: .Image.heartRed), for: .selected) | |
| 94 | + return obj | |
| 95 | + }() | |
| 96 | + | |
| 97 | + var removeCellButton: UIButton = { | |
| 98 | + var obj = UIButton() | |
| 99 | + obj.setImage(UIImage(named: .Image.bin), for: .normal) | |
| 100 | + return obj | |
| 101 | + }() | |
| 102 | + | |
| 103 | + var gradientBG: CAGradientLayer = { | |
| 104 | + let obj = CAGradientLayer() | |
| 105 | + var leftColor = UIColor.GradientBlue.left | |
| 106 | + var rightColor = UIColor.GradientBlue.right | |
| 107 | + obj.colors = [leftColor, rightColor] | |
| 108 | + obj.startPoint = CGPoint(x: 0, y: 0.5) | |
| 109 | + obj.endPoint = CGPoint(x: 1, y: 0.5) | |
| 110 | + return obj | |
| 111 | + }() | |
| 112 | + | |
| 113 | + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { | |
| 114 | + super.init(style: style, reuseIdentifier: reuseIdentifier) | |
| 115 | + setup() | |
| 116 | + } | |
| 117 | + | |
| 118 | + required init?(coder: NSCoder) { | |
| 119 | + fatalError("init(coder:) has not been implemented") | |
| 120 | + } | |
| 121 | + | |
| 122 | + func setup() { | |
| 123 | + selectionStyle = .none | |
| 124 | + serialNumberView.layer.insertSublayer(gradientBG, at: 0) | |
| 125 | + | |
| 126 | + contentView.addSubview(containerView) | |
| 127 | + containerView.addSubview(serialNumberView) | |
| 128 | + serialNumberView.addSubview(serialNumberLabel) | |
| 129 | + | |
| 130 | + containerView.addSubview(nameLabel) | |
| 131 | + containerView.addSubview(phoneNumberLabel) | |
| 132 | + containerView.addSubview(managerButton) | |
| 133 | + containerView.addSubview(hiddenButton) | |
| 134 | + containerView.addSubview(heartButton) | |
| 135 | + containerView.addSubview(removeCellButton) | |
| 136 | + | |
| 137 | + containerView.snp.makeConstraints { | |
| 138 | + $0.leading.trailing.equalToSuperview().inset(25) | |
| 139 | + $0.bottom.top.equalToSuperview().inset(8) | |
| 140 | + } | |
| 141 | + | |
| 142 | + serialNumberView.snp.makeConstraints { | |
| 143 | + $0.height.width.equalTo(41) | |
| 144 | + $0.leading.equalToSuperview().offset(23) | |
| 145 | + $0.top.equalToSuperview().offset(19) | |
| 146 | + } | |
| 147 | + | |
| 148 | + serialNumberLabel.snp.makeConstraints { | |
| 149 | + $0.centerX.centerY.equalToSuperview() | |
| 150 | + } | |
| 151 | + | |
| 152 | + nameLabel.snp.makeConstraints { | |
| 153 | + $0.leading.equalTo(serialNumberView.snp.trailing).offset(18) | |
| 154 | + $0.top.equalToSuperview().offset(22) | |
| 155 | + } | |
| 156 | + | |
| 157 | + removeCellButton.snp.makeConstraints { | |
| 158 | + $0.centerY.equalTo(nameLabel.snp.centerY) | |
| 159 | + $0.trailing.equalToSuperview().offset(-22.5) | |
| 160 | + } | |
| 161 | + | |
| 162 | + phoneNumberLabel.snp.makeConstraints { | |
| 163 | + $0.leading.equalTo(nameLabel.snp.leading) | |
| 164 | + $0.top.equalTo(nameLabel.snp.bottom).offset(1) | |
| 165 | + } | |
| 166 | + | |
| 167 | + managerButton.snp.makeConstraints { | |
| 168 | + $0.top.equalTo(phoneNumberLabel.snp.bottom).offset(30) | |
| 169 | + $0.leading.equalToSuperview().offset(24) | |
| 170 | + $0.height.equalTo(20) | |
| 171 | + } | |
| 172 | + | |
| 173 | + hiddenButton.snp.makeConstraints { | |
| 174 | + $0.leading.equalTo(managerButton.snp.trailing).offset(23) | |
| 175 | + $0.centerY.equalTo(managerButton) | |
| 176 | + $0.height.equalTo(20) | |
| 177 | + } | |
| 178 | + | |
| 179 | + heartButton.snp.makeConstraints { | |
| 180 | + $0.centerY.equalTo(hiddenButton) | |
| 181 | + $0.bottom.equalToSuperview().offset(-18) | |
| 182 | + $0.trailing.equalToSuperview().offset(-22) | |
| 183 | + } | |
| 184 | + | |
| 185 | + removeCellButton.addTarget(self, action: #selector(didRemoveButtonTapped(_:)), for: .touchUpInside) | |
| 186 | + managerButton.addTarget(self, action: #selector(didManagerButtonTapped(_:)), for: .touchUpInside) | |
| 187 | + hiddenButton.addTarget(self, action: #selector(didHiddenButtonTapped(_:)), for: .touchUpInside) | |
| 188 | + heartButton.addTarget(self, action: #selector(didHeartButtonTapped(_:)), for: .touchUpInside) | |
| 189 | + } | |
| 190 | + | |
| 191 | + override func layoutSubviews() { | |
| 192 | + super.layoutSubviews() | |
| 193 | + gradientBG.frame = serialNumberView.bounds | |
| 194 | + } | |
| 195 | + | |
| 196 | +} | |
| 197 | + | |
| 198 | +//MARK: targets | |
| 199 | +extension ResidentTableViewCell { | |
| 200 | + @objc private func didRemoveButtonTapped(_ sender: UIButton) { | |
| 201 | + delegate?.didRemoveButtonTapped(cell: self) | |
| 202 | + } | |
| 203 | + | |
| 204 | + @objc private func didManagerButtonTapped(_ sender: UIButton) { | |
| 205 | + delegate?.didManagerButtonTapped(cell: self) | |
| 206 | + } | |
| 207 | + | |
| 208 | + @objc private func didHiddenButtonTapped(_ sender: UIButton) { | |
| 209 | + delegate?.didHiddenButtonTapped(cell: self) | |
| 210 | + } | |
| 211 | + | |
| 212 | + @objc private func didHeartButtonTapped(_ sender: UIButton) { | |
| 213 | + delegate?.didHeardButtonTapped(cell: self) | |
| 214 | + } | |
| 215 | + | |
| 216 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ResidentsView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 14.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class ResidentsView: UIView { | |
| 11 | + var backButton: UIButton = { | |
| 12 | + var obj = UIButton() | |
| 13 | + obj.setImage(UIImage(named: .Image.backPointer), for: .normal) | |
| 14 | + obj.backgroundColor = .white | |
| 15 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 16 | + obj.layer.cornerRadius = 13 | |
| 17 | + obj.layer.borderWidth = 1 | |
| 18 | + return obj | |
| 19 | + }() | |
| 20 | + | |
| 21 | + var logoImage: UIImageView = { | |
| 22 | + var obj = UIImageView() | |
| 23 | + obj.image = UIImage(named: .Image.USA) | |
| 24 | + return obj | |
| 25 | + }() | |
| 26 | + | |
| 27 | + let apartNameLabel: UILabel = { | |
| 28 | + var obj = UILabel() | |
| 29 | + obj.font = .skModernist(type: .bold, ofSize: 35) | |
| 30 | + obj.text = .Text.myApartName | |
| 31 | + return obj | |
| 32 | + }() | |
| 33 | + | |
| 34 | + var dividingLineView: UIView = { | |
| 35 | + var view = UIView() | |
| 36 | + view.backgroundColor = .Background.lightGrey | |
| 37 | + return view | |
| 38 | + }() | |
| 39 | + | |
| 40 | + var residentsLabel: UILabel = { | |
| 41 | + var obj = UILabel() | |
| 42 | + obj.font = .skModernist(type: .bold, ofSize: 20) | |
| 43 | + obj.text = .Text.residents | |
| 44 | + return obj | |
| 45 | + }() | |
| 46 | + | |
| 47 | + var addResidentsButton: UIButton = { | |
| 48 | + var obj = UIButton() | |
| 49 | + obj.layer.borderWidth = 1 | |
| 50 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 51 | + obj.layer.cornerRadius = 13 | |
| 52 | + obj.setImage(UIImage(named: .Image.edit), for: .normal) | |
| 53 | + return obj | |
| 54 | + }() | |
| 55 | + | |
| 56 | + let tableView: UITableView = { | |
| 57 | + let obj = UITableView() | |
| 58 | + obj.showsVerticalScrollIndicator = false | |
| 59 | + obj.separatorStyle = .none | |
| 60 | + obj.rowHeight = UITableView.automaticDimension | |
| 61 | + return obj | |
| 62 | + }() | |
| 63 | + | |
| 64 | + let addResidentView: AddResidentsView = { | |
| 65 | + var obj = AddResidentsView() | |
| 66 | + obj.isHidden = true | |
| 67 | + return obj | |
| 68 | + }() | |
| 69 | + | |
| 70 | + override init(frame: CGRect) { | |
| 71 | + super.init(frame: frame) | |
| 72 | + backgroundColor = .white | |
| 73 | + setup() | |
| 74 | + } | |
| 75 | + | |
| 76 | + required init?(coder: NSCoder) { | |
| 77 | + fatalError("init(coder:) has not been implemented") | |
| 78 | + } | |
| 79 | + | |
| 80 | + func setup() { | |
| 81 | + | |
| 82 | + addSubview(backButton) | |
| 83 | + addSubview(logoImage) | |
| 84 | + addSubview(apartNameLabel) | |
| 85 | + addSubview(dividingLineView) | |
| 86 | + addSubview(residentsLabel) | |
| 87 | + addSubview(addResidentsButton) | |
| 88 | + addSubview(tableView) | |
| 89 | + addSubview(addResidentView) | |
| 90 | + | |
| 91 | + backButton.snp.makeConstraints { | |
| 92 | + $0.top.equalTo(snp.top).offset(66) | |
| 93 | + $0.leading.equalTo(snp.leading).offset(25) | |
| 94 | + $0.height.width.equalTo(45) | |
| 95 | + } | |
| 96 | + | |
| 97 | + logoImage.snp.makeConstraints { | |
| 98 | + $0.leading.equalTo(backButton.snp.trailing).offset(20) | |
| 99 | + $0.top.equalTo(snp.top).offset(79) | |
| 100 | + } | |
| 101 | + | |
| 102 | + apartNameLabel.snp.makeConstraints { | |
| 103 | + $0.leading.equalTo(backButton.snp.leading) | |
| 104 | + $0.top.equalTo(backButton.snp.bottom).offset(46) | |
| 105 | + } | |
| 106 | + | |
| 107 | + dividingLineView.snp.makeConstraints { | |
| 108 | + $0.leading.trailing.equalToSuperview() | |
| 109 | + $0.height.equalTo(1) | |
| 110 | + $0.top.equalTo(apartNameLabel.snp.bottom).offset(42) | |
| 111 | + } | |
| 112 | + | |
| 113 | + residentsLabel.snp.makeConstraints { | |
| 114 | + $0.leading.equalToSuperview().offset(24) | |
| 115 | + $0.top.equalTo(dividingLineView.snp.bottom).offset(43) | |
| 116 | + } | |
| 117 | + | |
| 118 | + addResidentsButton.snp.makeConstraints { | |
| 119 | + $0.height.width.equalTo(45) | |
| 120 | + $0.top.equalTo(dividingLineView.snp.bottom).offset(32) | |
| 121 | + $0.trailing.equalToSuperview().offset(-29) | |
| 122 | + } | |
| 123 | + | |
| 124 | + tableView.snp.makeConstraints { | |
| 125 | + $0.top.equalTo(residentsLabel.snp.bottom).offset(30) | |
| 126 | + $0.leading.trailing.equalToSuperview() | |
| 127 | + $0.bottom.equalToSuperview() | |
| 128 | + } | |
| 129 | + | |
| 130 | + addResidentView.snp.makeConstraints { | |
| 131 | + $0.top.trailing.leading.bottom.equalToSuperview() | |
| 132 | + } | |
| 133 | + } | |
| 134 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ResidentsViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 14.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class ResidentsViewController: UIViewController { | |
| 11 | + var mainView = ResidentsView() | |
| 12 | + var myData: [ResidentModel] = [] | |
| 13 | + | |
| 14 | + override func loadView() { | |
| 15 | + view = mainView | |
| 16 | + } | |
| 17 | + | |
| 18 | + override func viewDidLoad() { | |
| 19 | + initViewController() | |
| 20 | + } | |
| 21 | + | |
| 22 | + func initViewController() { | |
| 23 | + mainView.tableView.delegate = self | |
| 24 | + mainView.tableView.dataSource = self | |
| 25 | + mainView.tableView.register(ResidentTableViewCell.self, forCellReuseIdentifier: ResidentTableViewCell.id) | |
| 26 | + | |
| 27 | + mainView.backButton.addTarget(self, action: #selector(didShowChooseApartVC), for: .touchUpInside) | |
| 28 | + mainView.addResidentsButton.addTarget(self, action: #selector(willShowAddResidentVC), for: .touchUpInside) | |
| 29 | + } | |
| 30 | + | |
| 31 | + @objc private func didShowChooseApartVC() { | |
| 32 | + navigationController?.popViewController(animated: true) | |
| 33 | + } | |
| 34 | + | |
| 35 | + @objc private func willShowAddResidentVC() { | |
| 36 | + let addResidentsVC = AddResidentsViewController() | |
| 37 | + addResidentsVC.modalPresentationStyle = .overCurrentContext | |
| 38 | + addResidentsVC.modalTransitionStyle = .crossDissolve | |
| 39 | + addResidentsVC.delegate = self | |
| 40 | + present(addResidentsVC, animated: true) | |
| 41 | + } | |
| 42 | +} | |
| 43 | + | |
| 44 | +//MARK: - TableView delegate & data source | |
| 45 | +extension ResidentsViewController: UITableViewDelegate, UITableViewDataSource { | |
| 46 | + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
| 47 | + myData.count | |
| 48 | + } | |
| 49 | + | |
| 50 | + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
| 51 | + guard let cell = tableView.dequeueReusableCell(withIdentifier: ResidentTableViewCell.id, for: indexPath) as? ResidentTableViewCell else { return UITableViewCell() } | |
| 52 | + cell.serialNumberLabel.text = "\(indexPath.row + 1)" | |
| 53 | + let data = myData[indexPath.row] | |
| 54 | + cell.model = data | |
| 55 | + cell.delegate = self | |
| 56 | + return cell | |
| 57 | + } | |
| 58 | +} | |
| 59 | +//MARK: - ResidentSavable delegate | |
| 60 | +extension ResidentsViewController: ResidentSavable { | |
| 61 | + func save(_ data: ResidentModel) { | |
| 62 | + self.myData.append(data) | |
| 63 | + mainView.tableView.reloadData() | |
| 64 | + } | |
| 65 | +} | |
| 66 | + | |
| 67 | +//MARK: residentcell delegate | |
| 68 | +extension ResidentsViewController: ResidentTableViewCellDelegate { | |
| 69 | + func didButtonsTapped(cell: ResidentTableViewCell) { | |
| 70 | + if !cell.managerButton.isSelected { | |
| 71 | + cell.managerButton.isSelected = true | |
| 72 | + } else { | |
| 73 | + cell.managerButton.isSelected = false | |
| 74 | + } | |
| 75 | + } | |
| 76 | + | |
| 77 | + func didRemoveButtonTapped(cell: ResidentTableViewCell) { | |
| 78 | + guard let model = cell.model else { | |
| 79 | + return | |
| 80 | + } | |
| 81 | + myData.removeAll(where: {$0.name == model.name}) | |
| 82 | + mainView.tableView.reloadData() | |
| 83 | + } | |
| 84 | + | |
| 85 | + func didManagerButtonTapped(cell: ResidentTableViewCell) { | |
| 86 | + if !cell.managerButton.isSelected { | |
| 87 | + cell.managerButton.isSelected = true | |
| 88 | + } else { | |
| 89 | + cell.managerButton.isSelected = false | |
| 90 | + } | |
| 91 | + } | |
| 92 | + | |
| 93 | + func didHiddenButtonTapped(cell: ResidentTableViewCell) { | |
| 94 | + if !cell.hiddenButton.isSelected { | |
| 95 | + cell.hiddenButton.isSelected = true | |
| 96 | + } else { | |
| 97 | + cell.hiddenButton.isSelected = false | |
| 98 | + } | |
| 99 | + } | |
| 100 | + | |
| 101 | + func didHeardButtonTapped(cell: ResidentTableViewCell) { | |
| 102 | + if !cell.heartButton.isSelected { | |
| 103 | + cell.heartButton.isSelected = true | |
| 104 | + } else { | |
| 105 | + cell.heartButton.isSelected = false | |
| 106 | + } | |
| 107 | + } | |
| 108 | +} | ... | ... |
| 1 | + | |
| 2 | +// | |
| 3 | +// SettingsModel.swift | |
| 4 | +// InterQR-Internship | |
| 5 | +// | |
| 6 | +// Created by Дмитрий Тимофеев on 09.06.2022. | |
| 7 | +// | |
| 8 | + | |
| 9 | +import Foundation | |
| 10 | +import UIKit | |
| 11 | +enum SettingsModel: CaseIterable { | |
| 12 | + case displayName | |
| 13 | + case doNotDisturb | |
| 14 | + case ringtone | |
| 15 | + case editResidents | |
| 16 | + case widgetLock | |
| 17 | + | |
| 18 | + func getTitle() -> String { | |
| 19 | + switch self { | |
| 20 | + case .displayName : | |
| 21 | + return "Your display name" | |
| 22 | + case .doNotDisturb : | |
| 23 | + return "Do not disturb" | |
| 24 | + case .editResidents : | |
| 25 | + return "Edit residents" | |
| 26 | + case .widgetLock: | |
| 27 | + return "Widget lock" | |
| 28 | + case .ringtone: | |
| 29 | + return "Ringtone" | |
| 30 | + } | |
| 31 | + } | |
| 32 | + | |
| 33 | + func getIcon() -> UIImage? { | |
| 34 | + switch self { | |
| 35 | + case .displayName: | |
| 36 | + return UIImage(named: "Profile") | |
| 37 | + case .doNotDisturb: | |
| 38 | + return UIImage(named: "Notification") | |
| 39 | + case .editResidents: | |
| 40 | + return UIImage(named: "Password") | |
| 41 | + case .widgetLock: | |
| 42 | + return UIImage(named: "Profile") | |
| 43 | + case .ringtone: | |
| 44 | + return UIImage(named: "Volume") | |
| 45 | + } | |
| 46 | + } | |
| 47 | + | |
| 48 | + func getDescription() -> String { | |
| 49 | + switch self { | |
| 50 | + case .displayName : | |
| 51 | + return "This name will be dispayed everywhere" | |
| 52 | + case .doNotDisturb : | |
| 53 | + return "This name will be dispayed everywhere" | |
| 54 | + case .editResidents : | |
| 55 | + return "This name will be dispayed everywhere" | |
| 56 | + case .widgetLock: | |
| 57 | + return "This name will be dispayed everywhere" | |
| 58 | + case .ringtone: | |
| 59 | + return "This name will be dispayed everywhere" | |
| 60 | + } | |
| 61 | + } | |
| 62 | +} | ... | ... |
| 1 | +// | |
| 2 | +// File.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 15.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class DisplayNameCell: UITableViewCell, Reusable { | |
| 11 | + var settingsIcon: UIImageView = { | |
| 12 | + var obj = UIImageView() | |
| 13 | + obj.image = UIImage(named: .Image.profile) | |
| 14 | + return obj | |
| 15 | + }() | |
| 16 | + | |
| 17 | + var titleLabel: UILabel = { | |
| 18 | + var obj = UILabel() | |
| 19 | + obj.text = .Text.yourDisplayName | |
| 20 | + obj.font = .skModernist(type: .bold, ofSize: 16) | |
| 21 | + obj.textColor = .TextColor.darkBlue | |
| 22 | + return obj | |
| 23 | + }() | |
| 24 | + | |
| 25 | + var descriptionLabel: UILabel = { | |
| 26 | + var obj = UILabel() | |
| 27 | + obj.text = .Text.nameWillBeDisplay | |
| 28 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 29 | + obj.textColor = .TextColor.lightGrey | |
| 30 | + return obj | |
| 31 | + }() | |
| 32 | + | |
| 33 | + var displayNameTextField: TextFieldWithPadding = { | |
| 34 | + var obj = TextFieldWithPadding() | |
| 35 | + obj.text = .Text.johnDoe | |
| 36 | + obj.returnKeyType = .done | |
| 37 | + obj.backgroundColor = .TextFieldColor.general | |
| 38 | + obj.clipsToBounds = true | |
| 39 | + obj.layer.cornerRadius = 15 | |
| 40 | + obj.textPadding = UIEdgeInsets(top: 0, left: 24, bottom: 0, right: 15) | |
| 41 | + return obj | |
| 42 | + }() | |
| 43 | + | |
| 44 | + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { | |
| 45 | + super.init(style: style, reuseIdentifier: reuseIdentifier) | |
| 46 | + setup() | |
| 47 | + } | |
| 48 | + | |
| 49 | + required init?(coder: NSCoder) { | |
| 50 | + super.init(coder: coder) | |
| 51 | + setup() | |
| 52 | + } | |
| 53 | + | |
| 54 | + private func setup() { | |
| 55 | + selectionStyle = .none | |
| 56 | + contentView.addSubview(settingsIcon) | |
| 57 | + contentView.addSubview(titleLabel) | |
| 58 | + contentView.addSubview(descriptionLabel) | |
| 59 | + contentView.addSubview(displayNameTextField) | |
| 60 | + | |
| 61 | + settingsIcon.snp.makeConstraints { make in | |
| 62 | + make.top.equalToSuperview() | |
| 63 | + make.leading.equalTo(snp.leading).offset(32) | |
| 64 | + } | |
| 65 | + | |
| 66 | + titleLabel.snp.makeConstraints { make in | |
| 67 | + make.top.equalTo(settingsIcon.snp.top) | |
| 68 | + make.leading.equalTo(settingsIcon.snp.trailing).offset(18) | |
| 69 | + } | |
| 70 | + | |
| 71 | + descriptionLabel.snp.makeConstraints { make in | |
| 72 | + make.top.equalTo(titleLabel.snp.bottom).offset(5) | |
| 73 | + make.leading.equalTo(titleLabel.snp.leading) | |
| 74 | + } | |
| 75 | + | |
| 76 | + displayNameTextField.snp.makeConstraints { make in | |
| 77 | + make.top.equalTo(descriptionLabel.snp.bottom).offset(20) | |
| 78 | + make.leading.equalTo(snp.leading).offset(66) | |
| 79 | + make.trailing.equalTo(snp.trailing).offset(-28) | |
| 80 | + make.height.equalTo(47) | |
| 81 | + make.bottom.equalToSuperview().offset(-30) | |
| 82 | + } | |
| 83 | + } | |
| 84 | +} | |
| 85 | + | ... | ... |
| 1 | +// | |
| 2 | +// SettingsSwitchCell.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 15.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class SettingsSwitchCell: UITableViewCell, Reusable { | |
| 11 | + var settingsIcon: UIImageView = { | |
| 12 | + var obj = UIImageView() | |
| 13 | + obj.image = UIImage(named: .Image.notification) | |
| 14 | + return obj | |
| 15 | + }() | |
| 16 | + | |
| 17 | + var titleLabel: UILabel = { | |
| 18 | + var obj = UILabel() | |
| 19 | + obj.text = .Text.doNotDisturb | |
| 20 | + obj.textColor = .TextColor.darkBlue | |
| 21 | + obj.font = .skModernist(type: .bold, ofSize: 16) | |
| 22 | + return obj | |
| 23 | + }() | |
| 24 | + | |
| 25 | + var descriptionLabel: UILabel = { | |
| 26 | + var obj = UILabel() | |
| 27 | + obj.text = .Text.youWillNotBeNotified | |
| 28 | + obj.textColor = .TextColor.lightGrey | |
| 29 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 30 | + obj.numberOfLines = 0 | |
| 31 | + return obj | |
| 32 | + }() | |
| 33 | + | |
| 34 | + var notificationSwitch: UISwitch = { | |
| 35 | + var obj = UISwitch() | |
| 36 | + obj.isOn = false | |
| 37 | + obj.clipsToBounds = true | |
| 38 | + return obj | |
| 39 | + }() | |
| 40 | + | |
| 41 | + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { | |
| 42 | + super.init(style: style, reuseIdentifier: reuseIdentifier) | |
| 43 | + setup() | |
| 44 | + } | |
| 45 | + | |
| 46 | + required init?(coder: NSCoder) { | |
| 47 | + super.init(coder: coder) | |
| 48 | + setup() | |
| 49 | + } | |
| 50 | + | |
| 51 | + func setup() { | |
| 52 | + selectionStyle = .none | |
| 53 | + contentView.addSubview(settingsIcon) | |
| 54 | + contentView.addSubview(titleLabel) | |
| 55 | + contentView.addSubview(descriptionLabel) | |
| 56 | + contentView.addSubview(notificationSwitch) | |
| 57 | + | |
| 58 | + settingsIcon.snp.makeConstraints { make in | |
| 59 | + make.leading.equalToSuperview().offset(31) | |
| 60 | + make.top.equalToSuperview().offset(38) | |
| 61 | + } | |
| 62 | + | |
| 63 | + titleLabel.snp.makeConstraints { make in | |
| 64 | + make.leading.equalTo(settingsIcon.snp.trailing).offset(17.5) | |
| 65 | + make.top.equalToSuperview().offset(38) | |
| 66 | + } | |
| 67 | + | |
| 68 | + descriptionLabel.snp.makeConstraints { make in | |
| 69 | + make.top.equalTo(titleLabel.snp.bottom).offset(5) | |
| 70 | + make.leading.equalTo(titleLabel.snp.leading) | |
| 71 | + make.bottom.equalToSuperview().offset(-22) | |
| 72 | + } | |
| 73 | + | |
| 74 | + notificationSwitch.snp.makeConstraints { make in | |
| 75 | + make.top.equalTo(snp.top).offset(36) | |
| 76 | + make.trailing.equalTo(snp.trailing).offset(-28) | |
| 77 | + } | |
| 78 | + } | |
| 79 | +} | |
| 80 | + | |
| 81 | + | ... | ... |
| 1 | +// | |
| 2 | +// SettingsTableViewCell.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 15.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | + | |
| 10 | +import UIKit | |
| 11 | + | |
| 12 | +class SettingsTableViewCell: UITableViewCell, Reusable { | |
| 13 | + var settingsIcon: UIImageView = { | |
| 14 | + var obj = UIImageView() | |
| 15 | + obj.image = UIImage(named: .Image.edit) | |
| 16 | + obj.contentMode = .scaleAspectFill | |
| 17 | + return obj | |
| 18 | + }() | |
| 19 | + | |
| 20 | + var titleLabel: UILabel = { | |
| 21 | + var obj = UILabel() | |
| 22 | + obj.text = .Text.editResidents | |
| 23 | + obj.textColor = .TextColor.darkBlue | |
| 24 | + obj.font = .skModernist(type: .bold, ofSize: 16) | |
| 25 | + return obj | |
| 26 | + }() | |
| 27 | + | |
| 28 | + var descriptionLabel: UILabel = { | |
| 29 | + var obj = UILabel() | |
| 30 | + obj.text = .Text.editResidentsAndInfo | |
| 31 | + obj.textColor = .TextColor.lightGrey | |
| 32 | + obj.font = .skModernist(type: .regular, ofSize: 14) | |
| 33 | + return obj | |
| 34 | + }() | |
| 35 | + | |
| 36 | + var arrowImageView: UIImageView = { | |
| 37 | + var obj = UIImageView() | |
| 38 | + obj.image = UIImage(named: .Image.nextPointer) | |
| 39 | + return obj | |
| 40 | + }() | |
| 41 | + | |
| 42 | + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { | |
| 43 | + super.init(style: style, reuseIdentifier: reuseIdentifier) | |
| 44 | + setup() | |
| 45 | + } | |
| 46 | + | |
| 47 | + required init?(coder: NSCoder) { | |
| 48 | + super.init(coder: coder) | |
| 49 | + setup() | |
| 50 | + } | |
| 51 | + | |
| 52 | + func setup() { | |
| 53 | + selectionStyle = .none | |
| 54 | + contentView.addSubview(settingsIcon) | |
| 55 | + contentView.addSubview(titleLabel) | |
| 56 | + contentView.addSubview(descriptionLabel) | |
| 57 | + contentView.addSubview(arrowImageView) | |
| 58 | + | |
| 59 | + settingsIcon.snp.makeConstraints { make in | |
| 60 | + make.top.equalToSuperview().offset(26) | |
| 61 | + make.leading.equalToSuperview().offset(32) | |
| 62 | + make.height.width.equalTo(18) | |
| 63 | + } | |
| 64 | + | |
| 65 | + titleLabel.snp.makeConstraints { make in | |
| 66 | + make.top.equalToSuperview().offset(26) | |
| 67 | + make.leading.equalTo(settingsIcon.snp.trailing).offset(15) | |
| 68 | + } | |
| 69 | + | |
| 70 | + descriptionLabel.snp.makeConstraints { make in | |
| 71 | + make.top.equalTo(titleLabel.snp.bottom).offset(5) | |
| 72 | + make.leading.equalTo(titleLabel.snp.leading) | |
| 73 | + make.bottom.equalToSuperview().offset(-22) | |
| 74 | + } | |
| 75 | + | |
| 76 | + arrowImageView.snp.makeConstraints { make in | |
| 77 | + make.centerY.equalToSuperview() | |
| 78 | + make.trailing.equalTo(snp.trailing).offset(-28) | |
| 79 | + } | |
| 80 | + } | |
| 81 | +} | |
| 82 | + | ... | ... |
| 1 | +// | |
| 2 | +// SettingsView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 08.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class SettingsView: UIView { | |
| 11 | + var backButton: UIButton = { | |
| 12 | + var obj = UIButton() | |
| 13 | + obj.setImage(UIImage(named: .Image.backPointer), for: .normal) | |
| 14 | + obj.backgroundColor = .white | |
| 15 | + obj.layer.borderColor = .BorderColor.lightGrey | |
| 16 | + obj.layer.cornerRadius = 13 | |
| 17 | + obj.layer.borderWidth = 1 | |
| 18 | + return obj | |
| 19 | + }() | |
| 20 | + | |
| 21 | + var logoImage: UIImageView = { | |
| 22 | + var obj = UIImageView() | |
| 23 | + obj.image = UIImage(named: .Image.USA) | |
| 24 | + return obj | |
| 25 | + }() | |
| 26 | + | |
| 27 | + var gearImage: UIImageView = { | |
| 28 | + var obj = UIImageView() | |
| 29 | + obj.image = UIImage(named: .Image.gear) | |
| 30 | + return obj | |
| 31 | + }() | |
| 32 | + | |
| 33 | + let settingsLabel: UILabel = { | |
| 34 | + var obj = UILabel() | |
| 35 | + obj.font = .skModernist(type: .bold, ofSize: 35) | |
| 36 | + obj.text = .Text.settings | |
| 37 | + return obj | |
| 38 | + }() | |
| 39 | + | |
| 40 | + let settingsTableView: UITableView = { | |
| 41 | + let obj = UITableView() | |
| 42 | + return obj | |
| 43 | + }() | |
| 44 | + | |
| 45 | + var logoutButton: UIButton = { | |
| 46 | + var obj = UIButton() | |
| 47 | + obj.backgroundColor = .Background.lightRed?.withAlphaComponent(0.07) | |
| 48 | + obj.setTitle(.Text.logout, for: .normal) | |
| 49 | + obj.setTitleColor(.TextColor.redError, for: .normal) | |
| 50 | + obj.layer.cornerRadius = 15 | |
| 51 | + return obj | |
| 52 | + }() | |
| 53 | + | |
| 54 | + override init(frame: CGRect) { | |
| 55 | + super.init(frame: frame) | |
| 56 | + backgroundColor = .white | |
| 57 | + setup() | |
| 58 | + } | |
| 59 | + | |
| 60 | + required init?(coder: NSCoder) { | |
| 61 | + fatalError("init(coder:) has not been implemented") | |
| 62 | + } | |
| 63 | + | |
| 64 | + func setup() { | |
| 65 | + addSubview(backButton) | |
| 66 | + addSubview(logoImage) | |
| 67 | + addSubview(gearImage) | |
| 68 | + addSubview(settingsLabel) | |
| 69 | + addSubview(settingsTableView) | |
| 70 | + addSubview(logoutButton) | |
| 71 | + | |
| 72 | + backButton.snp.makeConstraints { | |
| 73 | + $0.top.equalTo(snp.top).offset(66) | |
| 74 | + $0.leading.equalTo(snp.leading).offset(25) | |
| 75 | + $0.height.width.equalTo(45) | |
| 76 | + } | |
| 77 | + | |
| 78 | + logoImage.snp.makeConstraints { | |
| 79 | + $0.leading.equalTo(backButton.snp.trailing).offset(20) | |
| 80 | + $0.top.equalTo(snp.top).offset(79) | |
| 81 | + } | |
| 82 | + | |
| 83 | + gearImage.snp.makeConstraints { | |
| 84 | + $0.trailing.equalTo(snp.trailing) | |
| 85 | + $0.top.equalTo(snp.top).offset(106) | |
| 86 | + } | |
| 87 | + | |
| 88 | + settingsLabel.snp.makeConstraints { | |
| 89 | + $0.leading.equalTo(backButton.snp.leading) | |
| 90 | + $0.top.equalTo(backButton.snp.bottom).offset(46) | |
| 91 | + } | |
| 92 | + | |
| 93 | + settingsTableView.snp.makeConstraints { make in | |
| 94 | + make.leading.trailing.equalToSuperview() | |
| 95 | + make.top.equalTo(settingsLabel.snp.bottom).offset(85) | |
| 96 | + } | |
| 97 | + | |
| 98 | + logoutButton.snp.makeConstraints { | |
| 99 | + $0.top.equalTo(settingsTableView.snp.bottom).offset(42) | |
| 100 | + $0.leading.equalTo(snp.leading).offset(25) | |
| 101 | + $0.trailing.equalTo(snp.trailing).offset(-26) | |
| 102 | + $0.height.equalTo(56) | |
| 103 | + $0.bottom.equalToSuperview().offset(-51) | |
| 104 | + } | |
| 105 | + } | |
| 106 | +} | |
| 107 | + | ... | ... |
| 1 | +// | |
| 2 | +// SettingsViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 08.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class SettingsViewController: UIViewController { | |
| 11 | + var logoutMessage: String? | |
| 12 | + var mainView = SettingsView() | |
| 13 | + let settingsModel = SettingsModel.allCases | |
| 14 | + | |
| 15 | + override func loadView() { | |
| 16 | + view = mainView | |
| 17 | + } | |
| 18 | + override func viewDidLoad() { | |
| 19 | + super.viewDidLoad() | |
| 20 | + initViewController() | |
| 21 | + } | |
| 22 | + | |
| 23 | + private func initViewController() { | |
| 24 | + mainView.settingsTableView.delegate = self | |
| 25 | + mainView.settingsTableView.dataSource = self | |
| 26 | + | |
| 27 | + mainView.settingsTableView.registerReusableCell(DisplayNameCell.self) | |
| 28 | + mainView.settingsTableView.registerReusableCell(SettingsSwitchCell.self) | |
| 29 | + mainView.settingsTableView.registerReusableCell(SettingsTableViewCell.self) | |
| 30 | + | |
| 31 | + mainView.backButton.addTarget(self, action: #selector(didShowHomeVC), for: .touchUpInside) | |
| 32 | + mainView.logoutButton.addTarget(self, action: #selector(didTapLogoutButton), for: .touchUpInside) | |
| 33 | + } | |
| 34 | +} | |
| 35 | +//MARK: - Delegate | |
| 36 | +extension SettingsViewController { | |
| 37 | + @objc private func didShowHomeVC() { | |
| 38 | + navigationController?.popViewController(animated: true) | |
| 39 | + } | |
| 40 | + | |
| 41 | + @objc private func didTapLogoutButton() { | |
| 42 | + logoutRequestProcessing() | |
| 43 | + | |
| 44 | + } | |
| 45 | + | |
| 46 | + func logoutRequestProcessing() { | |
| 47 | + guard let logoutModel = getLogoutModel() else { return } | |
| 48 | + AuthService.shared.logoutRequest(model: logoutModel) { response in | |
| 49 | + self.logoutMessage = response.message | |
| 50 | + self.logoutDataProcessing() | |
| 51 | + print("5️⃣❇️\(response.message ?? "Data not received!")❇️") | |
| 52 | + } fail: { error in | |
| 53 | + self.logoutErrorProcessing() | |
| 54 | + print("5️⃣❗️\(error)❗️") | |
| 55 | + } | |
| 56 | + } | |
| 57 | + | |
| 58 | + func getLogoutModel() -> LogoutRequestModel? { | |
| 59 | + guard let deviceUUID = UIDevice.current.identifierForVendor?.uuidString else { | |
| 60 | + return nil | |
| 61 | + } | |
| 62 | + return LogoutRequestModel(deviceUUID: deviceUUID) | |
| 63 | + } | |
| 64 | + | |
| 65 | + private func logoutDataProcessing() { | |
| 66 | + let alert = UIAlertController(title: "Do you really want to logout?", message: "", preferredStyle: .alert) | |
| 67 | + alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { action in | |
| 68 | + let vc = VerificationViewController() | |
| 69 | + self.navigationController?.pushViewController(vc, animated: true) | |
| 70 | + })) | |
| 71 | + alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil)) | |
| 72 | + present(alert, animated: true, completion: nil) | |
| 73 | + } | |
| 74 | + | |
| 75 | + private func logoutErrorProcessing() { | |
| 76 | + if logoutMessage != "OK" { | |
| 77 | + let alert = UIAlertController(title: "Some network problems", message: "", preferredStyle: .alert) | |
| 78 | + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) | |
| 79 | + present(alert, animated: true, completion: nil) | |
| 80 | + } else { | |
| 81 | + let vc = VerificationViewController() | |
| 82 | + self.navigationController?.pushViewController(vc, animated: true) | |
| 83 | + } | |
| 84 | + } | |
| 85 | +} | |
| 86 | + | |
| 87 | +//MARK: tableView delegate and datasource | |
| 88 | +extension SettingsViewController: UITableViewDelegate, UITableViewDataSource { | |
| 89 | + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
| 90 | + return settingsModel.count | |
| 91 | + } | |
| 92 | + | |
| 93 | + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
| 94 | + let row = indexPath.row | |
| 95 | + let model: SettingsModel = settingsModel[row] | |
| 96 | + | |
| 97 | + switch model { | |
| 98 | + case .displayName: | |
| 99 | + let cell: DisplayNameCell = tableView.dequeueReusableCell(for: indexPath) | |
| 100 | + cell.titleLabel.text = model.getTitle() | |
| 101 | + cell.descriptionLabel.text = model.getDescription() | |
| 102 | + cell.settingsIcon.image = model.getIcon() | |
| 103 | + return cell | |
| 104 | + case .doNotDisturb, .ringtone: | |
| 105 | + let cell: SettingsSwitchCell = tableView.dequeueReusableCell(for: indexPath) | |
| 106 | + cell.titleLabel.text = model.getTitle() | |
| 107 | + cell.descriptionLabel.text = model.getDescription() | |
| 108 | + cell.settingsIcon.image = model.getIcon() | |
| 109 | + return cell | |
| 110 | + case .editResidents, .widgetLock: | |
| 111 | + let cell: SettingsTableViewCell = tableView.dequeueReusableCell(for: indexPath) | |
| 112 | + cell.titleLabel.text = model.getTitle() | |
| 113 | + cell.descriptionLabel.text = model.getDescription() | |
| 114 | + cell.settingsIcon.image = model.getIcon() | |
| 115 | + return cell | |
| 116 | + } | |
| 117 | + } | |
| 118 | + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | |
| 119 | + if indexPath.row == 3 { | |
| 120 | + let vc = ChooseApartmentsViewController() | |
| 121 | + navigationController?.pushViewController(vc, animated: true) | |
| 122 | + } | |
| 123 | + } | |
| 124 | +} | |
| 125 | + | ... | ... |
| 1 | +// | |
| 2 | +// PhoneNumberView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 31.05.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | +import CoreTelephony | |
| 10 | + | |
| 11 | +class PhoneNumberView: UIView { | |
| 12 | + var containerPickerView: UIView = { | |
| 13 | + var view = UIView() | |
| 14 | + view.backgroundColor = .systemRed | |
| 15 | + return view | |
| 16 | + }() | |
| 17 | + | |
| 18 | + var titleButton: UIButton = { | |
| 19 | + var obj = UIButton() | |
| 20 | + obj.setTitle(.Text.selectYourCountry, for: .normal) | |
| 21 | + obj.setTitleColor(.TextColor.darkBlue, for: .normal) | |
| 22 | + obj.titleLabel?.font = .skModernist(type: .bold, ofSize: 18) | |
| 23 | + obj.titleLabel?.textAlignment = .center | |
| 24 | + return obj | |
| 25 | + }() | |
| 26 | + | |
| 27 | + var dividingLineView: UIView = { | |
| 28 | + var view = UIView() | |
| 29 | + view.backgroundColor = .Background.lightGrey | |
| 30 | + return view | |
| 31 | + }() | |
| 32 | + | |
| 33 | + var phoneNumberPicker: UIPickerView = { | |
| 34 | + var picker = UIPickerView() | |
| 35 | + return picker | |
| 36 | + }() | |
| 37 | + | |
| 38 | + var gradientBG: CAGradientLayer = { | |
| 39 | + let obj = CAGradientLayer() | |
| 40 | + var leftColor = CGColor.GradientBlue.left | |
| 41 | + var rightColor = CGColor.GradientBlue.right | |
| 42 | + obj.colors = [leftColor, rightColor] | |
| 43 | + obj.startPoint = CGPoint(x: 0, y: 0.5) | |
| 44 | + obj.endPoint = CGPoint(x: 1, y: 0.5) | |
| 45 | + return obj | |
| 46 | + }() | |
| 47 | + | |
| 48 | + var selectButton: UIButton = { | |
| 49 | + var button = UIButton() | |
| 50 | + button.clipsToBounds = true | |
| 51 | + button.layer.masksToBounds = true | |
| 52 | + return button | |
| 53 | + }() | |
| 54 | + | |
| 55 | + var selectLabel: UILabel = { | |
| 56 | + var label = UILabel() | |
| 57 | + label.text = .Text.select | |
| 58 | + label.font = .skModernist(type: .bold, ofSize: 16) | |
| 59 | + label.textColor = .white | |
| 60 | + return label | |
| 61 | + }() | |
| 62 | + | |
| 63 | + override init(frame: CGRect) { | |
| 64 | + super.init(frame: frame) | |
| 65 | + layout() | |
| 66 | + setup() | |
| 67 | + backgroundColor = .white | |
| 68 | + } | |
| 69 | + | |
| 70 | + required init?(coder: NSCoder) { | |
| 71 | + fatalError("init(coder:) has not been implemented") | |
| 72 | + } | |
| 73 | + | |
| 74 | + func layout() { | |
| 75 | + self.backgroundColor = .white | |
| 76 | + addSubview(titleButton) | |
| 77 | + addSubview(dividingLineView) | |
| 78 | + addSubview(phoneNumberPicker) | |
| 79 | + addSubview(selectButton) | |
| 80 | + | |
| 81 | + selectButton.layer.addSublayer(gradientBG) | |
| 82 | + selectButton.addSubview(selectLabel) | |
| 83 | + | |
| 84 | + titleButton.snp.makeConstraints { make in | |
| 85 | + make.top.equalToSuperview().offset(20) | |
| 86 | + make.leading.trailing.equalToSuperview() | |
| 87 | + } | |
| 88 | + | |
| 89 | + dividingLineView.snp.makeConstraints { | |
| 90 | + $0.left.right.equalToSuperview() | |
| 91 | + $0.height.equalTo(1) | |
| 92 | + $0.top.equalTo(titleButton.snp.bottom).offset(22) | |
| 93 | + } | |
| 94 | + phoneNumberPicker.snp.makeConstraints { | |
| 95 | + $0.left.right.equalToSuperview().inset(5) | |
| 96 | + $0.top.equalTo(dividingLineView.snp.bottom).offset(20) | |
| 97 | + } | |
| 98 | + selectButton.snp.makeConstraints { | |
| 99 | + $0.right.equalToSuperview() | |
| 100 | + $0.left.equalToSuperview() | |
| 101 | + $0.bottom.equalToSuperview() | |
| 102 | + $0.height.equalTo(70) | |
| 103 | + $0.top.equalTo(phoneNumberPicker.snp.bottom).offset(20) | |
| 104 | + } | |
| 105 | + selectLabel.snp.makeConstraints { | |
| 106 | + $0.centerX.equalTo(selectButton.snp.centerX) | |
| 107 | + $0.top.equalTo(selectButton.snp.top).offset(20) | |
| 108 | + } | |
| 109 | + } | |
| 110 | + | |
| 111 | + override func layoutSubviews() { | |
| 112 | + super.layoutSubviews() | |
| 113 | + gradientBG.frame = selectButton.bounds | |
| 114 | + } | |
| 115 | +} | |
| 116 | + | |
| 117 | +extension PhoneNumberView { | |
| 118 | + func setup() { | |
| 119 | + let countryCode: String | |
| 120 | + if let carrier = CTTelephonyNetworkInfo().serviceSubscriberCellularProviders?.first?.value, | |
| 121 | + let code = carrier.isoCountryCode?.uppercased() { | |
| 122 | + countryCode = code | |
| 123 | + } else { | |
| 124 | + countryCode = "USA" | |
| 125 | + } | |
| 126 | + phoneNumberPicker.selectRow(0, inComponent: 0, animated: true) | |
| 127 | + phoneNumberPicker.subviews[1].backgroundColor = .clear | |
| 128 | + } | |
| 129 | +} | |
| 130 | + | ... | ... |
| 1 | +// | |
| 2 | +// PickerView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 01.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +final class PickerView: UIView { | |
| 11 | + | |
| 12 | + private let iconView: UIImageView = { | |
| 13 | + var obj = UIImageView() | |
| 14 | + obj.contentMode = .scaleAspectFill | |
| 15 | + obj.layer.cornerRadius = 10 | |
| 16 | + return obj | |
| 17 | + }() | |
| 18 | + private let label: UILabel = { | |
| 19 | + var obj = UILabel() | |
| 20 | + obj.textColor = .TextColor.darkBlue | |
| 21 | + obj.font = .skModernist(type: .bold, ofSize: 15) | |
| 22 | + return obj | |
| 23 | + }() | |
| 24 | + private let countryCode: UILabel = { | |
| 25 | + var obj = UILabel() | |
| 26 | + obj.textColor = .TextColor.darkBlue | |
| 27 | + obj.font = .skModernist(type: .bold, ofSize: 15) | |
| 28 | + return obj | |
| 29 | + }() | |
| 30 | + override init(frame: CGRect) { | |
| 31 | + super.init(frame: frame) | |
| 32 | + setup() | |
| 33 | + } | |
| 34 | + | |
| 35 | + required init?(coder: NSCoder) { | |
| 36 | + super.init(coder: coder) | |
| 37 | + setup() | |
| 38 | + } | |
| 39 | + | |
| 40 | + private func setup() { | |
| 41 | + addSubview(iconView) | |
| 42 | + addSubview(label) | |
| 43 | + addSubview(countryCode) | |
| 44 | + | |
| 45 | + iconView.snp.makeConstraints { make in | |
| 46 | + make.leading.equalToSuperview().offset(25) | |
| 47 | + make.centerY.equalTo(snp.centerY) | |
| 48 | + make.height.width.equalTo(20) | |
| 49 | + } | |
| 50 | + | |
| 51 | + label.snp.makeConstraints { make in | |
| 52 | + make.leading.equalTo(iconView.snp.trailing).offset(20) | |
| 53 | + make.top.bottom.equalToSuperview() | |
| 54 | + } | |
| 55 | + | |
| 56 | + countryCode.snp.makeConstraints { make in | |
| 57 | + make.trailing.equalToSuperview().offset(-25) | |
| 58 | + make.top.bottom.equalToSuperview() | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | + static func create(icon: UIImage, title: String, code: String) -> PickerView { | |
| 63 | + let numberView = PickerView() | |
| 64 | + numberView.iconView.image = icon | |
| 65 | + numberView.label.text = title | |
| 66 | + numberView.countryCode.text = code | |
| 67 | + return numberView | |
| 68 | + } | |
| 69 | +} | ... | ... |
| 1 | +// | |
| 2 | +// VerificationView.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 30.05.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | + | |
| 11 | +class VerificationView: UIView { | |
| 12 | + var isShow: Bool = false | |
| 13 | + | |
| 14 | + var logoImage: UIImageView = { | |
| 15 | + var view = UIImageView() | |
| 16 | + view.image = UIImage(named: .Image.USA) | |
| 17 | + return view | |
| 18 | + }() | |
| 19 | + | |
| 20 | + var greetingsLabel: UILabel = { | |
| 21 | + var label = UILabel() | |
| 22 | + label.text = .Text.hello | |
| 23 | + label.font = .skModernist(type: .bold, ofSize: 35) | |
| 24 | + return label | |
| 25 | + }() | |
| 26 | + | |
| 27 | + var verifyLabel: UILabel = { | |
| 28 | + var label = UILabel() | |
| 29 | + label.text = .Text.letsVerifyYourAccount | |
| 30 | + label.numberOfLines = 2 | |
| 31 | + label.font = .skModernist(type: .regular, ofSize: 28) | |
| 32 | + return label | |
| 33 | + }() | |
| 34 | + | |
| 35 | + var shieldImage: UIImageView = { | |
| 36 | + var view = UIImageView() | |
| 37 | + view.image = UIImage(named: .Image.shield) | |
| 38 | + return view | |
| 39 | + }() | |
| 40 | + | |
| 41 | + var chooseLabel: UILabel = { | |
| 42 | + var label = UILabel() | |
| 43 | + label.text = .Text.chooseWhatToStartWith | |
| 44 | + label.font = .skModernist(type: .bold, ofSize: 16) | |
| 45 | + return label | |
| 46 | + }() | |
| 47 | + | |
| 48 | + var emailButton: Checkbox = { | |
| 49 | + var button = Checkbox() | |
| 50 | + button.checkboxTitle = .Text.email | |
| 51 | + button.isSelected = true | |
| 52 | + return button | |
| 53 | + }() | |
| 54 | + | |
| 55 | + var phoneNumberButton: Checkbox = { | |
| 56 | + var button = Checkbox() | |
| 57 | + button.checkboxTitle = .Text.phoneNumber | |
| 58 | + return button | |
| 59 | + }() | |
| 60 | + | |
| 61 | + var dividingLineView: UIView = { | |
| 62 | + var view = UIView() | |
| 63 | + view.backgroundColor = .Background.lightGrey | |
| 64 | + return view | |
| 65 | + }() | |
| 66 | + | |
| 67 | + var enterChosenAuthenticatorLabel: UILabel = { | |
| 68 | + var label = UILabel() | |
| 69 | + label.text = .Text.enterYourEmailAddress | |
| 70 | + label.font = UIFont(name: SkModernistFontType.bold.rawValue, size: 16) | |
| 71 | + return label | |
| 72 | + }() | |
| 73 | + | |
| 74 | + var emailTextField: UITextField = { | |
| 75 | + var textField = UITextField() | |
| 76 | + textField.backgroundColor = .TextFieldColor.general | |
| 77 | + textField.textAlignment = .left | |
| 78 | + textField.layer.cornerRadius = 15 | |
| 79 | + textField.keyboardType = .emailAddress | |
| 80 | + textField.placeholder = .Text.exampleEmail | |
| 81 | + textField.font = .skModernist(type: .regular, ofSize: 15) | |
| 82 | + textField.layer.masksToBounds = true | |
| 83 | + textField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 22, height: textField.frame.height)) | |
| 84 | + textField.leftViewMode = .always | |
| 85 | + textField.returnKeyType = .done | |
| 86 | + return textField | |
| 87 | + }() | |
| 88 | + | |
| 89 | + var phoneTextField: TextFieldWithPadding = { | |
| 90 | + var textField = TextFieldWithPadding() | |
| 91 | + textField.backgroundColor = .TextFieldColor.general | |
| 92 | + textField.textAlignment = .left | |
| 93 | + textField.layer.cornerRadius = 15 | |
| 94 | + textField.keyboardType = .phonePad | |
| 95 | + textField.text = .Text.plusOne | |
| 96 | + textField.font = .skModernist(type: .regular, ofSize: 15) | |
| 97 | + textField.layer.masksToBounds = true | |
| 98 | + textField.isHidden = true | |
| 99 | + textField.textPadding = UIEdgeInsets(top: 0, left: 75, bottom: 0, right: 15) | |
| 100 | + return textField | |
| 101 | + }() | |
| 102 | + | |
| 103 | + var verificationDescriptionLabel: UILabel = { | |
| 104 | + var label = UILabel() | |
| 105 | + label.numberOfLines = 0 | |
| 106 | + label.text = .Text.verificationCodeWillBeSentToYourEmail | |
| 107 | + label.font = .skModernist(type: .regular, ofSize: 14) | |
| 108 | + return label | |
| 109 | + }() | |
| 110 | + | |
| 111 | + var continueButton: UIButton = { | |
| 112 | + var button = UIButton() | |
| 113 | + button.setImage(UIImage(named: .Image.RectangleWithShadow), for: .normal) | |
| 114 | + button.clipsToBounds = true | |
| 115 | + button.contentMode = .scaleAspectFit | |
| 116 | + button.layer.cornerRadius = 15 | |
| 117 | + return button | |
| 118 | + }() | |
| 119 | + | |
| 120 | + var continueLabel: UILabel = { | |
| 121 | + var label = UILabel() | |
| 122 | + label.text = .Text.continueText | |
| 123 | + label.font = .skModernist(type: .bold, ofSize: 16) | |
| 124 | + label.textColor = .white | |
| 125 | + return label | |
| 126 | + }() | |
| 127 | + | |
| 128 | + var pointerImage: UIImageView = { | |
| 129 | + var image = UIImageView() | |
| 130 | + image.image = UIImage(named: .Image.pointer) | |
| 131 | + return image | |
| 132 | + }() | |
| 133 | + | |
| 134 | + var phonePickerView: PhoneNumberView = { | |
| 135 | + var view = PhoneNumberView() | |
| 136 | + view.isUserInteractionEnabled = true | |
| 137 | + return view | |
| 138 | + }() | |
| 139 | + | |
| 140 | + var showPickerButton: UIButton = { | |
| 141 | + var button = UIButton() | |
| 142 | + button.isHidden = true | |
| 143 | + return button | |
| 144 | + }() | |
| 145 | + | |
| 146 | + var flagPickerView: UIImageView = { | |
| 147 | + var image = UIImageView() | |
| 148 | + image.image = UIImage(named: .Image.USA) | |
| 149 | + image.layer.cornerRadius = 11 | |
| 150 | + image.contentMode = .scaleAspectFit | |
| 151 | + return image | |
| 152 | + }() | |
| 153 | + | |
| 154 | + var flagPointerView: UIImageView = { | |
| 155 | + var image = UIImageView() | |
| 156 | + image.image = UIImage(named: .Image.flagPointer) | |
| 157 | + return image | |
| 158 | + }() | |
| 159 | + | |
| 160 | + override init(frame: CGRect) { | |
| 161 | + super.init(frame: frame) | |
| 162 | + backgroundColor = .white | |
| 163 | + setup() | |
| 164 | + } | |
| 165 | + | |
| 166 | + required init?(coder: NSCoder) { | |
| 167 | + fatalError("init(coder:) has not been implemented") | |
| 168 | + } | |
| 169 | + | |
| 170 | + func setup() { | |
| 171 | + addSubview(logoImage) | |
| 172 | + addSubview(greetingsLabel) | |
| 173 | + addSubview(verifyLabel) | |
| 174 | + addSubview(shieldImage) | |
| 175 | + | |
| 176 | + addSubview(chooseLabel) | |
| 177 | + addSubview(emailButton) | |
| 178 | + addSubview(phoneNumberButton) | |
| 179 | + addSubview(dividingLineView) | |
| 180 | + | |
| 181 | + addSubview(enterChosenAuthenticatorLabel) | |
| 182 | + addSubview(emailTextField) | |
| 183 | + addSubview(phoneTextField) | |
| 184 | + addSubview(verificationDescriptionLabel) | |
| 185 | + phoneTextField.addSubview(showPickerButton) | |
| 186 | + | |
| 187 | + showPickerButton.addSubview(flagPickerView) | |
| 188 | + showPickerButton.addSubview(flagPointerView) | |
| 189 | + | |
| 190 | + addSubview(continueButton) | |
| 191 | + continueButton.addSubview(continueLabel) | |
| 192 | + continueButton.addSubview(pointerImage) | |
| 193 | + | |
| 194 | + addSubview(phonePickerView) | |
| 195 | + | |
| 196 | + logoImage.snp.makeConstraints { | |
| 197 | + $0.top.equalTo(snp.top).offset(80) | |
| 198 | + $0.left.equalTo(snp.left).offset(27) | |
| 199 | + } | |
| 200 | + | |
| 201 | + greetingsLabel.snp.makeConstraints { | |
| 202 | + $0.top.equalTo(logoImage.snp.bottom).offset(42) | |
| 203 | + $0.left.equalTo(snp.left).offset(24) | |
| 204 | + } | |
| 205 | + | |
| 206 | + shieldImage.snp.makeConstraints { | |
| 207 | + $0.right.equalToSuperview() | |
| 208 | + $0.top.equalTo(logoImage.snp.bottom).offset(27) | |
| 209 | + } | |
| 210 | + | |
| 211 | + verifyLabel.snp.makeConstraints { | |
| 212 | + $0.left.equalTo(27) | |
| 213 | + $0.top.equalTo(greetingsLabel.snp.bottom).offset(10) | |
| 214 | + } | |
| 215 | + | |
| 216 | + chooseLabel.snp.makeConstraints { | |
| 217 | + $0.top.equalTo(shieldImage.snp.bottom).offset(52) | |
| 218 | + $0.left.equalTo(snp.left).offset(27) | |
| 219 | + } | |
| 220 | + | |
| 221 | + emailButton.snp.makeConstraints { | |
| 222 | + $0.left.equalTo(snp.left).offset(27) | |
| 223 | + $0.top.equalTo(chooseLabel.snp.bottom).offset(29) | |
| 224 | + $0.height.equalTo(20) | |
| 225 | + } | |
| 226 | + | |
| 227 | + phoneNumberButton.snp.makeConstraints { | |
| 228 | + $0.top.equalTo(emailButton.snp.top) | |
| 229 | + $0.height.equalTo(20) | |
| 230 | + $0.left.equalTo(emailButton.snp.right).offset(44) | |
| 231 | + } | |
| 232 | + | |
| 233 | + dividingLineView.snp.makeConstraints { | |
| 234 | + $0.left.right.equalToSuperview() | |
| 235 | + $0.top.equalTo(emailButton.snp.bottom).offset(41) | |
| 236 | + $0.height.equalTo(1) | |
| 237 | + } | |
| 238 | + | |
| 239 | + enterChosenAuthenticatorLabel.snp.makeConstraints { | |
| 240 | + $0.top.equalTo(dividingLineView.snp.bottom).offset(39) | |
| 241 | + $0.left.equalTo(logoImage.snp.left) | |
| 242 | + } | |
| 243 | + | |
| 244 | + emailTextField.snp.makeConstraints { | |
| 245 | + $0.left.equalTo(logoImage.snp.left) | |
| 246 | + $0.right.equalTo(snp.right).offset(-27) | |
| 247 | + $0.top.equalTo(enterChosenAuthenticatorLabel.snp.bottom).offset(23) | |
| 248 | + $0.height.equalTo(57) | |
| 249 | + } | |
| 250 | + | |
| 251 | + phoneTextField.snp.makeConstraints { | |
| 252 | + $0.left.equalTo(logoImage.snp.left) | |
| 253 | + $0.right.equalTo(snp.right).offset(-27) | |
| 254 | + $0.top.equalTo(enterChosenAuthenticatorLabel.snp.bottom).offset(23) | |
| 255 | + $0.height.equalTo(57) | |
| 256 | + } | |
| 257 | + | |
| 258 | + verificationDescriptionLabel.snp.makeConstraints { | |
| 259 | + $0.top.equalTo(emailTextField.snp.bottom).offset(8) | |
| 260 | + $0.left.equalTo(snp.left).offset(46) | |
| 261 | + $0.right.equalTo(snp.right).offset(-22) | |
| 262 | + } | |
| 263 | + | |
| 264 | + continueButton.snp.makeConstraints { | |
| 265 | + $0.left.equalTo(snp.left) | |
| 266 | + $0.right.equalTo(snp.right) | |
| 267 | + $0.top.equalTo(emailTextField.snp.bottom).offset(90) | |
| 268 | + $0.height.equalTo(125) | |
| 269 | + } | |
| 270 | + | |
| 271 | + continueLabel.snp.makeConstraints { | |
| 272 | + $0.left.equalTo(snp.left).offset(48) | |
| 273 | + $0.top.equalTo(continueButton.snp.top).offset(33) | |
| 274 | + } | |
| 275 | + | |
| 276 | + pointerImage.snp.makeConstraints { | |
| 277 | + $0.top.equalTo(continueButton.snp.top).offset(31) | |
| 278 | + $0.right.equalTo(snp.right).offset(-51.5) | |
| 279 | + } | |
| 280 | + | |
| 281 | + phonePickerView.snp.makeConstraints { make in | |
| 282 | + make.leading.trailing.equalToSuperview() | |
| 283 | + make.height.equalTo(390) | |
| 284 | + make.top.equalTo(self.snp.bottom) | |
| 285 | + } | |
| 286 | + | |
| 287 | + showPickerButton.snp.makeConstraints { | |
| 288 | + $0.height.equalTo(22) | |
| 289 | + $0.width.equalTo(50) | |
| 290 | + $0.left.equalTo(emailTextField.snp.left).offset(22) | |
| 291 | + $0.top.equalTo(emailTextField.snp.top).offset(18) | |
| 292 | + } | |
| 293 | + | |
| 294 | + flagPickerView.snp.makeConstraints { | |
| 295 | + $0.left.equalToSuperview() | |
| 296 | + $0.size.equalTo(20) | |
| 297 | + $0.centerY.equalTo(showPickerButton.snp.centerY) | |
| 298 | + } | |
| 299 | + | |
| 300 | + flagPointerView.snp.makeConstraints { | |
| 301 | + $0.left.equalTo(flagPickerView.snp.right).offset(10) | |
| 302 | + $0.centerYWithinMargins.equalTo(flagPickerView.snp.centerYWithinMargins) | |
| 303 | + } | |
| 304 | + } | |
| 305 | + | |
| 306 | + func showPickerView() { | |
| 307 | + UIView.animate(withDuration: 0.3) { | |
| 308 | + self.phonePickerView.snp.updateConstraints { make in | |
| 309 | + make.top.equalTo(self.snp.bottom).offset(-390) | |
| 310 | + } | |
| 311 | + self.layoutIfNeeded() | |
| 312 | + } | |
| 313 | + } | |
| 314 | + | |
| 315 | + func hidePickerView() { | |
| 316 | + UIView.animate(withDuration: 0.3) { | |
| 317 | + self.phonePickerView.snp.updateConstraints { make in | |
| 318 | + make.top.equalTo(self.snp.bottom).offset(0) | |
| 319 | + } | |
| 320 | + self.layoutIfNeeded() | |
| 321 | + } | |
| 322 | + } | |
| 323 | + | |
| 324 | + func handleUI(_ isChanged: Bool) { | |
| 325 | + emailTextField.isHidden = !isChanged | |
| 326 | + phoneTextField.isHidden = isChanged | |
| 327 | + verificationDescriptionLabel.text = isChanged ? .Text.verificationCodeWillBeSentToYourEmail : .Text.verificationCodeWillBeSentToYourNumber | |
| 328 | + enterChosenAuthenticatorLabel.text = isChanged ? .Text.enterYourEmailAddress : .Text.enterYourPhoneNumber | |
| 329 | + emailTextField.text = isChanged ? "" : .Text.plusOne | |
| 330 | + showPickerButton.isHidden = isChanged | |
| 331 | + } | |
| 332 | +} | ... | ... |
| 1 | +// | |
| 2 | +// ViewController.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 30.05.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | + | |
| 10 | +class VerificationViewController: UIViewController { | |
| 11 | + var isKeyboardAppear = false | |
| 12 | + var startMessage: String? | |
| 13 | + private let mainView = VerificationView() | |
| 14 | + var closeTap: UITapGestureRecognizer? | |
| 15 | + | |
| 16 | + lazy var phonePickerModels: [PhonePickerModel] = { | |
| 17 | + var models: [PhonePickerModel] = [] | |
| 18 | + | |
| 19 | + for (code, value) in PhoneService.phones | |
| 20 | + { | |
| 21 | + models.append(.init(code: code, countryCode: value.1, title: value.0, icon: value.2)) | |
| 22 | + } | |
| 23 | + return models | |
| 24 | + }() | |
| 25 | + | |
| 26 | + deinit { | |
| 27 | + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) | |
| 28 | + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) | |
| 29 | + } | |
| 30 | + | |
| 31 | + override func loadView() { | |
| 32 | + view = mainView | |
| 33 | + } | |
| 34 | + | |
| 35 | + override func viewDidLoad() { | |
| 36 | + super.viewDidLoad() | |
| 37 | + initViewController() | |
| 38 | + } | |
| 39 | + | |
| 40 | + private func initViewController() { | |
| 41 | + addDoneButtonOnKeyboard() | |
| 42 | + | |
| 43 | + mainView.emailTextField.delegate = self | |
| 44 | + mainView.phoneTextField.delegate = self | |
| 45 | + | |
| 46 | + mainView.phonePickerView.phoneNumberPicker.delegate = self | |
| 47 | + mainView.phonePickerView.phoneNumberPicker.dataSource = self | |
| 48 | + | |
| 49 | + mainView.phoneNumberButton.addTarget(self, action: #selector(didCheckboxTapped(_:)), for: .touchUpInside) | |
| 50 | + mainView.emailButton.addTarget(self, action: #selector(didCheckboxTapped(_:)), for: .touchUpInside) | |
| 51 | + mainView.showPickerButton.addTarget(self, action: #selector(didshowPickerButtonTapped(_:)), for: .touchUpInside) | |
| 52 | + mainView.phonePickerView.selectButton.addTarget(self, action: #selector(didshowPickerButtonTapped(_:)), for: .touchUpInside) | |
| 53 | + mainView.phonePickerView.titleButton.addTarget(self, action: #selector(didshowPickerButtonTapped(_:)), for: .touchDragInside) | |
| 54 | + mainView.continueButton.addTarget(self, action: #selector(didTapContinueButton), for: .touchUpInside) | |
| 55 | + | |
| 56 | + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) | |
| 57 | + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil) | |
| 58 | + } | |
| 59 | + | |
| 60 | + private func initDevice() { | |
| 61 | + guard let model = getInitModel() else { | |
| 62 | + return | |
| 63 | + } | |
| 64 | + AuthService.shared.initRequest(model: model) { result in | |
| 65 | + print("1️⃣✅\(result.message)✅") | |
| 66 | + self.startRequestProcessing() | |
| 67 | + } fail: { error in | |
| 68 | + print("1️⃣\(error)") | |
| 69 | + let alert = UIAlertController(title: "Error", message: "", preferredStyle: .alert) | |
| 70 | + alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) | |
| 71 | + self.present(alert, animated: true, completion: nil) | |
| 72 | + } | |
| 73 | + } | |
| 74 | + | |
| 75 | + func getInitModel() -> InitRequestModel? { | |
| 76 | + guard let deviceUUID = UIDevice.current.identifierForVendor?.uuidString else { | |
| 77 | + return nil | |
| 78 | + } | |
| 79 | + guard let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { | |
| 80 | + return nil | |
| 81 | + } | |
| 82 | + return InitRequestModel(deviceUUID: deviceUUID, | |
| 83 | + manufacturer: .Text.apple, | |
| 84 | + model: UIDevice.current.model, | |
| 85 | + platform: UIDevice.current.systemName, | |
| 86 | + osVersion: UIDevice.current.systemVersion, | |
| 87 | + appVersion: appVersion) | |
| 88 | + } | |
| 89 | + | |
| 90 | + private func startRequestProcessing() { | |
| 91 | + guard let startModel = startModelFilling() else { return } | |
| 92 | + AuthService.shared.startRequest(model: startModel) { response in | |
| 93 | + self.startMessage = response.message | |
| 94 | + print("2️⃣✅\(response.message)✅") | |
| 95 | + self.didShowCodeVerificationVC() | |
| 96 | + } fail: { error in | |
| 97 | + print("2️⃣❌\(error)❌") | |
| 98 | + self.errorProcessing() | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + func didShowCodeVerificationVC() { | |
| 103 | + if startMessage == "SMS successfully sent" { | |
| 104 | + let viewController = CodeVerificationViewController() | |
| 105 | + viewController.navigationItem.hidesBackButton = true | |
| 106 | + navigationController?.pushViewController(viewController, animated: true) | |
| 107 | + } else { | |
| 108 | + userDoesNotExistNotice() | |
| 109 | + } | |
| 110 | + | |
| 111 | + } | |
| 112 | + | |
| 113 | + private func userDoesNotExistNotice() { | |
| 114 | + let alert = UIAlertController(title: "User does not exist", message: "Try again", preferredStyle: .alert) | |
| 115 | + alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil)) | |
| 116 | + present(alert, animated: true) | |
| 117 | + } | |
| 118 | + | |
| 119 | + private func errorProcessing() { | |
| 120 | + let alert = UIAlertController(title: "Network error", message: "Try again later", preferredStyle: .alert) | |
| 121 | + alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil)) | |
| 122 | + present(alert, animated: true) | |
| 123 | + } | |
| 124 | + | |
| 125 | + func startModelFilling() -> StartRequestModel? { | |
| 126 | + let number = mainView.phoneTextField.text | |
| 127 | + let email = mainView.emailTextField.text | |
| 128 | + if number == nil { | |
| 129 | + return StartRequestModel(emailOrNumber: (String(describing: email))) | |
| 130 | + } else { | |
| 131 | + return StartRequestModel(emailOrNumber: (String(describing: number))) | |
| 132 | + } | |
| 133 | + } | |
| 134 | + | |
| 135 | + private func addDoneButtonOnKeyboard() { | |
| 136 | + let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50)) | |
| 137 | + doneToolbar.barStyle = .default | |
| 138 | + | |
| 139 | + let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) | |
| 140 | + let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction)) | |
| 141 | + | |
| 142 | + let items = [flexSpace, done] | |
| 143 | + doneToolbar.items = items | |
| 144 | + doneToolbar.sizeToFit() | |
| 145 | + | |
| 146 | + mainView.phoneTextField.inputAccessoryView = doneToolbar | |
| 147 | + } | |
| 148 | + | |
| 149 | + @objc private func doneButtonAction(){ | |
| 150 | + mainView.phoneTextField.resignFirstResponder() | |
| 151 | + } | |
| 152 | +} | |
| 153 | + | |
| 154 | +//MARK: helpers and handlers | |
| 155 | +extension VerificationViewController { | |
| 156 | + | |
| 157 | +} | |
| 158 | + | |
| 159 | +//MARK: targets | |
| 160 | +extension VerificationViewController { | |
| 161 | + @objc private func didCheckboxTapped(_ sender: Checkbox) { | |
| 162 | + switch sender { | |
| 163 | + case mainView.emailButton : | |
| 164 | + sender.isSelected = true | |
| 165 | + mainView.phoneNumberButton.isSelected = false | |
| 166 | + mainView.handleUI(true) | |
| 167 | + mainView.phoneTextField.resignFirstResponder() | |
| 168 | + case mainView.phoneNumberButton: | |
| 169 | + sender.isSelected = true | |
| 170 | + mainView.emailButton.isSelected = false | |
| 171 | + mainView.handleUI(false) | |
| 172 | + mainView.emailTextField.resignFirstResponder() | |
| 173 | + default: | |
| 174 | + return | |
| 175 | + } | |
| 176 | + } | |
| 177 | + | |
| 178 | + @objc private func didshowPickerButtonTapped(_ sender: UIButton) { | |
| 179 | + mainView.isShow ? mainView.showPickerView() : mainView.hidePickerView() | |
| 180 | + mainView.isShow.toggle() | |
| 181 | + } | |
| 182 | + | |
| 183 | + @objc private func didTapContinueButton() { | |
| 184 | + validatingTheLoginField() | |
| 185 | + } | |
| 186 | + | |
| 187 | + private func validatingTheLoginField() { | |
| 188 | + guard let email = mainView.emailTextField.text else { return } | |
| 189 | + guard let number = mainView.phoneTextField.text else { return } | |
| 190 | + | |
| 191 | + if email.isEmpty || number.isEmpty{ | |
| 192 | + let alert = UIAlertController(title: "Enter email or number fields", message: "", preferredStyle: .alert) | |
| 193 | + alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil)) | |
| 194 | + present(alert, animated: true) | |
| 195 | + } else { | |
| 196 | + initDevice() | |
| 197 | + } | |
| 198 | + } | |
| 199 | + | |
| 200 | + @objc private func keyboardWillShow(notification: NSNotification) { | |
| 201 | + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double | |
| 202 | + if !isKeyboardAppear { | |
| 203 | + UIView.animate(withDuration: duration ?? 0) { | |
| 204 | + self.mainView.chooseLabel.snp.updateConstraints { make in | |
| 205 | + make.top.equalTo(self.mainView.shieldImage.snp.bottom).offset(0) | |
| 206 | + } | |
| 207 | + self.mainView.dividingLineView.snp.updateConstraints { | |
| 208 | + $0.top.equalTo(self.mainView.emailButton.snp.bottom).offset(10) | |
| 209 | + } | |
| 210 | + self.mainView.enterChosenAuthenticatorLabel.snp.updateConstraints { | |
| 211 | + $0.top.equalTo(self.mainView.dividingLineView.snp.bottom).offset(5) | |
| 212 | + } | |
| 213 | + self.mainView.layoutIfNeeded() | |
| 214 | + } | |
| 215 | + isKeyboardAppear = true | |
| 216 | + } | |
| 217 | + } | |
| 218 | + | |
| 219 | + @objc private func keyboardWillHide(notification: NSNotification) { | |
| 220 | + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double | |
| 221 | + | |
| 222 | + if isKeyboardAppear { | |
| 223 | + | |
| 224 | + UIView.animate(withDuration: duration ?? 0) { | |
| 225 | + self.mainView.chooseLabel.snp.updateConstraints { make in | |
| 226 | + make.top.equalTo(self.mainView.shieldImage.snp.bottom).offset(52) | |
| 227 | + } | |
| 228 | + self.mainView.dividingLineView.snp.updateConstraints { | |
| 229 | + $0.top.equalTo(self.mainView.emailButton.snp.bottom).offset(41) | |
| 230 | + } | |
| 231 | + self.mainView.enterChosenAuthenticatorLabel.snp.updateConstraints { | |
| 232 | + $0.top.equalTo(self.mainView.dividingLineView.snp.bottom).offset(39) | |
| 233 | + } | |
| 234 | + self.mainView.layoutIfNeeded() | |
| 235 | + } | |
| 236 | + isKeyboardAppear = false | |
| 237 | + } | |
| 238 | + } | |
| 239 | +} | |
| 240 | +//MARK: - PickerView Delegate | |
| 241 | +extension VerificationViewController: UIPickerViewDataSource, UIPickerViewDelegate { | |
| 242 | + func numberOfComponents(in pickerView: UIPickerView) -> Int { | |
| 243 | + return 1 | |
| 244 | + } | |
| 245 | + | |
| 246 | + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { | |
| 247 | + return phonePickerModels.count | |
| 248 | + | |
| 249 | + } | |
| 250 | + | |
| 251 | + func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { | |
| 252 | + 60 | |
| 253 | + } | |
| 254 | + | |
| 255 | + func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { | |
| 256 | + let model = phonePickerModels[row] | |
| 257 | + return PickerView.create(icon: model.icon, title: model.title, code: model.countryCode) | |
| 258 | + } | |
| 259 | + | |
| 260 | + func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { | |
| 261 | + pickerView.subviews[1].backgroundColor = .clear | |
| 262 | + let model = phonePickerModels[row] | |
| 263 | + mainView.phoneTextField.text = "\(model.countryCode)" | |
| 264 | + mainView.flagPickerView.image = model.icon | |
| 265 | + } | |
| 266 | +} | |
| 267 | +//MARK: - TextField delegate | |
| 268 | +extension VerificationViewController: UITextFieldDelegate { | |
| 269 | + func textFieldShouldReturn(_ textField: UITextField) -> Bool { | |
| 270 | + mainView.emailTextField.resignFirstResponder() | |
| 271 | + return true | |
| 272 | + } | |
| 273 | +} | |
| 274 | + | |
| 275 | + | ... | ... |
TheButler/PhoneService.swift
0 → 100644
| 1 | +// | |
| 2 | +// PhoneService.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 31.05.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | + | |
| 11 | +class PhoneService { | |
| 12 | + static var phones: [String: (String, String, UIImage)] = { | |
| 13 | + var codes = [String: (String, String, UIImage)] () | |
| 14 | + codes["USA"] = ("United States", "+1", UIImage(named: "USA") ?? UIImage()) | |
| 15 | + codes["GB"] = ("Great Britain", "+123", UIImage(named: "GB") ?? UIImage()) | |
| 16 | + codes["AUS"] = ("Australia", "+12", UIImage(named: "AUS") ?? UIImage()) | |
| 17 | + return codes | |
| 18 | + }() | |
| 19 | +} | ... | ... |
TheButler/Protocols/ProtocolDelegate.swift
0 → 100644
TheButler/Protocols/Reusable + Cell.swift
0 → 100644
| 1 | +// | |
| 2 | +// Reusable + Cell.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 19.06.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import Foundation | |
| 9 | +import UIKit | |
| 10 | + | |
| 11 | +protocol Reusable: AnyObject { | |
| 12 | + static var reuseIdentifier: String { get } | |
| 13 | +} | |
| 14 | + | |
| 15 | +extension Reusable { | |
| 16 | + static var reuseIdentifier: String { | |
| 17 | + return String(describing: Self.self) | |
| 18 | + } | |
| 19 | +} | |
| 20 | + | |
| 21 | +// swiftlint:disable force_cast | |
| 22 | + | |
| 23 | +extension UICollectionView { | |
| 24 | + func registerReusableCell<T: UICollectionViewCell>(_: T.Type) where T: Reusable { | |
| 25 | + self.register(T.self, forCellWithReuseIdentifier: T.reuseIdentifier) | |
| 26 | + } | |
| 27 | + | |
| 28 | + func dequeueReusableCell<T: UICollectionViewCell>(for indexPath: IndexPath) -> T where T: Reusable { | |
| 29 | + return self.dequeueReusableCell(withReuseIdentifier: T.reuseIdentifier, for: indexPath) as! T | |
| 30 | + } | |
| 31 | + | |
| 32 | + func registerReusableSupplementaryView<T: UICollectionReusableView>(elementKind: String, _: T.Type) where T: Reusable { | |
| 33 | + self.register(T.self, forSupplementaryViewOfKind: elementKind, withReuseIdentifier: T.reuseIdentifier) | |
| 34 | + } | |
| 35 | + | |
| 36 | + func dequeueReusableSupplementaryView<T: UICollectionReusableView>(ofKind elementKind: String, for indexPath: IndexPath) -> T where T: Reusable { | |
| 37 | + return self.dequeueReusableSupplementaryView(ofKind: elementKind, withReuseIdentifier: T.reuseIdentifier, for: indexPath) as! T | |
| 38 | + } | |
| 39 | +} | |
| 40 | + | |
| 41 | +extension UITableView { | |
| 42 | + func registerReusableCell<T: UITableViewCell>(_: T.Type) where T: Reusable { | |
| 43 | + self.register(T.self, forCellReuseIdentifier: T.reuseIdentifier) | |
| 44 | + } | |
| 45 | + | |
| 46 | + func registerReusableView<T: UITableViewHeaderFooterView>(_: T.Type) where T: Reusable { | |
| 47 | + self.register(T.self, forHeaderFooterViewReuseIdentifier: T.reuseIdentifier) | |
| 48 | + } | |
| 49 | + | |
| 50 | + func dequeueReusableCell<T: UITableViewCell>(for indexPath: IndexPath) -> T where T: Reusable { | |
| 51 | + return self.dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as! T | |
| 52 | + } | |
| 53 | + | |
| 54 | + func dequeueReusableView<T: UITableViewHeaderFooterView>() -> T where T: Reusable { | |
| 55 | + return self.dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as! T | |
| 56 | + } | |
| 57 | +} | |
| 58 | + | ... | ... |
TheButler/SceneDelegate.swift
0 → 100644
| 1 | +// | |
| 2 | +// SceneDelegate.swift | |
| 3 | +// InterQR-Internship | |
| 4 | +// | |
| 5 | +// Created by Дмитрий Тимофеев on 30.05.2022. | |
| 6 | +// | |
| 7 | + | |
| 8 | +import UIKit | |
| 9 | +import SnapKit | |
| 10 | + | |
| 11 | +class SceneDelegate: UIResponder, UIWindowSceneDelegate { | |
| 12 | + | |
| 13 | + var window: UIWindow? | |
| 14 | + | |
| 15 | + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { | |
| 16 | + | |
| 17 | + guard let windowScene = (scene as? UIWindowScene) else { return } | |
| 18 | + window = UIWindow(windowScene: windowScene) | |
| 19 | + let viewController = VerificationViewController() | |
| 20 | + let homeVC = HomeViewController() | |
| 21 | + let residentVC = ResidentsViewController() | |
| 22 | + let navigation = UINavigationController(rootViewController: viewController) | |
| 23 | + navigation.isNavigationBarHidden = true | |
| 24 | + window?.rootViewController = navigation | |
| 25 | + window?.makeKeyAndVisible() | |
| 26 | + } | |
| 27 | +} | |
| 28 | + | ... | ... |
TheButler/uk.lproj/LaunchScreen.strings
0 → 100644
| 1 | + | ... | ... |
Please
register
or
login
to post a comment