diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index ef261630d7..9d0e0ec9a8 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -1173,6 +1173,10 @@ FDFE75B42ABD46B600655640 /* MockUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD83B9D127D59495005E1583 /* MockUserDefaults.swift */; }; FDFE75B52ABD46B700655640 /* MockUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD83B9D127D59495005E1583 /* MockUserDefaults.swift */; }; FDFF9FDF2A787F57005E0628 /* JSONEncoder+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDFF9FDE2A787F57005E0628 /* JSONEncoder+Utilities.swift */; }; + FE5809902E6EACB0000296AB /* Lucide in Frameworks */ = {isa = PBXBuildFile; productRef = FE58098F2E6EACB0000296AB /* Lucide */; }; + FE5809922E6EADFA000296AB /* Lucide in Frameworks */ = {isa = PBXBuildFile; productRef = FE5809912E6EADFA000296AB /* Lucide */; }; + FEACA5AF2E6FB03300AA20F3 /* Lucide in Frameworks */ = {isa = PBXBuildFile; productRef = FEACA5AE2E6FB03300AA20F3 /* Lucide */; }; + FEACA5B12E6FB10E00AA20F3 /* Lucide in Frameworks */ = {isa = PBXBuildFile; productRef = FEACA5B02E6FB10E00AA20F3 /* Lucide */; }; FED288F32E4C28CF00C31171 /* AppReviewPromptDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED288F22E4C28CF00C31171 /* AppReviewPromptDialog.swift */; }; FED288F82E4C3BE100C31171 /* AppReviewPromptModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED288F72E4C3BE100C31171 /* AppReviewPromptModel.swift */; }; /* End PBXBuildFile section */ @@ -2481,6 +2485,7 @@ B8D64FC725BA78520029CFC0 /* SessionMessagingKit.framework in Frameworks */, C3D90A5C25773A25002C9DF5 /* SessionUtilitiesKit.framework in Frameworks */, C3402FE52559036600EA6424 /* SessionUIKit.framework in Frameworks */, + FEACA5AF2E6FB03300AA20F3 /* Lucide in Frameworks */, B8D64FCB25BA78A90029CFC0 /* SignalUtilitiesKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2489,6 +2494,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + FEACA5B12E6FB10E00AA20F3 /* Lucide in Frameworks */, B8D64FBB25BA78310029CFC0 /* SessionMessagingKit.framework in Frameworks */, FD8A5B182DBF47E9004C689B /* SessionUIKit.framework in Frameworks */, B8D64FBD25BA78310029CFC0 /* SessionNetworkingKit.framework in Frameworks */, @@ -2514,6 +2520,8 @@ FD6A39222C2AA91D00762359 /* NVActivityIndicatorView in Frameworks */, FD22866F2C38D42300BC06F7 /* DifferenceKit in Frameworks */, C33FD9C2255A54EF00E217F9 /* SessionMessagingKit.framework in Frameworks */, + C33FD9C4255A54EF00E217F9 /* SessionSnodeKit.framework in Frameworks */, + FE5809922E6EADFA000296AB /* Lucide in Frameworks */, C33FD9C4255A54EF00E217F9 /* SessionNetworkingKit.framework in Frameworks */, C33FD9C5255A54EF00E217F9 /* SessionUtilitiesKit.framework in Frameworks */, ); @@ -2549,6 +2557,7 @@ FD6673FA2D7021F800041530 /* SessionUtil in Frameworks */, FD2286732C38D43900BC06F7 /* DifferenceKit in Frameworks */, FDC4386C27B4E90300C60D73 /* SessionUtilitiesKit.framework in Frameworks */, + FE5809902E6EACB0000296AB /* Lucide in Frameworks */, C3C2A70B25539E1E00C340D1 /* SessionNetworkingKit.framework in Frameworks */, FD6A39132C2A946A00762359 /* SwiftProtobuf in Frameworks */, ); @@ -5386,6 +5395,7 @@ name = SessionShareExtension; packageProductDependencies = ( FD860CC82D6ED2ED00BBE29C /* DifferenceKit */, + FEACA5AE2E6FB03300AA20F3 /* Lucide */, ); productName = SignalShareExtension; productReference = 453518681FC635DD00210559 /* SessionShareExtension.appex */; @@ -5455,6 +5465,7 @@ packageProductDependencies = ( FD6A39212C2AA91D00762359 /* NVActivityIndicatorView */, FD22866E2C38D42300BC06F7 /* DifferenceKit */, + FE5809912E6EADFA000296AB /* Lucide */, ); productName = SignalUtilitiesKit; productReference = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; @@ -5529,6 +5540,7 @@ FD6A39122C2A946A00762359 /* SwiftProtobuf */, FD2286722C38D43900BC06F7 /* DifferenceKit */, FD6673F92D7021F800041530 /* SessionUtil */, + FE58098F2E6EACB0000296AB /* Lucide */, ); productName = SessionMessagingKit; productReference = C3C2A6F025539DE700C340D1 /* SessionMessagingKit.framework */; @@ -10552,7 +10564,7 @@ repositoryURL = "https://github.com/session-foundation/session-lucide.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 0.468.0; + minimumVersion = 0.473.1; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -10701,6 +10713,26 @@ package = FD6A390E2C2A93CD00762359 /* XCRemoteSwiftPackageReference "WebRTC" */; productName = WebRTC; }; + FE58098F2E6EACB0000296AB /* Lucide */ = { + isa = XCSwiftPackageProductDependency; + package = FD756BEE2D06686500BD7199 /* XCRemoteSwiftPackageReference "session-lucide" */; + productName = Lucide; + }; + FE5809912E6EADFA000296AB /* Lucide */ = { + isa = XCSwiftPackageProductDependency; + package = FD756BEE2D06686500BD7199 /* XCRemoteSwiftPackageReference "session-lucide" */; + productName = Lucide; + }; + FEACA5AE2E6FB03300AA20F3 /* Lucide */ = { + isa = XCSwiftPackageProductDependency; + package = FD756BEE2D06686500BD7199 /* XCRemoteSwiftPackageReference "session-lucide" */; + productName = Lucide; + }; + FEACA5B02E6FB10E00AA20F3 /* Lucide */ = { + isa = XCSwiftPackageProductDependency; + package = FD756BEE2D06686500BD7199 /* XCRemoteSwiftPackageReference "session-lucide" */; + productName = Lucide; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D221A080169C9E5E00537ABF /* Project object */; diff --git a/Session.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Session.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 36a72ad9fd..d3337e9980 100644 --- a/Session.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Session.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -105,8 +105,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/session-foundation/session-lucide.git", "state" : { - "revision" : "af00ad53d714823e07f984aadd7af38bafaae69e", - "version" : "0.473.0" + "revision" : "7da7fc6a2c42ee8549b0b9804455b43c61a0e63f", + "version" : "0.473.1" } }, { diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index c10dc1bfc1..8fe7af190b 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -3,6 +3,7 @@ import UIKit import MediaPlayer import AVKit +import Lucide import SessionUIKit import SessionMessagingKit import SessionUtilitiesKit @@ -82,10 +83,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel result.themeBackgroundColor = .backgroundSecondary result.makeViewDraggable() - let noVideoIcon: UIImageView = UIImageView( - image: UIImage(systemName: "video.slash")? - .withRenderingMode(.alwaysTemplate) - ) + let noVideoIcon = LucideIconView(icon: .videoOff, size: 28) noVideoIcon.themeTintColor = .textPrimary noVideoIcon.set(.width, to: 34) noVideoIcon.set(.height, to: 28) @@ -98,10 +96,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel result.addSubview(floatingRemoteVideoView) floatingRemoteVideoView.pin(to: result) - let swappingVideoIcon: UIImageView = UIImageView( - image: UIImage(systemName: "arrow.2.squarepath")? - .withRenderingMode(.alwaysTemplate) - ) + let swappingVideoIcon = LucideIconView(icon: .repeat2, size: 12) swappingVideoIcon.themeTintColor = .textPrimary swappingVideoIcon.set(.width, to: 16) swappingVideoIcon.set(.height, to: 12) @@ -145,7 +140,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel private lazy var minimizeButton: UIButton = { let result = UIButton(type: .custom) result.setImage( - UIImage(named: "Minimize")? + Lucide.image(icon: .minimize2, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -164,7 +159,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel result.accessibilityIdentifier = "Answer call" result.accessibilityLabel = "Answer call" result.setImage( - UIImage(named: "AnswerCall")? + UIImage(named: "phone-fill-answer-custom")? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -184,7 +179,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel let result = UIButton(type: .custom) result.accessibilityLabel = "End call button" result.setImage( - UIImage(named: "EndCall")? + UIImage(named: "phone-fill-custom")? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -210,7 +205,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel let result = UIButton(type: .custom) result.isEnabled = call.isVideoEnabled result.setImage( - UIImage(named: "SwitchCamera")? + Lucide.image(icon: .switchCamera, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -227,7 +222,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel private lazy var switchAudioButton: UIButton = { let result = UIButton(type: .custom) result.setImage( - UIImage(named: "AudioOff")? + Lucide.image(icon: .micOff, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -250,7 +245,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel private lazy var videoButton: UIButton = { let result = UIButton(type: .custom) result.setImage( - UIImage(named: "VideoCall")? + Lucide.image(icon: .video, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -278,7 +273,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel private lazy var routePickerButton: UIButton = { let result = UIButton(type: .custom) result.setImage( - UIImage(named: "Speaker")? + Lucide.image(icon: .volume2, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -867,33 +862,43 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel switch currentOutput.portType { case .builtInSpeaker: - let image = UIImage(named: "Speaker")?.withRenderingMode(.alwaysTemplate) + let image = Lucide.image(icon: .volume2, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate) + routePickerButton.setImage(image, for: .normal) routePickerButton.themeTintColor = .backgroundSecondary routePickerButton.themeBackgroundColor = .textPrimary case .headphones: - let image = UIImage(named: "Headsets")?.withRenderingMode(.alwaysTemplate) + let image = UIImage(named: "Headsets")? + .withRenderingMode(.alwaysTemplate) + routePickerButton.setImage(image, for: .normal) routePickerButton.themeTintColor = .backgroundSecondary routePickerButton.themeBackgroundColor = .textPrimary case .bluetoothLE: fallthrough case .bluetoothA2DP: - let image = UIImage(named: "Bluetooth")?.withRenderingMode(.alwaysTemplate) + let image = UIImage(named: "Bluetooth")? + .withRenderingMode(.alwaysTemplate) + routePickerButton.setImage(image, for: .normal) routePickerButton.themeTintColor = .backgroundSecondary routePickerButton.themeBackgroundColor = .textPrimary case .bluetoothHFP: - let image = UIImage(named: "Airpods")?.withRenderingMode(.alwaysTemplate) + let image = UIImage(named: "Airpods")? + .withRenderingMode(.alwaysTemplate) + routePickerButton.setImage(image, for: .normal) routePickerButton.themeTintColor = .backgroundSecondary routePickerButton.themeBackgroundColor = .textPrimary case .builtInReceiver: fallthrough default: - let image = UIImage(named: "Speaker")?.withRenderingMode(.alwaysTemplate) + let image = Lucide.image(icon: .volume2, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate) + routePickerButton.setImage(image, for: .normal) routePickerButton.themeTintColor = .textPrimary routePickerButton.themeBackgroundColor = .backgroundSecondary diff --git a/Session/Calls/VideoPreviewVC.swift b/Session/Calls/VideoPreviewVC.swift index 449b36fbcf..1d95758d96 100644 --- a/Session/Calls/VideoPreviewVC.swift +++ b/Session/Calls/VideoPreviewVC.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import CoreMedia @@ -44,7 +45,7 @@ class VideoPreviewVC: UIViewController, CameraManagerDelegate { private lazy var closeButton: UIButton = { let result = UIButton(type: .custom) result.setImage( - UIImage(named: "X")? + Lucide.image(icon: .x, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -59,7 +60,7 @@ class VideoPreviewVC: UIViewController, CameraManagerDelegate { private lazy var confirmButton: UIButton = { let result = UIButton(type: .custom) result.setImage( - UIImage(named: "Check")? + Lucide.image(icon: .check, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) diff --git a/Session/Calls/Views & Modals/CallMissedTipsModal.swift b/Session/Calls/Views & Modals/CallMissedTipsModal.swift index d4b17a7eaf..2efa9707dd 100644 --- a/Session/Calls/Views & Modals/CallMissedTipsModal.swift +++ b/Session/Calls/Views & Modals/CallMissedTipsModal.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit @@ -11,10 +12,8 @@ final class CallMissedTipsModal: Modal { private lazy var tipsIconContainerView: UIView = UIView() - private lazy var tipsIconImageView: UIImageView = { - let result: UIImageView = UIImageView( - image: UIImage(named: "Tips")?.withRenderingMode(.alwaysTemplate) - ) + private lazy var tipsIconImageView: LucideIconView = { + let result = LucideIconView(icon: .lightbulb) result.themeTintColor = .textPrimary result.set(.width, to: 19) result.set(.height, to: 28) diff --git a/Session/Calls/Views & Modals/IncomingCallBanner.swift b/Session/Calls/Views & Modals/IncomingCallBanner.swift index e40a97724d..6e69f91b84 100644 --- a/Session/Calls/Views & Modals/IncomingCallBanner.swift +++ b/Session/Calls/Views & Modals/IncomingCallBanner.swift @@ -41,7 +41,7 @@ final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate { .withConfiguration( UIButton.Configuration .plain() - .withImage(UIImage(named: "AnswerCall")?.withRenderingMode(.alwaysTemplate)) + .withImage(UIImage(named: "phone-fill-answer-custom")?.withRenderingMode(.alwaysTemplate)) .withContentInsets(NSDirectionalEdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6)) ) .withConfigurationUpdateHandler { button in @@ -65,7 +65,7 @@ final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate { .withConfiguration( UIButton.Configuration .plain() - .withImage(UIImage(named: "EndCall")?.withRenderingMode(.alwaysTemplate)) + .withImage(UIImage(named: "phone-fill-custom")?.withRenderingMode(.alwaysTemplate)) .withContentInsets(NSDirectionalEdgeInsets(top: 13, leading: 9, bottom: 13, trailing: 9)) ) .withConfigurationUpdateHandler { button in diff --git a/Session/Closed Groups/EditGroupViewModel.swift b/Session/Closed Groups/EditGroupViewModel.swift index 8a4817f5dd..b7de757b83 100644 --- a/Session/Closed Groups/EditGroupViewModel.swift +++ b/Session/Closed Groups/EditGroupViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Lucide import GRDB import DifferenceKit import SessionUIKit @@ -255,7 +256,7 @@ class EditGroupViewModel: SessionTableViewModel, NavigatableStateHolder, Observa elements: [ SessionCell.Info( id: .invite, - leadingAccessory: .icon(UIImage(named: "icon_invite")?.withRenderingMode(.alwaysTemplate)), + leadingAccessory: .icon(Lucide.image(icon: .userRoundPlus, size: IconSize.medium.size)?.withRenderingMode(.alwaysTemplate)), title: "membersInvite".localized(), accessibility: Accessibility( identifier: "Invite button", @@ -266,7 +267,7 @@ class EditGroupViewModel: SessionTableViewModel, NavigatableStateHolder, Observa (!isUpdatedGroup || !dependencies[feature: .updatedGroupsAllowInviteById] ? nil : SessionCell.Info( id: .inviteById, - leadingAccessory: .icon(UIImage(named: "ic_plus_24")?.withRenderingMode(.alwaysTemplate)), + leadingAccessory: .icon(Lucide.image(icon: .plus, size: IconSize.medium.size)?.withRenderingMode(.alwaysTemplate)), title: "accountIdOrOnsInvite".localized(), accessibility: Accessibility( identifier: "Invite by id", diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index c332d1b6a2..16bab69a0d 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -2,6 +2,7 @@ import UIKit import Combine +import Lucide import GRDB import DifferenceKit import SessionUIKit @@ -228,7 +229,10 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate setNavBarTitle("groupCreate".localized(), customFontSize: customTitleFontSize) if !hideCloseButton { - let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) + let closeIcon = Lucide.image(icon: .x, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate) + + let closeButton = UIBarButtonItem(image: closeIcon, style: .plain, target: self, action: #selector(close)) closeButton.themeTintColor = .textPrimary navigationItem.rightBarButtonItem = closeButton navigationItem.leftBarButtonItem?.accessibilityIdentifier = "Cancel" diff --git a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift index 53b44ea9b5..b4de4747ca 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift @@ -58,7 +58,7 @@ extension ContextMenuVC { static func info(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action { return Action( - icon: UIImage(named: "ic_info"), + icon: Lucide.image(icon: .info, size: IconSize.medium.size), title: "info".localized(), accessibilityLabel: "Message info" ) { _ in delegate?.info(cellViewModel) } @@ -66,7 +66,7 @@ extension ContextMenuVC { static func retry(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action { return Action( - icon: UIImage(systemName: "arrow.triangle.2.circlepath"), + icon: Lucide.image(icon: .refreshCw, size: IconSize.medium.size), title: (cellViewModel.state == .failedToSync ? "resync".localized() : "resend".localized() @@ -77,7 +77,7 @@ extension ContextMenuVC { static func reply(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action { return Action( - icon: UIImage(named: "ic_reply"), + icon: Lucide.image(icon: .reply, size: IconSize.medium.size), title: "reply".localized(), shouldDismissInfoScreen: true, accessibilityLabel: "Reply to message" @@ -86,7 +86,7 @@ extension ContextMenuVC { static func copy(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action { return Action( - icon: UIImage(named: "ic_copy"), + icon: Lucide.image(icon: .copy, size: IconSize.medium.size), title: "copy".localized(), feedback: "copied".localized(), accessibilityLabel: "Copy text" @@ -95,7 +95,7 @@ extension ContextMenuVC { static func copySessionID(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action { return Action( - icon: UIImage(named: "ic_copy"), + icon: Lucide.image(icon: .copy, size: IconSize.medium.size), title: "accountIDCopy".localized(), feedback: "copied".localized(), accessibilityLabel: "Copy Session ID" @@ -104,7 +104,7 @@ extension ContextMenuVC { static func delete(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action { return Action( - icon: Lucide.image(icon: .trash2, size: 24), + icon: Lucide.image(icon: .trash2, size: IconSize.medium.size), title: "delete".localized(), expirationInfo: ExpirationInfo( expiresStartedAtMs: cellViewModel.expiresStartedAtMs, @@ -118,7 +118,7 @@ extension ContextMenuVC { static func save(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action { return Action( - icon: UIImage(named: "ic_download"), + icon: Lucide.image(icon: .arrowDownToLine, size: IconSize.medium.size), title: "save".localized(), feedback: "saved".localized(), accessibilityLabel: "Save attachment" diff --git a/Session/Conversations/Context Menu/ContextMenuVC+EmojiReactsView.swift b/Session/Conversations/Context Menu/ContextMenuVC+EmojiReactsView.swift index 1a855eafc8..47a03c8cdc 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+EmojiReactsView.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+EmojiReactsView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit @@ -83,7 +84,7 @@ extension ContextMenuVC { private func setUpViewHierarchy() { // Icon image - let iconImageView = UIImageView(image: #imageLiteral(resourceName: "ic_plus_24").withRenderingMode(.alwaysTemplate)) + let iconImageView = LucideIconView(icon: .plus, size: iconSize) iconImageView.themeTintColor = .textPrimary iconImageView.set(.width, to: iconSize) iconImageView.set(.height, to: iconSize) diff --git a/Session/Conversations/ConversationSearch.swift b/Session/Conversations/ConversationSearch.swift index 69e80a7b90..849562326b 100644 --- a/Session/Conversations/ConversationSearch.swift +++ b/Session/Conversations/ConversationSearch.swift @@ -2,6 +2,7 @@ import UIKit import Combine +import Lucide import GRDB import SignalUtilitiesKit import SessionUIKit @@ -149,7 +150,8 @@ public final class SearchResultsBar: UIView { }() private lazy var upButton: UIButton = { - let icon = #imageLiteral(resourceName: "ic_chevron_up").withRenderingMode(.alwaysTemplate) + let icon = Lucide.image(icon: .chevronUp, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate) let result: UIButton = UIButton() result.setImage(icon, for: UIControl.State.normal) result.themeTintColor = .primary @@ -159,7 +161,8 @@ public final class SearchResultsBar: UIView { }() private lazy var downButton: UIButton = { - let icon = #imageLiteral(resourceName: "ic_chevron_down").withRenderingMode(.alwaysTemplate) + let icon = Lucide.image(icon: .chevronDown, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate) let result: UIButton = UIButton() result.setImage(icon, for: UIControl.State.normal) result.themeTintColor = .primary diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 7ec260b5b3..f17dbfa2bd 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -321,7 +321,7 @@ final class ConversationVC: BaseVC, LibSessionRespondingViewController, Conversa lazy var scrollButton: RoundIconButton = { let result: RoundIconButton = RoundIconButton( - image: UIImage(named: "ic_chevron_down")? + image: Lucide.image(icon: .chevronDown, size: 32)? .withRenderingMode(.alwaysTemplate) ) { [weak self] in // The table view's content size is calculated by the estimated height of cells, @@ -1466,7 +1466,7 @@ final class ConversationVC: BaseVC, LibSessionRespondingViewController, Conversa if shouldHaveCallButton { let callButton = UIBarButtonItem( - image: UIImage(named: "Phone"), + image: Lucide.image(icon: .phone, size: IconSize.medium.size), style: .plain, target: self, action: #selector(startCall) diff --git a/Session/Conversations/Input View/ExpandingAttachmentsButton.swift b/Session/Conversations/Input View/ExpandingAttachmentsButton.swift index 7a86f0e68c..80d3754457 100644 --- a/Session/Conversations/Input View/ExpandingAttachmentsButton.swift +++ b/Session/Conversations/Input View/ExpandingAttachmentsButton.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit final class ExpandingAttachmentsButton: UIView, InputViewButtonDelegate { @@ -42,7 +43,11 @@ final class ExpandingAttachmentsButton: UIView, InputViewButtonDelegate { }() lazy var gifButtonContainer = container(for: gifButton) lazy var documentButton: InputViewButton = { - let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_document_black"), delegate: self, hasOpaqueBackground: true) + let result = InputViewButton( + icon: Lucide.image(icon: .file, size: InputViewButton.expandedSize), + delegate: self, + hasOpaqueBackground: true + ) result.accessibilityIdentifier = "Documents folder" result.accessibilityLabel = "Files" result.isAccessibilityElement = true @@ -51,7 +56,11 @@ final class ExpandingAttachmentsButton: UIView, InputViewButtonDelegate { }() lazy var documentButtonContainer = container(for: documentButton) lazy var libraryButton: InputViewButton = { - let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_roll_black"), delegate: self, hasOpaqueBackground: true) + let result = InputViewButton( + icon: Lucide.image(icon: .images, size: InputViewButton.expandedSize), + delegate: self, + hasOpaqueBackground: true + ) result.accessibilityIdentifier = "Images folder" result.accessibilityLabel = "Photo library" result.isAccessibilityElement = true @@ -60,7 +69,11 @@ final class ExpandingAttachmentsButton: UIView, InputViewButtonDelegate { }() lazy var libraryButtonContainer = container(for: libraryButton) lazy var cameraButton: InputViewButton = { - let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self, hasOpaqueBackground: true) + let result = InputViewButton( + icon: Lucide.image(icon: .camera, size: InputViewButton.expandedSize), + delegate: self, + hasOpaqueBackground: true + ) result.accessibilityIdentifier = "Select camera button" result.accessibilityLabel = "Camera" result.isAccessibilityElement = true @@ -69,7 +82,10 @@ final class ExpandingAttachmentsButton: UIView, InputViewButtonDelegate { }() lazy var cameraButtonContainer = container(for: cameraButton) lazy var mainButton: InputViewButton = { - let result = InputViewButton(icon: #imageLiteral(resourceName: "ic_plus_24"), delegate: self) + let result = InputViewButton( + icon: Lucide.image(icon: .plus, size: InputViewButton.expandedSize), + delegate: self + ) result.accessibilityLabel = "Add attachment" return result diff --git a/Session/Conversations/Input View/InputView.swift b/Session/Conversations/Input View/InputView.swift index 9b9b0bc674..c98199b881 100644 --- a/Session/Conversations/Input View/InputView.swift +++ b/Session/Conversations/Input View/InputView.swift @@ -2,6 +2,7 @@ import UIKit import Combine +import Lucide import SessionUIKit import SessionMessagingKit import SessionUtilitiesKit @@ -82,7 +83,10 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M }() private lazy var voiceMessageButton: InputViewButton = { - let result = InputViewButton(icon: #imageLiteral(resourceName: "Microphone"), delegate: self) + let result = InputViewButton( + icon: Lucide.image(icon: .mic, size: InputViewButton.iconSize), + delegate: self + ) result.accessibilityLabel = "New voice message" result.accessibilityIdentifier = "New voice message" result.isAccessibilityElement = true @@ -91,7 +95,11 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M }() private lazy var sendButton: InputViewButton = { - let result = InputViewButton(icon: #imageLiteral(resourceName: "ArrowUp"), isSendButton: true, delegate: self) + let result = InputViewButton( + icon: Lucide.image(icon: .arrowUp, size: InputViewButton.iconSize), + isSendButton: true, + delegate: self + ) result.isHidden = true result.accessibilityIdentifier = "Send message button" result.accessibilityLabel = "Send message button" diff --git a/Session/Conversations/Input View/VoiceMessageRecordingView.swift b/Session/Conversations/Input View/VoiceMessageRecordingView.swift index de2c7be67c..8cd5ede56c 100644 --- a/Session/Conversations/Input View/VoiceMessageRecordingView.swift +++ b/Session/Conversations/Input View/VoiceMessageRecordingView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit @@ -19,7 +20,7 @@ final class VoiceMessageRecordingView: UIView { private lazy var iconImageView: UIImageView = { let result: UIImageView = UIImageView() - result.image = UIImage(named: "Microphone")? + result.image = Lucide.image(icon: .mic, size: VoiceMessageRecordingView.iconSize)? .withRenderingMode(.alwaysTemplate) result.themeTintColor = .white result.contentMode = .scaleAspectFit @@ -58,12 +59,16 @@ final class VoiceMessageRecordingView: UIView { return result }() + + private lazy var chevronImage: UIImage? = Lucide.image( + icon: .chevronLeft, + size: VoiceMessageRecordingView.chevronSize + ) private lazy var chevronImageView: UIImageView = { let result: UIImageView = UIImageView( image: (Dependencies.isRTL ? - UIImage(named: "small_chevron_left")?.withHorizontallyFlippedOrientation() : - UIImage(named: "small_chevron_left") + chevronImage?.withHorizontallyFlippedOrientation() : chevronImage )? .withRenderingMode(.alwaysTemplate) ) @@ -320,7 +325,8 @@ final class VoiceMessageRecordingView: UIView { UIView.animate(withDuration: 0.25, delay: 0, options: .transitionCrossDissolve, animations: { self.lockView.alpha = 0 - self.iconImageView.image = UIImage(named: "ArrowUp")?.withRenderingMode(.alwaysTemplate) + self.iconImageView.image = Lucide.image(icon: .arrowUp, size: VoiceMessageRecordingView.iconSize)? + .withRenderingMode(.alwaysTemplate) self.slideToCancelStackView.alpha = 0 self.cancelButton.alpha = 1 }, completion: { _ in @@ -410,20 +416,14 @@ extension VoiceMessageRecordingView { layer.borderWidth = 1 // Lock icon - let lockIconImageView: UIImageView = UIImageView( - image: UIImage(named: "ic_lock_outline")? - .withRenderingMode(.alwaysTemplate) - ) + let lockIconImageView: LucideIconView = LucideIconView(icon: .lockKeyhole, size: LockView.lockIconSize) lockIconImageView.themeTintColor = .textPrimary lockIconImageView.set(.width, to: LockView.lockIconSize) lockIconImageView.set(.height, to: LockView.lockIconSize) stackView.addArrangedSubview(lockIconImageView) // Chevron icon - let chevronIconImageView: UIImageView = UIImageView( - image: UIImage(named: "ic_chevron_up")? - .withRenderingMode(.alwaysTemplate) - ) + let chevronIconImageView: LucideIconView = LucideIconView(icon: .chevronUp, size: LockView.chevronIconSize) chevronIconImageView.themeTintColor = .textPrimary chevronIconImageView.set(.width, to: LockView.chevronIconSize) chevronIconImageView.set(.height, to: LockView.chevronIconSize) diff --git a/Session/Conversations/Message Cells/CallMessageCell.swift b/Session/Conversations/Message Cells/CallMessageCell.swift index 75fbbfa946..746240c489 100644 --- a/Session/Conversations/Message Cells/CallMessageCell.swift +++ b/Session/Conversations/Message Cells/CallMessageCell.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import AVFAudio import SessionUIKit import SessionMessagingKit @@ -39,11 +40,9 @@ final class CallMessageCell: MessageCell { return result }() - private lazy var infoImageView: UIImageView = { - let result: UIImageView = UIImageView( - image: UIImage(named: "ic_info")? - .withRenderingMode(.alwaysTemplate) - ) + + private lazy var infoImageView: LucideIconView = { + let result: LucideIconView = LucideIconView(icon: .info, size: Self.iconSize) result.themeTintColor = .textPrimary result.set(.width, to: CallMessageCell.iconSize) result.set(.height, to: CallMessageCell.iconSize) @@ -150,10 +149,15 @@ final class CallMessageCell: MessageCell { iconImageView.image = { switch messageInfo.state { - case .outgoing: return UIImage(named: "CallOutgoing")?.withRenderingMode(.alwaysTemplate) - case .incoming: return UIImage(named: "CallIncoming")?.withRenderingMode(.alwaysTemplate) + case .outgoing: + return Lucide.image(icon: .phoneOutgoing, size: Self.iconSize)? + .withRenderingMode(.alwaysTemplate) + case .incoming: + return Lucide.image(icon: .phoneIncoming, size: Self.iconSize)? + .withRenderingMode(.alwaysTemplate) case .missed, .permissionDenied, .permissionDeniedMicrophone: - return UIImage(named: "CallMissed")?.withRenderingMode(.alwaysTemplate) + return Lucide.image(icon: .phoneMissed, size: Self.iconSize)? + .withRenderingMode(.alwaysTemplate) default: return nil } }() diff --git a/Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift b/Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift index 58ed68ab64..a40dd96125 100644 --- a/Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift +++ b/Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift @@ -31,10 +31,7 @@ final class DeletedMessageView: UIView { } private func setUpViewHierarchy(textColor: ThemeValue, variant: Interaction.Variant, maxWidth: CGFloat) { - let trashIcon = Lucide.image(icon: .trash2, size: DeletedMessageView.iconSize)? - .withRenderingMode(.alwaysTemplate) - - let imageView = UIImageView(image: trashIcon) + let imageView = LucideIconView(icon: .trash2, size: DeletedMessageView.iconSize) imageView.themeTintColor = textColor imageView.alpha = Values.highOpacity imageView.contentMode = .scaleAspectFit diff --git a/Session/Conversations/Message Cells/Content Views/DocumentView.swift b/Session/Conversations/Message Cells/Content Views/DocumentView.swift index aef1f49e9b..cc575aff27 100644 --- a/Session/Conversations/Message Cells/Content Views/DocumentView.swift +++ b/Session/Conversations/Message Cells/Content Views/DocumentView.swift @@ -1,5 +1,6 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. +import Lucide import UIKit import SessionUIKit import SessionMessagingKit @@ -22,33 +23,34 @@ final class DocumentView: UIView { } private func setUpViewHierarchy(attachment: Attachment, textColor: ThemeValue) { + let documentIconSize = CGSize(width: 24, height: 32) + let imageBackgroundView: UIView = UIView() imageBackgroundView.themeBackgroundColor = .messageBubble_overlay addSubview(imageBackgroundView) // Image view - let imageView = UIImageView( - image: UIImage(systemName: "doc")? - .withRenderingMode(.alwaysTemplate) - ) + let imageView = LucideIconView(icon: .file, size: documentIconSize.height) imageView.setContentCompressionResistancePriority(.required, for: .horizontal) imageView.setContentHuggingPriority(.required, for: .horizontal) imageView.contentMode = .scaleAspectFit imageView.themeTintColor = textColor - imageView.set(.width, to: 24) - imageView.set(.height, to: 32) + imageView.set(.width, to: documentIconSize.width) + imageView.set(.height, to: documentIconSize.height) if attachment.isAudio { + let audioIconSize = documentIconSize.height * 0.32 + let audioImageView = UIImageView( - image: UIImage(systemName: "music.note")? + image: Lucide.image(icon: .music2, size: audioIconSize)? .withRenderingMode(.alwaysTemplate) ) audioImageView.contentMode = .scaleAspectFit audioImageView.themeTintColor = textColor imageView.addSubview(audioImageView) audioImageView.center(.horizontal, in: imageView) - audioImageView.center(.vertical, in: imageView, withInset: 4) - audioImageView.set(.height, to: .height, of: imageView, multiplier: 0.32) + audioImageView.center(.vertical, in: imageView, withInset: 2) + audioImageView.set(.height, to: audioIconSize) } // Body label @@ -81,16 +83,17 @@ final class DocumentView: UIView { rightContainerView.addSubview(activityIndicator) activityIndicator.pin(to: rightContainerView, withInset: 8) + let accessoryIconSize = 24.0 + let rightImageView = UIImageView( image: { guard attachment.state != .failedDownload && attachment.state != .failedUpload else { - return UIImage(named: "warning")? - .withRenderingMode(.alwaysTemplate) + return Lucide.image(icon: .fileWarning, size: accessoryIconSize) } switch attachment.isAudio { case true: return UIImage(systemName: "play.fill") - case false: return UIImage(systemName: "arrow.down") + case false: return Lucide.image(icon: .arrowDown, size: accessoryIconSize) } }()?.withRenderingMode(.alwaysTemplate) ) @@ -99,7 +102,7 @@ final class DocumentView: UIView { rightImageView.contentMode = .scaleAspectFit rightImageView.themeTintColor = textColor rightImageView.isHidden = (attachment.state == .uploading || attachment.state == .downloading) - rightImageView.set(.height, to: 24) + rightImageView.set(.height, to: accessoryIconSize) rightContainerView.addSubview(rightImageView) rightImageView.center(in: rightContainerView) diff --git a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift index 7ec1765625..cac3c6a178 100644 --- a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift +++ b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import NVActivityIndicatorView import SessionUIKit import SessionMessagingKit @@ -70,7 +71,7 @@ final class LinkPreviewView: UIView { private lazy var cancelButton: UIButton = { let result: UIButton = UIButton(type: .custom) result.setImage( - UIImage(named: "X")? + Lucide.image(icon: .x, size: LinkPreviewView.cancelButtonSize)? .withRenderingMode(.alwaysTemplate), for: .normal ) @@ -156,7 +157,7 @@ final class LinkPreviewView: UIView { var image: UIImage? = state.image let stateHasImage: Bool = (image != nil) if image == nil && (state is LinkPreview.DraftState || state is LinkPreview.SentState) { - image = UIImage(named: "Link")?.withRenderingMode(.alwaysTemplate) + image = Lucide.image(icon: .link, size: 32)?.withRenderingMode(.alwaysTemplate) } // Image view diff --git a/Session/Conversations/Message Cells/Content Views/MediaPlaceholderView.swift b/Session/Conversations/Message Cells/Content Views/MediaPlaceholderView.swift index d70572f72b..96a483cdb3 100644 --- a/Session/Conversations/Message Cells/Content Views/MediaPlaceholderView.swift +++ b/Session/Conversations/Message Cells/Content Views/MediaPlaceholderView.swift @@ -1,5 +1,6 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. +import Lucide import UIKit import SessionMessagingKit import SessionUIKit @@ -29,13 +30,13 @@ final class MediaPlaceholderView: UIView { cellViewModel: MessageViewModel, textColor: ThemeValue ) { - let (iconName, attachmentDescription): (String, String) = { + let (icon, attachmentDescription): (Lucide.Icon?, String) = { guard cellViewModel.variant == .standardIncoming, let attachment: Attachment = cellViewModel.attachments?.first else { return ( - "actionsheet_document_black", // stringlint:ignore + .file, "file".localized().lowercased() ) // Should never occur } @@ -43,19 +44,19 @@ final class MediaPlaceholderView: UIView { switch (attachment.isAudio, (attachment.isImage || attachment.isVideo)) { case (true, _): return ( - "attachment_audio", // stringlint:ignore + .mic, "audio".localized().lowercased() ) case (_, true): return ( - "actionsheet_camera_roll_black", // stringlint:ignore + .images, "media".localized().lowercased() ) default: return ( - "actionsheet_document_black", // stringlint:ignore + .file, "file".localized().lowercased() ) } @@ -66,11 +67,9 @@ final class MediaPlaceholderView: UIView { imageContainerView.set(.width, to: MediaPlaceholderView.iconImageViewSize) imageContainerView.set(.height, to: MediaPlaceholderView.iconImageViewSize) - let imageView = UIImageView(image: UIImage(named: iconName)?.withRenderingMode(.alwaysTemplate)) + let imageView = LucideIconView(icon: .file, size: MediaPlaceholderView.iconSize) imageView.themeTintColor = textColor imageView.contentMode = .scaleAspectFit - imageView.set(.width, to: MediaPlaceholderView.iconSize) - imageView.set(.height, to: MediaPlaceholderView.iconSize) imageContainerView.addSubview(imageView) imageView.center(in: imageContainerView) diff --git a/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift index b076ac680a..4ea44eaf09 100644 --- a/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift +++ b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionMessagingKit @@ -69,10 +70,7 @@ final class OpenGroupInvitationView: UIView { iconContainerView.set(.width, to: OpenGroupInvitationView.iconImageViewSize) iconContainerView.set(.height, to: OpenGroupInvitationView.iconImageViewSize) - let iconName = (isOutgoing ? "Globe" : "Plus") // stringlint:ignore - let iconImageView = UIImageView( - image: UIImage(named: iconName)?.withRenderingMode(.alwaysTemplate) - ) + let iconImageView = LucideIconView(icon: isOutgoing ? .globe : .plus, size: Self.iconSize) iconImageView.themeTintColor = (isOutgoing ? .messageBubble_outgoingText : .textPrimary) iconImageView.contentMode = .scaleAspectFit iconImageView.set(.width, to: OpenGroupInvitationView.iconSize) diff --git a/Session/Conversations/Message Cells/Content Views/QuoteView.swift b/Session/Conversations/Message Cells/Content Views/QuoteView.swift index ecc93aef65..b2cfe19316 100644 --- a/Session/Conversations/Message Cells/Content Views/QuoteView.swift +++ b/Session/Conversations/Message Cells/Content Views/QuoteView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionMessagingKit import SessionUtilitiesKit @@ -99,7 +100,7 @@ final class QuoteView: UIView { if let attachment: Attachment = attachment { let isAudio: Bool = attachment.isAudio - let fallbackImageName: String = (isAudio ? "attachment_audio" : "actionsheet_document_black") // stringlint:ignore + let imageContainerView: UIView = UIView() imageContainerView.themeBackgroundColor = .messageBubble_overlay imageContainerView.layer.cornerRadius = VisibleMessageCell.smallCornerRadius @@ -108,8 +109,11 @@ final class QuoteView: UIView { imageContainerView.set(.height, to: thumbnailSize) mainStackView.addArrangedSubview(imageContainerView) + let fallbackIcon: Lucide.Icon = (isAudio ? .mic : .file) + let imageView: SessionImageView = SessionImageView( - image: UIImage(named: fallbackImageName)?.withRenderingMode(.alwaysTemplate), + image: Lucide.image(icon: fallbackIcon, size: Self.iconSize)? + .withRenderingMode(.alwaysTemplate), dataManager: dependencies[singleton: .imageDataManager] ) imageView.themeTintColor = { @@ -239,7 +243,8 @@ final class QuoteView: UIView { if mode == .draft { // Cancel button let cancelButton = UIButton(type: .custom) - cancelButton.setImage(UIImage(named: "X")?.withRenderingMode(.alwaysTemplate), for: .normal) + cancelButton.setImage(Lucide.image(icon: .x, size: Self.iconSize)? + .withRenderingMode(.alwaysTemplate), for: .normal) cancelButton.themeTintColor = .textPrimary cancelButton.set(.width, to: cancelButtonSize) cancelButton.set(.height, to: cancelButtonSize) diff --git a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift index 35cf6343e3..2a54d8ed27 100644 --- a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift +++ b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit import SignalUtilitiesKit @@ -55,9 +56,7 @@ final class ReactionContainerView: UIView { }() lazy var collapseButton: UIView = { - let arrow: UIImageView = UIImageView( - image: UIImage(named: "ic_chevron_up")?.withRenderingMode(.alwaysTemplate) - ) + let arrow = LucideIconView(icon: .chevronUp, size: ReactionContainerView.arrowSize.height) arrow.themeTintColor = .textPrimary arrow.set(.width, to: ReactionContainerView.arrowSize.width) arrow.set(.height, to: ReactionContainerView.arrowSize.height) diff --git a/Session/Conversations/Message Cells/Content Views/SwiftUI/DocumentView_SwiftUI.swift b/Session/Conversations/Message Cells/Content Views/SwiftUI/DocumentView_SwiftUI.swift index e6a8f1e56f..e611e9b460 100644 --- a/Session/Conversations/Message Cells/Content Views/SwiftUI/DocumentView_SwiftUI.swift +++ b/Session/Conversations/Message Cells/Content Views/SwiftUI/DocumentView_SwiftUI.swift @@ -1,6 +1,7 @@ // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import SwiftUI +import Lucide import SessionUIKit import SessionMessagingKit @@ -24,7 +25,7 @@ struct DocumentView_SwiftUI: View { spacing: 0 ) { ZStack { - Image(systemName: "doc") + LucideIcon(.file) .font(.system(size: Values.largeFontSize)) .foregroundColor(themeColor: textColor) @@ -77,7 +78,7 @@ struct DocumentView_SwiftUI: View { } else if attachment.state == .failedDownload || attachment.state == .failedUpload, - let invalidImage: UIImage = UIImage(named: "warning")?.withRenderingMode(.alwaysTemplate) + let invalidImage = Lucide.image(icon: .triangleAlert, size: IconSize.medium.size)?.withRenderingMode(.alwaysTemplate) { Image(uiImage: invalidImage) .resizable() diff --git a/Session/Conversations/Message Cells/Content Views/SwiftUI/LinkPreviewView_SwiftUI.swift b/Session/Conversations/Message Cells/Content Views/SwiftUI/LinkPreviewView_SwiftUI.swift index 82ba8d086d..6386eaee0b 100644 --- a/Session/Conversations/Message Cells/Content Views/SwiftUI/LinkPreviewView_SwiftUI.swift +++ b/Session/Conversations/Message Cells/Content Views/SwiftUI/LinkPreviewView_SwiftUI.swift @@ -1,6 +1,7 @@ // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import SwiftUI +import Lucide import SessionUIKit import SessionMessagingKit @@ -62,11 +63,8 @@ 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) + } else if state is LinkPreview.DraftState || state is LinkPreview.SentState { + LucideIcon(.link, size: IconSize.medium.size) .foregroundColor( themeColor: isOutgoing ? .messageBubble_outgoingText : @@ -108,7 +106,7 @@ public struct LinkPreviewView_SwiftUI: View { Button(action: { onCancel?() }, label: { - if let image: UIImage = UIImage(named: "X")?.withRenderingMode(.alwaysTemplate) { + if let image = Lucide.image(icon: .x, size: IconSize.medium.size)?.withRenderingMode(.alwaysTemplate) { Image(uiImage: image) .foregroundColor(themeColor: .textPrimary) } diff --git a/Session/Conversations/Message Cells/Content Views/SwiftUI/OpenGroupInvitationView_SwiftUI.swift b/Session/Conversations/Message Cells/Content Views/SwiftUI/OpenGroupInvitationView_SwiftUI.swift index ecf4994cdc..7fe7c9c0d4 100644 --- a/Session/Conversations/Message Cells/Content Views/SwiftUI/OpenGroupInvitationView_SwiftUI.swift +++ b/Session/Conversations/Message Cells/Content Views/SwiftUI/OpenGroupInvitationView_SwiftUI.swift @@ -1,6 +1,7 @@ // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import SwiftUI +import Lucide import SessionUIKit import SessionMessagingKit import SessionUtilitiesKit @@ -32,31 +33,27 @@ struct OpenGroupInvitationView_SwiftUI: View { self.textColor = textColor self.isOutgoing = isOutgoing } - + var body: some View { HStack( alignment: .center, spacing: Values.mediumSpacing ) { // Icon - if let iconImage = UIImage(named: isOutgoing ? "Globe" : "Plus")? - .withRenderingMode(.alwaysTemplate) - { - Circle() - .fill(themeColor: (isOutgoing ? .messageBubble_overlay : .primary)) - .frame( - width: Self.iconImageViewSize, - height: Self.iconImageViewSize - ) - .overlay { - Image(uiImage: iconImage) - .foregroundColor(themeColor: (isOutgoing ? .messageBubble_outgoingText : .textPrimary)) - .frame( - width: Self.iconSize, - height: Self.iconSize - ) - } - } + Circle() + .fill(themeColor: (isOutgoing ? .messageBubble_overlay : .primary)) + .frame( + width: Self.iconImageViewSize, + height: Self.iconImageViewSize + ) + .overlay { + LucideIcon(isOutgoing ? .globe : .plus, size: Self.iconSize) + .foregroundColor(themeColor: (isOutgoing ? .messageBubble_outgoingText : .textPrimary)) + .frame( + width: Self.iconSize, + height: Self.iconSize + ) + } // Text VStack( diff --git a/Session/Conversations/Message Cells/Content Views/SwiftUI/QuoteView_SwiftUI.swift b/Session/Conversations/Message Cells/Content Views/SwiftUI/QuoteView_SwiftUI.swift index 9f92551551..9e100b4238 100644 --- a/Session/Conversations/Message Cells/Content Views/SwiftUI/QuoteView_SwiftUI.swift +++ b/Session/Conversations/Message Cells/Content Views/SwiftUI/QuoteView_SwiftUI.swift @@ -1,6 +1,7 @@ // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import SwiftUI +import Lucide import SessionUIKit import SessionMessagingKit import SessionUtilitiesKit @@ -90,23 +91,16 @@ struct QuoteView_SwiftUI: View { .resizable() .aspectRatio(contentMode: .fill) } placeholder: { - let fallbackImageName: String = (attachment.isAudio ? "attachment_audio" : "actionsheet_document_black") - - if let image = UIImage(named: fallbackImageName)?.withRenderingMode(.alwaysTemplate) { - Image(uiImage: image) - .foregroundColor(themeColor: { - switch info.mode { - case .regular: return (info.direction == .outgoing ? - .messageBubble_outgoingText : - .messageBubble_incomingText - ) - case .draft: return .textPrimary - } - }()) - } - else { - Color.clear - } + LucideIcon((attachment.isAudio ? .mic : .file), size: Self.iconSize) + .foregroundColor(themeColor: { + switch info.mode { + case .regular: return (info.direction == .outgoing ? + .messageBubble_outgoingText : + .messageBubble_incomingText + ) + case .draft: return .textPrimary + } + }()) } .frame( width: Self.iconSize, @@ -187,15 +181,13 @@ struct QuoteView_SwiftUI: View { onCancel?() }, label: { - if let image = UIImage(named: "X")?.withRenderingMode(.alwaysTemplate) { - Image(uiImage: image) - .foregroundColor(themeColor: .textPrimary) - .frame( - width: Self.cancelButtonSize, - height: Self.cancelButtonSize, - alignment: .center - ) - } + LucideIcon(.x, size: Self.cancelButtonSize) + .foregroundColor(themeColor: .textPrimary) + .frame( + width: Self.cancelButtonSize, + height: Self.cancelButtonSize, + alignment: .center + ) } ) } diff --git a/Session/Conversations/Message Cells/Content Views/SwiftUI/VoiceMessageView_SwiftUI.swift b/Session/Conversations/Message Cells/Content Views/SwiftUI/VoiceMessageView_SwiftUI.swift index ad507a9117..fd334b7ead 100644 --- a/Session/Conversations/Message Cells/Content Views/SwiftUI/VoiceMessageView_SwiftUI.swift +++ b/Session/Conversations/Message Cells/Content Views/SwiftUI/VoiceMessageView_SwiftUI.swift @@ -36,7 +36,7 @@ struct VoiceMessageView_SwiftUI: View { width: Self.toggleContainerSize, height: Self.toggleContainerSize ) - if let toggleImage: UIImage = UIImage(named: isPlaying ? "Pause" : "Play")?.withRenderingMode(.alwaysTemplate) { + if let toggleImage: UIImage = UIImage(systemName: isPlaying ? "pause" : "play.fill")?.withRenderingMode(.alwaysTemplate) { Image(uiImage: toggleImage) .resizable() .foregroundColor(themeColor: .textPrimary) diff --git a/Session/Conversations/Message Cells/InfoMessageCell.swift b/Session/Conversations/Message Cells/InfoMessageCell.swift index e21578ad1d..47c7756ce9 100644 --- a/Session/Conversations/Message Cells/InfoMessageCell.swift +++ b/Session/Conversations/Message Cells/InfoMessageCell.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionMessagingKit import SessionUtilitiesKit @@ -109,9 +110,16 @@ final class InfoMessageCell: MessageCell { let icon: UIImage? = { switch cellViewModel.variant { case .infoDisappearingMessagesUpdate: - return UIImage(systemName: "timer") + return Lucide.image( + icon: .timer, + size: InfoMessageCell.iconSize + ) - case .infoMediaSavedNotification: return UIImage(named: "ic_download") + case .infoMediaSavedNotification: + return Lucide.image( + icon: .arrowDownToLine, + size: InfoMessageCell.iconSize + ) default: return nil } diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index f809ec9b80..a9213b2121 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SignalUtilitiesKit import SessionUtilitiesKit @@ -161,12 +162,12 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { return result }() - private lazy var replyIconImageView: UIImageView = { - let result = UIImageView() + private lazy var replyIconImageView: LucideIconView = { let size = VisibleMessageCell.replyButtonSize + + let result = LucideIconView(icon: .reply, size: size) result.set(.width, to: size) result.set(.height, to: size) - result.image = UIImage(named: "ic_reply")?.withRenderingMode(.alwaysTemplate) result.themeTintColor = .textPrimary return result diff --git a/Session/Conversations/Settings/ProfilePictureVC.swift b/Session/Conversations/Settings/ProfilePictureVC.swift index 8a21c190f9..7aaa8ea47f 100644 --- a/Session/Conversations/Settings/ProfilePictureVC.swift +++ b/Session/Conversations/Settings/ProfilePictureVC.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit @@ -65,7 +66,8 @@ final class ProfilePictureVC: BaseVC { // Close button let closeButton = UIBarButtonItem( - image: #imageLiteral(resourceName: "X").withRenderingMode(.alwaysTemplate), + image: Lucide.image(icon: .x, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate), style: .plain, target: self, action: #selector(close) diff --git a/Session/Conversations/Settings/ThreadSettingsViewModel.swift b/Session/Conversations/Settings/ThreadSettingsViewModel.swift index 5ae2cd91bc..6a8269b93a 100644 --- a/Session/Conversations/Settings/ThreadSettingsViewModel.swift +++ b/Session/Conversations/Settings/ThreadSettingsViewModel.swift @@ -1091,7 +1091,7 @@ class ThreadSettingsViewModel: SessionTableViewModel, NavigatableStateHolder, Ob SessionCell.Info( id: .debugDeleteAttachmentsBeforeNow, leadingAccessory: .icon( - Lucide.image(icon: .trash2, size: 24)? + Lucide.image(icon: .trash2, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), customTint: .danger ), diff --git a/Session/Conversations/Views & Modals/InfoBanner.swift b/Session/Conversations/Views & Modals/InfoBanner.swift index a76ec30f60..610d83099e 100644 --- a/Session/Conversations/Views & Modals/InfoBanner.swift +++ b/Session/Conversations/Views & Modals/InfoBanner.swift @@ -3,6 +3,7 @@ // stringlint:disable import UIKit +import Lucide import SessionUIKit final class InfoBanner: UIView { @@ -14,12 +15,11 @@ final class InfoBanner: UIView { var image: UIImage? { switch self { case .none: return nil - case .link: return UIImage(systemName: "arrow.up.right.square")?.withRenderingMode(.alwaysTemplate) + case .link: return Lucide.image(icon: .squareArrowUpRight, size: 12)? + .withRenderingMode(.alwaysTemplate) case .close: - return UIImage( - systemName: "xmark", - withConfiguration: UIImage.SymbolConfiguration(pointSize: 12, weight: .bold) - )?.withRenderingMode(.alwaysTemplate) + return Lucide.image(icon: .x, size: 12)? + .withRenderingMode(.alwaysTemplate) } } } diff --git a/Session/Conversations/Views & Modals/SessionLabelCarouselView.swift b/Session/Conversations/Views & Modals/SessionLabelCarouselView.swift index 25005c3324..5cdd238e87 100644 --- a/Session/Conversations/Views & Modals/SessionLabelCarouselView.swift +++ b/Session/Conversations/Views & Modals/SessionLabelCarouselView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit @@ -73,16 +74,16 @@ final class SessionLabelCarouselView: UIView, UIScrollViewDelegate { return result }() - private lazy var arrowLeft: UIImageView = { - let result = UIImageView(image: UIImage(systemName: "chevron.left")?.withRenderingMode(.alwaysTemplate)) + private lazy var arrowLeft: LucideIconView = { + let result = LucideIconView(icon: .chevronLeft) result.themeTintColor = .textPrimary result.set(.height, to: 10) result.set(.width, to: 5) return result }() - private lazy var arrowRight: UIImageView = { - let result = UIImageView(image: UIImage(systemName: "chevron.right")?.withRenderingMode(.alwaysTemplate)) + private lazy var arrowRight: LucideIconView = { + let result = LucideIconView(icon: .chevronRight) result.themeTintColor = .textPrimary result.set(.height, to: 10) result.set(.width, to: 5) diff --git a/Session/Database/Convenience/Interaction+UI.swift b/Session/Database/Convenience/Interaction+UI.swift index cb79dcfb24..58db6e55d6 100644 --- a/Session/Database/Convenience/Interaction+UI.swift +++ b/Session/Database/Convenience/Interaction+UI.swift @@ -1,6 +1,7 @@ // Copyright © 2025 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionMessagingKit @@ -34,7 +35,8 @@ public extension Interaction.State { case (.sent, false, _): return ( - UIImage(systemName: "checkmark.circle"), + Lucide.image(icon: .circleCheck, size: 12)? + .withRenderingMode(.alwaysTemplate), "disappearingMessagesSent".localized(), .messageBubble_deliveryStatus ) @@ -48,14 +50,16 @@ public extension Interaction.State { case (.failed, _, _): return ( - UIImage(systemName: "exclamationmark.triangle"), + Lucide.image(icon: .triangleAlert, size: 12)? + .withRenderingMode(.alwaysTemplate), "messageStatusFailedToSend".localized(), .danger ) case (.failedToSync, _, _): return ( - UIImage(systemName: "exclamationmark.triangle"), + Lucide.image(icon: .triangleAlert, size: 12)? + .withRenderingMode(.alwaysTemplate), "messageStatusFailedToSync".localized(), .warning ) diff --git a/Session/Home/App Review/View/AppReviewPromptDialog.swift b/Session/Home/App Review/View/AppReviewPromptDialog.swift index f1878753ea..ec3aa84e62 100644 --- a/Session/Home/App Review/View/AppReviewPromptDialog.swift +++ b/Session/Home/App Review/View/AppReviewPromptDialog.swift @@ -1,6 +1,7 @@ // Copyright © 2025 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit class AppReviewPromptDialog: UIView { @@ -14,7 +15,7 @@ class AppReviewPromptDialog: UIView { .withConfiguration( UIButton.Configuration .plain() - .withImage(UIImage(named: "X")?.withRenderingMode(.alwaysTemplate)) + .withImage(Lucide.image(icon: .x, size: Self.closeSize)?.withRenderingMode(.alwaysTemplate)) .withContentInsets(NSDirectionalEdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6)) ) .withConfigurationUpdateHandler { button in diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index cf9e8ed989..655b39fce7 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -2,6 +2,7 @@ import UIKit import Combine +import Lucide import GRDB import DifferenceKit import SessionUIKit @@ -108,7 +109,7 @@ public final class HomeVC: BaseVC, LibSessionRespondingViewController, UITableVi button.isAccessibilityElement = true button.clipsToBounds = true button.setImage( - UIImage(named: "Plus")? + Lucide.image(icon: .plus, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), for: .normal ) diff --git a/Session/Home/New Conversation/StartConversationScreen.swift b/Session/Home/New Conversation/StartConversationScreen.swift index 5937053c4e..e8971023a4 100644 --- a/Session/Home/New Conversation/StartConversationScreen.swift +++ b/Session/Home/New Conversation/StartConversationScreen.swift @@ -1,6 +1,7 @@ // Copyright © 2024 Rangeproof Pty Ltd. All rights reserved. import SwiftUI +import Lucide import SessionUIKit import SignalUtilitiesKit import SessionUtilitiesKit @@ -28,7 +29,7 @@ struct StartConversationScreen: View { .putNumber(1) .localized() NewConversationCell( - image: "Message", // stringlint:ignore + image: Lucide.image(icon: .messageSquare, size: IconSize.medium.size), title: title ) { let viewController: SessionHostingViewController = SessionHostingViewController( @@ -50,7 +51,7 @@ struct StartConversationScreen: View { .padding(.trailing, -Values.largeSpacing) NewConversationCell( - image: "Group", + image: UIImage(named: "users-group-custom"), title: "groupCreate".localized() ) { let viewController = NewClosedGroupVC(using: dependencies) @@ -68,7 +69,7 @@ struct StartConversationScreen: View { .padding(.trailing, -Values.largeSpacing) NewConversationCell( - image: "Globe", // stringlint:ignore + image: Lucide.image(icon: .globe, size: IconSize.medium.size), title: "communityJoin".localized() ) { let viewController = JoinOpenGroupVC(using: dependencies) @@ -86,7 +87,7 @@ struct StartConversationScreen: View { .padding(.trailing, -Values.largeSpacing) NewConversationCell( - image: "icon_invite", // stringlint:ignore + image: Lucide.image(icon: .userRoundPlus, size: IconSize.medium.size), title: "sessionInviteAFriend".localized() ) { let viewController: SessionHostingViewController = SessionHostingViewController( @@ -130,7 +131,7 @@ struct StartConversationScreen: View { } fileprivate struct NewConversationCell: View { - let image: String + let image: UIImage? let title: String let action: () -> () @@ -143,10 +144,13 @@ fileprivate struct NewConversationCell: View { spacing: Values.smallSpacing ) { ZStack(alignment: .center) { - Image(image) - .renderingMode(.template) - .foregroundColor(themeColor: .textPrimary) - .frame(width: 25, height: 24, alignment: .bottom) + if let icon = image { + Image(uiImage: icon) + .resizable() + .renderingMode(.template) + .foregroundColor(themeColor: .textPrimary) + .frame(width: 25, height: 24, alignment: .bottom) + } } .frame(width: 38, height: 38, alignment: .leading) diff --git a/Session/Media Viewing & Editing/DocumentTitleViewController.swift b/Session/Media Viewing & Editing/DocumentTitleViewController.swift index ea1814950e..9dcf2ba62b 100644 --- a/Session/Media Viewing & Editing/DocumentTitleViewController.swift +++ b/Session/Media Viewing & Editing/DocumentTitleViewController.swift @@ -2,6 +2,7 @@ import UIKit import QuartzCore +import Lucide import UniformTypeIdentifiers import GRDB import DifferenceKit @@ -358,8 +359,8 @@ class DocumentCell: UITableViewCell { // MARK: - UI - private let iconImageView: UIImageView = { - let result: UIImageView = UIImageView(image: UIImage(systemName: "doc")?.withRenderingMode(.alwaysTemplate)) + private let iconImageView: LucideIconView = { + let result: LucideIconView = LucideIconView(icon: .file, size: 46) result.translatesAutoresizingMaskIntoConstraints = false result.themeTintColor = .textPrimary result.contentMode = .scaleAspectFit diff --git a/Session/Media Viewing & Editing/ImagePickerController.swift b/Session/Media Viewing & Editing/ImagePickerController.swift index ae89e63281..aee465fafe 100644 --- a/Session/Media Viewing & Editing/ImagePickerController.swift +++ b/Session/Media Viewing & Editing/ImagePickerController.swift @@ -4,6 +4,7 @@ import Foundation import Combine import Photos import PhotosUI +import Lucide import SessionUIKit import SignalUtilitiesKit import SessionMessagingKit @@ -75,7 +76,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat // quickly toggle between the Capture and the Picker VC's, we use the same custom "X" // icon here rather than the system "stop" icon so that the spacing matches exactly. // Otherwise there's a noticable shift in the icon placement. - let cancelImage = #imageLiteral(resourceName: "X") + let cancelImage = Lucide.image(icon: .x, size: IconSize.medium.size) let cancelButton = UIBarButtonItem(image: cancelImage, style: .plain, target: self, action: #selector(didPressCancel)) cancelButton.themeTintColor = .textPrimary @@ -95,7 +96,9 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat collectionView.addGestureRecognizer(selectionPanGesture) if PHPhotoLibrary.authorizationStatus(for: .readWrite) == .limited { - let addSeletedPhotoButton = UIBarButtonItem.init(barButtonSystemItem: .add, target: self, action: #selector(addSelectedPhoto)) + let plusImage = Lucide.image(icon: .plus, size: IconSize.medium.size) + + let addSeletedPhotoButton = UIBarButtonItem.init(image: plusImage, style: .plain, target: self, action: #selector(addSelectedPhoto)) self.navigationItem.rightBarButtonItem = addSeletedPhotoButton } } diff --git a/Session/Media Viewing & Editing/MediaPageViewController.swift b/Session/Media Viewing & Editing/MediaPageViewController.swift index 4166834227..9c5611cc8c 100644 --- a/Session/Media Viewing & Editing/MediaPageViewController.swift +++ b/Session/Media Viewing & Editing/MediaPageViewController.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import GRDB import SessionUIKit import SessionMessagingKit @@ -300,7 +301,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou lazy var shareBarButton: UIBarButtonItem = { let shareBarButton = UIBarButtonItem( - barButtonSystemItem: .action, + image: Lucide.image(icon: .share, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate), + style: .plain, target: self, action: #selector(didPressShare) ) @@ -311,7 +314,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou lazy var deleteBarButton: UIBarButtonItem = { let deleteBarButton = UIBarButtonItem( - barButtonSystemItem: .trash, + image: Lucide.image(icon: .trash2, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate), + style: .plain, target: self, action: #selector(didPressDelete) ) diff --git a/Session/Media Viewing & Editing/MediaTileViewController.swift b/Session/Media Viewing & Editing/MediaTileViewController.swift index a5cc997b8c..100db65612 100644 --- a/Session/Media Viewing & Editing/MediaTileViewController.swift +++ b/Session/Media Viewing & Editing/MediaTileViewController.swift @@ -2,6 +2,7 @@ import UIKit import QuartzCore +import Lucide import GRDB import DifferenceKit import SessionUIKit @@ -127,7 +128,9 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour lazy var deleteButton: UIBarButtonItem = { let result: UIBarButtonItem = UIBarButtonItem( - barButtonSystemItem: .trash, + image: Lucide.image(icon: .trash2, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate), + style: .plain, target: self, action: #selector(didPressDelete) ) diff --git a/Session/Media Viewing & Editing/SendMediaNavigationController.swift b/Session/Media Viewing & Editing/SendMediaNavigationController.swift index 5be73955ea..d6a8f7fd7b 100644 --- a/Session/Media Viewing & Editing/SendMediaNavigationController.swift +++ b/Session/Media Viewing & Editing/SendMediaNavigationController.swift @@ -3,6 +3,7 @@ import UIKit import Combine import Photos +import Lucide import SignalUtilitiesKit import SessionUIKit import SessionMessagingKit @@ -193,7 +194,7 @@ class SendMediaNavigationController: UINavigationController { private lazy var mediaLibraryModeButton: InputViewButton = { let result: InputViewButton = InputViewButton( - icon: UIImage(named: "actionsheet_camera_roll_black")? + icon: Lucide.image(icon: .images, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate) ) { [weak self] in self?.didTapMediaLibraryModeButton() } @@ -648,12 +649,12 @@ private class DoneButton: UIView { }() private lazy var chevron: UIView = { - let image: UIImage = { - guard Dependencies.isRTL else { return #imageLiteral(resourceName: "small_chevron_right") } + let image: Lucide.Icon = { + guard Dependencies.isRTL else { return .chevronRight } - return #imageLiteral(resourceName: "small_chevron_left") + return .chevronLeft }() - let result: UIImageView = UIImageView(image: image.withRenderingMode(.alwaysTemplate)) + let result: LucideIconView = LucideIconView(icon: image) result.contentMode = .scaleAspectFit result.themeTintColor = .textPrimary result.set(.width, to: 10) diff --git a/Session/Meta/Images.xcassets/Session/phone-fill-answer-custom.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/phone-fill-answer-custom.imageset/Contents.json new file mode 100644 index 0000000000..f6d5fe83a1 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/phone-fill-answer-custom.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "phone-fill-answer-custom.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/phone-fill-answer-custom.imageset/phone-fill-answer-custom.pdf b/Session/Meta/Images.xcassets/Session/phone-fill-answer-custom.imageset/phone-fill-answer-custom.pdf new file mode 100644 index 0000000000..36cc3f4f05 Binary files /dev/null and b/Session/Meta/Images.xcassets/Session/phone-fill-answer-custom.imageset/phone-fill-answer-custom.pdf differ diff --git a/Session/Meta/Images.xcassets/Session/phone-fill-custom.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/phone-fill-custom.imageset/Contents.json new file mode 100644 index 0000000000..f9841d1038 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/phone-fill-custom.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "phone-fill-custom.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/phone-fill-custom.imageset/phone-fill-custom.pdf b/Session/Meta/Images.xcassets/Session/phone-fill-custom.imageset/phone-fill-custom.pdf new file mode 100644 index 0000000000..c0919401f0 Binary files /dev/null and b/Session/Meta/Images.xcassets/Session/phone-fill-custom.imageset/phone-fill-custom.pdf differ diff --git a/Session/Meta/Images.xcassets/Session/users-group-custom.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/users-group-custom.imageset/Contents.json new file mode 100644 index 0000000000..e3cee03aa8 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/users-group-custom.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "users-group-custom.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/users-group-custom.imageset/users-group-custom.pdf b/Session/Meta/Images.xcassets/Session/users-group-custom.imageset/users-group-custom.pdf new file mode 100644 index 0000000000..a9804b71e4 Binary files /dev/null and b/Session/Meta/Images.xcassets/Session/users-group-custom.imageset/users-group-custom.pdf differ diff --git a/Session/Meta/Images.xcassets/crop-lock-custom.imageset/Contents.json b/Session/Meta/Images.xcassets/crop-lock-custom.imageset/Contents.json new file mode 100644 index 0000000000..23dc2e687b --- /dev/null +++ b/Session/Meta/Images.xcassets/crop-lock-custom.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "crop-lock-custom.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/crop-lock-custom.imageset/crop-lock-custom.pdf b/Session/Meta/Images.xcassets/crop-lock-custom.imageset/crop-lock-custom.pdf new file mode 100644 index 0000000000..0d53a9cd84 Binary files /dev/null and b/Session/Meta/Images.xcassets/crop-lock-custom.imageset/crop-lock-custom.pdf differ diff --git a/Session/Meta/Images.xcassets/crop-unlock-custom.imageset/Contents.json b/Session/Meta/Images.xcassets/crop-unlock-custom.imageset/Contents.json new file mode 100644 index 0000000000..352cc1cbb4 --- /dev/null +++ b/Session/Meta/Images.xcassets/crop-unlock-custom.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "crop-unlock-custom.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/crop-unlock-custom.imageset/crop-unlock-custom.pdf b/Session/Meta/Images.xcassets/crop-unlock-custom.imageset/crop-unlock-custom.pdf new file mode 100644 index 0000000000..20759e9994 Binary files /dev/null and b/Session/Meta/Images.xcassets/crop-unlock-custom.imageset/crop-unlock-custom.pdf differ diff --git a/Session/Open Groups/JoinOpenGroupVC.swift b/Session/Open Groups/JoinOpenGroupVC.swift index 22bc293fc7..cb9494a24f 100644 --- a/Session/Open Groups/JoinOpenGroupVC.swift +++ b/Session/Open Groups/JoinOpenGroupVC.swift @@ -3,6 +3,7 @@ import UIKit import Combine import AVFoundation +import Lucide import GRDB import SessionUIKit import SessionMessagingKit @@ -87,7 +88,10 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC } } - let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) + let closeIcon = Lucide.image(icon: .x, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate) + + let closeButton = UIBarButtonItem(image: closeIcon, style: .plain, target: self, action: #selector(close)) closeButton.themeTintColor = .textPrimary navigationItem.rightBarButtonItem = closeButton diff --git a/Session/Open Groups/OpenGroupSuggestionGrid.swift b/Session/Open Groups/OpenGroupSuggestionGrid.swift index ddc4c72ba9..a76d6ee57f 100644 --- a/Session/Open Groups/OpenGroupSuggestionGrid.swift +++ b/Session/Open Groups/OpenGroupSuggestionGrid.swift @@ -3,6 +3,7 @@ import Foundation import GRDB import Combine +import Lucide import NVActivityIndicatorView import SessionNetworkingKit import SessionMessagingKit @@ -81,8 +82,8 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle return result }() - private lazy var errorImageView: UIImageView = { - let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "warning").withRenderingMode(.alwaysTemplate)) + private lazy var errorImageView: LucideIconView = { + let result: LucideIconView = LucideIconView(icon: .triangleAlert) result.themeTintColor = .danger return result diff --git a/Session/Settings/HelpViewModel.swift b/Session/Settings/HelpViewModel.swift index 4b3ddc2932..4c9ec0b962 100644 --- a/Session/Settings/HelpViewModel.swift +++ b/Session/Settings/HelpViewModel.swift @@ -74,8 +74,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa .put(key: "app_name", value: Constants.app_name) .localized(), trailingAccessory: .icon( - UIImage(systemName: "arrow.up.forward.app")? - .withRenderingMode(.alwaysTemplate), + .squareArrowUpRight, size: .small, pinEdges: [.right] ), @@ -96,8 +95,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa id: .feedback, title: "helpWedLoveYourFeedback".localized(), trailingAccessory: .icon( - UIImage(systemName: "arrow.up.forward.app")? - .withRenderingMode(.alwaysTemplate), + .squareArrowUpRight, size: .small, pinEdges: [.right] ), @@ -118,8 +116,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa id: .faq, title: "helpFAQ".localized(), trailingAccessory: .icon( - UIImage(systemName: "arrow.up.forward.app")? - .withRenderingMode(.alwaysTemplate), + .squareArrowUpRight, size: .small, pinEdges: [.right] ), @@ -140,8 +137,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa id: .support, title: "helpSupport".localized(), trailingAccessory: .icon( - UIImage(systemName: "arrow.up.forward.app")? - .withRenderingMode(.alwaysTemplate), + .squareArrowUpRight, size: .small, pinEdges: [.right] ), diff --git a/Session/Settings/PrivacySettingsViewModel.swift b/Session/Settings/PrivacySettingsViewModel.swift index 0764aa3b77..d759d2422f 100644 --- a/Session/Settings/PrivacySettingsViewModel.swift +++ b/Session/Settings/PrivacySettingsViewModel.swift @@ -2,6 +2,7 @@ import Foundation import Combine +import Lucide import GRDB import LocalAuthentication import DifferenceKit @@ -83,7 +84,7 @@ class PrivacySettingsViewModel: SessionTableViewModel, NavigationItemSource, Nav [ SessionNavItem( id: .close, - image: UIImage(named: "X")? + image: Lucide.image(icon: .x, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), style: .plain, accessibilityIdentifier: "Close button" diff --git a/Session/Settings/SettingsViewModel.swift b/Session/Settings/SettingsViewModel.swift index d725ccf4c4..6dfaa7e094 100644 --- a/Session/Settings/SettingsViewModel.swift +++ b/Session/Settings/SettingsViewModel.swift @@ -102,7 +102,7 @@ class SettingsViewModel: SessionTableViewModel, NavigationItemSource, Navigatabl lazy var leftNavItems: AnyPublisher<[SessionNavItem], Never> = [ SessionNavItem( id: .close, - image: UIImage(named: "X")? + image: Lucide.image(icon: .x, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), style: .plain, accessibilityIdentifier: "Close button" @@ -112,7 +112,7 @@ class SettingsViewModel: SessionTableViewModel, NavigationItemSource, Navigatabl lazy var rightNavItems: AnyPublisher<[SessionNavItem], Never> = [ SessionNavItem( id: .qrCode, - image: UIImage(named: "QRCode")? + image: Lucide.image(icon: .qrCode, size: IconSize.medium.size)? .withRenderingMode(.alwaysTemplate), style: .plain, accessibilityIdentifier: "View QR code", diff --git a/Session/Shared/SessionCarouselView.swift b/Session/Shared/SessionCarouselView.swift index 6111f6df07..81a437183f 100644 --- a/Session/Shared/SessionCarouselView.swift +++ b/Session/Shared/SessionCarouselView.swift @@ -1,6 +1,7 @@ // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit @@ -41,7 +42,8 @@ final class SessionCarouselView: UIView, UIScrollViewDelegate { private lazy var arrowLeft: UIButton = { let result = UIButton(type: .custom) - result.setImage(UIImage(systemName: "chevron.left")?.withRenderingMode(.alwaysTemplate), for: .normal) + result.setImage(Lucide.image(icon: .chevronLeft, size: self.info.arrowsSize.height)? + .withRenderingMode(.alwaysTemplate), for: .normal) result.addTarget(self, action: #selector(scrollToPreviousSlice), for: .touchUpInside) result.themeTintColor = .textPrimary result.set(.width, to: self.info.arrowsSize.width) @@ -53,7 +55,8 @@ final class SessionCarouselView: UIView, UIScrollViewDelegate { private lazy var arrowRight: UIButton = { let result = UIButton(type: .custom) - result.setImage(UIImage(systemName: "chevron.right")?.withRenderingMode(.alwaysTemplate), for: .normal) + result.setImage(Lucide.image(icon: .chevronRight, size: self.info.arrowsSize.height)? + .withRenderingMode(.alwaysTemplate), for: .normal) result.addTarget(self, action: #selector(scrollToNextSlice), for: .touchUpInside) result.themeTintColor = .textPrimary result.set(.width, to: self.info.arrowsSize.width) diff --git a/Session/Utilities/UIContextualAction+Utilities.swift b/Session/Utilities/UIContextualAction+Utilities.swift index c0edbc3b20..3da99570f3 100644 --- a/Session/Utilities/UIContextualAction+Utilities.swift +++ b/Session/Utilities/UIContextualAction+Utilities.swift @@ -122,7 +122,7 @@ public extension UIContextualAction { case .clear: return UIContextualAction( title: "clear".localized(), - icon: Lucide.image(icon: .trash2, size: 24, color: .white), + icon: Lucide.image(icon: .trash2, size: IconSize.medium.size), themeTintColor: .white, themeBackgroundColor: themeBackgroundColor, side: side, @@ -163,7 +163,7 @@ public extension UIContextualAction { case .hide: return UIContextualAction( title: "hide".localized(), - icon: UIImage(systemName: "eye.slash"), + icon: Lucide.image(icon: .eyeOff, size: IconSize.medium.size), themeTintColor: .white, themeBackgroundColor: themeBackgroundColor, accessibility: Accessibility(identifier: "Hide button"), @@ -214,9 +214,24 @@ public extension UIContextualAction { case .pin: let isCurrentlyPinned: Bool = (threadViewModel.threadPinnedPriority > 0) + + var pin: (title: String, icon: UIImage?) { + if isCurrentlyPinned { + return ( + "pinUnpin".localized(), + Lucide.image(icon: .pinOff, size: IconSize.medium.size) + ) + } else { + return ( + "pin".localized(), + Lucide.image(icon: .pin, size: IconSize.medium.size) + ) + } + } + return UIContextualAction( - title: (isCurrentlyPinned ? "pinUnpin".localized() : "pin".localized()), - icon: (isCurrentlyPinned ? UIImage(systemName: "pin.slash") : UIImage(systemName: "pin")), + title: pin.title, + icon: pin.icon, themeTintColor: .white, themeBackgroundColor: .conversationButton_swipeTertiary, // Always Tertiary accessibility: Accessibility( @@ -274,15 +289,23 @@ public extension UIContextualAction { // MARK: -- mute case .mute: + var mute: (title: String, icon: UIImage?) { + guard threadViewModel.threadMutedUntilTimestamp == nil else { + return ( + "notificationsMute".localized(), + Lucide.image(icon: .volumeOff, size: IconSize.medium.size) + ) + } + return ( + "notificationsMuteUnmute".localized(), + Lucide.image(icon: .volume, size: IconSize.medium.size) + ) + } + + return UIContextualAction( - title: (threadViewModel.threadMutedUntilTimestamp == nil ? - "notificationsMute".localized() : - "notificationsMuteUnmute".localized() - ), - icon: (threadViewModel.threadMutedUntilTimestamp == nil ? - UIImage(systemName: "speaker.slash") : - UIImage(systemName: "speaker") - ), + title: mute.title, + icon: mute.icon, themeTintColor: .white, themeBackgroundColor: themeBackgroundColor, accessibility: Accessibility( @@ -615,7 +638,7 @@ public extension UIContextualAction { case .delete: return UIContextualAction( title: "delete".localized(), - icon: Lucide.image(icon: .trash2, size: 24, color: .white), + icon: Lucide.image(icon: .trash2, size: IconSize.medium.size), themeTintColor: .white, themeBackgroundColor: themeBackgroundColor, accessibility: Accessibility(identifier: "Delete button"), diff --git a/SessionShareExtension/SAEScreenLockViewController.swift b/SessionShareExtension/SAEScreenLockViewController.swift index 216365d4cb..a3130c4031 100644 --- a/SessionShareExtension/SAEScreenLockViewController.swift +++ b/SessionShareExtension/SAEScreenLockViewController.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SignalUtilitiesKit import SessionUIKit import SessionUtilitiesKit @@ -43,7 +44,13 @@ final class SAEScreenLockViewController: ScreenLockViewController { }() private lazy var closeButton: UIBarButtonItem = { - let closeButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "X"), style: .plain, target: self, action: #selector(dismissPressed)) + let closeButton: UIBarButtonItem = UIBarButtonItem( + image: Lucide.image(icon: .x, size: IconSize.medium.size)? + .withRenderingMode(.alwaysTemplate), + style: .plain, + target: self, + action: #selector(dismissPressed) + ) closeButton.themeTintColor = .textPrimary return closeButton diff --git a/SessionUIKit/Components/Modals & Toast/ConfirmationModal.swift b/SessionUIKit/Components/Modals & Toast/ConfirmationModal.swift index 2bf257d7cb..3473d93707 100644 --- a/SessionUIKit/Components/Modals & Toast/ConfirmationModal.swift +++ b/SessionUIKit/Components/Modals & Toast/ConfirmationModal.swift @@ -297,7 +297,7 @@ public class ConfirmationModal: Modal, UITextFieldDelegate, UITextViewDelegate { .withConfiguration( UIButton.Configuration .plain() - .withImage(UIImage(named: "X")?.withRenderingMode(.alwaysTemplate)) + .withImage(Lucide.image(icon: .x, size: IconSize.medium.size)?.withRenderingMode(.alwaysTemplate)) .withContentInsets(NSDirectionalEdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6)) ) .withConfigurationUpdateHandler { button in diff --git a/SessionUIKit/Components/SessionHostingViewController.swift b/SessionUIKit/Components/SessionHostingViewController.swift index fdedd738df..3d3d1c71b5 100644 --- a/SessionUIKit/Components/SessionHostingViewController.swift +++ b/SessionUIKit/Components/SessionHostingViewController.swift @@ -1,6 +1,7 @@ // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import SwiftUI +import Lucide public class HostWrapper: ObservableObject { public weak var controller: UIViewController? @@ -117,7 +118,10 @@ open class SessionHostingViewController: UIHostingController UIView { + let button = OWSButton() + button.setImage(image: image) + button.themeTintColor = .textPrimary + button.addTarget(self, action: selector, for: .touchUpInside) + + return button + } } // MARK: - diff --git a/SignalUtilitiesKit/Shared Views/ApprovalRailCellView.swift b/SignalUtilitiesKit/Shared Views/ApprovalRailCellView.swift index 30fd976c21..7d589c976b 100644 --- a/SignalUtilitiesKit/Shared Views/ApprovalRailCellView.swift +++ b/SignalUtilitiesKit/Shared Views/ApprovalRailCellView.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit +import Lucide import SessionUIKit import SessionUtilitiesKit @@ -27,7 +28,7 @@ public class ApprovalRailCellView: GalleryRailCellView { strongSelf.approvalRailCellDelegate?.approvalRailCellView(strongSelf, didRemoveItem: attachmentItem) } - button.setImage(UIImage(named: "x-24")?.withRenderingMode(.alwaysTemplate), for: .normal) + button.setImage(Lucide.image(icon: .x, size: IconSize.medium.size)?.withRenderingMode(.alwaysTemplate), for: .normal) button.themeTintColor = .white button.themeShadowColor = .black button.layer.shadowRadius = 2 diff --git a/SignalUtilitiesKit/Shared Views/OWSButton.swift b/SignalUtilitiesKit/Shared Views/OWSButton.swift index c06726e35c..93c539f006 100644 --- a/SignalUtilitiesKit/Shared Views/OWSButton.swift +++ b/SignalUtilitiesKit/Shared Views/OWSButton.swift @@ -32,6 +32,17 @@ public class OWSButton: UIButton { setImage(imageName: imageName) self.themeTintColor = tintColor } + + public init(image: UIImage?, tintColor: ThemeValue?, block: @escaping () -> Void = { }) { + super.init(frame: .zero) + + self.block = block + addTarget(self, action: #selector(didTap), for: .touchUpInside) + + setImage(image: image) + + self.themeTintColor = tintColor + } public func setImage(imageName: String) { setImage( @@ -40,6 +51,14 @@ public class OWSButton: UIButton { for: .normal ) } + + public func setImage(image: UIImage?) { + setImage( + image? + .withRenderingMode(.alwaysTemplate), + for: .normal + ) + } public required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented")