Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Create a cache system for images #573

Merged
59 changes: 59 additions & 0 deletions app-ios/Sources/CommonComponents/Timetable/CircularUserIcon.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Foundation
import SwiftUI

private actor CircularUserIconInMemoryCache {
static let shared = CircularUserIconInMemoryCache()
private init() {}

private var cache: [String: Data] = [:]

func data(urlString: String) -> Data? {
return cache[urlString]
}

func set(data: Data, urlString: String) {
cache[urlString] = data
}
}

public struct CircularUserIcon: View {
let urlString: String
@State private var iconData: Data?

public init(urlString: String) {
self.urlString = urlString
}

public var body: some View {
Group {
if let data = iconData,
let uiImage = UIImage(data: data) {
Image(uiImage: uiImage)
.resizable()
} else {
Circle().stroke(Color.gray)
}
}
.clipShape(Circle())
.task {
if let data = await CircularUserIconInMemoryCache.shared.data(urlString: urlString) {
iconData = data
return
}

guard let url = URL(string: urlString) else {
return
}
let urlRequest = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy)
if let (data, _) = try? await URLSession.shared.data(for: urlRequest) {

Check warning on line 48 in app-ios/Sources/CommonComponents/Timetable/CircularUserIcon.swift

View workflow job for this annotation

GitHub Actions / build-test-ios

passing argument of non-sendable type '(any URLSessionTaskDelegate)?' outside of main actor-isolated context may introduce data races
iconData = data
await CircularUserIconInMemoryCache.shared.set(data: data, urlString: urlString)
}
}
}
}

#Preview {
CircularUserIcon(urlString: "https://avatars.githubusercontent.com/u/10727543?s=96&v=4")
.frame(width: 32, height: 32)
}
14 changes: 2 additions & 12 deletions app-ios/Sources/CommonComponents/Timetable/TimetableCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,8 @@ public struct TimetableCard: View {

ForEach(timetableItem.speakers, id: \.id) { speaker in
HStack(spacing: 8) {
Group {
if let url = URL(string: speaker.iconUrl) {
AsyncImage(url: url) {
$0.image?.resizable()
}
} else {
Circle().stroke(Color.gray)
}
}
.frame(width: 32, height: 32)
.clipShape(Circle())

CircularUserIcon(urlString: speaker.iconUrl)
.frame(width: 32, height: 32)
Text(speaker.name)
.textStyle(.titleSmall)
.foregroundStyle(AssetColors.Surface.onSurfaceVariant.swiftUIColor)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import SwiftUI
import Theme
import Model
import CommonComponents

struct ContributorListItemView: View {
let contributor: Contributor
Expand All @@ -13,11 +14,8 @@ struct ContributorListItemView: View {
}
} label: {
HStack(alignment: .center, spacing: 12) {
AsyncImage(url: contributor.iconUrl) {
$0.image?.resizable()
}
.frame(width: 52, height: 52)
.clipShape(Circle())
CircularUserIcon(urlString: contributor.iconUrl.absoluteString)
.frame(width: 52, height: 52)

Text(contributor.userName)
.textStyle(.bodyLarge)
Expand Down
18 changes: 8 additions & 10 deletions app-ios/Sources/StaffFeature/StaffLabel.swift
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import SwiftUI
import Theme
import CommonComponents

struct StaffLabel: View {
let name: String
let icon: URL

var body: some View {
HStack(alignment: .center, spacing: 12) {
AsyncImage(url: icon) {
$0.image?.resizable()
}
.frame(width: 52, height: 52)
.clipShape(Circle())
.overlay(
Circle()
.stroke(AssetColors.Outline.outline.swiftUIColor, lineWidth: 1)
)
CircularUserIcon(urlString: icon.absoluteString)
.frame(width: 52, height: 52)
.overlay(
Circle()
.stroke(AssetColors.Outline.outline.swiftUIColor, lineWidth: 1)
)

Text(name)
.textStyle(.bodyLarge)
Expand All @@ -27,5 +25,5 @@ struct StaffLabel: View {
}

#Preview {
StaffLabel(name: "hoge", icon: .init(string: "")!)
StaffLabel(name: "hoge", icon: .init(string: "https://avatars.githubusercontent.com/u/10727543?s=156&v=4")!)
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,8 @@ public struct TimetableDetailView: View {

ForEach(store.timetableItem.speakers, id: \.id) { speaker in
HStack(spacing: 12) {
if let url = URL(string: speaker.iconUrl) {
AsyncImage(url: url) {
$0.image?.resizable()
}
CircularUserIcon(urlString: speaker.iconUrl)
.frame(width: 52, height: 52)
.clipShape(Circle())
}

VStack(alignment: .leading, spacing: 8) {
Text(speaker.name)
Expand Down
Loading