first commit
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"platform" : "watchos",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// music playerWatch Watch App
|
||||
//
|
||||
// Created by aswer on 30.06.2026.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Главный экран часов
|
||||
// Замени этим содержимым ContentView.swift, который Xcode сгенерировал
|
||||
// в таргете часов (структура должна остаться по имени ContentView,
|
||||
// чтобы App.swift на часах продолжил работать без изменений).
|
||||
struct ContentView: View {
|
||||
@StateObject private var connectivity = WatchConnectivityManager.shared
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
if !connectivity.currentTitle.isEmpty {
|
||||
NavigationLink(destination: NowPlayingView()) {
|
||||
HStack {
|
||||
Image(systemName: connectivity.isPlaying ? "pause.circle.fill" : "play.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
VStack(alignment: .leading) {
|
||||
Text(connectivity.currentTitle)
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
Text(connectivity.currentArtist)
|
||||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if connectivity.tracks.isEmpty {
|
||||
Text("Открой приложение на iPhone, чтобы список треков появился здесь")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.gray)
|
||||
} else {
|
||||
ForEach(connectivity.tracks) { track in
|
||||
Button(action: { connectivity.playTrack(id: track.id) }) {
|
||||
VStack(alignment: .leading) {
|
||||
Text(track.title)
|
||||
.font(.body)
|
||||
.foregroundColor(track.id == connectivity.currentId ? .green : .primary)
|
||||
.lineLimit(1)
|
||||
Text(track.artist)
|
||||
.font(.caption2)
|
||||
.foregroundColor(.gray)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Музыка")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Экран "Сейчас играет" на часах
|
||||
struct NowPlayingView: View {
|
||||
@StateObject private var connectivity = WatchConnectivityManager.shared
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 10) {
|
||||
Text(connectivity.currentTitle)
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(2)
|
||||
|
||||
Text(connectivity.currentArtist)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.gray)
|
||||
.lineLimit(1)
|
||||
|
||||
HStack(spacing: 22) {
|
||||
Button(action: connectivity.previous) {
|
||||
Image(systemName: "backward.fill")
|
||||
.font(.title2)
|
||||
}
|
||||
|
||||
Button(action: connectivity.playPause) {
|
||||
Image(systemName: connectivity.isPlaying ? "pause.fill" : "play.fill")
|
||||
.font(.largeTitle)
|
||||
}
|
||||
|
||||
Button(action: connectivity.next) {
|
||||
Image(systemName: "forward.fill")
|
||||
.font(.title2)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.padding(.top, 6)
|
||||
}
|
||||
.padding()
|
||||
.navigationTitle("Сейчас играет")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import Foundation
|
||||
import WatchConnectivity
|
||||
import Combine
|
||||
|
||||
// MARK: - Та же лёгкая модель трека, что и на телефоне
|
||||
struct WatchTrackInfo: Codable, Identifiable {
|
||||
let id: String
|
||||
let title: String
|
||||
let artist: String
|
||||
}
|
||||
|
||||
// MARK: - Связь Apple Watch <-> iPhone
|
||||
// Добавь этот файл в таргет часов (например "music playerWatch").
|
||||
class WatchConnectivityManager: NSObject, WCSessionDelegate, ObservableObject {
|
||||
static let shared = WatchConnectivityManager()
|
||||
|
||||
@Published var tracks: [WatchTrackInfo] = []
|
||||
@Published var isPlaying: Bool = false
|
||||
@Published var currentTitle: String = ""
|
||||
@Published var currentArtist: String = ""
|
||||
@Published var currentId: String = ""
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
guard WCSession.isSupported() else { return }
|
||||
let session = WCSession.default
|
||||
session.delegate = self
|
||||
session.activate()
|
||||
}
|
||||
|
||||
// MARK: - WCSessionDelegate
|
||||
|
||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
|
||||
|
||||
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) {
|
||||
DispatchQueue.main.async {
|
||||
self.apply(applicationContext)
|
||||
}
|
||||
}
|
||||
|
||||
private func apply(_ context: [String: Any]) {
|
||||
if let data = context["tracks"] as? Data,
|
||||
let decoded = try? JSONDecoder().decode([WatchTrackInfo].self, from: data) {
|
||||
self.tracks = decoded
|
||||
}
|
||||
self.isPlaying = context["isPlaying"] as? Bool ?? false
|
||||
self.currentTitle = context["currentTitle"] as? String ?? ""
|
||||
self.currentArtist = context["currentArtist"] as? String ?? ""
|
||||
self.currentId = context["currentId"] as? String ?? ""
|
||||
}
|
||||
|
||||
// MARK: - Отправка команд на телефон
|
||||
|
||||
private func send(action: String, extra: [String: Any] = [:]) {
|
||||
guard WCSession.isSupported() else { return }
|
||||
var payload = extra
|
||||
payload["action"] = action
|
||||
|
||||
let session = WCSession.default
|
||||
if session.isReachable {
|
||||
session.sendMessage(payload, replyHandler: nil) { _ in
|
||||
session.transferUserInfo(payload)
|
||||
}
|
||||
} else {
|
||||
session.transferUserInfo(payload)
|
||||
}
|
||||
}
|
||||
|
||||
func playPause() { send(action: "playPause") }
|
||||
func next() { send(action: "next") }
|
||||
func previous() { send(action: "previous") }
|
||||
func playTrack(id: String) { send(action: "playTrack", extra: ["id": id]) }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// music_playerWatchApp.swift
|
||||
// music playerWatch Watch App
|
||||
//
|
||||
// Created by aswer on 30.06.2026.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct music_playerWatch_Watch_AppApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user