├── Screenshots
└── ShazamClone.gif
├── ShazamClone
├── Assets.xcassets
│ ├── Contents.json
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── ShazamCloneApp.swift
├── Presentation
│ ├── Model
│ │ └── Song.swift
│ └── Shazam
│ │ └── ShazamViewModel.swift
├── ContentView.swift
├── UI
│ ├── NoResult
│ │ └── NoResultView.swift
│ ├── SongDetail
│ │ └── SongDetailView.swift
│ └── Shazam
│ │ └── ShazamView.swift
└── Info.plist
├── ShazamClone.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── emmanuelkehinde.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
└── README.md
/Screenshots/ShazamClone.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emmanuelkehinde/ShazamClone/HEAD/Screenshots/ShazamClone.gif
--------------------------------------------------------------------------------
/ShazamClone/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ShazamClone/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ShazamClone.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ShazamClone/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShazamClone.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ShazamClone/ShazamCloneApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShazamCloneApp.swift
3 | // ShazamClone
4 | //
5 | // Created by Emmanuel Kehinde on 03/07/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct ShazamCloneApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ShazamClone/Presentation/Model/Song.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Song.swift
3 | // ShazamClone
4 | //
5 | // Created by Emmanuel Kehinde on 03/07/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Song {
11 | let title: String
12 | let artist: String
13 | let genres: [String]
14 | let artworkUrl: URL?
15 | let appleMusicUrl: URL?
16 | }
17 |
--------------------------------------------------------------------------------
/ShazamClone/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // ShazamClone
4 | //
5 | // Created by Emmanuel Kehinde on 03/07/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ContentView: View {
11 | var body: some View {
12 | ShazamView().environmentObject(ShazamViewModel())
13 | }
14 | }
15 |
16 | struct ContentView_Previews: PreviewProvider {
17 | static var previews: some View {
18 | ContentView()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ShazamClone.xcodeproj/xcuserdata/emmanuelkehinde.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ShazamClone.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ShazamClone
2 | A simple Shazam clone using ShazamKit, built with SwiftUI.
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | |
11 |
12 |
13 |
14 | ### Requirements
15 | - iOS 15
16 | - Xcode 13
17 | - Mac OS 11.3 or higher
18 |
19 | ### Tools
20 | - [ShazamKit](https://developer.apple.com/shazamkit/): Lets you enrich your app experience with audio recognition
21 | - [SwiftUI](https://developer.apple.com/xcode/swiftui/): UI Toolkit for building user interfaces in a declarative way.
22 |
23 | ### Blog Post
24 | https://emmanuelkehinde.io/swiftui-building-a-simple-shazam-clone-using-shazamkit/
25 |
--------------------------------------------------------------------------------
/ShazamClone/UI/NoResult/NoResultView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NoResultView.swift
3 | // ShazamClone
4 | //
5 | // Created by Emmanuel Kehinde on 03/07/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct NoResultView: View {
11 | var buttonAction: () -> Void
12 |
13 | var body: some View {
14 | VStack(alignment: .center, spacing: 12) {
15 | Image(systemName: "headphones.circle")
16 | .font(.system(size: 40, weight: .light))
17 | .foregroundColor(Color.black.opacity(0.8))
18 |
19 | Text("No Result Found")
20 | .font(.headline)
21 | .foregroundColor(Color.black.opacity(0.8))
22 |
23 | Button(action: {
24 | buttonAction()
25 | }, label: {
26 | Text("Try Again")
27 | .font(.system(size: 14, weight: .bold, design: .default))
28 | .foregroundColor(.white)
29 | .frame(width: 200, height: 48, alignment: .center)
30 | .background(
31 | RoundedRectangle(cornerRadius: 24).fill(Color.blue)
32 | .shadow(radius: 1)
33 | )
34 | })
35 | }
36 | }
37 | }
38 |
39 | struct NoResultView_Previews: PreviewProvider {
40 | static var previews: some View {
41 | NoResultView(buttonAction: {})
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ShazamClone/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSMicrophoneUsageDescription
24 | Allow Shazam Clone access to your microphone to listen to music around you
25 | UIApplicationSceneManifest
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 |
30 | UIApplicationSupportsIndirectInputEvents
31 |
32 | UILaunchScreen
33 |
34 | UIRequiredDeviceCapabilities
35 |
36 | armv7
37 |
38 | UIStatusBarStyle
39 | UIStatusBarStyleDarkContent
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 |
44 | UISupportedInterfaceOrientations~ipad
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationPortraitUpsideDown
48 | UIInterfaceOrientationLandscapeLeft
49 | UIInterfaceOrientationLandscapeRight
50 |
51 | UIViewControllerBasedStatusBarAppearance
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/ShazamClone/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ShazamClone/UI/SongDetail/SongDetailView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SongDetailView.swift
3 | // ShazamClone
4 | //
5 | // Created by Emmanuel Kehinde on 03/07/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct SongDetailView: View {
11 | var song: Song
12 |
13 | var body: some View {
14 | ZStack {
15 | GeometryReader { geometry in
16 | VStack {
17 | AsyncImage(url: song.artworkUrl) { phase in
18 | if let image = phase.image {
19 | image.resizable()
20 | .aspectRatio(contentMode: .fill)
21 | .frame(maxHeight: 200)
22 | .clipped()
23 | } else if phase.error != nil {
24 | Color.blue
25 | } else {
26 | ProgressView()
27 | }
28 | }
29 | .frame(height: 200, alignment: .center)
30 |
31 | VStack(alignment: .leading) {
32 | Text(song.title)
33 | .font(.headline)
34 | .foregroundColor(Color.black)
35 |
36 | Text(song.artist)
37 | .font(.subheadline)
38 | .foregroundColor(Color.black)
39 |
40 | ScrollView(.horizontal, showsIndicators: false, content: {
41 | HStack {
42 | ForEach(0.. = []
19 | @EnvironmentObject private var shazamViewModel: ShazamViewModel
20 |
21 | var body: some View {
22 | ZStack {
23 | Color.white
24 |
25 | ZStack {
26 | VStack(spacing: 20) {
27 | if shouldShowRippleView {
28 | RippleView(
29 | style: .solid,
30 | rippleCount: 5,
31 | tintColor: Color.blue,
32 | timeIntervalBetweenRipples: 0.18
33 | )
34 | .padding(.horizontal, 48)
35 | }
36 |
37 | if shouldShowNoResultView {
38 | NoResultView {
39 | onRecordButtonTapped()
40 | }
41 | }
42 |
43 | if shouldShowRecordButton {
44 | recordButton
45 | .alert(isPresented: $shouldShowRecordPermissionAlert, content: {
46 | permissionAlert
47 | })
48 | }
49 |
50 | if foundSong != nil {
51 | VStack {
52 | withAnimation(.easeInOut) {
53 | SongDetailView(song: foundSong)
54 | }
55 | Spacer()
56 | recordButton
57 | }
58 | .padding(.vertical, 64)
59 | }
60 |
61 | }
62 |
63 | VStack {
64 | HStack {
65 | Spacer()
66 | infoButton
67 | .alert(isPresented: $shouldShowInfoAlert, content: {
68 | infoAlert
69 | })
70 | }
71 | .padding(EdgeInsets(top: 16, leading: 0, bottom: 0, trailing: 32))
72 |
73 | Spacer()
74 | }
75 |
76 | VStack {
77 | Spacer()
78 | footerText.padding(.bottom, 16)
79 | }
80 | }
81 | .padding(EdgeInsets(top: Constants.topInset, leading: 0, bottom: Constants.bottomInset, trailing: 0))
82 | }
83 | .onAppear(perform: {
84 | bindViewModel()
85 | })
86 | .onDisappear(perform: {
87 | shazamViewModel.stopListening()
88 | })
89 | .ignoresSafeArea()
90 | }
91 |
92 | private var infoAlert: Alert {
93 | Alert(
94 | title: Text("Shazam Clone"),
95 | message: Text("Tap the record button to listen to music around you"),
96 | dismissButton: .default(Text("OK"))
97 | )
98 | }
99 |
100 | private var permissionAlert: Alert {
101 | Alert(
102 | title: Text("Microphone access not allowed"),
103 | message: Text("Turn on microphone access to listen to music around you"),
104 | primaryButton: .default(
105 | Text("Go to Setting"),
106 | action: {
107 | goToPermissionSettings()
108 | }
109 | ),
110 | secondaryButton: .cancel(Text("Close"))
111 | )
112 | }
113 |
114 | @ViewBuilder
115 | private var infoButton: some View {
116 | Button(action: {
117 | shazamViewModel.showInfo()
118 | }, label: {
119 | Image(systemName: "info.circle")
120 | .resizable()
121 | .frame(width: 20, height: 20, alignment: .center)
122 | .scaledToFit()
123 | .foregroundColor(Color.black.opacity(0.7))
124 | })
125 |
126 | }
127 |
128 | @ViewBuilder
129 | private var recordButton: some View {
130 | Button(action: {
131 | onRecordButtonTapped()
132 | }, label: {
133 | Image(systemName: "mic")
134 | .font(.system(size: 24, weight: .bold))
135 | .foregroundColor(.white)
136 | .frame(width: 100, height: 100, alignment: .center)
137 | .background(
138 | Circle().fill(Color.blue)
139 | .shadow(radius: 1)
140 | )
141 | })
142 |
143 | }
144 |
145 | @ViewBuilder
146 | private var footerText: some View {
147 | Text("Shazam Clone")
148 | .font(.footnote)
149 | .foregroundColor(Color.black.opacity(0.7))
150 | }
151 |
152 | private func bindViewModel() {
153 | shazamViewModel.$viewState.sink { viewState in
154 | switch viewState {
155 | case .initial:
156 | shouldShowRippleView = false
157 | shouldShowRecordButton = true
158 | shouldShowNoResultView = false
159 | case .recordingInProgress:
160 | shouldShowRecordButton = false
161 | shouldShowRippleView = true
162 | shouldShowNoResultView = false
163 | foundSong = nil
164 | case .infoAlert:
165 | shouldShowInfoAlert = true
166 | case .recordPermissionSettingsAlert:
167 | shouldShowRecordPermissionAlert = true
168 | case .noResult:
169 | shouldShowRippleView = false
170 | shouldShowNoResultView = true
171 | foundSong = nil
172 | case .result(let song):
173 | withAnimation {
174 | foundSong = song
175 | }
176 | shouldShowRippleView = false
177 | }
178 | }.store(in: &cancellables)
179 | }
180 |
181 | private func onRecordButtonTapped() {
182 | shazamViewModel.startListening()
183 | }
184 |
185 | private func goToPermissionSettings() {
186 | if let bundleId = Bundle.main.bundleIdentifier,
187 | let url = URL(string: "\(UIApplication.openSettingsURLString)&path=LOCATION/\(bundleId)") {
188 | UIApplication.shared.open(url, options: [:], completionHandler: nil)
189 | }
190 | }
191 |
192 | enum Constants {
193 | // Temporary hack for the iOS 15 weird top and bottom inset
194 | static let topInset: CGFloat = UIApplication.shared.keyWindow?.safeAreaInsets.top ?? UIApplication.shared.statusBarFrame.size.height
195 | static let bottomInset: CGFloat = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 20
196 | }
197 | }
198 |
199 | struct ShazamView_Previews: PreviewProvider {
200 | static var previews: some View {
201 | ShazamView()
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/ShazamClone.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 514A626B26978E3B008ABBDF /* RippleView in Frameworks */ = {isa = PBXBuildFile; productRef = 514A626A26978E3B008ABBDF /* RippleView */; };
11 | 51B7BFFB2690CFB200DA2E87 /* ShazamCloneApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B7BFFA2690CFB200DA2E87 /* ShazamCloneApp.swift */; };
12 | 51B7BFFD2690CFB200DA2E87 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B7BFFC2690CFB200DA2E87 /* ContentView.swift */; };
13 | 51B7BFFF2690CFB200DA2E87 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51B7BFFE2690CFB200DA2E87 /* Assets.xcassets */; };
14 | 51B7C0022690CFB200DA2E87 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51B7C0012690CFB200DA2E87 /* Preview Assets.xcassets */; };
15 | 51B7C00F2690DA2700DA2E87 /* NoResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B7C00E2690DA2700DA2E87 /* NoResultView.swift */; };
16 | 51B7C0122690F0F000DA2E87 /* ShazamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B7C0112690F0F000DA2E87 /* ShazamView.swift */; };
17 | 51B7C01B2690F16500DA2E87 /* ShazamViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B7C01A2690F16500DA2E87 /* ShazamViewModel.swift */; };
18 | 51D043192690FB3500B2DA1F /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D043182690FB3500B2DA1F /* Song.swift */; };
19 | 51D04321269109DE00B2DA1F /* SongDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D04320269109DE00B2DA1F /* SongDetailView.swift */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 51B7BFF72690CFB200DA2E87 /* ShazamClone.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShazamClone.app; sourceTree = BUILT_PRODUCTS_DIR; };
24 | 51B7BFFA2690CFB200DA2E87 /* ShazamCloneApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShazamCloneApp.swift; sourceTree = ""; };
25 | 51B7BFFC2690CFB200DA2E87 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
26 | 51B7BFFE2690CFB200DA2E87 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
27 | 51B7C0012690CFB200DA2E87 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
28 | 51B7C0032690CFB200DA2E87 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
29 | 51B7C00E2690DA2700DA2E87 /* NoResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoResultView.swift; sourceTree = ""; };
30 | 51B7C0112690F0F000DA2E87 /* ShazamView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShazamView.swift; sourceTree = ""; };
31 | 51B7C01A2690F16500DA2E87 /* ShazamViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShazamViewModel.swift; sourceTree = ""; };
32 | 51D043182690FB3500B2DA1F /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = ""; };
33 | 51D04320269109DE00B2DA1F /* SongDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongDetailView.swift; sourceTree = ""; };
34 | /* End PBXFileReference section */
35 |
36 | /* Begin PBXFrameworksBuildPhase section */
37 | 51B7BFF42690CFB200DA2E87 /* Frameworks */ = {
38 | isa = PBXFrameworksBuildPhase;
39 | buildActionMask = 2147483647;
40 | files = (
41 | 514A626B26978E3B008ABBDF /* RippleView in Frameworks */,
42 | );
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXFrameworksBuildPhase section */
46 |
47 | /* Begin PBXGroup section */
48 | 5192A6CA2693C26300809316 /* UI */ = {
49 | isa = PBXGroup;
50 | children = (
51 | 51B7C0182690F13A00DA2E87 /* NoResult */,
52 | 51B7C0142690F12200DA2E87 /* Shazam */,
53 | 51D0432326910D5300B2DA1F /* SongDetail */,
54 | );
55 | path = UI;
56 | sourceTree = "";
57 | };
58 | 5192A6CB2693C26D00809316 /* Presentation */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 51D043172690FB2600B2DA1F /* Model */,
62 | 5192A6CC2693C27E00809316 /* Shazam */,
63 | );
64 | path = Presentation;
65 | sourceTree = "";
66 | };
67 | 5192A6CC2693C27E00809316 /* Shazam */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 51B7C01A2690F16500DA2E87 /* ShazamViewModel.swift */,
71 | );
72 | path = Shazam;
73 | sourceTree = "";
74 | };
75 | 51B7BFEE2690CFB200DA2E87 = {
76 | isa = PBXGroup;
77 | children = (
78 | 51B7BFF92690CFB200DA2E87 /* ShazamClone */,
79 | 51B7BFF82690CFB200DA2E87 /* Products */,
80 | );
81 | sourceTree = "";
82 | };
83 | 51B7BFF82690CFB200DA2E87 /* Products */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 51B7BFF72690CFB200DA2E87 /* ShazamClone.app */,
87 | );
88 | name = Products;
89 | sourceTree = "";
90 | };
91 | 51B7BFF92690CFB200DA2E87 /* ShazamClone */ = {
92 | isa = PBXGroup;
93 | children = (
94 | 51B7BFFA2690CFB200DA2E87 /* ShazamCloneApp.swift */,
95 | 51B7BFFC2690CFB200DA2E87 /* ContentView.swift */,
96 | 51B7BFFE2690CFB200DA2E87 /* Assets.xcassets */,
97 | 51B7C0032690CFB200DA2E87 /* Info.plist */,
98 | 51B7C0002690CFB200DA2E87 /* Preview Content */,
99 | 5192A6CB2693C26D00809316 /* Presentation */,
100 | 5192A6CA2693C26300809316 /* UI */,
101 | );
102 | path = ShazamClone;
103 | sourceTree = "";
104 | };
105 | 51B7C0002690CFB200DA2E87 /* Preview Content */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 51B7C0012690CFB200DA2E87 /* Preview Assets.xcassets */,
109 | );
110 | path = "Preview Content";
111 | sourceTree = "";
112 | };
113 | 51B7C0142690F12200DA2E87 /* Shazam */ = {
114 | isa = PBXGroup;
115 | children = (
116 | 51B7C0112690F0F000DA2E87 /* ShazamView.swift */,
117 | );
118 | path = Shazam;
119 | sourceTree = "";
120 | };
121 | 51B7C0182690F13A00DA2E87 /* NoResult */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 51B7C00E2690DA2700DA2E87 /* NoResultView.swift */,
125 | );
126 | path = NoResult;
127 | sourceTree = "";
128 | };
129 | 51D043172690FB2600B2DA1F /* Model */ = {
130 | isa = PBXGroup;
131 | children = (
132 | 51D043182690FB3500B2DA1F /* Song.swift */,
133 | );
134 | path = Model;
135 | sourceTree = "";
136 | };
137 | 51D0432326910D5300B2DA1F /* SongDetail */ = {
138 | isa = PBXGroup;
139 | children = (
140 | 51D04320269109DE00B2DA1F /* SongDetailView.swift */,
141 | );
142 | path = SongDetail;
143 | sourceTree = "";
144 | };
145 | /* End PBXGroup section */
146 |
147 | /* Begin PBXNativeTarget section */
148 | 51B7BFF62690CFB200DA2E87 /* ShazamClone */ = {
149 | isa = PBXNativeTarget;
150 | buildConfigurationList = 51B7C0062690CFB200DA2E87 /* Build configuration list for PBXNativeTarget "ShazamClone" */;
151 | buildPhases = (
152 | 51B7BFF32690CFB200DA2E87 /* Sources */,
153 | 51B7BFF42690CFB200DA2E87 /* Frameworks */,
154 | 51B7BFF52690CFB200DA2E87 /* Resources */,
155 | );
156 | buildRules = (
157 | );
158 | dependencies = (
159 | );
160 | name = ShazamClone;
161 | packageProductDependencies = (
162 | 514A626A26978E3B008ABBDF /* RippleView */,
163 | );
164 | productName = ShazamClone;
165 | productReference = 51B7BFF72690CFB200DA2E87 /* ShazamClone.app */;
166 | productType = "com.apple.product-type.application";
167 | };
168 | /* End PBXNativeTarget section */
169 |
170 | /* Begin PBXProject section */
171 | 51B7BFEF2690CFB200DA2E87 /* Project object */ = {
172 | isa = PBXProject;
173 | attributes = {
174 | LastSwiftUpdateCheck = 1240;
175 | LastUpgradeCheck = 1240;
176 | TargetAttributes = {
177 | 51B7BFF62690CFB200DA2E87 = {
178 | CreatedOnToolsVersion = 12.4;
179 | };
180 | };
181 | };
182 | buildConfigurationList = 51B7BFF22690CFB200DA2E87 /* Build configuration list for PBXProject "ShazamClone" */;
183 | compatibilityVersion = "Xcode 9.3";
184 | developmentRegion = en;
185 | hasScannedForEncodings = 0;
186 | knownRegions = (
187 | en,
188 | Base,
189 | );
190 | mainGroup = 51B7BFEE2690CFB200DA2E87;
191 | packageReferences = (
192 | 514A626926978E3B008ABBDF /* XCRemoteSwiftPackageReference "RippleView" */,
193 | );
194 | productRefGroup = 51B7BFF82690CFB200DA2E87 /* Products */;
195 | projectDirPath = "";
196 | projectRoot = "";
197 | targets = (
198 | 51B7BFF62690CFB200DA2E87 /* ShazamClone */,
199 | );
200 | };
201 | /* End PBXProject section */
202 |
203 | /* Begin PBXResourcesBuildPhase section */
204 | 51B7BFF52690CFB200DA2E87 /* Resources */ = {
205 | isa = PBXResourcesBuildPhase;
206 | buildActionMask = 2147483647;
207 | files = (
208 | 51B7C0022690CFB200DA2E87 /* Preview Assets.xcassets in Resources */,
209 | 51B7BFFF2690CFB200DA2E87 /* Assets.xcassets in Resources */,
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | };
213 | /* End PBXResourcesBuildPhase section */
214 |
215 | /* Begin PBXSourcesBuildPhase section */
216 | 51B7BFF32690CFB200DA2E87 /* Sources */ = {
217 | isa = PBXSourcesBuildPhase;
218 | buildActionMask = 2147483647;
219 | files = (
220 | 51D043192690FB3500B2DA1F /* Song.swift in Sources */,
221 | 51B7C0122690F0F000DA2E87 /* ShazamView.swift in Sources */,
222 | 51B7C00F2690DA2700DA2E87 /* NoResultView.swift in Sources */,
223 | 51D04321269109DE00B2DA1F /* SongDetailView.swift in Sources */,
224 | 51B7BFFD2690CFB200DA2E87 /* ContentView.swift in Sources */,
225 | 51B7C01B2690F16500DA2E87 /* ShazamViewModel.swift in Sources */,
226 | 51B7BFFB2690CFB200DA2E87 /* ShazamCloneApp.swift in Sources */,
227 | );
228 | runOnlyForDeploymentPostprocessing = 0;
229 | };
230 | /* End PBXSourcesBuildPhase section */
231 |
232 | /* Begin XCBuildConfiguration section */
233 | 51B7C0042690CFB200DA2E87 /* Debug */ = {
234 | isa = XCBuildConfiguration;
235 | buildSettings = {
236 | ALWAYS_SEARCH_USER_PATHS = NO;
237 | CLANG_ANALYZER_NONNULL = YES;
238 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
240 | CLANG_CXX_LIBRARY = "libc++";
241 | CLANG_ENABLE_MODULES = YES;
242 | CLANG_ENABLE_OBJC_ARC = YES;
243 | CLANG_ENABLE_OBJC_WEAK = YES;
244 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
245 | CLANG_WARN_BOOL_CONVERSION = YES;
246 | CLANG_WARN_COMMA = YES;
247 | CLANG_WARN_CONSTANT_CONVERSION = YES;
248 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
250 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
251 | CLANG_WARN_EMPTY_BODY = YES;
252 | CLANG_WARN_ENUM_CONVERSION = YES;
253 | CLANG_WARN_INFINITE_RECURSION = YES;
254 | CLANG_WARN_INT_CONVERSION = YES;
255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
256 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
257 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
259 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
260 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
261 | CLANG_WARN_STRICT_PROTOTYPES = YES;
262 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
263 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
264 | CLANG_WARN_UNREACHABLE_CODE = YES;
265 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
266 | COPY_PHASE_STRIP = NO;
267 | DEBUG_INFORMATION_FORMAT = dwarf;
268 | ENABLE_STRICT_OBJC_MSGSEND = YES;
269 | ENABLE_TESTABILITY = YES;
270 | GCC_C_LANGUAGE_STANDARD = gnu11;
271 | GCC_DYNAMIC_NO_PIC = NO;
272 | GCC_NO_COMMON_BLOCKS = YES;
273 | GCC_OPTIMIZATION_LEVEL = 0;
274 | GCC_PREPROCESSOR_DEFINITIONS = (
275 | "DEBUG=1",
276 | "$(inherited)",
277 | );
278 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
279 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
280 | GCC_WARN_UNDECLARED_SELECTOR = YES;
281 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
282 | GCC_WARN_UNUSED_FUNCTION = YES;
283 | GCC_WARN_UNUSED_VARIABLE = YES;
284 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
285 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
286 | MTL_FAST_MATH = YES;
287 | ONLY_ACTIVE_ARCH = YES;
288 | SDKROOT = iphoneos;
289 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
290 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
291 | };
292 | name = Debug;
293 | };
294 | 51B7C0052690CFB200DA2E87 /* Release */ = {
295 | isa = XCBuildConfiguration;
296 | buildSettings = {
297 | ALWAYS_SEARCH_USER_PATHS = NO;
298 | CLANG_ANALYZER_NONNULL = YES;
299 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
300 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
301 | CLANG_CXX_LIBRARY = "libc++";
302 | CLANG_ENABLE_MODULES = YES;
303 | CLANG_ENABLE_OBJC_ARC = YES;
304 | CLANG_ENABLE_OBJC_WEAK = YES;
305 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
306 | CLANG_WARN_BOOL_CONVERSION = YES;
307 | CLANG_WARN_COMMA = YES;
308 | CLANG_WARN_CONSTANT_CONVERSION = YES;
309 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
310 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
311 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
312 | CLANG_WARN_EMPTY_BODY = YES;
313 | CLANG_WARN_ENUM_CONVERSION = YES;
314 | CLANG_WARN_INFINITE_RECURSION = YES;
315 | CLANG_WARN_INT_CONVERSION = YES;
316 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
317 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
318 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
319 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
320 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
321 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
322 | CLANG_WARN_STRICT_PROTOTYPES = YES;
323 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
324 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
325 | CLANG_WARN_UNREACHABLE_CODE = YES;
326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
327 | COPY_PHASE_STRIP = NO;
328 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
329 | ENABLE_NS_ASSERTIONS = NO;
330 | ENABLE_STRICT_OBJC_MSGSEND = YES;
331 | GCC_C_LANGUAGE_STANDARD = gnu11;
332 | GCC_NO_COMMON_BLOCKS = YES;
333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
335 | GCC_WARN_UNDECLARED_SELECTOR = YES;
336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
337 | GCC_WARN_UNUSED_FUNCTION = YES;
338 | GCC_WARN_UNUSED_VARIABLE = YES;
339 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
340 | MTL_ENABLE_DEBUG_INFO = NO;
341 | MTL_FAST_MATH = YES;
342 | SDKROOT = iphoneos;
343 | SWIFT_COMPILATION_MODE = wholemodule;
344 | SWIFT_OPTIMIZATION_LEVEL = "-O";
345 | VALIDATE_PRODUCT = YES;
346 | };
347 | name = Release;
348 | };
349 | 51B7C0072690CFB200DA2E87 /* Debug */ = {
350 | isa = XCBuildConfiguration;
351 | buildSettings = {
352 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
353 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
354 | CODE_SIGN_STYLE = Automatic;
355 | DEVELOPMENT_ASSET_PATHS = "\"ShazamClone/Preview Content\"";
356 | DEVELOPMENT_TEAM = UXB3TMTR3F;
357 | ENABLE_PREVIEWS = YES;
358 | INFOPLIST_FILE = ShazamClone/Info.plist;
359 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
360 | LD_RUNPATH_SEARCH_PATHS = (
361 | "$(inherited)",
362 | "@executable_path/Frameworks",
363 | );
364 | PRODUCT_BUNDLE_IDENTIFIER = com.emmanuelkehinde.ShazamClone;
365 | PRODUCT_NAME = "$(TARGET_NAME)";
366 | SWIFT_VERSION = 5.0;
367 | TARGETED_DEVICE_FAMILY = "1,2";
368 | };
369 | name = Debug;
370 | };
371 | 51B7C0082690CFB200DA2E87 /* Release */ = {
372 | isa = XCBuildConfiguration;
373 | buildSettings = {
374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
375 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
376 | CODE_SIGN_STYLE = Automatic;
377 | DEVELOPMENT_ASSET_PATHS = "\"ShazamClone/Preview Content\"";
378 | DEVELOPMENT_TEAM = UXB3TMTR3F;
379 | ENABLE_PREVIEWS = YES;
380 | INFOPLIST_FILE = ShazamClone/Info.plist;
381 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
382 | LD_RUNPATH_SEARCH_PATHS = (
383 | "$(inherited)",
384 | "@executable_path/Frameworks",
385 | );
386 | PRODUCT_BUNDLE_IDENTIFIER = com.emmanuelkehinde.ShazamClone;
387 | PRODUCT_NAME = "$(TARGET_NAME)";
388 | SWIFT_VERSION = 5.0;
389 | TARGETED_DEVICE_FAMILY = "1,2";
390 | };
391 | name = Release;
392 | };
393 | /* End XCBuildConfiguration section */
394 |
395 | /* Begin XCConfigurationList section */
396 | 51B7BFF22690CFB200DA2E87 /* Build configuration list for PBXProject "ShazamClone" */ = {
397 | isa = XCConfigurationList;
398 | buildConfigurations = (
399 | 51B7C0042690CFB200DA2E87 /* Debug */,
400 | 51B7C0052690CFB200DA2E87 /* Release */,
401 | );
402 | defaultConfigurationIsVisible = 0;
403 | defaultConfigurationName = Release;
404 | };
405 | 51B7C0062690CFB200DA2E87 /* Build configuration list for PBXNativeTarget "ShazamClone" */ = {
406 | isa = XCConfigurationList;
407 | buildConfigurations = (
408 | 51B7C0072690CFB200DA2E87 /* Debug */,
409 | 51B7C0082690CFB200DA2E87 /* Release */,
410 | );
411 | defaultConfigurationIsVisible = 0;
412 | defaultConfigurationName = Release;
413 | };
414 | /* End XCConfigurationList section */
415 |
416 | /* Begin XCRemoteSwiftPackageReference section */
417 | 514A626926978E3B008ABBDF /* XCRemoteSwiftPackageReference "RippleView" */ = {
418 | isa = XCRemoteSwiftPackageReference;
419 | repositoryURL = "https://github.com/emmanuelkehinde/RippleView.git";
420 | requirement = {
421 | kind = upToNextMajorVersion;
422 | minimumVersion = 1.0.2;
423 | };
424 | };
425 | /* End XCRemoteSwiftPackageReference section */
426 |
427 | /* Begin XCSwiftPackageProductDependency section */
428 | 514A626A26978E3B008ABBDF /* RippleView */ = {
429 | isa = XCSwiftPackageProductDependency;
430 | package = 514A626926978E3B008ABBDF /* XCRemoteSwiftPackageReference "RippleView" */;
431 | productName = RippleView;
432 | };
433 | /* End XCSwiftPackageProductDependency section */
434 | };
435 | rootObject = 51B7BFEF2690CFB200DA2E87 /* Project object */;
436 | }
437 |
--------------------------------------------------------------------------------