Skip to content

Commit

Permalink
Feature/ABW-1288 Actions for addresses (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikola-milicevic committed May 3, 2023
1 parent 92a065c commit affbb14
Show file tree
Hide file tree
Showing 53 changed files with 686 additions and 681 deletions.
290 changes: 135 additions & 155 deletions .swiftpm/xcode/xcshareddata/xcschemes/Unit Tests.xcscheme

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ package.addModules([
"AccountPortfoliosClient",
"FactorSourcesClient", // check if `device` or `ledger` controlled for security prompting
],
tests: .yes()
tests: .no
),
.feature(
name: "AccountPreferencesFeature",
Expand Down Expand Up @@ -647,7 +647,7 @@ package.addModules([
.package(url: "https://github.com/davdroman/TextBuilder", from: "2.2.0")
},
],
tests: .yes()
tests: .no
),
.core(
name: "Resources",
Expand Down
73 changes: 0 additions & 73 deletions Sources/Core/DesignSystem/Components/AccountButton.swift

This file was deleted.

89 changes: 0 additions & 89 deletions Sources/Core/DesignSystem/Components/AddressView.swift

This file was deleted.

16 changes: 16 additions & 0 deletions Sources/Core/DesignSystem/Extensions/Button+Extra.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Resources
import SwiftUI

extension Button where Label == SwiftUI.Label<Text, Image> {
public init(_ titleKey: LocalizedStringKey, asset: ImageAsset, action: @escaping () -> Void) {
self.init(action: action) {
SwiftUI.Label(titleKey, asset: asset)
}
}

public init<S>(_ title: S, asset: ImageAsset, action: @escaping () -> Void) where S: StringProtocol {
self.init(action: action) {
SwiftUI.Label(title, asset: asset)
}
}
}
22 changes: 22 additions & 0 deletions Sources/Core/DesignSystem/Extensions/Label+Extra.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Resources
import SwiftUI

extension Label where Title == Text, Icon == Image {
public init(_ titleKey: LocalizedStringKey, asset: ImageAsset) {
self.init {
Text(titleKey)
} icon: {
Image(asset: asset)
.renderingMode(.template)
}
}

public init<S>(_ title: S, asset: ImageAsset) where S: StringProtocol {
self.init {
Text(title)
} icon: {
Image(asset: asset)
.renderingMode(.template)
}
}
}
28 changes: 28 additions & 0 deletions Sources/Core/FeaturePrelude/AddressView/AddressFormat.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Foundation

// MARK: - AddressFormat
public enum AddressFormat: String, Sendable {
case `default`
case nonFungibleLocalId
}

extension String {
public func truncatedMiddle(keepFirst first: Int, last: Int) -> Self {
guard count > first + last else { return self }
return prefix(first) + "..." + suffix(last)
}

public func colonSeparated() -> Self {
guard let index = range(of: ":")?.upperBound else { return self }
return String(self[index...])
}

public func formatted(_ format: AddressFormat) -> Self {
switch format {
case .default:
return truncatedMiddle(keepFirst: 4, last: 6)
case .nonFungibleLocalId:
return colonSeparated()
}
}
}
134 changes: 134 additions & 0 deletions Sources/Core/FeaturePrelude/AddressView/AddressView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import Prelude
import Resources
import SharedModels
import SwiftUI

// MARK: - AddressView
public struct AddressView: SwiftUI.View, Sendable {
let identifiable: LedgerIdentifiable
let isTappable: Bool
private let format: AddressFormat
private let action: Action

@Dependency(\.pasteboardClient) var pasteboardClient
@Dependency(\.openURL) var openURL

public init(
_ identifiable: LedgerIdentifiable,
isTappable: Bool = true
) {
self.identifiable = identifiable
self.isTappable = isTappable

switch identifiable {
case .address:
format = .default
action = .copy
case let .identifier(identifier):
switch identifier {
case .transaction:
format = .default
action = .viewOnDashboard
case .nonFungibleGlobalID:
format = .nonFungibleLocalId
action = .copy
}
}
}
}

extension AddressView {
@ViewBuilder
public var body: some View {
if isTappable {
tappableAddressView
} else {
addressView
}
}

private var tappableAddressView: some View {
Button {
tapAction()
} label: {
HStack(spacing: .small3) {
addressView
image
}
.contentShape(.contextMenuPreview, RoundedRectangle(cornerRadius: .medium1))
.contextMenu {
Button(copyText, asset: AssetResource.copyBig) {
copyToPasteboard()
}

Button(L10n.AddressAction.viewOnDashboard, asset: AssetResource.iconLinkOut) {
viewOnRadixDashboard()
}
}
}
}

private var addressView: some View {
Text((identifiable.address).formatted(format))
.lineLimit(1)
.minimumScaleFactor(0.5)
}

private var image: Image {
Image(asset: action == .copy ? AssetResource.copy : AssetResource.iconLinkOut)
}

private var copyText: String {
switch identifiable {
case .address:
return L10n.AddressAction.copyAddress
case let .identifier(identifier):
switch identifier {
case .transaction:
return L10n.AddressAction.copyTransactionId
case .nonFungibleGlobalID:
return L10n.AddressAction.copyNftId
}
}
}
}

extension AddressView {
private func tapAction() {
action == .copy ? copyToPasteboard() : viewOnRadixDashboard()
}

private func copyToPasteboard() {
pasteboardClient.copyString(identifiable.address)
}

private func viewOnRadixDashboard() {
guard let addressURL else { return }
Task { await openURL(addressURL) }
}

private var path: String? {
identifiable.addressPrefix + "/" + identifiable.address
}

private var addressURL: URL? {
guard let path else { return nil }
return Radix.Dashboard.rcnet.url.appending(path: path)
}
}

// MARK: AddressView.Action
extension AddressView {
private enum Action {
case copy
case viewOnDashboard
}
}

#if DEBUG
struct AddressView_Previews: PreviewProvider {
static var previews: some View {
AddressView(.address(.account(try! .init(address: "account_wqs8qxdx7qw8c"))))
}
}
#endif
Loading

0 comments on commit affbb14

Please sign in to comment.