Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(create-meeting): custom url for new meetings #137

Merged
merged 10 commits into from
Jan 15, 2021
10 changes: 6 additions & 4 deletions MeetingBar.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
40DC7053250E5E1000217DD9 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
40E60312250E81EA005986C7 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
E249D533259BBC3800429BF1 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
E2AE715525AA54A600D3C7CF /* DevTeamOverride.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DevTeamOverride.xcconfig; sourceTree = "<group>"; };
E4DD0F0A2529D0D20029E395 /* Project-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Project-Release.xcconfig"; sourceTree = "<group>"; };
E4DD0F0B2529D0D20029E395 /* Project.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Project.xcconfig; sourceTree = "<group>"; };
E4DD0F0C2529D0D20029E395 /* Project-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Project-Debug.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -229,6 +230,7 @@
E4DD0F092529D0D20029E395 /* XCConfig */ = {
isa = PBXGroup;
children = (
E2AE715525AA54A600D3C7CF /* DevTeamOverride.xcconfig */,
E4DD0F0B2529D0D20029E395 /* Project.xcconfig */,
E4DD0F0A2529D0D20029E395 /* Project-Release.xcconfig */,
E4DD0F0C2529D0D20029E395 /* Project-Debug.xcconfig */,
Expand Down Expand Up @@ -540,7 +542,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = MeetingBar/MeetingBar.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 108;
Expand All @@ -566,7 +568,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = MeetingBar/MeetingBar.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 108;
Expand All @@ -592,7 +594,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoLauncher/AutoLauncher.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -614,7 +616,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoLauncher/AutoLauncher.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
ENABLE_HARDENED_RUNTIME = YES;
Expand Down
19 changes: 17 additions & 2 deletions MeetingBar/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
}
}

/**
* implementation is necessary to show notifications even when the app has focus!
*/
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
completionHandler([.alert, .badge, .sound]) }

internal func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
switch response.actionIdentifier {
Expand Down Expand Up @@ -330,6 +332,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
openMeetingURL(nil, CreateMeetingLinks.outlook_office365)
case .outlook_live:
openMeetingURL(nil, CreateMeetingLinks.outlook_live)
case .url:
var url: String = Defaults[.createMeetingServiceUrl]
let checkedUrl = NSURL(string: url)

if !url.isEmpty && checkedUrl != nil {
openMeetingURL(nil, URL(string: url)!)
leits marked this conversation as resolved.
Show resolved Hide resolved
} else {
if !url.isEmpty {
url += " "
}

sendNotification("Cannot create new meeeting", "Custom url \(url)is missing or invalid. Please enter a value in the app preferences.")
}
}
}

Expand Down
1 change: 1 addition & 0 deletions MeetingBar/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ enum CreateMeetingServices: String, Codable, CaseIterable {
case gcalendar = "Google Calendar"
case outlook_live = "Outlook Live"
case outlook_office365 = "Outlook Office365"
case url = "Custom url"
}

