Skip to content

Commit 6011389

Browse files
author
Trent Guillory
committed
Added Spotify example.
1 parent 0c9f988 commit 6011389

File tree

56 files changed

+1132
-28
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1132
-28
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# ScrollViewReactiveHeader
22

3-
A description of this package.
3+
A replacement `ScrollView` that provides a header with subtle scroll animations.
4+
5+
Using `ScrollViewReactiveHeader` is easy:

ScrollViewReactiveHeaderDemoApp/ScrollViewReactiveHeaderDemoApp.xcodeproj/project.pbxproj

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@
1818
848BCF8C26DE4EDA00F8D967 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 848BCF8B26DE4EDA00F8D967 /* Assets.xcassets */; };
1919
848BCF8F26DE4EDA00F8D967 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 848BCF8E26DE4EDA00F8D967 /* Preview Assets.xcassets */; };
2020
84D4F3B926DE4FE300E6C464 /* ScrollViewReactiveHeader in Frameworks */ = {isa = PBXBuildFile; productRef = 84D4F3B826DE4FE300E6C464 /* ScrollViewReactiveHeader */; };
21+
84D76F0E26E51FDA004C937D /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76EFC26E51FDA004C937D /* NetworkManager.swift */; };
22+
84D76F0F26E51FDA004C937D /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76EFE26E51FDA004C937D /* Song.swift */; };
23+
84D76F1026E51FDA004C937D /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76EFF26E51FDA004C937D /* HomeViewModel.swift */; };
24+
84D76F1126E51FDA004C937D /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0026E51FDA004C937D /* Album.swift */; };
25+
84D76F1426E51FDA004C937D /* AlbumThumbnail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0526E51FDA004C937D /* AlbumThumbnail.swift */; };
26+
84D76F1526E51FDA004C937D /* SpotifyHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0626E51FDA004C937D /* SpotifyHomeView.swift */; };
27+
84D76F1626E51FDA004C937D /* QuickPlayGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0726E51FDA004C937D /* QuickPlayGrid.swift */; };
28+
84D76F1726E51FDA004C937D /* HomeSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0826E51FDA004C937D /* HomeSectionHeader.swift */; };
29+
84D76F1826E51FDA004C937D /* AlbumScroll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0926E51FDA004C937D /* AlbumScroll.swift */; };
30+
84D76F1926E51FDA004C937D /* HomeHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0A26E51FDA004C937D /* HomeHeaderView.swift */; };
31+
84D76F1A26E51FDA004C937D /* SpotifyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F0B26E51FDA004C937D /* SpotifyView.swift */; };
32+
84D76F1D26E5243E004C937D /* PremiumBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D76F1C26E5243E004C937D /* PremiumBannerView.swift */; };
2133
/* End PBXBuildFile section */
2234

2335
/* Begin PBXFileReference section */
@@ -34,6 +46,18 @@
3446
848BCF8E26DE4EDA00F8D967 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
3547
848BCF9026DE4EDA00F8D967 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3648
84D4F3B626DE4FCE00E6C464 /* ScrollViewReactiveHeader */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ScrollViewReactiveHeader; path = ..; sourceTree = "<group>"; };
49+
84D76EFC26E51FDA004C937D /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
50+
84D76EFE26E51FDA004C937D /* Song.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
51+
84D76EFF26E51FDA004C937D /* HomeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
52+
84D76F0026E51FDA004C937D /* Album.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
53+
84D76F0526E51FDA004C937D /* AlbumThumbnail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumThumbnail.swift; sourceTree = "<group>"; };
54+
84D76F0626E51FDA004C937D /* SpotifyHomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpotifyHomeView.swift; sourceTree = "<group>"; };
55+
84D76F0726E51FDA004C937D /* QuickPlayGrid.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickPlayGrid.swift; sourceTree = "<group>"; };
56+
84D76F0826E51FDA004C937D /* HomeSectionHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeSectionHeader.swift; sourceTree = "<group>"; };
57+
84D76F0926E51FDA004C937D /* AlbumScroll.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumScroll.swift; sourceTree = "<group>"; };
58+
84D76F0A26E51FDA004C937D /* HomeHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeHeaderView.swift; sourceTree = "<group>"; };
59+
84D76F0B26E51FDA004C937D /* SpotifyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpotifyView.swift; sourceTree = "<group>"; };
60+
84D76F1C26E5243E004C937D /* PremiumBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumBannerView.swift; sourceTree = "<group>"; };
3761
/* End PBXFileReference section */
3862

