diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 3c940a890..1c05bd73e 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -122,6 +122,7 @@ 7B81682828B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */; }; 7B81682A28B6F1420069F315 /* ReactionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682928B6F1420069F315 /* ReactionResponse.swift */; }; 7B81682C28B72F480069F315 /* PendingChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682B28B72F480069F315 /* PendingChange.swift */; }; + 7B81FB5A2AB01B17002FB267 /* LoadingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81FB582AB01AA8002FB267 /* LoadingIndicatorView.swift */; }; 7B8914772A7CAAE200A4C627 /* SessionHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8914762A7CAAE200A4C627 /* SessionHostingViewController.swift */; }; 7B8C44C528B49DDA00FBE25F /* NewConversationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */; }; 7B8D5FC428332600008324D9 /* VisibleMessage+Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */; }; @@ -1239,6 +1240,7 @@ 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _007_HomeQueryOptimisationIndexes.swift; sourceTree = ""; }; 7B81682928B6F1420069F315 /* ReactionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionResponse.swift; sourceTree = ""; }; 7B81682B28B72F480069F315 /* PendingChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PendingChange.swift; sourceTree = ""; }; + 7B81FB582AB01AA8002FB267 /* LoadingIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingIndicatorView.swift; sourceTree = ""; }; 7B8914762A7CAAE200A4C627 /* SessionHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionHostingViewController.swift; sourceTree = ""; }; 7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationVC.swift; sourceTree = ""; }; 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Reaction.swift"; sourceTree = ""; }; @@ -2697,6 +2699,7 @@ 7B2561C329874851005C086C /* SessionCarouselView+Info.swift */, 7B3A3933298882D6002FE4AC /* SessionCarouselViewDelegate.swift */, 7B8914762A7CAAE200A4C627 /* SessionHostingViewController.swift */, + 7B81FB582AB01AA8002FB267 /* LoadingIndicatorView.swift */, ); path = Shared; sourceTree = ""; @@ -6141,6 +6144,7 @@ 7BD976972A776C76001B466F /* SessionCarouselView+SwiftUI.swift in Sources */, B8041A9525C8FA1D003C2166 /* MediaLoaderView.swift in Sources */, 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */, + 7B81FB5A2AB01B17002FB267 /* LoadingIndicatorView.swift in Sources */, 7B9F71D42852EEE2006DFE7B /* Emoji+Name.swift in Sources */, 4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */, C328253025CA55370062D0A7 /* ContextMenuWindow.swift in Sources */, diff --git a/Session/Conversations/Message Cells/Content Views/LinkPreviewView_SwiftUI.swift b/Session/Conversations/Message Cells/Content Views/LinkPreviewView_SwiftUI.swift index 6257d56c1..c762e0c35 100644 --- a/Session/Conversations/Message Cells/Content Views/LinkPreviewView_SwiftUI.swift +++ b/Session/Conversations/Message Cells/Content Views/LinkPreviewView_SwiftUI.swift @@ -1,7 +1,6 @@ // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import SwiftUI -import NVActivityIndicatorView // TODO: Loading view import SessionUIKit import SessionMessagingKit @@ -60,23 +59,28 @@ public struct LinkPreviewView_SwiftUI: View { height: imageSize ) .cornerRadius(state is LinkPreview.SentState ? 0 : 8) + } else if + state is LinkPreview.DraftState || state is LinkPreview.SentState, + let defaultImage: UIImage = UIImage(named: "Link")?.withRenderingMode(.alwaysTemplate) + { + Image(uiImage: defaultImage) + .foregroundColor( + themeColor: isOutgoing ? + .messageBubble_outgoingText : + .messageBubble_incomingText + ) + .frame( + width: imageSize, + height: imageSize + ) + .cornerRadius(state is LinkPreview.SentState ? 0 : 8) } else { - if - state is LinkPreview.DraftState || state is LinkPreview.SentState, - let defaultImage: UIImage = UIImage(named: "Link")?.withRenderingMode(.alwaysTemplate) - { - Image(uiImage: defaultImage) - .foregroundColor( - themeColor: isOutgoing ? - .messageBubble_outgoingText : - .messageBubble_incomingText - ) - .frame( - width: imageSize, - height: imageSize - ) - .cornerRadius(state is LinkPreview.SentState ? 0 : 8) - } + ActivityIndicator() + .foregroundColor(.black) + .frame( + width: Self.loaderSize, + height: Self.loaderSize + ) } // Link preview title @@ -116,16 +120,28 @@ public struct LinkPreviewView_SwiftUI: View { struct LinkPreviewView_SwiftUI_Previews: PreviewProvider { static var previews: some View { - LinkPreviewView_SwiftUI( - state: LinkPreview.DraftState( - linkPreviewDraft: .init( - urlString: "https://github.com/oxen-io", - title: "Github - oxen-io/session-ios: A private messenger for iOS.", - jpegImageData: UIImage(named: "AppIcon")?.jpegData(compressionQuality: 1) - ) - ), - isOutgoing: true - ) - .padding(.horizontal, Values.mediumSpacing) + VStack { + LinkPreviewView_SwiftUI( + state: LinkPreview.DraftState( + linkPreviewDraft: .init( + urlString: "https://github.com/oxen-io", + title: "Github - oxen-io/session-ios: A private messenger for iOS.", + jpegImageData: UIImage(named: "AppIcon")?.jpegData(compressionQuality: 1) + ) + ), + isOutgoing: true + ) + .padding(.horizontal, Values.mediumSpacing) + + LinkPreviewView_SwiftUI( + state: LinkPreview.LoadingState(), + isOutgoing: true + ) + .frame( + width: .infinity, + height: 80 + ) + .padding(.horizontal, Values.mediumSpacing) + } } } diff --git a/Session/Shared/LoadingIndicatorView.swift b/Session/Shared/LoadingIndicatorView.swift new file mode 100644 index 000000000..0db36e853 --- /dev/null +++ b/Session/Shared/LoadingIndicatorView.swift @@ -0,0 +1,37 @@ +// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. + +import SwiftUI + +public struct ActivityIndicator: View { + @State private var isAnimating: Bool = false + + public var body: some View { + GeometryReader { (geometry: GeometryProxy) in + ForEach(0..<5) { index in + Group { + Circle() + .frame( + width: geometry.size.width / 5, + height: geometry.size.height / 5 + ) + .scaleEffect(!self.isAnimating ? 1 - CGFloat(index) / 5 : 0.2 + CGFloat(index) / 5) + .offset(y: geometry.size.width / 10 - geometry.size.height / 2) + } + .frame( + width: geometry.size.width, + height: geometry.size.height + ) + .rotationEffect(!self.isAnimating ? .degrees(0) : .degrees(360)) + .animation(Animation + .timingCurve(0.5, 0.15 + Double(index) / 5, 0.25, 1, duration: 1.5) + .repeatForever(autoreverses: false) + ) + } + } + .aspectRatio(1, contentMode: .fit) + .onAppear { + self.isAnimating = true + } + } +} +