Skip to content

Commit 2dd48c4

Browse files
authored
Merge pull request #27 from Capstone-Projects-2023-Spring/iOSMessagingViaTwilio
iOS automatic calling/messaging via twilio MERGE
2 parents 3e87e90 + a3c5544 commit 2dd48c4

File tree

17 files changed

+507
-129
lines changed

17 files changed

+507
-129
lines changed

iosApp/VC.xcodeproj/project.pbxproj

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
920C054229C69CD400009395 /* BluetoothManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920C054129C69CD400009395 /* BluetoothManager.swift */; };
11+
92692B5129D9CE7A001B215D /* CountdownViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92692B5029D9CE7A001B215D /* CountdownViewController.swift */; };
1112
D88E9AAB298AFE0A00EB1305 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AAA298AFE0A00EB1305 /* AppDelegate.swift */; };
1213
D88E9AAD298AFE0A00EB1305 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AAC298AFE0A00EB1305 /* SceneDelegate.swift */; };
1314
D88E9AAF298AFE0A00EB1305 /* VCTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AAE298AFE0A00EB1305 /* VCTabBarController.swift */; };
@@ -17,7 +18,7 @@
1718
D88E9ACF298AFE1000EB1305 /* VCUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9ACE298AFE1000EB1305 /* VCUITests.swift */; };
1819
D88E9AD1298AFE1000EB1305 /* VCUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AD0298AFE1000EB1305 /* VCUITestsLaunchTests.swift */; };
1920
D88E9AE1298B05FA00EB1305 /* VCHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AE0298B05FA00EB1305 /* VCHomeViewController.swift */; };
20-
D88E9AE3298B060C00EB1305 /* VCSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AE2298B060C00EB1305 /* VCSettingViewController.swift */; };
21+
D88E9AE3298B060C00EB1305 /* VCTestingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AE2298B060C00EB1305 /* VCTestingViewController.swift */; };
2122
D88E9AE5298B073200EB1305 /* VCContactsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88E9AE4298B073200EB1305 /* VCContactsViewController.swift */; };
2223
D8EEC46429B011CA006FE065 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = D8EEC46229B011CA006FE065 /* Model.xcdatamodeld */; };
2324
D8EEC46A29B013D6006FE065 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8EEC46929B013D6006FE065 /* CoreDataStack.swift */; };
@@ -44,6 +45,7 @@
4445