3963
/* Begin PBXFrameworksBuildPhase section */
@@ -109,6 +133,7 @@
109133
848BCF9626DE4EFC00F8D967 /* Resource Files */,
110134
848BCF8726DE4ED800F8D967 /* ScrollViewReactiveHeaderDemoAppApp.swift */,
111135
848BCF8926DE4ED800F8D967 /* ContentView.swift */,
136+
84D76EFA26E51FDA004C937D /* Example2 */,
112137
8459FC3626E3B1B100EB434F /* Example3 */,
113138
);
114139
path = Sources;
@@ -139,6 +164,41 @@
139164
name = Frameworks;
140165
sourceTree = "<group>";
141166
};
167+
84D76EFA26E51FDA004C937D /* Example2 */ = {
168+
isa = PBXGroup;
169+
children = (
170+
84D76EFC26E51FDA004C937D /* NetworkManager.swift */,
171+
84D76EFD26E51FDA004C937D /* Models */,
172+
84D76F0426E51FDA004C937D /* Views */,
173+
84D76F0B26E51FDA004C937D /* SpotifyView.swift */,
174+
);
175+
path = Example2;
176+
sourceTree = "<group>";
177+
};
178+
84D76EFD26E51FDA004C937D /* Models */ = {
179+
isa = PBXGroup;
180+
children = (
181+
84D76EFE26E51FDA004C937D /* Song.swift */,
182+
84D76EFF26E51FDA004C937D /* HomeViewModel.swift */,
183+
84D76F0026E51FDA004C937D /* Album.swift */,
184+
);
185+
path = Models;
186+
sourceTree = "<group>";
187+
};
188+
84D76F0426E51FDA004C937D /* Views */ = {
189+
isa = PBXGroup;
190+
children = (
191+
84D76F0526E51FDA004C937D /* AlbumThumbnail.swift */,
192+
84D76F0626E51FDA004C937D /* SpotifyHomeView.swift */,
193+
84D76F0726E51FDA004C937D /* QuickPlayGrid.swift */,
194+
84D76F0826E51FDA004C937D /* HomeSectionHeader.swift */,
195+
84D76F0926E51FDA004C937D /* AlbumScroll.swift */,
196+
84D76F0A26E51FDA004C937D /* HomeHeaderView.swift */,
197+
84D76F1C26E5243E004C937D /* PremiumBannerView.swift */,
198+
);
199+
path = Views;
200+
sourceTree = "<group>";
201+
};
142202
/* End PBXGroup section */
143203

144204
/* Begin PBXNativeTarget section */
@@ -211,14 +271,26 @@
211271
isa = PBXSourcesBuildPhase;
212272
buildActionMask = 2147483647;
213273
files = (
274+
84D76F0E26E51FDA004C937D /* NetworkManager.swift in Sources */,
275+
84D76F1026E51FDA004C937D /* HomeViewModel.swift in Sources */,
214276
8459FC3D26E3C94900EB434F /* StoryListContentView.swift in Sources */,
277+
84D76F1526E51FDA004C937D /* SpotifyHomeView.swift in Sources */,
215278
8459FC3226E39AB400EB434F /* StoryListViewModel.swift in Sources */,
216279
8459FC3526E39DA600EB434F /* StoryListHeaderOverlay.swift in Sources */,
280+
84D76F1A26E51FDA004C937D /* SpotifyView.swift in Sources */,
281+
84D76F0F26E51FDA004C937D /* Song.swift in Sources */,
282+
84D76F1626E51FDA004C937D /* QuickPlayGrid.swift in Sources */,
283+
84D76F1926E51FDA004C937D /* HomeHeaderView.swift in Sources */,
284+
84D76F1826E51FDA004C937D /* AlbumScroll.swift in Sources */,
217285
8459FC3826E3B1D700EB434F /* StoryListView.swift in Sources */,
218286
848BCF8A26DE4ED800F8D967 /* ContentView.swift in Sources */,
219287
848BCF8826DE4ED800F8D967 /* ScrollViewReactiveHeaderDemoAppApp.swift in Sources */,
288+
84D76F1426E51FDA004C937D /* AlbumThumbnail.swift in Sources */,
220289
8459FC3026E39A7600EB434F /* Story.swift in Sources */,
221290
8459FC3B26E3B36E00EB434F /* StoryListCell.swift in Sources */,
291+
84D76F1126E51FDA004C937D /* Album.swift in Sources */,
292+
84D76F1D26E5243E004C937D /* PremiumBannerView.swift in Sources */,
293+
84D76F1726E51FDA004C937D /* HomeSectionHeader.swift in Sources */,
222294
);
223295
runOnlyForDeploymentPostprocessing = 0;
224296
};