enum Links {
Expand Down
4 changes: 4 additions & 0 deletions MeetingBar/Extensions/DefaultsKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ extension Defaults.Keys {

// Integrations
static let createMeetingService = Key<CreateMeetingServices>("createMeetingService", default: .zoom)

// custom url to create meetings
static let createMeetingServiceUrl = Key<String>("createMeetingServiceUrl", default: "")

static let useChromeForMeetLinks = Key<ChromeExecutable>("useChromeForMeetLinks", default: .defaultBrowser)
static let useChromeForHangoutsLinks = Key<ChromeExecutable>("useChromeForHangoutsLinks", default: .defaultBrowser)
static let useAppForZoomLinks = Key<Bool>("useAppForZoomLinks", default: false)
Expand Down
59 changes: 55 additions & 4 deletions MeetingBar/Notifications.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//
import EventKit
import UserNotifications

import AppKit
import Defaults

func requestNotificationAuthorization() {
Expand Down Expand Up @@ -52,7 +52,7 @@ func registerNotificationCategories() {
func sendNotification(title: String, text: String, subtitle: String = "") {
requestNotificationAuthorization() // By the apple best practices

NSLog("Send notification: \(title) - \(text)")
NSLog("Send notification: \(title) - \(text) - \(subtitle)")
let center = UNUserNotificationCenter.current()

let content = UNMutableNotificationContent()
Expand All @@ -62,8 +62,8 @@ func sendNotification(title: String, text: String, subtitle: String = "") {
content.subtitle = subtitle
}

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)

center.add(request) { error in
if let error = error {
NSLog("%@", "request \(request) could not be added because of error \(error)")
Expand All @@ -72,6 +72,57 @@ func sendNotification(title: String, text: String, subtitle: String = "") {
}
}}

/**
* check whether the notifications for meetingbar are enabled and alert or banner style is enabled.
* in this case the method will return true, otherwise false.
*
*/
func notificationsEnabled() -> Bool {
let center = UNUserNotificationCenter.current()
let group = DispatchGroup()
group.enter()

var correctAlertStyle = false
var notificationsEnabled = false

center.getNotificationSettings { notificationSettings in
correctAlertStyle = notificationSettings.alertStyle == UNAlertStyle.alert || notificationSettings.alertStyle == UNAlertStyle.banner
notificationsEnabled = notificationSettings.authorizationStatus == UNAuthorizationStatus.authorized
group.leave()
}

group.wait()
return correctAlertStyle && notificationsEnabled
}

/**
* sends a notification to the user.
*/
func sendNotification(_ title: String, _ text: String) {
requestNotificationAuthorization() // By the apple best practices

if notificationsEnabled() {
sendNotification(title, text)
} else {
displayAlert(title: title, text: text)
}
}

/**
* adds an alert for the user- we will only use NSAlert if the user has switched off notifications
*/
func displayAlert(title: String, text: String) {
NSLog("Display alert: \(title) - \(text)")

let userAlert = NSAlert()
userAlert.messageText = title
userAlert.informativeText = text
userAlert.alertStyle = NSAlert.Style.informational
userAlert.addButton(withTitle: "OK")

userAlert.runModal()
}

func scheduleEventNotification(_ event: EKEvent) {
requestNotificationAuthorization() // By the apple best practices

Expand Down
23 changes: 19 additions & 4 deletions MeetingBar/Views/Preferences/ServicesTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ struct ServicesTab: View {
@Default(.useChromeForHangoutsLinks) var useChromeForHangoutsLinks
@Default(.useAppForZoomLinks) var useAppForZoomLinks
@Default(.useAppForTeamsLinks) var useAppForTeamsLinks
@Default(.createMeetingServiceUrl) var createMeetingServiceUrl
@Default(.createMeetingService) var createMeetingService

var body: some View {
VStack {
Expand All @@ -41,10 +43,22 @@ struct ServicesTab: View {
}
}.foregroundColor(.gray).font(.system(size: 12)).padding(.horizontal, 10)
Divider()
HStack {
Text("Create meetings in").frame(width: 150, alignment: .leading)
CreateMeetingServicePicker()
}.padding(.horizontal, 10)
VStack {
HStack {
Text("Create meetings via").frame(width: 150, alignment: .leading)
CreateMeetingServicePicker()
}.padding(.horizontal, 10)

if createMeetingService == CreateMeetingServices.url {
HStack {
Text("Custom url").frame(width: 150, alignment: .leading)
TextField("Please enter a valid url (with the url scheme, e.g. https://)", text: $createMeetingServiceUrl).textFieldStyle(RoundedBorderTextFieldStyle())
}.padding(.horizontal, 10)
HStack {
Text("Tip: Google Meet supports choosing account via parameter, e.g. https://meet.google.com/new?authuser=1").foregroundColor(.gray).font(.system(size: 12))
}
}
}
Spacer()
}.padding()
}
Expand All @@ -62,6 +76,7 @@ struct CreateMeetingServicePicker: View {
Text(CreateMeetingServices.gcalendar.rawValue).tag(CreateMeetingServices.gcalendar)
Text(CreateMeetingServices.outlook_live.rawValue).tag(CreateMeetingServices.outlook_live)
Text(CreateMeetingServices.outlook_office365.rawValue).tag(CreateMeetingServices.outlook_office365)
Text(CreateMeetingServices.url.rawValue).tag(CreateMeetingServices.url)
}.labelsHidden()
}
}