|
@@ -190,17 +190,11 @@ private extension ViewController {
|
|
|
@objc private func joinMeetClicked(_ sender: Any?) {
|
|
@objc private func joinMeetClicked(_ sender: Any?) {
|
|
|
let rawInput = meetLinkField?.stringValue.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
let rawInput = meetLinkField?.stringValue.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
|
|
|
|
|
|
- if rawInput.isEmpty {
|
|
|
|
|
- guard let url = URL(string: "https://meet.google.com/") else { return }
|
|
|
|
|
- openInAppBrowser(with: url, policy: inAppBrowserDefaultPolicy)
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let normalized = normalizedURLString(from: rawInput)
|
|
|
|
|
- guard let url = URL(string: normalized),
|
|
|
|
|
- let host = url.host?.lowercased(),
|
|
|
|
|
- host.contains("meet.google.com") else {
|
|
|
|
|
- showSimpleAlert(title: "Invalid Link", message: "Please enter a valid Google Meet link.")
|
|
|
|
|
|
|
+ guard let url = normalizedMeetJoinURL(from: rawInput) else {
|
|
|
|
|
+ showSimpleAlert(
|
|
|
|
|
+ title: "Invalid Meet link",
|
|
|
|
|
+ message: "Enter a valid Google Meet link or meeting code (for example nkd-grps-duv, meet.google.com/nkd-grps-duv, or https://meet.google.com/nkd-grps-duv)."
|
|
|
|
|
+ )
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -247,6 +241,49 @@ private extension ViewController {
|
|
|
return "https://\(value)"
|
|
return "https://\(value)"
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /// Typical Meet meeting code shape: three hyphen-separated groups (e.g. `nkd-grps-duv`).
|
|
|
|
|
+ private func isValidMeetMeetingCode(_ code: String) -> Bool {
|
|
|
|
|
+ let trimmed = code.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
|
|
+ guard trimmed.isEmpty == false else { return false }
|
|
|
|
|
+ let pattern = "^[a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{3}$"
|
|
|
|
|
+ return trimmed.range(of: pattern, options: [.regularExpression, .caseInsensitive]) != nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Accepts `https://meet.google.com/...`, `meet.google.com/...`, or a bare code; returns canonical Meet URL or `nil`.
|
|
|
|
|
+ private func normalizedMeetJoinURL(from rawInput: String) -> URL? {
|
|
|
|
|
+ let trimmed = rawInput.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
|
|
+ guard trimmed.isEmpty == false else { return nil }
|
|
|
|
|
+
|
|
|
|
|
+ let lower = trimmed.lowercased()
|
|
|
|
|
+
|
|
|
|
|
+ if lower.hasPrefix("http://") || lower.hasPrefix("https://") {
|
|
|
|
|
+ guard let url = URL(string: trimmed),
|
|
|
|
|
+ let host = url.host?.lowercased(),
|
|
|
|
|
+ host == "meet.google.com" || host.hasSuffix(".meet.google.com") else {
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+ let path = url.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
|
|
|
|
+ guard path.isEmpty == false else { return nil }
|
|
|
|
|
+ let firstSegment = path.split(separator: "/").first.map(String.init) ?? path
|
|
|
|
|
+ guard isValidMeetMeetingCode(firstSegment) else { return nil }
|
|
|
|
|
+ return URL(string: "https://meet.google.com/\(firstSegment.lowercased())")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if lower.hasPrefix("meet.google.com/") {
|
|
|
|
|
+ let afterHost = trimmed.dropFirst("meet.google.com/".count)
|
|
|
|
|
+ let beforeQuery = String(afterHost).split(separator: "?").first.map(String.init) ?? String(afterHost)
|
|
|
|
|
+ let firstSegment = beforeQuery.split(separator: "/").first.map(String.init) ?? beforeQuery
|
|
|
|
|
+ guard isValidMeetMeetingCode(firstSegment) else { return nil }
|
|
|
|
|
+ return URL(string: "https://meet.google.com/\(firstSegment.lowercased())")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if isValidMeetMeetingCode(trimmed) {
|
|
|
|
|
+ return URL(string: "https://meet.google.com/\(trimmed.lowercased())")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private func openInAppBrowser(with url: URL, policy: InAppBrowserURLPolicy = .allowAll) {
|
|
private func openInAppBrowser(with url: URL, policy: InAppBrowserURLPolicy = .allowAll) {
|
|
|
let browserController: InAppBrowserWindowController
|
|
let browserController: InAppBrowserWindowController
|
|
|
if let existing = inAppBrowserWindowController {
|
|
if let existing = inAppBrowserWindowController {
|
|
@@ -887,7 +924,7 @@ private extension ViewController {
|
|
|
codeField.focusRingType = .none
|
|
codeField.focusRingType = .none
|
|
|
codeField.font = NSFont.systemFont(ofSize: 36 / 2, weight: .regular)
|
|
codeField.font = NSFont.systemFont(ofSize: 36 / 2, weight: .regular)
|
|
|
codeField.textColor = palette.textPrimary
|
|
codeField.textColor = palette.textPrimary
|
|
|
- codeField.placeholderString = "Enter Link"
|
|
|
|
|
|
|
+ codeField.placeholderString = "Code or meet.google.com/…"
|
|
|
codeInputShell.addSubview(codeField)
|
|
codeInputShell.addSubview(codeField)
|
|
|
meetLinkField = codeField
|
|
meetLinkField = codeField
|
|
|
codeCard.addSubview(codeTitle)
|
|
codeCard.addSubview(codeTitle)
|