Skip to content

Commit

Permalink
feat(profile): friends slider
Browse files Browse the repository at this point in the history
also: fixes when user has no image + style improvements
  • Loading branch information
angristan committed Jul 26, 2021
1 parent db39df9 commit 71c833c
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 18 deletions.
4 changes: 4 additions & 0 deletions firstfm.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
82428B2826AECFC700AAC835 /* TopAlbum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82428B2726AECFC700AAC835 /* TopAlbum.swift */; };
82428B2A26AED01F00AAC835 /* UserTopAlbumsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82428B2926AED01F00AAC835 /* UserTopAlbumsResponse.swift */; };
82428B2C26AF216100AAC835 /* FriendProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82428B2B26AF216100AAC835 /* FriendProfileView.swift */; };
82428B3026AF440E00AAC835 /* UserFriendsHView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82428B2F26AF440E00AAC835 /* UserFriendsHView.swift */; };
82505CDF2675074E00CCCB58 /* ArtistRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82505CDC2675074E00CCCB58 /* ArtistRow.swift */; };
82505CE02675074E00CCCB58 /* ChartListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82505CDD2675074E00CCCB58 /* ChartListView.swift */; };
82505CE12675074E00CCCB58 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82505CDE2675074E00CCCB58 /* ContentView.swift */; };
Expand Down Expand Up @@ -135,6 +136,7 @@
82428B2726AECFC700AAC835 /* TopAlbum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopAlbum.swift; sourceTree = "<group>"; };
82428B2926AED01F00AAC835 /* UserTopAlbumsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTopAlbumsResponse.swift; sourceTree = "<group>"; };
82428B2B26AF216100AAC835 /* FriendProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendProfileView.swift; sourceTree = "<group>"; };
82428B2F26AF440E00AAC835 /* UserFriendsHView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserFriendsHView.swift; sourceTree = "<group>"; };
82505CDC2675074E00CCCB58 /* ArtistRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArtistRow.swift; sourceTree = "<group>"; };
82505CDD2675074E00CCCB58 /* ChartListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartListView.swift; sourceTree = "<group>"; };
82505CDE2675074E00CCCB58 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -344,6 +346,7 @@
82428B2326AEC53C00AAC835 /* TopUserTracksView.swift */,
82428B2526AECDBC00AAC835 /* TopUserAlbumsView.swift */,
82428B2B26AF216100AAC835 /* FriendProfileView.swift */,
82428B2F26AF440E00AAC835 /* UserFriendsHView.swift */,
);
path = Profile;
sourceTree = "<group>";
Expand Down Expand Up @@ -621,6 +624,7 @@
82505CE72675300400CCCB58 /* SpotifyArtistSearchResponse.swift in Sources */,
82BBD2482698B37F009B42FC /* TrendsViewModel.swift in Sources */,
82F0D54D2697AAC7007CEA98 /* SearchViewModel.swift in Sources */,
82428B3026AF440E00AAC835 /* UserFriendsHView.swift in Sources */,
82D5B4D22696DBD700716931 /* ScrobblesViewModel.swift in Sources */,
82A006BE2679636F0009BD71 /* SpotifyTrackSearchResponse.swift in Sources */,
825F0FC126A6F72F007BA84B /* ArtistInfoView.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion firstfm/Models/LastFM/Friend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ struct Friend: Codable, Identifiable {
var id: String { name }
let playlists, playcount, subscriber, name: String
let country: String
let image: [LastFMImage ]
var image: [LastFMImage]
let registered: Registered
let url: String
let realname, bootstrap: String
Expand Down
5 changes: 5 additions & 0 deletions firstfm/Service/LastFMAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ class LastFMAPI {
if let statusCode = nsHTTPResponse?.statusCode {
print("LastFMAPI status code = \(statusCode)")
if statusCode != 200 {
if lastFMMethod == "user.getFriends" && statusCode == 400 {
// The API returns a 400 when the user has no friends 🤨
callback(FriendsResponse(friends: Friends(user: [])) as! T, nil)
return
}
let error = NSError(domain: "", code: statusCode, userInfo: [ NSLocalizedDescriptionKey: "Invalid API response 😢. Please try again"])
callback(callbackData, error as Error)
return
Expand Down
24 changes: 16 additions & 8 deletions firstfm/ViewModel/ProfileViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,43 +25,51 @@ class ProfileViewModel: ObservableObject {
self.getTopArtists(username: username, period: "overall")
self.getTopTracks(username: username, period: "overall")
self.getTopAlbums(username: username, period: "overall")
self.getFriends(username: username)
}

func getProfile(username: String) {
// self.isLoading = true

LastFMAPI.request(lastFMMethod: "user.getInfo", args: ["user": username]) { (data: UserInfoResponse?, error) -> Void in
if error != nil {
DispatchQueue.main.async {
FloatingNotificationBanner(title: "Failed to load profile", subtitle: error?.localizedDescription, style: .danger).show()
}
}
// self.isLoading = false

if let data = data {
var user = data.user
if user.image[3].url == "" {
user.image[3].url = "https://bonds-and-shares.com/wp-content/uploads/2019/07/placeholder-user.png"
}
DispatchQueue.main.async {
self.user = data.user
self.user = user
}
}
}
}

func getFriends(username: String) {
// self.isFriendsLoading = true

LastFMAPI.request(lastFMMethod: "user.getFriends", args: ["user": username]) { (data: FriendsResponse?, error) -> Void in
if error != nil {
DispatchQueue.main.async {
FloatingNotificationBanner(title: "Failed to load friends", subtitle: error?.localizedDescription, style: .danger).show()
}
}
// self.isFriendsLoading = false

if let data = data {
var friends = data.friends.user

for index in friends.indices {
if friends[index].image[3].url == "" {
friends[index].image[3].url = "https://bonds-and-shares.com/wp-content/uploads/2019/07/placeholder-user.png"
}
}

DispatchQueue.main.async {
self.friends = data.friends.user
self.friends = friends
}
}
self.isFriendsLoading = false
}
}

Expand Down
19 changes: 12 additions & 7 deletions firstfm/Views/Profile/FriendProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,19 @@ struct FriendProfileView: View {
.resizable()
.loadImmediately()
.aspectRatio(contentMode: .fill)
.overlay(TintOverlayView().opacity(0.2))
.overlay(TintOverlayView().opacity(0.3))
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(y: geometry.frame(in: .global).minY/9)
.clipped()
.blur(radius: 3)
} else {
KFImage.url(URL(string: !self.profile.topArtists.isEmpty ? self.profile.topArtists[0].image[0].url : "https://www.nme.com/wp-content/uploads/2021/04/twice-betterconceptphoto-2020.jpg" )!)
.resizable()
.loadImmediately()
.aspectRatio(contentMode: .fill)
.overlay(TintOverlayView().opacity(0.2))
.overlay(TintOverlayView().opacity(0.3))
.frame(width: geometry.size.width, height: geometry.size.height + geometry.frame(in: .global).minY)
.clipped()
.offset(y: -geometry.frame(in: .global).minY)
.blur(radius: 3)
}
} .redacted(reason: self.profile.topArtists.isEmpty ? .placeholder : [])
}
Expand Down Expand Up @@ -90,20 +88,27 @@ struct FriendProfileView: View {
.environmentObject(profile)
.frame(
width: g.size.width - 5,
height: g.size.height * 0.7,
height: g.size.height * 0.75,
alignment: .center
)
.offset(y: -100)

TopUserAlbumsView(albums: profile.topAlbums)
.environmentObject(profile)
.offset(y: -120)
}

if !profile.isFriendsLoading && !profile.friends.isEmpty {
UserFriendsHView()
.environmentObject(profile)
.offset(y: -120)
}

}.padding(.bottom, -100)
}
}
.onLoad {
self.profile.getAll(username: friend.name)
}.navigationTitle("\(friend.name)'s profile")
}.navigationBarTitle("\(friend.name)'s profile", displayMode: .inline)

}
}
Expand Down
9 changes: 7 additions & 2 deletions firstfm/Views/Profile/ProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ struct ProfileView: View {
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(y: geometry.frame(in: .global).minY/9)
.clipped()
.blur(radius: 3)
} else {
KFImage.url(URL(string: !self.profile.topArtists.isEmpty ? self.profile.topArtists[0].image[0].url : "https://www.nme.com/wp-content/uploads/2021/04/twice-betterconceptphoto-2020.jpg" )!)
.resizable()
Expand All @@ -39,7 +38,6 @@ struct ProfileView: View {
.frame(width: geometry.size.width, height: geometry.size.height + geometry.frame(in: .global).minY)
.clipped()
.offset(y: -geometry.frame(in: .global).minY)
.blur(radius: 3)
}
} .redacted(reason: self.profile.topArtists.isEmpty ? .placeholder : [])
}
Expand Down Expand Up @@ -99,7 +97,14 @@ struct ProfileView: View {
TopUserAlbumsView(albums: profile.topAlbums)
.environmentObject(profile)
.offset(y: -120)

if !profile.isFriendsLoading && !profile.friends.isEmpty {
UserFriendsHView()
.environmentObject(profile)
.offset(y: -120)
}
}
.padding(.bottom, -100)
.edgesIgnoringSafeArea(.top)
}.edgesIgnoringSafeArea(.top)
.navigationBarTitle("")
Expand Down
69 changes: 69 additions & 0 deletions firstfm/Views/Profile/UserFriendsHView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import SwiftUI
import Kingfisher

struct UserFriendsHView: View {
@EnvironmentObject var vm: ProfileViewModel

var body: some View {
Section {
HStack {
Text("Friends").font(.headline).unredacted()
Spacer()
}
ScrollView(.horizontal, showsIndicators: false) {
HStack {
if !vm.friends.isEmpty {
ForEach(vm.friends, id: \.name) {friend in
ZStack {
Button("") {}
NavigationLink(
destination: FriendProfileView(friend: friend),
label: {
VStack {
if friend.image[3].url == "" {
KFImage.url(URL(string: "https://bonds-and-shares.com/wp-content/uploads/2019/07/placeholder-user.png" )!)
.resizable()
.loadImmediately()
.aspectRatio(contentMode: .fill)
.frame(width: 120, height: 120)
.clipShape(Circle())
.cornerRadius(.infinity)
} else {
KFImage.url(URL(string: friend.image[3].url )!)
.resizable()
.loadImmediately()
.aspectRatio(contentMode: .fill)
.frame(width: 120, height: 120)
.clipShape(Circle())
.cornerRadius(.infinity)
}

Text(friend.name).font(.subheadline)
.foregroundColor(.gray).lineLimit(1)
}.padding(.horizontal, 10)
})
}

}
} else {
// Placeholder for redacted
ForEach((1...5), id: \.self) {_ in
VStack {
KFImage.url(URL(string: "https://lastfm.freetls.fastly.net/i/u/64s/4128a6eb29f94943c9d206c08e625904.webp")!)
.resizable()
.loadImmediately()
.aspectRatio(contentMode: .fill)
.frame(width: 120, height: 120)
.clipShape(Circle())
.cornerRadius(.infinity)

Text("Friend").font(.subheadline)
.foregroundColor(.gray).lineLimit(1)
}
}
}
}
}
}.padding()
}
}

0 comments on commit 71c833c

Please sign in to comment.