├── sample.gif
├── HoldRecordButton
├── Assets.xcassets
│ ├── Contents.json
│ ├── left_arrow.imageset
│ │ ├── chevron-left.png
│ │ └── Contents.json
│ ├── microphone.imageset
│ │ ├── microphone (1).png
│ │ └── Contents.json
│ ├── microphone_button.imageset
│ │ ├── microphone.png
│ │ └── Contents.json
│ ├── send_button.imageset
│ │ ├── baseline_send_white_24pt_1x.png
│ │ ├── baseline_send_white_24pt_2x.png
│ │ ├── baseline_send_white_24pt_3x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
└── ViewController.swift
├── README.md
└── HoldRecordButton.xcodeproj
├── xcuserdata
└── matheusfroes.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ └── xcschememanagement.plist
├── project.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── project.pbxproj
/sample.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froesmatheus/hold-to-record-button-ios/HEAD/sample.gif
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hold to record button for iOS
2 |
3 | 
4 |
--------------------------------------------------------------------------------
/HoldRecordButton.xcodeproj/xcuserdata/matheusfroes.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/left_arrow.imageset/chevron-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froesmatheus/hold-to-record-button-ios/HEAD/HoldRecordButton/Assets.xcassets/left_arrow.imageset/chevron-left.png
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/microphone.imageset/microphone (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froesmatheus/hold-to-record-button-ios/HEAD/HoldRecordButton/Assets.xcassets/microphone.imageset/microphone (1).png
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/microphone_button.imageset/microphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froesmatheus/hold-to-record-button-ios/HEAD/HoldRecordButton/Assets.xcassets/microphone_button.imageset/microphone.png
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/send_button.imageset/baseline_send_white_24pt_1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froesmatheus/hold-to-record-button-ios/HEAD/HoldRecordButton/Assets.xcassets/send_button.imageset/baseline_send_white_24pt_1x.png
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/send_button.imageset/baseline_send_white_24pt_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froesmatheus/hold-to-record-button-ios/HEAD/HoldRecordButton/Assets.xcassets/send_button.imageset/baseline_send_white_24pt_2x.png
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/send_button.imageset/baseline_send_white_24pt_3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froesmatheus/hold-to-record-button-ios/HEAD/HoldRecordButton/Assets.xcassets/send_button.imageset/baseline_send_white_24pt_3x.png
--------------------------------------------------------------------------------
/HoldRecordButton.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/HoldRecordButton.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/left_arrow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "chevron-left.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/microphone.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "microphone (1).png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/microphone_button.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "microphone.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/HoldRecordButton.xcodeproj/xcuserdata/matheusfroes.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | HoldRecordButton.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/HoldRecordButton/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // HoldRecordButton
4 | //
5 | // Created by Matheus Fróes on 08/05/19.
6 | // Copyright © 2019 Matheus Fróes. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | return true
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/send_button.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "baseline_send_white_24pt_1x.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "baseline_send_white_24pt_2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "baseline_send_white_24pt_3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
--------------------------------------------------------------------------------
/HoldRecordButton/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSMicrophoneUsageDescription
6 | Microphone
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/HoldRecordButton/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/HoldRecordButton/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/HoldRecordButton/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // HoldRecordButton
4 | //
5 | // Created by Matheus Fróes on 08/05/19.
6 | // Copyright © 2019 Matheus Fróes. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AVFoundation
11 |
12 | class ViewController: UIViewController {
13 | @IBOutlet private var textField: UITextField!
14 | @IBOutlet private var sendButton: UIButton!
15 | @IBOutlet private var viewAudioTimer: UIView!
16 | @IBOutlet private var slideToCancelView: UIStackView!
17 | @IBOutlet private var sendButtonLongPressGesture: UILongPressGestureRecognizer!
18 | @IBOutlet private var sendButtonPanGesture: UIPanGestureRecognizer!
19 | @IBOutlet private var sendButtonWidthConstraint: NSLayoutConstraint!
20 | @IBOutlet private var sendButtonHeightConstraint: NSLayoutConstraint!
21 | @IBOutlet private var sendButtonTrailingConstraint: NSLayoutConstraint!
22 | @IBOutlet private var ivAudioMic: UIImageView!
23 | @IBOutlet private var lbAudioTimer: UILabel!
24 | @IBOutlet private var containerViewBottomConstraint: NSLayoutConstraint!
25 |
26 | private var audioDurationInSecs = 0
27 | private var audioTimer: Timer?
28 | private var recordingSession: AVAudioSession!
29 | private var audioRecorder: AVAudioRecorder!
30 | private var audioFilename = ""
31 | private var audioPlayer: AVPlayer!
32 |
33 | override func viewDidLoad() {
34 | super.viewDidLoad()
35 |
36 | registerKeyboardNotifications()
37 |
38 | // Setting up AudioSession
39 | recordingSession = AVAudioSession.sharedInstance()
40 | AVAudioSession.sharedInstance().requestRecordPermission { (hasPermission) in
41 | if hasPermission {}
42 | }
43 |
44 | sendButtonLongPressGesture.delegate = self
45 |
46 | textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
47 |
48 | textField.placeholder = "Type a message"
49 | sendButton.backgroundColor = .blue
50 | }
51 |
52 | private func registerKeyboardNotifications() {
53 | NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { [weak self] notification in
54 | if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
55 | let keyboardRectangle = keyboardFrame.cgRectValue
56 | let keyboardHeight = keyboardRectangle.height
57 | self?.containerViewBottomConstraint.constant = keyboardHeight
58 | self?.view.layoutIfNeeded()
59 | }
60 | }
61 |
62 | NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: nil) { [weak self] _ in
63 | self?.containerViewBottomConstraint.constant = 0
64 | self?.view.layoutIfNeeded()
65 | }
66 | }
67 |
68 | @objc private func textFieldDidChange() {
69 | let mensagem = textField.text ?? ""
70 | if mensagem.isEmpty {
71 | sendButton.setImage(UIImage(named: "microphone_button"), for: .normal)
72 | sendButtonLongPressGesture.isEnabled = true
73 | sendButtonPanGesture.isEnabled = true
74 | } else {
75 | sendButton.setImage(UIImage(named: "send_button"), for: .normal)
76 | sendButtonLongPressGesture.isEnabled = false
77 | sendButtonPanGesture.isEnabled = false
78 | }
79 | }
80 |
81 | deinit {
82 | NotificationCenter.default.removeObserver(self)
83 | }
84 | }
85 |
86 | // MARK: Send button long press gesture delegate
87 | extension ViewController : UIGestureRecognizerDelegate {
88 |
89 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
90 | return (gestureRecognizer == sendButtonLongPressGesture && otherGestureRecognizer == sendButtonPanGesture)
91 | }
92 | }
93 |
94 | // MARK: Audio recorder delegate
95 | extension ViewController : AVAudioRecorderDelegate {
96 | private func updateInterface(recording: Bool) {
97 | UIView.animate(withDuration: 0.3, animations: {
98 | if recording {
99 | self.sendButtonWidthConstraint.constant = 45
100 | self.sendButtonHeightConstraint.constant = 45
101 | self.view.layoutIfNeeded()
102 | self.sendButton.layer.cornerRadius = 22.5
103 | } else {
104 | self.sendButtonWidthConstraint.constant = 35
105 | self.sendButtonHeightConstraint.constant = 35
106 | self.view.layoutIfNeeded()
107 | self.sendButton.layer.cornerRadius = 17.5
108 | }
109 |
110 | self.viewAudioTimer.isHidden = !recording
111 | self.slideToCancelView.isHidden = !recording
112 |
113 | self.textField.isHidden = recording
114 | })
115 | }
116 |
117 | @IBAction private func sendButtonLongPress(_ sender: UILongPressGestureRecognizer) {
118 | if sender.state == .began { // Send button is being pressed, start recording
119 | updateInterface(recording: true)
120 | startAudioTimer()
121 | startRecording()
122 | } else if sender.state == .ended { // Send button was released, stop recording
123 | updateInterface(recording: false)
124 | stopRecording()
125 | sendAudio()
126 | stopAudioTimer()
127 | } else if sender.state == .cancelled { // Send button long press gesture was cancelled, cancel recording
128 | stopAudioTimer()
129 | cancelRecording()
130 | updateInterface(recording: false)
131 | }
132 | }
133 |
134 | @IBAction private func sendButtonPanGesture(_ sender: UIPanGestureRecognizer) {
135 | let translation = sender.translation(in: self.view)
136 |
137 | // Enable pan gesture only if the send button is being pressed
138 | if sender.view != nil && sendButtonLongPressGesture.state == .changed {
139 | sendButtonTrailingConstraint.constant = sendButtonTrailingConstraint.constant - translation.x
140 |
141 | let percentage = 100 * (sendButtonTrailingConstraint.constant / self.view.frame.width)
142 |
143 | if percentage > 30 {
144 | stopAudioTimer()
145 | }
146 | }
147 |
148 | sender.setTranslation(.zero, in: self.view)
149 | }
150 |
151 | private func stopAudioTimer() {
152 | if audioTimer != nil {
153 | sendButtonLongPressGesture.isEnabled = false
154 | sendButtonPanGesture.isEnabled = false
155 |
156 | UIView.animate(withDuration: 1, animations: {
157 | self.sendButtonTrailingConstraint.constant = 5
158 | })
159 |
160 | audioTimer?.invalidate()
161 | audioDurationInSecs = 0
162 | lbAudioTimer.text = "0:00"
163 | audioTimer = nil
164 |
165 | sendButtonPanGesture.isEnabled = true
166 | sendButtonLongPressGesture.isEnabled = true
167 | }
168 | }
169 |
170 | private func startAudioTimer() {
171 | audioTimer = Timer.scheduledTimer(
172 | timeInterval: 1,
173 | target: self,
174 | selector: #selector(updateAudioTimer),
175 | userInfo: nil,
176 | repeats: true)
177 | }
178 |
179 | @objc private func updateAudioTimer() {
180 | audioDurationInSecs += 1
181 | let minutes = Int(floor(Double(audioDurationInSecs / 60)))
182 |
183 | UIView.animate(withDuration: 0.3) {
184 | let alpha = self.ivAudioMic.alpha
185 |
186 | self.ivAudioMic.alpha = alpha == 0 ? 1 : 0
187 | }
188 |
189 | lbAudioTimer.text = "\(minutes):\(String(format: "%02d", audioDurationInSecs % 60))"
190 | }
191 |
192 | private func startRecording() {
193 | if audioRecorder == nil {
194 | audioFilename = UUID().uuidString
195 | let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
196 | let documentDirectory = paths[0]
197 | let filename = documentDirectory.appendingPathComponent("\(audioFilename).m4a")
198 |
199 | let settings = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 12000, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.medium.rawValue]
200 |
201 | do {
202 | audioRecorder = try AVAudioRecorder(url: filename, settings: settings)
203 | audioRecorder.delegate = self
204 |
205 | let recording = audioRecorder.record()
206 | print("Recording audio = \(recording)")
207 | } catch {
208 | print(error)
209 | }
210 | }
211 | }
212 |
213 | private func stopRecording() {
214 | print("Stopped recording...")
215 | audioRecorder.stop()
216 | audioRecorder = nil
217 | }
218 |
219 | private func cancelRecording() {
220 | stopRecording()
221 |
222 | let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
223 | let documentDirectory = paths[0]
224 | let url = documentDirectory.appendingPathComponent("\(audioFilename).m4a")
225 |
226 | do {
227 | print("Removing audio -> \(audioFilename).m4a")
228 | try FileManager.default.removeItem(at: url)
229 | } catch {
230 | print(error)
231 | }
232 | }
233 |
234 | private func sendAudio() {
235 | let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
236 | let documentDirectory = paths[0]
237 | _ = documentDirectory.appendingPathComponent("\(audioFilename).m4a")
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/HoldRecordButton.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | CEC1FC3022832FC300863961 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC1FC2F22832FC300863961 /* AppDelegate.swift */; };
11 | CEC1FC3222832FC300863961 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC1FC3122832FC300863961 /* ViewController.swift */; };
12 | CEC1FC3522832FC300863961 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CEC1FC3322832FC300863961 /* Main.storyboard */; };
13 | CEC1FC3722832FC400863961 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEC1FC3622832FC400863961 /* Assets.xcassets */; };
14 | CEC1FC3A22832FC400863961 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CEC1FC3822832FC400863961 /* LaunchScreen.storyboard */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXFileReference section */
18 | CEC1FC2C22832FC300863961 /* HoldRecordButton.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HoldRecordButton.app; sourceTree = BUILT_PRODUCTS_DIR; };
19 | CEC1FC2F22832FC300863961 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
20 | CEC1FC3122832FC300863961 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
21 | CEC1FC3422832FC300863961 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
22 | CEC1FC3622832FC400863961 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23 | CEC1FC3922832FC400863961 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
24 | CEC1FC3B22832FC400863961 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
25 | /* End PBXFileReference section */
26 |
27 | /* Begin PBXFrameworksBuildPhase section */
28 | CEC1FC2922832FC300863961 /* Frameworks */ = {
29 | isa = PBXFrameworksBuildPhase;
30 | buildActionMask = 2147483647;
31 | files = (
32 | );
33 | runOnlyForDeploymentPostprocessing = 0;
34 | };
35 | /* End PBXFrameworksBuildPhase section */
36 |
37 | /* Begin PBXGroup section */
38 | CEC1FC2322832FC300863961 = {
39 | isa = PBXGroup;
40 | children = (
41 | CEC1FC2E22832FC300863961 /* HoldRecordButton */,
42 | CEC1FC2D22832FC300863961 /* Products */,
43 | );
44 | sourceTree = "";
45 | };
46 | CEC1FC2D22832FC300863961 /* Products */ = {
47 | isa = PBXGroup;
48 | children = (
49 | CEC1FC2C22832FC300863961 /* HoldRecordButton.app */,
50 | );
51 | name = Products;
52 | sourceTree = "";
53 | };
54 | CEC1FC2E22832FC300863961 /* HoldRecordButton */ = {
55 | isa = PBXGroup;
56 | children = (
57 | CEC1FC2F22832FC300863961 /* AppDelegate.swift */,
58 | CEC1FC3122832FC300863961 /* ViewController.swift */,
59 | CEC1FC3322832FC300863961 /* Main.storyboard */,
60 | CEC1FC3622832FC400863961 /* Assets.xcassets */,
61 | CEC1FC3822832FC400863961 /* LaunchScreen.storyboard */,
62 | CEC1FC3B22832FC400863961 /* Info.plist */,
63 | );
64 | path = HoldRecordButton;
65 | sourceTree = "";
66 | };
67 | /* End PBXGroup section */
68 |
69 | /* Begin PBXNativeTarget section */
70 | CEC1FC2B22832FC300863961 /* HoldRecordButton */ = {
71 | isa = PBXNativeTarget;
72 | buildConfigurationList = CEC1FC3E22832FC400863961 /* Build configuration list for PBXNativeTarget "HoldRecordButton" */;
73 | buildPhases = (
74 | CEC1FC2822832FC300863961 /* Sources */,
75 | CEC1FC2922832FC300863961 /* Frameworks */,
76 | CEC1FC2A22832FC300863961 /* Resources */,
77 | );
78 | buildRules = (
79 | );
80 | dependencies = (
81 | );
82 | name = HoldRecordButton;
83 | productName = HoldRecordButton;
84 | productReference = CEC1FC2C22832FC300863961 /* HoldRecordButton.app */;
85 | productType = "com.apple.product-type.application";
86 | };
87 | /* End PBXNativeTarget section */
88 |
89 | /* Begin PBXProject section */
90 | CEC1FC2422832FC300863961 /* Project object */ = {
91 | isa = PBXProject;
92 | attributes = {
93 | LastSwiftUpdateCheck = 1010;
94 | LastUpgradeCheck = 1010;
95 | ORGANIZATIONNAME = "Matheus Fróes";
96 | TargetAttributes = {
97 | CEC1FC2B22832FC300863961 = {
98 | CreatedOnToolsVersion = 10.1;
99 | };
100 | };
101 | };
102 | buildConfigurationList = CEC1FC2722832FC300863961 /* Build configuration list for PBXProject "HoldRecordButton" */;
103 | compatibilityVersion = "Xcode 9.3";
104 | developmentRegion = en;
105 | hasScannedForEncodings = 0;
106 | knownRegions = (
107 | en,
108 | Base,
109 | );
110 | mainGroup = CEC1FC2322832FC300863961;
111 | productRefGroup = CEC1FC2D22832FC300863961 /* Products */;
112 | projectDirPath = "";
113 | projectRoot = "";
114 | targets = (
115 | CEC1FC2B22832FC300863961 /* HoldRecordButton */,
116 | );
117 | };
118 | /* End PBXProject section */
119 |
120 | /* Begin PBXResourcesBuildPhase section */
121 | CEC1FC2A22832FC300863961 /* Resources */ = {
122 | isa = PBXResourcesBuildPhase;
123 | buildActionMask = 2147483647;
124 | files = (
125 | CEC1FC3A22832FC400863961 /* LaunchScreen.storyboard in Resources */,
126 | CEC1FC3722832FC400863961 /* Assets.xcassets in Resources */,
127 | CEC1FC3522832FC300863961 /* Main.storyboard in Resources */,
128 | );
129 | runOnlyForDeploymentPostprocessing = 0;
130 | };
131 | /* End PBXResourcesBuildPhase section */
132 |
133 | /* Begin PBXSourcesBuildPhase section */
134 | CEC1FC2822832FC300863961 /* Sources */ = {
135 | isa = PBXSourcesBuildPhase;
136 | buildActionMask = 2147483647;
137 | files = (
138 | CEC1FC3222832FC300863961 /* ViewController.swift in Sources */,
139 | CEC1FC3022832FC300863961 /* AppDelegate.swift in Sources */,
140 | );
141 | runOnlyForDeploymentPostprocessing = 0;
142 | };
143 | /* End PBXSourcesBuildPhase section */
144 |
145 | /* Begin PBXVariantGroup section */
146 | CEC1FC3322832FC300863961 /* Main.storyboard */ = {
147 | isa = PBXVariantGroup;
148 | children = (
149 | CEC1FC3422832FC300863961 /* Base */,
150 | );
151 | name = Main.storyboard;
152 | sourceTree = "";
153 | };
154 | CEC1FC3822832FC400863961 /* LaunchScreen.storyboard */ = {
155 | isa = PBXVariantGroup;
156 | children = (
157 | CEC1FC3922832FC400863961 /* Base */,
158 | );
159 | name = LaunchScreen.storyboard;
160 | sourceTree = "";
161 | };
162 | /* End PBXVariantGroup section */
163 |
164 | /* Begin XCBuildConfiguration section */
165 | CEC1FC3C22832FC400863961 /* Debug */ = {
166 | isa = XCBuildConfiguration;
167 | buildSettings = {
168 | ALWAYS_SEARCH_USER_PATHS = NO;
169 | CLANG_ANALYZER_NONNULL = YES;
170 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
171 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
172 | CLANG_CXX_LIBRARY = "libc++";
173 | CLANG_ENABLE_MODULES = YES;
174 | CLANG_ENABLE_OBJC_ARC = YES;
175 | CLANG_ENABLE_OBJC_WEAK = YES;
176 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
177 | CLANG_WARN_BOOL_CONVERSION = YES;
178 | CLANG_WARN_COMMA = YES;
179 | CLANG_WARN_CONSTANT_CONVERSION = YES;
180 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
181 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
182 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
183 | CLANG_WARN_EMPTY_BODY = YES;
184 | CLANG_WARN_ENUM_CONVERSION = YES;
185 | CLANG_WARN_INFINITE_RECURSION = YES;
186 | CLANG_WARN_INT_CONVERSION = YES;
187 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
188 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
189 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
190 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
191 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
192 | CLANG_WARN_STRICT_PROTOTYPES = YES;
193 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
194 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
195 | CLANG_WARN_UNREACHABLE_CODE = YES;
196 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
197 | CODE_SIGN_IDENTITY = "iPhone Developer";
198 | COPY_PHASE_STRIP = NO;
199 | DEBUG_INFORMATION_FORMAT = dwarf;
200 | ENABLE_STRICT_OBJC_MSGSEND = YES;
201 | ENABLE_TESTABILITY = YES;
202 | GCC_C_LANGUAGE_STANDARD = gnu11;
203 | GCC_DYNAMIC_NO_PIC = NO;
204 | GCC_NO_COMMON_BLOCKS = YES;
205 | GCC_OPTIMIZATION_LEVEL = 0;
206 | GCC_PREPROCESSOR_DEFINITIONS = (
207 | "DEBUG=1",
208 | "$(inherited)",
209 | );
210 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
211 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
212 | GCC_WARN_UNDECLARED_SELECTOR = YES;
213 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
214 | GCC_WARN_UNUSED_FUNCTION = YES;
215 | GCC_WARN_UNUSED_VARIABLE = YES;
216 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
217 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
218 | MTL_FAST_MATH = YES;
219 | ONLY_ACTIVE_ARCH = YES;
220 | SDKROOT = iphoneos;
221 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
222 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
223 | };
224 | name = Debug;
225 | };
226 | CEC1FC3D22832FC400863961 /* Release */ = {
227 | isa = XCBuildConfiguration;
228 | buildSettings = {
229 | ALWAYS_SEARCH_USER_PATHS = NO;
230 | CLANG_ANALYZER_NONNULL = YES;
231 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
232 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
233 | CLANG_CXX_LIBRARY = "libc++";
234 | CLANG_ENABLE_MODULES = YES;
235 | CLANG_ENABLE_OBJC_ARC = YES;
236 | CLANG_ENABLE_OBJC_WEAK = YES;
237 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
238 | CLANG_WARN_BOOL_CONVERSION = YES;
239 | CLANG_WARN_COMMA = YES;
240 | CLANG_WARN_CONSTANT_CONVERSION = YES;
241 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
243 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
244 | CLANG_WARN_EMPTY_BODY = YES;
245 | CLANG_WARN_ENUM_CONVERSION = YES;
246 | CLANG_WARN_INFINITE_RECURSION = YES;
247 | CLANG_WARN_INT_CONVERSION = YES;
248 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
249 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
250 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
252 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
253 | CLANG_WARN_STRICT_PROTOTYPES = YES;
254 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
255 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
256 | CLANG_WARN_UNREACHABLE_CODE = YES;
257 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
258 | CODE_SIGN_IDENTITY = "iPhone Developer";
259 | COPY_PHASE_STRIP = NO;
260 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
261 | ENABLE_NS_ASSERTIONS = NO;
262 | ENABLE_STRICT_OBJC_MSGSEND = YES;
263 | GCC_C_LANGUAGE_STANDARD = gnu11;
264 | GCC_NO_COMMON_BLOCKS = YES;
265 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
266 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
267 | GCC_WARN_UNDECLARED_SELECTOR = YES;
268 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
269 | GCC_WARN_UNUSED_FUNCTION = YES;
270 | GCC_WARN_UNUSED_VARIABLE = YES;
271 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
272 | MTL_ENABLE_DEBUG_INFO = NO;
273 | MTL_FAST_MATH = YES;
274 | SDKROOT = iphoneos;
275 | SWIFT_COMPILATION_MODE = wholemodule;
276 | SWIFT_OPTIMIZATION_LEVEL = "-O";
277 | VALIDATE_PRODUCT = YES;
278 | };
279 | name = Release;
280 | };
281 | CEC1FC3F22832FC400863961 /* Debug */ = {
282 | isa = XCBuildConfiguration;
283 | buildSettings = {
284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
285 | CODE_SIGN_STYLE = Automatic;
286 | INFOPLIST_FILE = HoldRecordButton/Info.plist;
287 | LD_RUNPATH_SEARCH_PATHS = (
288 | "$(inherited)",
289 | "@executable_path/Frameworks",
290 | );
291 | PRODUCT_BUNDLE_IDENTIFIER = teste.HoldRecordButton;
292 | PRODUCT_NAME = "$(TARGET_NAME)";
293 | SWIFT_VERSION = 4.2;
294 | TARGETED_DEVICE_FAMILY = "1,2";
295 | };
296 | name = Debug;
297 | };
298 | CEC1FC4022832FC400863961 /* Release */ = {
299 | isa = XCBuildConfiguration;
300 | buildSettings = {
301 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
302 | CODE_SIGN_STYLE = Automatic;
303 | INFOPLIST_FILE = HoldRecordButton/Info.plist;
304 | LD_RUNPATH_SEARCH_PATHS = (
305 | "$(inherited)",
306 | "@executable_path/Frameworks",
307 | );
308 | PRODUCT_BUNDLE_IDENTIFIER = teste.HoldRecordButton;
309 | PRODUCT_NAME = "$(TARGET_NAME)";
310 | SWIFT_VERSION = 4.2;
311 | TARGETED_DEVICE_FAMILY = "1,2";
312 | };
313 | name = Release;
314 | };
315 | /* End XCBuildConfiguration section */
316 |
317 | /* Begin XCConfigurationList section */
318 | CEC1FC2722832FC300863961 /* Build configuration list for PBXProject "HoldRecordButton" */ = {
319 | isa = XCConfigurationList;
320 | buildConfigurations = (
321 | CEC1FC3C22832FC400863961 /* Debug */,
322 | CEC1FC3D22832FC400863961 /* Release */,
323 | );
324 | defaultConfigurationIsVisible = 0;
325 | defaultConfigurationName = Release;
326 | };
327 | CEC1FC3E22832FC400863961 /* Build configuration list for PBXNativeTarget "HoldRecordButton" */ = {
328 | isa = XCConfigurationList;
329 | buildConfigurations = (
330 | CEC1FC3F22832FC400863961 /* Debug */,
331 | CEC1FC4022832FC400863961 /* Release */,
332 | );
333 | defaultConfigurationIsVisible = 0;
334 | defaultConfigurationName = Release;
335 | };
336 | /* End XCConfigurationList section */
337 | };
338 | rootObject = CEC1FC2422832FC300863961 /* Project object */;
339 | }
340 |
--------------------------------------------------------------------------------
/HoldRecordButton/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------