diff --git a/Social Contributor.xcodeproj/project.pbxproj b/Social Contributor.xcodeproj/project.pbxproj index fd87735..e95ed78 100644 --- a/Social Contributor.xcodeproj/project.pbxproj +++ b/Social Contributor.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0AD87B87282307FA00904E4E /* MuseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AD87B86282307FA00904E4E /* MuseView.swift */; }; 5C66C0932822ECCE00B66FF8 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5C66C0912822ECCE00B66FF8 /* Model.xcdatamodeld */; }; 5C66C0952822ECDA00B66FF8 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C66C0942822ECDA00B66FF8 /* PersistenceController.swift */; }; E334B3772822D5BD002E9640 /* Social_ContributorApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E334B3762822D5BD002E9640 /* Social_ContributorApp.swift */; }; @@ -19,6 +20,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0AD87B86282307FA00904E4E /* MuseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuseView.swift; sourceTree = ""; }; 5C66C0922822ECCE00B66FF8 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; 5C66C0942822ECDA00B66FF8 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = ""; }; E334B3732822D5BD002E9640 /* Social Contributor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Social Contributor.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -94,6 +96,7 @@ children = ( FA0DC4302822F3D5009AC9CC /* SettingsView.swift */, FA0DC4322822F4E3009AC9CC /* SettingsLabelStyle.swift */, + 0AD87B86282307FA00904E4E /* MuseView.swift */, ); path = Screens; sourceTree = ""; @@ -182,6 +185,7 @@ E334B3772822D5BD002E9640 /* Social_ContributorApp.swift in Sources */, 5C66C0932822ECCE00B66FF8 /* Model.xcdatamodeld in Sources */, 5C66C0952822ECDA00B66FF8 /* PersistenceController.swift in Sources */, + 0AD87B87282307FA00904E4E /* MuseView.swift in Sources */, FA0DC4332822F4E3009AC9CC /* SettingsLabelStyle.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -314,6 +318,7 @@ DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSAppleMusicUsageDescription = "Social Contributer uses Music access to play music and create a pleasant experience."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -343,6 +348,7 @@ DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSAppleMusicUsageDescription = "Social Contributer uses Music access to play music and create a pleasant experience."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/Social Contributor/ContentView.swift b/Social Contributor/ContentView.swift index 0e0b7c1..942c068 100644 --- a/Social Contributor/ContentView.swift +++ b/Social Contributor/ContentView.swift @@ -7,25 +7,36 @@ // import SwiftUI +import MusicKit struct ContentView: View { + @State private var showMuseView = false + var body: some View { TabView { Text("Hello, Home!") .tabItem { Label("Home", systemImage: "house") } - + + if showMuseView { + MuseView() + .tabItem { + Label("Muse", systemImage: "wand.and.stars.inverse") + } + } + SettingsView() .tabItem { Label("Settings", systemImage: "gearshape") } } - } -} + .task { + let status = await MusicAuthorization.request() -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() + if status == .authorized { + showMuseView.toggle() + } + } } } diff --git a/Social Contributor/Screens/MuseView.swift b/Social Contributor/Screens/MuseView.swift new file mode 100644 index 0000000..544dc7f --- /dev/null +++ b/Social Contributor/Screens/MuseView.swift @@ -0,0 +1,93 @@ +// +// MuseView.swift +// Social Contributor +// +// Created by Rudrank Riyam on 05/05/22. +// + +import SwiftUI +import MusicKit + +struct MuseView: View { + @StateObject private var viewModel = MuseViewModel() + + var body: some View { + NavigationView { + List { + if viewModel.tracks.isEmpty { + ProgressView() + } else { + ForEach(viewModel.tracks) { track in + Button(action: { viewModel.play(track) }) { + trackRow(track) + } + .buttonStyle(.plain) + } + } + } + .navigationTitle("Muse") + } + .navigationViewStyle(.stack) + .task { + do { + try await viewModel.fetchTracks() + } catch { + print(error) + } + } + } + + private func trackRow(_ track: Track) -> some View { + HStack { + if let artwork = track.artwork { + ArtworkImage(artwork, height: 50) + .cornerRadius(8) + } + + VStack(alignment: .leading) { + Text(track.title) + .font(.headline) + + Text(track.artistName) + .font(.subheadline) + } + } + .padding(8) + } +} + +struct MuseView_Previews: PreviewProvider { + static var previews: some View { + MuseView() + } +} + +class MuseViewModel: ObservableObject { + @Published private(set) var tracks: MusicItemCollection = [] + @Published private(set) var player = ApplicationMusicPlayer.shared + + @MainActor func fetchTracks() async throws { + let url = URL(string: "https://api.music.apple.com/v1/me/recent/played/tracks") + + guard let url = url else { return } + + let request = MusicDataRequest(urlRequest: .init(url: url)) + let response = try await request.response() + + let tracks = try JSONDecoder().decode(MusicItemCollection.self, from: response.data) + + self.tracks = tracks + } + + func play(_ track: Track) { + player.queue = ApplicationMusicPlayer.Queue(for: tracks, startingAt: track) + + Task { + do { + try await player.play() + } catch { + print("Failed to prepare to play with error: \(error).") + } + } + } +}