4546
/* Begin PBXFileReference section */
4647
920C054129C69CD400009395 /* BluetoothManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothManager.swift; sourceTree = "<group>"; };
48+
92692B5029D9CE7A001B215D /* CountdownViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountdownViewController.swift; sourceTree = "<group>"; };
4749
D88E9AA7298AFE0A00EB1305 /* VC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VC.app; sourceTree = BUILT_PRODUCTS_DIR; };
4850
D88E9AAA298AFE0A00EB1305 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4951
D88E9AAC298AFE0A00EB1305 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
@@ -57,7 +59,7 @@
5759
D88E9ACE298AFE1000EB1305 /* VCUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCUITests.swift; sourceTree = "<group>"; };
5860
D88E9AD0298AFE1000EB1305 /* VCUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCUITestsLaunchTests.swift; sourceTree = "<group>"; };
5961
D88E9AE0298B05FA00EB1305 /* VCHomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCHomeViewController.swift; sourceTree = "<group>"; };
60-
D88E9AE2298B060C00EB1305 /* VCSettingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCSettingViewController.swift; sourceTree = "<group>"; };
62+
D88E9AE2298B060C00EB1305 /* VCTestingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCTestingViewController.swift; sourceTree = "<group>"; };
6163
D88E9AE4298B073200EB1305 /* VCContactsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCContactsViewController.swift; sourceTree = "<group>"; };
6264
D8EEC46329B011CA006FE065 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; };
6365
D8EEC46929B013D6006FE065 /* CoreDataStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataStack.swift; sourceTree = "<group>"; };
@@ -161,11 +163,12 @@
161163
D88E9ADF298B05A600EB1305 /* Core */ = {
162164
isa = PBXGroup;
163165
children = (
164-
D88E9AAE298AFE0A00EB1305 /* VCTabBarController.swift */,
165166
D88E9AE0298B05FA00EB1305 /* VCHomeViewController.swift */,
166167
D88E9AE4298B073200EB1305 /* VCContactsViewController.swift */,
167-
D88E9AE2298B060C00EB1305 /* VCSettingViewController.swift */,
168+
D88E9AE2298B060C00EB1305 /* VCTestingViewController.swift */,
169+
D88E9AAE298AFE0A00EB1305 /* VCTabBarController.swift */,
168170
920C054129C69CD400009395 /* BluetoothManager.swift */,
171+
92692B5029D9CE7A001B215D /* CountdownViewController.swift */,
169172
);
170173
name = Core;
171174
sourceTree = "<group>";
@@ -196,6 +199,8 @@
196199
dependencies = (
197200
);
198201
name = VC;
202+
packageProductDependencies = (
203+
);
199204
productName = VC;
200205
productReference = D88E9AA7298AFE0A00EB1305 /* VC.app */;
201206
productType = "com.apple.product-type.application";
@@ -268,6 +273,8 @@
268273
Base,
269274
);
270275
mainGroup = D88E9A9E298AFE0A00EB1305;
276+
packageReferences = (
277+
);
271278
productRefGroup = D88E9AA8298AFE0A00EB1305 /* Products */;
272279
projectDirPath = "";
273280
projectRoot = "";
@@ -310,7 +317,8 @@
310317
isa = PBXSourcesBuildPhase;
311318
buildActionMask = 2147483647;
312319
files = (
313-
D88E9AE3298B060C00EB1305 /* VCSettingViewController.swift in Sources */,
320+
92692B5129D9CE7A001B215D /* CountdownViewController.swift in Sources */,
321+
D88E9AE3298B060C00EB1305 /* VCTestingViewController.swift in Sources */,
314322
D88E9AE5298B073200EB1305 /* VCContactsViewController.swift in Sources */,
315323
D88E9AE1298B05FA00EB1305 /* VCHomeViewController.swift in Sources */,
316324
D8EEC46A29B013D6006FE065 /* CoreDataStack.swift in Sources */,
@@ -418,10 +426,12 @@
418426
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
419427
GCC_WARN_UNUSED_FUNCTION = YES;
420428
GCC_WARN_UNUSED_VARIABLE = YES;
429+
INFOPLIST_KEY_NSContactsUsageDescription = "";
421430
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
422431
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
423432
MTL_FAST_MATH = YES;
424433
ONLY_ACTIVE_ARCH = YES;
434+
OTHER_LDFLAGS = "";
425435
SDKROOT = iphoneos;
426436
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
427437
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -472,9 +482,11 @@
472482
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
473483
GCC_WARN_UNUSED_FUNCTION = YES;
474484
GCC_WARN_UNUSED_VARIABLE = YES;
485+
INFOPLIST_KEY_NSContactsUsageDescription = "";
475486
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
476487
MTL_ENABLE_DEBUG_INFO = NO;
477488
MTL_FAST_MATH = YES;
489+
OTHER_LDFLAGS = "";
478490
SDKROOT = iphoneos;
479491
SWIFT_COMPILATION_MODE = wholemodule;
480492
SWIFT_OPTIMIZATION_LEVEL = "-O";
@@ -494,21 +506,28 @@
494506
GENERATE_INFOPLIST_FILE = YES;
495507
INFOPLIST_FILE = VC/Info.plist;
496508
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "This app uses Bluetooth to connect to a peripheral device.";
509+
INFOPLIST_KEY_NSContactsUsageDescription = "This app uses contacts to retrieve user's contact information";
510+
INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "This app uses location to notify contacts with current location";
511+
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This app uses location to notify contacts with current location";
497512
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
498513
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
499514
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
500515
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
516+
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
501517
LD_RUNPATH_SEARCH_PATHS = (
502518
"$(inherited)",
503519
"@executable_path/Frameworks",
504520
);
505521
MARKETING_VERSION = 1.0;
506-
PRODUCT_BUNDLE_IDENTIFIER = VehicleCollision;
522+
PRODUCT_BUNDLE_IDENTIFIER = Temple.VC;
507523
PRODUCT_NAME = "$(TARGET_NAME)";
508524
PROVISIONING_PROFILE_SPECIFIER = "";
525+
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
526+
SUPPORTS_MACCATALYST = NO;
527+
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
509528
SWIFT_EMIT_LOC_STRINGS = YES;
510529
SWIFT_VERSION = 5.0;
511-
TARGETED_DEVICE_FAMILY = "1,2";
530+
TARGETED_DEVICE_FAMILY = 1;
512531
};
513532
name = Debug;
514533
};
@@ -524,21 +543,28 @@
524543
GENERATE_INFOPLIST_FILE = YES;
525544
INFOPLIST_FILE = VC/Info.plist;
526545
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "This app uses Bluetooth to connect to a peripheral device.";
546+
INFOPLIST_KEY_NSContactsUsageDescription = "This app uses contacts to retrieve user's contact information";
547+
INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "This app uses location to notify contacts with current location";
548+
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This app uses location to notify contacts with current location";
527549
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
528550
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
529551
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
530552
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
553+
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
531554
LD_RUNPATH_SEARCH_PATHS = (
532555
"$(inherited)",
533556
"@executable_path/Frameworks",
534557
);
535558
MARKETING_VERSION = 1.0;
536-
PRODUCT_BUNDLE_IDENTIFIER = VehicleCollision;
559+
PRODUCT_BUNDLE_IDENTIFIER = Temple.VC;
537560
PRODUCT_NAME = "$(TARGET_NAME)";
538561
PROVISIONING_PROFILE_SPECIFIER = "";
562+
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
563+
SUPPORTS_MACCATALYST = NO;
564+
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
539565
SWIFT_EMIT_LOC_STRINGS = YES;
540566
SWIFT_VERSION = 5.0;
541-
TARGETED_DEVICE_FAMILY = "1,2";
567+
TARGETED_DEVICE_FAMILY = 1;
542568
};
543569
name = Release;
544570
};

