Fix loading data on waterfall widget

This commit is contained in:
Marcin Czachurski 2023-09-20 16:22:15 +02:00
parent 3664464224
commit b2655e419f
3 changed files with 83 additions and 32 deletions

View File

@ -32,3 +32,9 @@ In the name of the folders you have to put the code of the new language ([here](
Then you have to open files in these folders and translate them 🇯🇵🇫🇷🇨🇮🇧🇪. After translation create a Pull Request 👍.
From time to time you have to come back and translate lines which has been added since the last translation.
## Technical debt
- Use auto generated resources (Color/Images) instead static extensions (how to do this in separete Swift Packages?)
- Enable swiftlint (https://github.com/realm/SwiftLint/issues/5053)
- Investigate new (iOS 17) Observables
- Check how to migrate to SwiftData (iOS 17)

View File

@ -183,6 +183,7 @@
F89D6C4629718193001DA3D4 /* GeneralSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C4529718193001DA3D4 /* GeneralSectionView.swift */; };
F89D6C4A297196FF001DA3D4 /* ImageViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C49297196FF001DA3D4 /* ImageViewer.swift */; };
F89F57B029D1C11200001EE3 /* RelationshipModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89F57AF29D1C11200001EE3 /* RelationshipModel.swift */; };
F8A192102ABB322E00C2599A /* Semaphore in Frameworks */ = {isa = PBXBuildFile; productRef = F8A1920F2ABB322E00C2599A /* Semaphore */; };
F8A93D7E2965FD89001D8331 /* UserProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A93D7D2965FD89001D8331 /* UserProfileView.swift */; };
F8AFF7C129B259150087D083 /* HashtagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AFF7C029B259150087D083 /* HashtagsView.swift */; };
F8AFF7C429B25EF40087D083 /* ImagesGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AFF7C329B25EF40087D083 /* ImagesGrid.swift */; };
@ -455,6 +456,7 @@
F8210DD72966BB7E001D9973 /* NukeExtensions in Frameworks */,
F88BC52D29E04BB600CE6141 /* EnvironmentKit in Frameworks */,
F8210DD92966BB7E001D9973 /* NukeUI in Frameworks */,
F8A192102ABB322E00C2599A /* Semaphore in Frameworks */,
F89B5CC029D019B600549F2F /* HTMLString in Frameworks */,
F88BC52A29E046D700CE6141 /* WidgetsKit in Frameworks */,
);
@ -999,6 +1001,7 @@
F88BC52629E0431D00CE6141 /* ServicesKit */,
F88BC52929E046D700CE6141 /* WidgetsKit */,
F88BC52C29E04BB600CE6141 /* EnvironmentKit */,
F8A1920F2ABB322E00C2599A /* Semaphore */,
);
productName = Vernissage;
productReference = F88C2468295C37B80006098B /* Vernissage.app */;
@ -1042,6 +1045,7 @@
F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */,
F89B5CBE29D019B600549F2F /* XCRemoteSwiftPackageReference "HTMLString" */,
F84625F929FE393B002D3AF4 /* XCRemoteSwiftPackageReference "QRCode" */,
F8A1920E2ABB322E00C2599A /* XCRemoteSwiftPackageReference "Semaphore" */,
);
productRefGroup = F88C2469295C37B80006098B /* Products */;
projectDirPath = "";
@ -1310,12 +1314,14 @@
F864F76E29BB91B600B13921 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 204;
CURRENT_PROJECT_VERSION = 205;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageWidget/Info.plist;
@ -1340,11 +1346,13 @@
F864F76F29BB91B600B13921 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 204;
CURRENT_PROJECT_VERSION = 205;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageWidget/Info.plist;
@ -1369,10 +1377,12 @@
F88BC50D29E02F3900CE6141 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO;
CODE_SIGN_ENTITLEMENTS = VernissageShare/VernissageShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 204;
CURRENT_PROJECT_VERSION = 205;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageShare/Info.plist;
@ -1397,9 +1407,11 @@
F88BC50E29E02F3900CE6141 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO;
CODE_SIGN_ENTITLEMENTS = VernissageShare/VernissageShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 204;
CURRENT_PROJECT_VERSION = 205;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageShare/Info.plist;
@ -1547,12 +1559,13 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "Violet Blue Pride Pride-Camera Blue-Camera Violet-Camera Orange-Camera Orange Yellow-Camera Yellow Gradient-Camera Gradient";
ASSETCATALOG_COMPILER_APPICON_NAME = Default;
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 204;
CURRENT_PROJECT_VERSION = 205;
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
DEVELOPMENT_TEAM = B2U9FEKYP8;
ENABLE_PREVIEWS = YES;
@ -1590,11 +1603,12 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "Violet Blue Pride Pride-Camera Blue-Camera Violet-Camera Orange-Camera Orange Yellow-Camera Yellow Gradient-Camera Gradient";
ASSETCATALOG_COMPILER_APPICON_NAME = Default;
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 204;
CURRENT_PROJECT_VERSION = 205;
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
DEVELOPMENT_TEAM = B2U9FEKYP8;
ENABLE_PREVIEWS = YES;
@ -1699,6 +1713,14 @@
minimumVersion = 6.0.0;
};
};
F8A1920E2ABB322E00C2599A /* XCRemoteSwiftPackageReference "Semaphore" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/groue/Semaphore";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.0.8;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@ -1772,6 +1794,11 @@
package = F89B5CBE29D019B600549F2F /* XCRemoteSwiftPackageReference "HTMLString" */;
productName = HTMLString;
};
F8A1920F2ABB322E00C2599A /* Semaphore */ = {
isa = XCSwiftPackageProductDependency;
package = F8A1920E2ABB322E00C2599A /* XCRemoteSwiftPackageReference "Semaphore" */;
productName = Semaphore;
};
/* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */

