six-card-golf/Six Card Golf MessagesExtension/MessagesViewController.swift
Lukas Schaefer a976f91f2e
Send message automatically in background
Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
2026-08-09 15:17:27 -04:00

117 lines
4.3 KiB
Swift

import Messages
import SwiftUI
import UIKit
class MessagesViewController: MSMessagesAppViewController {
private let gameController = GameController()
private var hostingController: UIHostingController<RootView>?
private var currentSession: MSSession?
override func viewDidLoad() {
super.viewDidLoad()
gameController.onRequestExpand = { [weak self] in
self?.requestPresentationStyle(.expanded)
}
gameController.onRequestCollapse = { [weak self] in
self?.requestPresentationStyle(.compact)
}
gameController.onShareGame = { [weak self] gameID, password, caption, newSession in
self?.insertGameMessage(
gameID: gameID,
password: password,
caption: caption,
newSession: newSession
)
}
embedRootIfNeeded()
}
override func willBecomeActive(with conversation: MSConversation) {
apply(conversation: conversation, style: presentationStyle)
embedRootIfNeeded()
}
override func didResignActive(with conversation: MSConversation) {
gameController.stopPolling()
}
override func didReceive(_ message: MSMessage, conversation: MSConversation) {
apply(conversation: conversation, style: presentationStyle)
}
override func didCancelSending(_ message: MSMessage, conversation: MSConversation) {
apply(conversation: conversation, style: presentationStyle)
}
override func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
gameController.presentationStyle = chrome(for: presentationStyle)
}
override func didTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
gameController.presentationStyle = chrome(for: presentationStyle)
}
private func apply(conversation: MSConversation, style: MSMessagesAppPresentationStyle) {
if let selected = conversation.selectedMessage {
currentSession = selected.session
}
gameController.configureMessages(
style: chrome(for: style),
remoteParticipantCount: conversation.remoteParticipantIdentifiers.count,
gameURL: conversation.selectedMessage?.url
)
}
private func chrome(for style: MSMessagesAppPresentationStyle) -> PresentationChrome {
style == .expanded ? .expanded : .compact
}
private func insertGameMessage(
gameID: Int,
password: String?,
caption: String,
newSession: Bool
) {
guard let conversation = activeConversation else {
gameController.errorMessage = "No active conversation to send into."
return
}
let session = newSession ? nil : (conversation.selectedMessage?.session ?? currentSession)
let message = MSMessage(session: session ?? MSSession())
message.url = MessageGameID.url(gameID: gameID, password: password)
message.summaryText = caption
let layout = MSMessageTemplateLayout()
layout.caption = "Six Card Golf"
layout.subcaption = caption
layout.trailingCaption = "#\(gameID)"
message.layout = layout
currentSession = message.session
// `send` delivers immediately (no compose-field Send tap), like Game Pigeon.
conversation.send(message) { [weak self] error in
DispatchQueue.main.async {
if let error {
self?.gameController.errorMessage = error.localizedDescription
}
}
}
}
private func embedRootIfNeeded() {
guard hostingController == nil else { return }
let hosting = UIHostingController(rootView: RootView(controller: gameController))
hostingController = hosting
addChild(hosting)
hosting.view.translatesAutoresizingMaskIntoConstraints = false
hosting.view.backgroundColor = .clear
view.addSubview(hosting.view)
NSLayoutConstraint.activate([
hosting.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hosting.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hosting.view.topAnchor.constraint(equalTo: view.topAnchor),
hosting.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
hosting.didMove(toParent: self)
}
}