iosApp/VC/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

iosApp/VC/Controllers/BluetoothManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// BluetoothManager.swift
33
// VC
44
//
5-
// Created by Thanh Nguyen on 3/11/23.
5+
// Created/Modified by Thanh N & Nathan A.
66
//
77

88
import CoreBluetooth
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//
2+
// CountdownViewController.swift
3+
// VC
4+
//
5+
// Created/Modified by Thanh N & Nathan A.
6+
//
7+
8+
import Foundation
9+
import UIKit
10+
import SwiftUI
11+
12+
class CountdownViewController: UIViewController {
13+
14+
private var countdownTimer: Timer?
15+
public var cancelPressed = false
16+
public var notificationSent = false
17+
18+
override func viewDidLoad() {
19+
super.viewDidLoad()
20+
}
21+
22+
func showCountdownUI() {
23+
let countDownTitle = "Crash Detected!"
24+
let countDownMessage = "\nTo cancel automatic notifications, press 'Cancel'"
25+
let alertController = UIAlertController(title: countDownTitle, message: countDownMessage, preferredStyle: .alert)
26+
27+
// Change countDownTitle attributes
28+
if let titleString = countDownTitle as? NSString {
29+
let attributes: [NSAttributedString.Key: Any] = [
30+
.foregroundColor: UIColor(named: "CountDownColor") as Any,
31+
.font: UIFont.boldSystemFont(ofSize: 30)
32+
]
33+
let attributedTitle = NSAttributedString(string: titleString as String, attributes: attributes)
34+
alertController.setValue(attributedTitle, forKey: "attributedTitle")
35+
}
36+
37+
// Change countDownMessage color and font size
38+
if let messageString = countDownMessage as? NSString {
39+
let attributes = [
40+
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15)
41+
]
42+
let attributedMessage = NSAttributedString(string: messageString as String, attributes: attributes)
43+
alertController.setValue(attributedMessage, forKey: "attributedMessage")
44+
}
45+
46+
// Add text label
47+
let countDownTextLabel = UILabel()
48+
countDownTextLabel.font = UIFont.systemFont(ofSize: 16)
49+
countDownTextLabel.textAlignment = .center
50+
countDownTextLabel.text = "Time Until Emergency Alerts"
51+
alertController.view.addSubview(countDownTextLabel)
52+
countDownTextLabel.translatesAutoresizingMaskIntoConstraints = false
53+
countDownTextLabel.centerXAnchor.constraint(equalTo: alertController.view.centerXAnchor).isActive = true
54+
countDownTextLabel.bottomAnchor.constraint(equalTo: alertController.view.centerYAnchor, constant: 20).isActive = true
55+
56+
// Create the countdown label and add it to the alert controller
57+
let countDownLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
58+
countDownLabel.font = UIFont.systemFont(ofSize: 40)
59+
countDownLabel.textColor = UIColor(named: "CountDownColor")
60+
countDownLabel.textAlignment = .center
61+
countDownLabel.text = "10"
62+
alertController.view.addSubview(countDownLabel)
63+
countDownLabel.translatesAutoresizingMaskIntoConstraints = false
64+
countDownLabel.centerXAnchor.constraint(equalTo: alertController.view.centerXAnchor).isActive = true
65+
countDownLabel.centerYAnchor.constraint(equalTo: alertController.view.centerYAnchor, constant: 60).isActive = true
66+
67+
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { [weak self] _ in
68+
self?.cancelPressed = true
69+
self?.dismiss(animated: true, completion: nil)
70+
}
71+
alertController.addAction(cancelAction)
72+
73+
// Start the countdown timer
74+
var countdownSeconds = 10
75+
let countdownTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
76+
countdownSeconds -= 1
77+
countDownLabel.text = "\(countdownSeconds)"
78+
79+
// Change to text color to red
80+
if countdownSeconds <= 3 {
81+
if let titleString = countDownTitle as? NSString {
82+
let attributes: [NSAttributedString.Key: Any] = [
83+
.foregroundColor: UIColor.red,
84+
.font: UIFont.boldSystemFont(ofSize: 30)
85+
]
86+
let attributedTitle = NSAttributedString(string: titleString as String, attributes: attributes)
87+
alertController.setValue(attributedTitle, forKey: "attributedTitle")
88+
}
89+
countDownLabel.textColor = .red
90+
}
91+
92+
// Exit loop
93+
if self.cancelPressed {
94+
countdownSeconds = 0
95+
timer.invalidate()
96+
}
97+
98+
// Notify Emergency Contacts
99+
else if countdownSeconds == 0 {
100+
timer.invalidate()
101+
if !self.cancelPressed && !self.notificationSent {
102+
let vcContact = VCContactsViewController()
103+
vcContact.textMessageWithTwilio()
104+
vcContact.callWithTwilio()
105+
self.notificationSent = true
106+
}
107+
self.dismiss(animated: true, completion: nil)
108+
}
109+
}
110+
111+
// Store the countdown timer in a property so it can be invalidated if necessary
112+
self.countdownTimer = countdownTimer
113+
114+
115+
// Set the alert controller's height and width
116+
let height: NSLayoutConstraint = NSLayoutConstraint(item: alertController.view!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 350)
117+
let width:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view!, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 500)
118+
alertController.view.addConstraint(height)
119+
alertController.view.addConstraint(width)
120+
121+
// Present the alert controller
122+
present(alertController, animated: true, completion: nil)
123+
}
124+
}

0 commit comments

Comments
 (0)