View File

@ -6,6 +6,7 @@
import SwiftUI
import WidgetsKit
import Semaphore
struct WaterfallGrid<Data, ID, Content>: View where Data: RandomAccessCollection, Data: Equatable, Content: View,
ID: Hashable, Data.Element: Equatable, Data.Element: Identifiable, Data.Element: Hashable, Data.Element: Sizable {
@ -17,9 +18,9 @@ struct WaterfallGrid<Data, ID, Content>: View where Data: RandomAccessCollection
@State private var columnsData: [ColumnData<Data.Element>] = []
@State private var processedItems: [Data.Element.ID] = []
@State private var isDuringLoading: Bool = false
private let onLoadMore: () async -> Void
private let semaphore = AsyncSemaphore(value: 1)
var body: some View {
HStack(alignment: .top, spacing: 20) {
@ -30,12 +31,12 @@ struct WaterfallGrid<Data, ID, Content>: View where Data: RandomAccessCollection
}
if self.hideLoadMore == false {
// We can show multiple loading indicators. Each indicator can run loading feature in pararell.
// Thus we have to be sure that loading will exeute one by one.
LoadingIndicator()
.task {
if isDuringLoading == false {
isDuringLoading = true
await self.onLoadMore()
isDuringLoading = false
Task { @MainActor in
await self.loadMoreData()
}
}
}
@ -52,31 +53,48 @@ struct WaterfallGrid<Data, ID, Content>: View where Data: RandomAccessCollection
self.recalculateArrays()
}
}
private func loadMoreData() async {
await semaphore.wait()
defer { semaphore.signal() }
await self.onLoadMore()
}
private func recalculateArrays() {
self.columnsData = []
self.processedItems = []
for _ in 0 ..< self.columns {
self.columnsData.append(ColumnData())
}
for item in self.data {
let index = self.minimumHeightIndex()
self.columnsData[index].data.append(item)
self.columnsData[index].height = self.columnsData[index].height + self.calculateHeight(item: item)
self.processedItems.append(item.id)
Task { @MainActor in
await semaphore.wait()
defer { semaphore.signal() }
self.columnsData = []
self.processedItems = []
for _ in 0 ..< self.columns {
self.columnsData.append(ColumnData())
}
for item in self.data {
let index = self.minimumHeightIndex()
self.columnsData[index].data.append(item)
self.columnsData[index].height = self.columnsData[index].height + self.calculateHeight(item: item)
self.processedItems.append(item.id)
}
}
}
private func appendToArrays() {
for item in self.data where self.processedItems.contains(where: { $0 == item.id }) == false {
let index = self.minimumHeightIndex()
self.columnsData[index].data.append(item)
self.columnsData[index].height = self.columnsData[index].height + self.calculateHeight(item: item)
self.processedItems.append(item.id)
Task { @MainActor in
await semaphore.wait()
defer { semaphore.signal() }
for item in self.data where self.processedItems.contains(where: { $0 == item.id }) == false {
let index = self.minimumHeightIndex()
self.columnsData[index].data.append(item)
self.columnsData[index].height = self.columnsData[index].height + self.calculateHeight(item: item)
self.processedItems.append(item.id)
}
}
}