first commit

This commit is contained in:
Artemon4ik8091
2026-07-14 12:06:58 +03:00
commit 01088b112b
31 changed files with 4678 additions and 0 deletions
@@ -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()
}
}
}