diff --git a/MusicPlayer Watch App/ContentView.swift b/MusicPlayer Watch App/ContentView.swift
index 5eb8c6f..87a014f 100644
--- a/MusicPlayer Watch App/ContentView.swift
+++ b/MusicPlayer Watch App/ContentView.swift
@@ -33,11 +33,19 @@ class ListViewModel: ObservableObject {
}
}
+class PlaybackViewProxy {
+ var pbv : PlaybackView
+ init(v : PlaybackView) {
+ self.pbv = v
+ }
+}
+
struct ContentView: View {
@ObservedObject var music = ListViewModel()
@State var pushState = false
@State var geo :CGSize = .zero
@State var _curr_sel_music : IDStr = IDStr()
+ let pbv : PlaybackViewProxy
var body: some View {
GeometryReader { geometry in
NavigationView(){
@@ -61,18 +69,21 @@ struct ContentView: View {
m.m!.seek(to: .zero)
}
}
+ self._curr_sel_music = m
+ self.pbv.pbv.update(music: _curr_sel_music)
pushState = true
- _curr_sel_music = m
}).ignoresSafeArea(.all).cornerRadius(.zero).padding(.zero).frame(maxHeight: CGFloat(50)).foregroundColor(.white)
- NavigationLink(destination: PlaybackView(parent:self, music: _curr_sel_music), isActive: $pushState) {
+ NavigationLink(destination: self.pbv.pbv, isActive: $pushState) {
EmptyView()
}
}
}
+ Label("\(music.music.count) Files. ", systemImage: "heart.fill").background(.clear).labelStyle(.titleAndIcon).frame(width: geometry.size.width, alignment: .center)
}
}.onAppear {
geo = geometry.size
+ self.pbv.pbv.parent = self
}
}
}
@@ -80,7 +91,7 @@ struct ContentView: View {
var player : AVQueuePlayer? = nil
init() {
- print("'sibal'");
+ self.pbv = PlaybackViewProxy(v: PlaybackView())
let base = "https://billsun.dev/webdav/music-test"
let url = URL(string: base)
let request: URLRequest = URLRequest(url: url!)
@@ -89,27 +100,38 @@ struct ContentView: View {
session.dataTask(with: request, completionHandler:
{ (data, response, error) -> Void in
- if (error == nil) { return }
+ if (error != nil) { return }
let reply = String(data: data!, encoding: String.Encoding.utf8)!
do {
- let pattern = try Regex(#".*()"#)
+ 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 {
+ for _file in s {
+ var file = _file
+ if _file.count > 68 {
+ file = _file.removingPercentEncoding ?? _file
+ if file.count > 36 {
+ file = String(file.prefix(31) + file.suffix(5))
+ }
+ }
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
+ let check_file = { fpath -> Void in
+ if(FileManager.default.fileExists(atPath: fpath)) {
+ let sz = try! FileManager.default.attributesOfItem(atPath: fpath)[FileAttributeKey.size] as! UInt64
+ download = sz < 40960 // (ignore files <40k)
+ }
}
- if (download)
- {
- session.dataTask(with: URLRequest(url: URL(string: base + "/" + file)!)) {
+
+ check_file(filepath)
+ check_file("\(dir)/Documents/\(_file)")
+ if (download) {
+ session.dataTask(with: URLRequest(url: URL(string: base + "/" + _file)!)) {
(data, response, error) -> Void in
if (error == nil) {
let fp = fopen(filepath, "wb")
@@ -120,7 +142,6 @@ struct ContentView: View {
}
}.resume()
}
-
}
}catch{}
}
@@ -143,14 +164,15 @@ struct ContentView: View {
let geo = self.geo
asset.loadMetadata(for: .iTunesMetadata) {
items, b in
+ if (items == nil) { return }
for i in items! {
if(i.identifier == .iTunesMetadataCoverArt) {
Task{
let imageData = try await i.load(.dataValue)
idstr.art = Image(uiImage: UIImage(data: imageData!)!)
- if (idstr.art != nil) {
+ /*if (idstr.art != nil) {
idstr.art!.resizable().scaledToFill().frame(width: geo.width, height: geo.height)
- }
+ }*/
}
}
}
diff --git a/MusicPlayer Watch App/MusicPlayerApp.swift b/MusicPlayer Watch App/MusicPlayerApp.swift
index 9694bb7..f1d0dca 100644
--- a/MusicPlayer Watch App/MusicPlayerApp.swift
+++ b/MusicPlayer Watch App/MusicPlayerApp.swift
@@ -7,7 +7,6 @@
import SwiftUI
import WatchKit
-import UserNotifications
@main
struct MusicPlayer_Watch_AppApp: App {
diff --git a/MusicPlayer Watch App/PlaybackView.swift b/MusicPlayer Watch App/PlaybackView.swift
index 268ed86..293e289 100644
--- a/MusicPlayer Watch App/PlaybackView.swift
+++ b/MusicPlayer Watch App/PlaybackView.swift
@@ -6,23 +6,113 @@
//
import SwiftUI
+import UIKit
+
+
struct PlaybackView: View {
var placeholder: Image? = nil
-
- var body: some View {
- placeholder == nil ?
- nil : placeholder!.resizable().scaledToFill()
-
+ var music : IDStr? = nil
+ var parent : ContentView? = nil
+ //@ObservedObject var timeout = Timeout(timeout: 5)
+ var title = ""
+ @State var playing = true
+ @State private var appearSelf = true
+
+ var body: some View {
+ if parent != nil {
+ GeometryReader { geo in
+ ZStack {
+ if(placeholder == nil) {
+ Image(systemName: "square")
+ .resizable()
+ .scaledToFill()
+ .foregroundColor(.black)
+ }
+ else {
+ placeholder!.resizable().scaledToFill()
+ }
+ if (appearSelf)
+ {
+ NavigationView{
+ VStack{
+ HStack{
+ Button {
+ if ( parent!.player!.timeControlStatus == .playing ) {
+ parent!.player!.pause()
+ self.playing = false
+ } else {
+ parent!.player!.play()
+ self.playing = true
+ }
+ } label: {
+ (
+ self.playing ?
+ Image(systemName: "stop") :
+ Image(systemName: "play")
+ )
+ .resizable()
+ .scaledToFit()
+ .frame(width: geo.size.width/5.5)
+ }.background(Color(red: 0,green: 0,blue: 0,opacity: 0.2))
+ .frame(width: geo.size.width/2.5)
+ .cornerRadius(90, antialiased: true)
+ .foregroundColor(.white)
+ .opacity(1)
+ .buttonStyle(.plain)
+ Button {
+ let curr = parent!.player!.currentItem
+ parent!.player!.advanceToNextItem()
+ curr!.seek(to: .zero)
+ parent!.player!.play()
+ self.playing = true
+ } label : {
+ Image(systemName: "chevron.forward")
+ .resizable()
+ .scaledToFit()
+ .frame(width: geo.size.width/7, height: geo.size.height/7)
+ }.background(Color.clear)
+ .clipShape(Circle())
+ .foregroundColor(.white)
+ .frame(width: geo.size.width/4, height: geo.size.height/4)
+ .padding(0)
+ .opacity(1)
+ .buttonStyle(.plain)
+ }
+ }.onAppear(){
+ DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
+ appearSelf = false
+ })
+ }.navigationTitle("\(self.title)")
+ }.opacity(0.65).navigationBarBackButtonHidden(false)
+ }
+ }.onTapGesture {
+ appearSelf = true
+ DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
+ appearSelf = false
+ })
+ }
+ }
+ }
}
- init() {}
- init(parent:ContentView, music: IDStr) {
- if music.art != nil {
- self.placeholder = music.art!
+ init() { }
+ init(parent:ContentView, music: IDStr? = nil) {
+ if music != nil && music!.art != nil {
+ self.placeholder = music!.art!
+ self.music = music
+ self.parent = parent
+ self.playing = parent.player!.timeControlStatus == .playing
}
}
+
+ mutating func update (music: IDStr) {
+ self.placeholder = music.art
+ self.music = music
+ self.title = music.s
+ self.playing = self.parent!.player!.timeControlStatus == .playing
+ }
}
struct PlaybackView_Previews: PreviewProvider {
diff --git a/MusicPlayer Watch App/TODO.md b/MusicPlayer Watch App/TODO.md
index d274003..39334b7 100644
--- a/MusicPlayer Watch App/TODO.md
+++ b/MusicPlayer Watch App/TODO.md
@@ -1,10 +1,21 @@
-# TODO
+# Roadmap
-- 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)
-
+ - multiple datasources (smb, webdav, webserver(better regex))
+- A download view
+ - That shows files to download (can select which ones to sync)
+ - Download progress bar, pause/cancel/resume
+- Optimize Detailed Control View
+ - Use customized controls
+ - Performance tuning, reuse one view object!
+ - Volume and Seekbar
+- UI Improvements
+- Playback functions Shuffle, Stop after next song, Repeat
+- Support for multiple formats (flac, possibly others?)
+- Database for caching
+- Playlist, creation/management
+- Lyrics
+- Tidy up code, credit page, test on real devices and submit to the appstore
diff --git a/MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist b/MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist
index ab79c2a..4729816 100644
--- a/MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist
+++ b/MusicPlayer.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/xcdebugger/Expressions.xcexplist
@@ -8,6 +8,9 @@
+
+
diff --git a/MusicPlayer.xcodeproj/xcshareddata/xcschemes/MusicPlayer Watch App.xcscheme b/MusicPlayer.xcodeproj/xcshareddata/xcschemes/MusicPlayer Watch App.xcscheme
new file mode 100644
index 0000000..2236bda
--- /dev/null
+++ b/MusicPlayer.xcodeproj/xcshareddata/xcschemes/MusicPlayer Watch App.xcscheme
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index 1cc0737..929fe43 100644
--- a/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ b/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -3,4 +3,22 @@
uuid = "E40B0B2F-0F7C-4049-8384-96A6D265F1C3"
type = "1"
version = "2.0">
+
+
+
+
+
+
diff --git a/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcschemes/xcschememanagement.plist b/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcschemes/xcschememanagement.plist
index 25f5f82..2665082 100644
--- a/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/MusicPlayer.xcodeproj/xcuserdata/bill.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -10,5 +10,18 @@
0
+ SuppressBuildableAutocreation
+
+ A95C117829C531C100737618
+
+ primary
+
+
+ A95C117E29C531C100737618
+
+ primary
+
+
+