diff --git a/Vernissage.xcodeproj/project.pbxproj b/Vernissage.xcodeproj/project.pbxproj index 967cfda..f8bec6e 100644 --- a/Vernissage.xcodeproj/project.pbxproj +++ b/Vernissage.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ F8210DE32966D256001D9973 /* Status+StatusData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE22966D256001D9973 /* Status+StatusData.swift */; }; F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE42966E160001D9973 /* Color+SystemColors.swift */; }; F8210DE72966E1D1001D9973 /* Color+Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE62966E1D1001D9973 /* Color+Assets.swift */; }; + F8210DEA2966E4F9001D9973 /* AnimatePlaceholderModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE92966E4F9001D9973 /* AnimatePlaceholderModifier.swift */; }; F8341F90295C636C009C8EE6 /* UIImage+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8341F8F295C636C009C8EE6 /* UIImage+Exif.swift */; }; F8341F92295C63BB009C8EE6 /* ImageStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8341F91295C63BB009C8EE6 /* ImageStatus.swift */; }; F83901A6295D8EC000456AE2 /* LabelIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83901A5295D8EC000456AE2 /* LabelIcon.swift */; }; @@ -81,6 +82,7 @@ F8210DE22966D256001D9973 /* Status+StatusData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Status+StatusData.swift"; sourceTree = ""; }; F8210DE42966E160001D9973 /* Color+SystemColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+SystemColors.swift"; sourceTree = ""; }; F8210DE62966E1D1001D9973 /* Color+Assets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Assets.swift"; sourceTree = ""; }; + F8210DE92966E4F9001D9973 /* AnimatePlaceholderModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatePlaceholderModifier.swift; sourceTree = ""; }; F8341F8F295C636C009C8EE6 /* UIImage+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Exif.swift"; sourceTree = ""; }; F8341F91295C63BB009C8EE6 /* ImageStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageStatus.swift; sourceTree = ""; }; F83901A5295D8EC000456AE2 /* LabelIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelIcon.swift; sourceTree = ""; }; @@ -141,6 +143,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + F8210DE82966E4D8001D9973 /* Modifiers */ = { + isa = PBXGroup; + children = ( + F8210DE92966E4F9001D9973 /* AnimatePlaceholderModifier.swift */, + ); + path = Modifiers; + sourceTree = ""; + }; F8341F93295C63E2009C8EE6 /* Views */ = { isa = PBXGroup; children = ( @@ -247,6 +257,7 @@ isa = PBXGroup; children = ( F866F6A829604FFF002E8F88 /* Info.plist */, + F8210DE82966E4D8001D9973 /* Modifiers */, F88FAD30295F5010009B20C9 /* Services */, F83901A2295D863B00456AE2 /* Widgets */, F8341F97295C6434009C8EE6 /* Formatters */, @@ -367,6 +378,7 @@ F8210DDF2966CFC7001D9973 /* AttachmentData+Attachment.swift in Sources */, F80048082961E6DE00E6868A /* StatusDataHandler.swift in Sources */, F866F6A0296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift in Sources */, + F8210DEA2966E4F9001D9973 /* AnimatePlaceholderModifier.swift in Sources */, F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */, F88FAD23295F3FC4009B20C9 /* LocalFeedView.swift in Sources */, F88FAD2B295F43B8009B20C9 /* AccountData+CoreDataProperties.swift in Sources */, diff --git a/Vernissage/Modifiers/AnimatePlaceholderModifier.swift b/Vernissage/Modifiers/AnimatePlaceholderModifier.swift new file mode 100644 index 0000000..9fb6050 --- /dev/null +++ b/Vernissage/Modifiers/AnimatePlaceholderModifier.swift @@ -0,0 +1,45 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the MIT License. +// + +import SwiftUI + +struct AnimatePlaceholderModifier: AnimatableModifier { + @Binding var isLoading: Bool + + @State private var isAnim: Bool = false + private var center = (UIScreen.main.bounds.width / 2) + 110 + // private let animation: Animation = .linear(duration: 1.5) + private let animation: Animation = .easeOut(duration: 1) + + init(isLoading: Binding) { + self._isLoading = isLoading + } + + func body(content: Content) -> some View { + content.overlay(animView.mask(content)) + } + + var animView: some View { + LinearGradient( + gradient: .init(colors: [.black, .black.opacity(0.6), .black.opacity(0.3), .clear]), + startPoint: .leading, + endPoint: isAnim ? .trailing : .leading) + .animation(isLoading ? animation.repeatForever(autoreverses: false) : nil, value: isAnim) + .onAppear { + guard isLoading else { return } + isAnim.toggle() + } + .onChange(of: isLoading) { _ in + isAnim.toggle() + } + } +} + +extension View { + func animatePlaceholder(isLoading: Binding) -> some View { + self.modifier(AnimatePlaceholderModifier(isLoading: isLoading)) + } +} diff --git a/Vernissage/Views/DetailsView.swift b/Vernissage/Views/DetailsView.swift index ee55ca6..7092b8b 100644 --- a/Vernissage/Views/DetailsView.swift +++ b/Vernissage/Views/DetailsView.swift @@ -68,25 +68,38 @@ struct DetailsView: View { Rectangle() .fill(Color.placeholderText) .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width) - .redacted(reason: .placeholder) + HStack (alignment: .center) { Circle() .fill(Color.placeholderText) .frame(width: 48.0, height: 48.0) - .redacted(reason: .placeholder) VStack (alignment: .leading) { Text("Verylong Displayname") .foregroundColor(Color.mainTextColor) - .redacted(reason: .placeholder) Text("@username") .foregroundColor(Color.lightGrayColor) .font(.footnote) - .redacted(reason: .placeholder) } .padding(.leading, 8) }.padding(8) + + VStack(alignment: .leading) { + Text("Lorem ispum text something") + .foregroundColor(Color.lightGrayColor) + .font(.footnote) + Text("Lorem ispum text something sdf sdfsdf sdfdsfsdfsdf") + .foregroundColor(Color.lightGrayColor) + .font(.footnote) + + LabelIcon(iconName: "camera", value: "SONY ILCE-7M3") + LabelIcon(iconName: "camera.aperture", value: "Viltrox 24mm F1.8 E") + LabelIcon(iconName: "timelapse", value: "24.0 mm, f/1.8, 1/640s, ISO 100") + LabelIcon(iconName: "calendar", value: "2 Oct 2022") + }.padding(8) } + .redacted(reason: .placeholder) + .animatePlaceholder(isLoading: .constant(true)) } } .navigationBarTitle("Details")