From 87c5ff74acd543e3ad2b7c38e325b440c649b380 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 18 Mar 2023 17:47:44 +0800 Subject: [PATCH] initial commit, minial working code --- MusicPlayer Watch App/ContentView.swift | 152 +++++++++++++++++- MusicPlayer Watch App/MusicPlayerApp.swift | 6 +- MusicPlayer Watch App/PlaybackView.swift | 24 +++ MusicPlayer Watch App/TODO.md | 10 ++ MusicPlayer-Watch-App-Info.plist | 10 ++ MusicPlayer.xcodeproj/project.pbxproj | 10 ++ .../xcdebugger/Expressions.xcexplist | 14 ++ .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + 8 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 MusicPlayer Watch App/PlaybackView.swift create mode 100644 MusicPlayer Watch App/TODO.md create mode 100644 MusicPlayer-Watch-App-Info.plist create mode 100644 MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist create mode 100644 MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist diff --git a/MusicPlayer Watch App/ContentView.swift b/MusicPlayer Watch App/ContentView.swift index 2a03fd9..dc34c7c 100644 --- a/MusicPlayer Watch App/ContentView.swift +++ b/MusicPlayer Watch App/ContentView.swift @@ -6,21 +6,159 @@ // import SwiftUI +import Network +import AVFoundation +import UIKit + +class IDStr : Identifiable { + var s : String = "" + var art : Image? + var m : AVPlayerItem? + init () {self.m = nil} + init (str : String, music : AVPlayerItem) { + self.s = str + self.m = music + } +} + +class ListViewModel: ObservableObject { + + @Published var music = Array() + + func addItem(i : String, m : AVPlayerItem) { + music.append(IDStr(str: i, music: m)) + } + func addItem(str : IDStr) { + music.append(str) + } +} struct ContentView: View { + @ObservedObject var music = ListViewModel() var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundColor(.accentColor) - Text("Hello, world!") + + List() { + ForEach(music.music) { m in + + Button(m.s, action: { + let idx = music.music.firstIndex { s in + s.s == m.s + } + if (idx != nil) { + if (idx != 0) { + music.music = Array(music.music[idx! ... (music.music.endIndex - 1)] + music.music[0...idx! - 1]) + self.player?.removeAllItems() + for i in music.music { + i.m!.seek(to: .zero) + player?.insert(i.m!, after: nil) + } + } + else { + m.m!.seek(to: .zero) + } + } + + }).ignoresSafeArea(.all).cornerRadius(.zero).padding(.zero).frame(maxHeight: CGFloat(50)).foregroundColor(.white) + + } + + } + } + var player : AVQueuePlayer? = nil + + init() { + print("'sibal'"); + let base = "https://billsun.dev/webdav/music-test" + let url = URL(string: base) + let request: URLRequest = URLRequest(url: url!) + let session = URLSession(configuration: .default) + let dir = NSHomeDirectory() + + session.dataTask(with: request, completionHandler: + { (data, response, error) -> Void in + if (error == nil) { return } + let reply = String(data: data!, encoding: String.Encoding.utf8)! + + do { + let pattern = try Regex(#".*()"#) + let matched = reply.matches(of: pattern) + + var s = Set() + for match in matched { + s.insert(String(match.output[2].substring!)) + } + for file in s { + let filepath = dir + "/Documents/" + file + var download = true + if(FileManager.default.fileExists(atPath: filepath)) { + let sz = try! FileManager.default.attributesOfItem(atPath: filepath)[FileAttributeKey.size] as! UInt64 + download = sz < 1024 + } + if (download) + { + session.dataTask(with: URLRequest(url: URL(string: base + "/" + file)!)) { + (data, response, error) -> Void in + if (error == nil) { + let fp = fopen(filepath, "wb") + data!.withUnsafeBytes({ ptr in + fwrite(ptr, 1, data!.count, fp) + }) + fclose(fp) + } + }.resume() + } + + } + }catch{} } - .padding() + ).resume() + let enumerator = FileManager.default.enumerator(atPath: dir + "/Documents/") + enumerator!.forEach({ e in + if (self.player == nil) { + do { + let session = AVAudioSession.sharedInstance() + try session.setCategory(AVAudioSession.Category.playback) + } catch { + print(error) + } + self.player = AVQueuePlayer() + } + let filename = (e as! String) + let file_url = URL(filePath: dir + "/Documents/" + filename) + let asset = AVAsset(url: file_url) + let idstr = IDStr() + asset.loadMetadata(for: .iTunesMetadata) { + items, b in + for i in items! { + if(i.identifier == .iTunesMetadataCoverArt) { + Task{ + let imageData = try await i.load(.dataValue) + idstr.art = Image(uiImage: UIImage(data: imageData!)!) + } + } + } + } + let item = AVPlayerItem(url: file_url) + idstr.s = filename.prefix(filename.count - 4).removingPercentEncoding! + idstr.m = item + self.music.addItem(str: idstr) + //item.addObserver(self, forKeyPath: "status", context: nil) + self.player?.insert(item, after: nil) + + if (self.player?.status == .failed) { + print(self.player!.error!) + } + else { + self.player?.play() + } + }) } + } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView() + ContentView().ignoresSafeArea(.all).cornerRadius(.zero).padding(.zero) } + } diff --git a/MusicPlayer Watch App/MusicPlayerApp.swift b/MusicPlayer Watch App/MusicPlayerApp.swift index 590d38c..9694bb7 100644 --- a/MusicPlayer Watch App/MusicPlayerApp.swift +++ b/MusicPlayer Watch App/MusicPlayerApp.swift @@ -6,12 +6,16 @@ // import SwiftUI +import WatchKit +import UserNotifications @main struct MusicPlayer_Watch_AppApp: App { + var body: some Scene { WindowGroup { - ContentView() + ContentView().cornerRadius(.zero).padding(.zero) } } + } diff --git a/MusicPlayer Watch App/PlaybackView.swift b/MusicPlayer Watch App/PlaybackView.swift new file mode 100644 index 0000000..a69a29f --- /dev/null +++ b/MusicPlayer Watch App/PlaybackView.swift @@ -0,0 +1,24 @@ +// +// PlaybackView.swift +// MusicPlayer Watch App +// +// Created by BillSun on 3/18/23. +// + +import SwiftUI + +struct PlaybackView: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } + init() {} + init(parent:ContentView) { + + } +} + +struct PlaybackView_Previews: PreviewProvider { + static var previews: some View { + PlaybackView() + } +} diff --git a/MusicPlayer Watch App/TODO.md b/MusicPlayer Watch App/TODO.md new file mode 100644 index 0000000..d274003 --- /dev/null +++ b/MusicPlayer Watch App/TODO.md @@ -0,0 +1,10 @@ +# TODO + +- push to new view +- view with media control and background +- control menu + - with option to delete song + - remove all songs + - change data source + - multiple datasources (smb, webdav, webserver) + diff --git a/MusicPlayer-Watch-App-Info.plist b/MusicPlayer-Watch-App-Info.plist new file mode 100644 index 0000000..f753731 --- /dev/null +++ b/MusicPlayer-Watch-App-Info.plist @@ -0,0 +1,10 @@ + + + + + UIBackgroundModes + + audio + + + diff --git a/MusicPlayer.xcodeproj/project.pbxproj b/MusicPlayer.xcodeproj/project.pbxproj index feb19c0..1be7e87 100644 --- a/MusicPlayer.xcodeproj/project.pbxproj +++ b/MusicPlayer.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ A95C118729C531C100737618 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95C118629C531C100737618 /* ContentView.swift */; }; A95C118929C531C300737618 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A95C118829C531C300737618 /* Assets.xcassets */; }; A95C118C29C531C300737618 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A95C118B29C531C300737618 /* Preview Assets.xcassets */; }; + A982CD2A29C5BA7D00A1DBDE /* PlaybackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A982CD2929C5BA7D00A1DBDE /* PlaybackView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -45,6 +46,9 @@ A95C118629C531C100737618 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; A95C118829C531C300737618 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; A95C118B29C531C300737618 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + A982CD2829C5907A00A1DBDE /* MusicPlayer-Watch-App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "MusicPlayer-Watch-App-Info.plist"; sourceTree = SOURCE_ROOT; }; + A982CD2929C5BA7D00A1DBDE /* PlaybackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackView.swift; sourceTree = ""; }; + A982CD2B29C5BE8800A1DBDE /* TODO.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = TODO.md; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -78,10 +82,13 @@ A95C118329C531C100737618 /* MusicPlayer Watch App */ = { isa = PBXGroup; children = ( + A982CD2829C5907A00A1DBDE /* MusicPlayer-Watch-App-Info.plist */, A95C118429C531C100737618 /* MusicPlayerApp.swift */, + A982CD2929C5BA7D00A1DBDE /* PlaybackView.swift */, A95C118629C531C100737618 /* ContentView.swift */, A95C118829C531C300737618 /* Assets.xcassets */, A95C118A29C531C300737618 /* Preview Content */, + A982CD2B29C5BE8800A1DBDE /* TODO.md */, ); path = "MusicPlayer Watch App"; sourceTree = ""; @@ -193,6 +200,7 @@ buildActionMask = 2147483647; files = ( A95C118729C531C100737618 /* ContentView.swift in Sources */, + A982CD2A29C5BA7D00A1DBDE /* PlaybackView.swift in Sources */, A95C118529C531C100737618 /* MusicPlayerApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -328,6 +336,7 @@ DEVELOPMENT_TEAM = 7P35HLZ26U; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "MusicPlayer-Watch-App-Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = MusicPlayer; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_WKWatchOnly = YES; @@ -358,6 +367,7 @@ DEVELOPMENT_TEAM = 7P35HLZ26U; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "MusicPlayer-Watch-App-Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = MusicPlayer; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_WKWatchOnly = YES; diff --git a/MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist b/MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist new file mode 100644 index 0000000..ab79c2a --- /dev/null +++ b/MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..1cc0737 --- /dev/null +++ b/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + +