|
|
@@ -190,17 +190,11 @@ private extension ViewController {
|
|
190
|
190
|
@objc private func joinMeetClicked(_ sender: Any?) {
|
|
191
|
191
|
let rawInput = meetLinkField?.stringValue.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
192
|
192
|
|
|
193
|
|
- if rawInput.isEmpty {
|
|
194
|
|
- guard let url = URL(string: "https://meet.google.com/") else { return }
|
|
195
|
|
- openInAppBrowser(with: url, policy: inAppBrowserDefaultPolicy)
|
|
196
|
|
- return
|
|
197
|
|
- }
|
|
198
|
|
-
|
|
199
|
|
- let normalized = normalizedURLString(from: rawInput)
|
|
200
|
|
- guard let url = URL(string: normalized),
|
|
201
|
|
- let host = url.host?.lowercased(),
|
|
202
|
|
- host.contains("meet.google.com") else {
|
|
203
|
|
- showSimpleAlert(title: "Invalid Link", message: "Please enter a valid Google Meet link.")
|
|
|
193
|
+ guard let url = normalizedMeetJoinURL(from: rawInput) else {
|
|
|
194
|
+ showSimpleAlert(
|
|
|
195
|
+ title: "Invalid Meet link",
|
|
|
196
|
+ 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)."
|
|
|
197
|
+ )
|
|
204
|
198
|
return
|
|
205
|
199
|
}
|
|
206
|
200
|
|
|
|
@@ -247,6 +241,49 @@ private extension ViewController {
|
|
247
|
241
|
return "https://\(value)"
|
|
248
|
242
|
}
|
|
249
|
243
|
|
|
|
244
|
+ /// Typical Meet meeting code shape: three hyphen-separated groups (e.g. `nkd-grps-duv`).
|
|
|
245
|
+ private func isValidMeetMeetingCode(_ code: String) -> Bool {
|
|
|
246
|
+ let trimmed = code.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
247
|
+ guard trimmed.isEmpty == false else { return false }
|
|
|
248
|
+ let pattern = "^[a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{3}$"
|
|
|
249
|
+ return trimmed.range(of: pattern, options: [.regularExpression, .caseInsensitive]) != nil
|
|
|
250
|
+ }
|
|
|
251
|
+
|
|
|
252
|
+ /// Accepts `https://meet.google.com/...`, `meet.google.com/...`, or a bare code; returns canonical Meet URL or `nil`.
|
|
|
253
|
+ private func normalizedMeetJoinURL(from rawInput: String) -> URL? {
|
|
|
254
|
+ let trimmed = rawInput.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
255
|
+ guard trimmed.isEmpty == false else { return nil }
|
|
|
256
|
+
|
|
|
257
|
+ let lower = trimmed.lowercased()
|
|
|
258
|
+
|
|
|
259
|
+ if lower.hasPrefix("http://") || lower.hasPrefix("https://") {
|
|
|
260
|
+ guard let url = URL(string: trimmed),
|
|
|
261
|
+ let host = url.host?.lowercased(),
|
|
|
262
|
+ host == "meet.google.com" || host.hasSuffix(".meet.google.com") else {
|
|
|
263
|
+ return nil
|
|
|
264
|
+ }
|
|
|
265
|
+ let path = url.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
|
|
266
|
+ guard path.isEmpty == false else { return nil }
|
|
|
267
|
+ let firstSegment = path.split(separator: "/").first.map(String.init) ?? path
|
|
|
268
|
+ guard isValidMeetMeetingCode(firstSegment) else { return nil }
|
|
|
269
|
+ return URL(string: "https://meet.google.com/\(firstSegment.lowercased())")
|
|
|
270
|
+ }
|
|
|
271
|
+
|
|
|
272
|
+ if lower.hasPrefix("meet.google.com/") {
|
|
|
273
|
+ let afterHost = trimmed.dropFirst("meet.google.com/".count)
|
|
|
274
|
+ let beforeQuery = String(afterHost).split(separator: "?").first.map(String.init) ?? String(afterHost)
|
|
|
275
|
+ let firstSegment = beforeQuery.split(separator: "/").first.map(String.init) ?? beforeQuery
|
|
|
276
|
+ guard isValidMeetMeetingCode(firstSegment) else { return nil }
|
|
|
277
|
+ return URL(string: "https://meet.google.com/\(firstSegment.lowercased())")
|
|
|
278
|
+ }
|
|
|
279
|
+
|
|
|
280
|
+ if isValidMeetMeetingCode(trimmed) {
|
|
|
281
|
+ return URL(string: "https://meet.google.com/\(trimmed.lowercased())")
|
|
|
282
|
+ }
|
|
|
283
|
+
|
|
|
284
|
+ return nil
|
|
|
285
|
+ }
|
|
|
286
|
+
|
|
250
|
287
|
private func openInAppBrowser(with url: URL, policy: InAppBrowserURLPolicy = .allowAll) {
|
|
251
|
288
|
let browserController: InAppBrowserWindowController
|
|
252
|
289
|
if let existing = inAppBrowserWindowController {
|
|
|
@@ -887,7 +924,7 @@ private extension ViewController {
|
|
887
|
924
|
codeField.focusRingType = .none
|
|
888
|
925
|
codeField.font = NSFont.systemFont(ofSize: 36 / 2, weight: .regular)
|
|
889
|
926
|
codeField.textColor = palette.textPrimary
|
|
890
|
|
- codeField.placeholderString = "Enter Link"
|
|
|
927
|
+ codeField.placeholderString = "Code or meet.google.com/…"
|
|
891
|
928
|
codeInputShell.addSubview(codeField)
|
|
892
|
929
|
meetLinkField = codeField
|
|
893
|
930
|
codeCard.addSubview(codeTitle)
|