bind images and fix ranking row (#36)

Co-authored-by: ludelanier <lucas.delanier@etu.uca.fr>
Reviewed-on: #36
pull/38/head
Lucas DELANIER 11 months ago
parent 5d1ea8492a
commit ef1f130ec5

@ -29,7 +29,7 @@ struct Friend: View {
var body: some View {
HStack{
UserPicture(picture: nil,username: user.username, size: 45)
UserPicture(picture: user.image,username: user.username, size: 45)
Text(user.username)
.fontWeight(.medium)
.padding(.leading, 5)

@ -10,7 +10,7 @@ import SwiftUI
struct RankingRow: View {
var number: Int
var image: String
var image: String?
var pseudo: String
var allCoins: Int
@ -18,12 +18,12 @@ struct RankingRow: View {
HStack(){
Text(number.description)
.textStyle(weight: .bold, color: AllInColors.lightPurpleColor, size: 18)
.padding(.leading, 15)
UserInfo(username: pseudo, value: allCoins)
UserInfo(username: pseudo, picture: image, value: allCoins)
}
.padding(10)
.padding(.horizontal, 5)
.background(AllInColors.componentBackgroundColor)
.cornerRadius(8)
.padding([.leading,.trailing],20)
.frame(maxWidth: 750)
}
}

@ -10,10 +10,11 @@ import Model
struct UserInfo: View {
var username: String
var picture: String?
var value: Int
var body: some View {
HStack {
UserPicture(username: username, size: 35)
UserPicture(picture: picture, username: username, size: 35)
.padding(.trailing, 7)
Text(username)
.font(.system(size: 15))
@ -24,10 +25,10 @@ struct UserInfo: View {
.font(.system(size: 18))
.foregroundStyle(AllInColors.lightPurpleColor)
.fontWeight(.bold)
.padding(.trailing, 8)
.padding(.trailing, 4)
Image("PurpleAllCoin")
.resizable()
.frame(width: 11, height: 12)
.frame(width: 15, height: 16)
}
}
}

@ -6,41 +6,46 @@
//
import SwiftUI
struct UserPicture: View {
var picture: String?
var username: String
var size: CGFloat
var body: some View {
ZStack {
if picture != nil {
AsyncImage(
url: URL(string:picture!),
content: { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(Circle())
},
placeholder: {
ProgressView()
}
)
if let pictureURL = picture {
userImage(url: pictureURL)
} else {
Circle()
.foregroundColor(.gray)
.frame(width: size, height: size)
.overlay(
Text(username.prefix(2).uppercased())
.fontWeight(.medium)
.foregroundStyle(.white)
.font(.system(size: fontSize(for: size)))
)
placeholderImage
}
}
}
func fontSize(for diameter: CGFloat) -> CGFloat {
@MainActor private func userImage(url: String) -> some View {
AsyncCachedImage(url: URL(string: url)) { image in
image
.resizable()
.frame(width: size, height: size)
.clipShape(Circle())
} placeholder: {
placeholderImage
}
}
private var placeholderImage: some View {
Circle()
.foregroundColor(.gray)
.frame(width: size, height: size)
.overlay(
Text(username.prefix(2).uppercased())
.fontWeight(.medium)
.foregroundStyle(.white)
.font(.system(size: fontSize(for: size)))
)
}
private func fontSize(for diameter: CGFloat) -> CGFloat {
let fontScaleFactor: CGFloat = 0.45
return diameter * fontScaleFactor
}

@ -0,0 +1,71 @@
//
// asyncCachedImage.swift
// AllIn
//
// Created by Lucas Delanier on 06/06/2024.
//
import SwiftUI
@MainActor
struct AsyncCachedImage<ImageView: View, PlaceholderView: View>: View {
// Input dependencies
var url: URL?
@ViewBuilder var content: (Image) -> ImageView
@ViewBuilder var placeholder: () -> PlaceholderView
// Downloaded image
@State var image: UIImage? = nil
init(
url: URL?,
@ViewBuilder content: @escaping (Image) -> ImageView,
@ViewBuilder placeholder: @escaping () -> PlaceholderView
) {
self.url = url
self.content = content
self.placeholder = placeholder
}
var body: some View {
VStack {
if let uiImage = image {
content(Image(uiImage: uiImage))
} else {
placeholder()
.onAppear {
Task {
image = await downloadPhoto()
}
}
}
}
}
// Downloads if the image is not cached already
// Otherwise returns from the cache
private func downloadPhoto() async -> UIImage? {
do {
guard let url else { return nil }
// Check if the image is cached already
if let cachedResponse = URLCache.shared.cachedResponse(for: .init(url: url)) {
return UIImage(data: cachedResponse.data)
} else {
let (data, response) = try await URLSession.shared.data(from: url)
// Save returned image data into the cache
URLCache.shared.storeCachedResponse(.init(response: response, data: data), for: .init(url: url))
guard let image = UIImage(data: data) else {
return nil
}
return image
}
} catch {
print("Error downloading: \(error)")
return nil
}
}
}

@ -122,7 +122,8 @@ struct DetailsView: View {
.padding(.bottom, 10)
ScrollView(showsIndicators: false) {
ForEach(viewModel.betDetail?.participations ?? []) { participation in
UserInfo(username: participation.username, value: participation.stake).padding(.horizontal, 10)
// TODO
UserInfo(username: participation.username, picture: nil , value: participation.stake).padding(.horizontal, 10)
}
}
.padding(.bottom, geometry.safeAreaInsets.bottom + 28)

@ -60,8 +60,8 @@ struct MainView: View {
if self.showMenu {
Menu()
.frame(width: geometry.size.width*0.83)
.transition(.move(edge: .leading))
.frame(width: geometry.size.width*0.83)
}
}

@ -51,7 +51,7 @@ struct RankingView: View {
.cornerRadius(41.5, corners: .topLeft)
.cornerRadius(8, corners: .topRight)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight])
UserPicture(picture: nil, username: viewModel.friends[0].username, size: 70)
UserPicture(picture: viewModel.friends[0].image, username: viewModel.friends[0].username, size: 70)
.offset(x: 0, y: -55)
Text("1")
@ -95,7 +95,7 @@ struct RankingView: View {
.cornerRadius(8, corners: .topLeft)
.cornerRadius(15, corners: [.bottomLeft, .bottomRight])
UserPicture(picture: nil, username: viewModel.friends[1].username, size: 50)
UserPicture(picture: viewModel.friends[1].image, username: viewModel.friends[1].username, size: 50)
.offset(x: 0, y: -50)
Text("2")
@ -122,13 +122,14 @@ struct RankingView: View {
let friend = viewModel.friends[index]
RankingRow(
number: index + 1,
image: "defaultUserImage",
image: friend.image,
pseudo: friend.username,
allCoins: friend.nbCoins
)
}
}
.padding(.top, 10)
.padding(.horizontal, 20)
}
Spacer()
}

@ -15,6 +15,7 @@
123590B62B5537E200F7AEBD /* ResultBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B52B5537E200F7AEBD /* ResultBanner.swift */; };
123590B82B5541BA00F7AEBD /* ParticipateButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123590B72B5541BA00F7AEBD /* ParticipateButton.swift */; };
123F31DB2C0F26E8009B6D65 /* userPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123F31DA2C0F26E8009B6D65 /* userPicture.swift */; };
123F31E02C11E99E009B6D65 /* asyncCachedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */; };
1244EF602B4EC31E00374ABF /* HistoricBetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */; };
1244EF622B4EC67000374ABF /* ReviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1244EF612B4EC67000374ABF /* ReviewCard.swift */; };
129D051D2B6E7FF0003D3E08 /* OddCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */; };
@ -154,6 +155,7 @@
123590B52B5537E200F7AEBD /* ResultBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultBanner.swift; sourceTree = "<group>"; };
123590B72B5541BA00F7AEBD /* ParticipateButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipateButton.swift; sourceTree = "<group>"; };
123F31DA2C0F26E8009B6D65 /* userPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = userPicture.swift; sourceTree = "<group>"; };
123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = asyncCachedImage.swift; sourceTree = "<group>"; };
1244EF5F2B4EC31E00374ABF /* HistoricBetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricBetView.swift; sourceTree = "<group>"; };
1244EF612B4EC67000374ABF /* ReviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewCard.swift; sourceTree = "<group>"; };
129D051C2B6E7FF0003D3E08 /* OddCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OddCapsule.swift; sourceTree = "<group>"; };
@ -274,6 +276,14 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
123F31DE2C11E979009B6D65 /* Utils */ = {
isa = PBXGroup;
children = (
123F31DF2C11E99E009B6D65 /* asyncCachedImage.swift */,
);
path = Utils;
sourceTree = "<group>";
};
EC1D15402B715A7A0094833E /* Protocols */ = {
isa = PBXGroup;
children = (
@ -309,6 +319,7 @@
EC6B969A2B24B4CC00FC1C58 /* AllIn */ = {
isa = PBXGroup;
children = (
123F31DE2C11E979009B6D65 /* Utils */,
ECF872852B93B9D900F9D240 /* AllIn.entitlements */,
EC7EF7462B87E3470022B5D9 /* QuickActions */,
ECB7BC662B2F1AAD002A6654 /* ViewModels */,
@ -676,6 +687,7 @@
EC6B969C2B24B4CC00FC1C58 /* AllInApp.swift in Sources */,
123590B42B51792000F7AEBD /* DetailsView.swift in Sources */,
ECB26A192B40744F00FE06B3 /* RankingViewModel.swift in Sources */,
123F31E02C11E99E009B6D65 /* asyncCachedImage.swift in Sources */,
EC650A502B2793D5003AFCAD /* TextCapsule.swift in Sources */,
EC650A482B25DCFF003AFCAD /* UsersPreview.swift in Sources */,
EC17A15E2B6A955E008A8679 /* CurrentBetView.swift in Sources */,

Loading…
Cancel
Save