ScrollViewReactiveHeaderDemoApp/Sources/ContentView.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,28 @@ struct ContentView: View {
99

1010
TabView {
1111

12+
SpotifyView()
13+
.tabItem {
14+
VStack {
15+
16+
Image(systemName: "music.note.list")
17+
18+
Text("Music")
19+
}
20+
}
21+
1222
StoryListView()
1323
.tabItem {
1424
VStack {
25+
1526
Image(systemName: "book")
1627

1728
Text("Reader")
1829
}
1930
}
2031
}
21-
.accentColor(.black)
2232
.preferredColorScheme(.light)
33+
.accentColor(.black)
2334
}
2435
}
2536

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Foundation
2+
import SwiftUI
3+
4+
struct Album: Hashable {
5+
6+
var cover: String
7+
var title: String
8+
var artist: String
9+
var songs: [Song]
10+
11+
static func == (lhs: Album, rhs: Album) -> Bool {
12+
lhs.title == rhs.title && lhs.artist == rhs.artist
13+
}
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Foundation
2+
3+
// MARK: - HomeViewSection
4+
5+
struct HomeViewSection {
6+
var order: Int
7+
var title: String
8+
var albums: [Album]
9+
var type: HomeSectionType
10+
}
11+
12+
// MARK: - HomeSectionType
13+
14+
enum HomeSectionType {
15+
case albumScroll, quickShuffle
16+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Foundation
2+
3+
struct Song: Hashable {
4+
var title: String
5+
var artist: String
6+
var duration: TimeInterval
7+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import Foundation
2+
import SwiftUI
3+
4+
class NetworkManager {
5+
6+
// MARK: Internal
7+
8+
static let shared = NetworkManager()
9+
10+
func fetchHomeScreen() -> [HomeViewSection] {
11+
// Recently played albums.
12+
let tribe = Album(
13+
cover: "a-tribe-called-quest",
14+
title: "Midnight Marauders",
15+
artist: "A Tribe Called Quest",
16+
songs: exampleSongs)
17+
let abbeyRoad = Album(
18+
cover: "abbey-road",
19+
title: "Abbey Road",
20+
artist: "The Beatles",
21+
songs: exampleSongs)
22+
let banana = Album(
23+
cover: "banana",
24+
title: "Feel Slowly",
25+
artist: "Andy Warhol",
26+
songs: exampleSongs)
27+
let blueTrain = Album(
28+
cover: "blue-train",
29+
title: "Blue Train",
30+
artist: "John Coltrane",
31+
songs: exampleSongs)
32+
33+
let recentlyPlayed = HomeViewSection(
34+
order: 1,
35+
title: "Recently Played",
36+
albums: [tribe, abbeyRoad, banana, blueTrain],
37+
type: .albumScroll)
38+
39+
// Heavy rotation albums
40+
let boutique = Album(
41+
cover: "boutique",
42+
title: "Paul's Boutique",
43+
artist: "Beastie Boys",
44+
songs: exampleSongs)
45+
let flyWithMe = Album(
46+
cover: "frank-sinatra",
47+
title: "Come Fly With Me",
48+
artist: "Frank Sinatra",
49+
songs: exampleSongs)
50+
let funkadelic = Album(
51+
cover: "funkadelic",
52+
title: "Maggot Brain",
53+
artist: "Funkadelic",
54+
songs: exampleSongs)
55+
let go2 = Album(cover: "go-2", title: "XTC Go 2", artist: "XTC", songs: exampleSongs)
56+
57+
let heavyRotation = HomeViewSection(
58+
order: 2,
59+
title: "Heavy Rotation",
60+
albums: [boutique, flyWithMe, funkadelic, go2],
61+
type: .albumScroll)
62+
63+
// Recommended albums
64+
let heavenOrVegas = Album(
65+
cover: "heaven-or-vegas",
66+
title: "Heaven or Vegas",
67+
artist: "Cocteau Twins",
68+
songs: exampleSongs)
69+
let heroes = Album(
70+
cover: "heroes",
71+
title: "Heroes",
72+
artist: "David Bowie",
73+
songs: exampleSongs)
74+
let jesusOfCool = Album(
75+
cover: "jesus-of-cool",
76+
title: "Jesus of Cool",
77+
artist: "Nick Lowe",
78+
songs: exampleSongs)
79+
let odessa = Album(
80+
cover: "odessa",
81+
title: "Odessa",
82+
artist: "Bee Gees",
83+
songs: exampleSongs)
84+
let peppers = Album(
85+
cover: "peppers",
86+
title: "Lonely Hearts",
87+
artist: "The Beatles",
88+
songs: exampleSongs)
89+
90+
let recommended = HomeViewSection(
91+
order: 3,
92+
title: "Recommended",
93+
albums: [heavenOrVegas, heroes, jesusOfCool, odessa, peppers],
94+
type: .albumScroll)
95+
96+
// Summer rewind albums
97+
let rush = Album(
98+
cover: "moving-pictures",
99+
title: "Moving Pictures",
100+
artist: "Rush",
101+
songs: exampleSongs)
102+
let tongues = Album(
103+
cover: "speaking-in-tongues",
104+
title: "Speaking in Tongues",
105+
artist: "Talking Heads",
106+
songs: exampleSongs)
107+
let pleasures = Album(
108+
cover: "unknown-pleasures",
109+
title: "Unknown Pleasures",
110+
artist: "Joywave",
111+
songs: exampleSongs)
112+
let yeezus = Album(
113+
cover: "yeezus",
114+
title: "Yeezus",
115+
artist: "Kanye West",
116+
songs: exampleSongs)
117+
118+
let summerRewind = HomeViewSection(
119+
order: 4,
120+
title: "Summer Rewind",
121+
albums: [rush, tongues, pleasures, yeezus],
122+
type: .albumScroll)
123+
124+
// Quick shuffles
125+
let quickShuffles = HomeViewSection(
126+
order: 0,
127+
title: "Good afternoon",
128+
albums: [rush, tongues, pleasures, yeezus, peppers, odessa],
129+
type: .quickShuffle)
130+
131+
return [quickShuffles, recentlyPlayed, heavyRotation, recommended, summerRewind]
132+
}
133+
134+
// MARK: Private
135+
136+
private let exampleSongs = [
137+
Song(title: "Track One", artist: "None", duration: TimeInterval(180)),
138+
Song(title: "Track Two", artist: "None", duration: TimeInterval(180)),
139+
Song(title: "Track Three", artist: "None", duration: TimeInterval(180)),
140+
Song(title: "Track Four", artist: "None", duration: TimeInterval(180)),
141+
Song(title: "Track Five", artist: "None", duration: TimeInterval(180)),
142+
Song(title: "Track Six", artist: "None", duration: TimeInterval(180)),
143+
Song(title: "Track Seven", artist: "None", duration: TimeInterval(180)),
144+
Song(title: "Track Eight", artist: "None", duration: TimeInterval(180)),
145+
Song(title: "Track Nine", artist: "None", duration: TimeInterval(180)),
146+
Song(title: "Track Ten", artist: "None", duration: TimeInterval(180)),
147+
]
148+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import SwiftUI
2+
3+
// MARK: - SpotifyHomeView
4+
5+
struct SpotifyView: View {
6+
7+
var body: some View {
8+
9+
SpotifyHomeView(sections: NetworkManager.shared.fetchHomeScreen())
10+
.edgesIgnoringSafeArea(.top)
11+
}
12+
}
13+
14+
// MARK: - SpotifyHomeView_Previews
15+
16+
struct SpotifyHomeView_Previews: PreviewProvider {
17+
18+
static var previews: some View {
19+
SpotifyView()
20+
}
21+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// AlbumScroll.swift
3+
// SpotifyClone
4+
//
5+
// Created by Trent Guillory on 10/31/20.
6+
//
7+
8+
import SwiftUI
9+
10+
struct AlbumScroll: View {
11+
@State var section: HomeViewSection
12+
13+
// add this later too (add spacing elements)
14+
@State var hPadding: CGFloat
15+
16+
var body: some View {
17+
VStack(alignment: .leading) {
18+
HomeSectionHeader(header: section.title, hPadding: hPadding)
19+
ScrollView(.horizontal, showsIndicators: false) {
20+
HStack(spacing: 18) {
21+
Color.clear
22+
.frame(width: hPadding - 18)
23+
ForEach(section.albums, id: \.self) { album in
24+
AlbumThumbnail(album: album)
25+
}
26+
}
27+
}.frame(height: 150) // add after showing scroll
28+
}
29+
}
30+
}
31+
32+
struct AlbumScroll_Previews: PreviewProvider {
33+
static var previews: some View {
34+
AlbumScroll(section: NetworkManager.shared.fetchHomeScreen().first!, hPadding: 24)
35+
}
36+
}

0 commit comments

Comments
 (0)