Skip to content

Commit

Permalink
Merge pull request #319 from nova-wallet/release/3.3.0
Browse files Browse the repository at this point in the history
v3.3.0
  • Loading branch information
ERussel authored Jul 21, 2022
2 parents 4076e7c + b7dc5c4 commit 502e06c
Show file tree
Hide file tree
Showing 118 changed files with 4,521 additions and 2,569 deletions.
170 changes: 121 additions & 49 deletions novawallet.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions novawallet/Assets.xcassets/iconSearchButton.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "iconSearchButton.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ class CrowdloanOffchainProviderFactory: CrowdloanOffchainProviderFactoryProtocol
private var providers: [String: WeakWrapper] = [:]

let storageFacade: StorageFacadeProtocol
let paraIdOperationFactory: ParaIdOperationFactoryProtocol

init(storageFacade: StorageFacadeProtocol) {
init(storageFacade: StorageFacadeProtocol, paraIdOperationFactory: ParaIdOperationFactoryProtocol) {
self.storageFacade = storageFacade
self.paraIdOperationFactory = paraIdOperationFactory
}

func getExternalContributionProvider(
Expand All @@ -30,10 +32,15 @@ class CrowdloanOffchainProviderFactory: CrowdloanOffchainProviderFactoryProtocol
let repository: CoreDataRepository<SingleValueProviderObject, CDSingleValue> =
storageFacade.createRepository()

let externalSources = ExternalContributionSourcesFactory.createExternalSources(
for: chain.chainId,
paraIdOperationFactory: paraIdOperationFactory
)

let source = ExternalContributionDataProviderSource(
accountId: accountId,
chain: chain,
children: ExternalContributionSourcesFactory.createExternalSources(for: chain.chainId)
children: externalSources
)

let trigger: DataProviderEventTrigger = [.onAddObserver, .onInitialization]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ final class NftLocalSubscriptionFactory: SubstrateLocalSubscriptionFactory,
storageFacade: SubstrateDataStorageFacade.shared,
operationManager: OperationManagerFacade.sharedManager,
logger: Logger.shared,
operationQueue: OperationManagerFacade.sharedDefaultQueue
operationQueue: OperationManagerFacade.nftQueue
)

typealias NftOption = (chain: ChainModel, ownerId: AccountId, type: NftType)
Expand Down
15 changes: 13 additions & 2 deletions novawallet/Common/DataProvider/PriceProviderFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,32 @@ extension PriceProviderFactory: PriceProviderFactoryProtocol {
}

func getPriceListProvider(for priceIds: [AssetModel.PriceId]) -> AnySingleValueProvider<[PriceData]> {
let priceListIdentifier = "coingecko_price_list_identifier"
clearIfNeeded()

let fullKey = priceIds.joined()
let cacheKey = fullKey.data(using: .utf8)?.sha256().toHex() ?? fullKey

if let provider = providers[cacheKey]?.target as? SingleValueProvider<[PriceData]> {
return AnySingleValueProvider(provider)
}

let repository: CoreDataRepository<SingleValueProviderObject, CDSingleValue> =
storageFacade.createRepository()

let source = CoingeckoPriceListSource(priceIds: priceIds)

let databaseIdentifier = "coingecko_price_list_identifier"

let trigger: DataProviderEventTrigger = [.onAddObserver, .onInitialization]
let provider = SingleValueProvider(
targetIdentifier: priceListIdentifier,
targetIdentifier: databaseIdentifier,
source: AnySingleValueProviderSource(source),
repository: AnyDataProviderRepository(repository),
updateTrigger: trigger
)

providers[cacheKey] = WeakWrapper(target: provider)

return AnySingleValueProvider(provider)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extension ExternalContributionDataProviderSource: SingleValueProviderSourceProto
typealias Model = [ExternalContribution]

func fetchOperation() -> CompoundOperationWrapper<Model?> {
let contributionOperations: [BaseOperation<[ExternalContribution]>] = children.map { source in
let contributionOperations: [CompoundOperationWrapper<[ExternalContribution]>] = children.map { source in
source.getContributions(accountId: accountId, chain: chain)
}

Expand All @@ -27,15 +27,14 @@ extension ExternalContributionDataProviderSource: SingleValueProviderSourceProto

let mergeOperation = ClosureOperation<[ExternalContribution]?> {
contributionOperations.compactMap { operation in
try? operation.extractNoCancellableResultData()
try? operation.targetOperation.extractNoCancellableResultData()
}.flatMap { $0 }
}

contributionOperations.forEach { mergeOperation.addDependency($0) }
contributionOperations.forEach { mergeOperation.addDependency($0.targetOperation) }

return CompoundOperationWrapper(
targetOperation: mergeOperation,
dependencies: contributionOperations
)
let dependencies = contributionOperations.flatMap(\.allOperations)

return CompoundOperationWrapper(targetOperation: mergeOperation, dependencies: dependencies)
}
}
5 changes: 5 additions & 0 deletions novawallet/Common/Extension/Foundation/Bool+Int.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Foundation

extension Bool {
var intValue: Int { self ? 1 : 0 }
}
37 changes: 37 additions & 0 deletions novawallet/Common/Extension/Foundation/ChainModel+Comparator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation

enum ChainModelCompator {
static func priorityAndTestnetComparator(chain1: ChainModel, chain2: ChainModel) -> ComparisonResult {
let priority1 = chainPriority(for: chain1.chainId)
let priority2 = chainPriority(for: chain2.chainId)

if priority1 != priority2 {
return priority1 < priority2 ? .orderedAscending : .orderedDescending
} else if chain1.isTestnet != chain2.isTestnet {
return chain1.isTestnet.intValue < chain2.isTestnet.intValue ? .orderedAscending : .orderedDescending
}

return .orderedSame
}

static func defaultComparator(chain1: ChainModel, chain2: ChainModel) -> Bool {
let priorityAndTestResult = priorityAndTestnetComparator(chain1: chain1, chain2: chain2)

if priorityAndTestResult != .orderedSame {
return priorityAndTestResult == .orderedAscending
} else {
return chain1.name.lexicographicallyPrecedes(chain2.name)
}
}

private static func chainPriority(for chainId: ChainModel.Id) -> UInt8 {
switch chainId {
case KnowChainId.polkadot:
return 0
case KnowChainId.kusama:
return 1
default:
return 2
}
}
}
6 changes: 3 additions & 3 deletions novawallet/Common/Helpers/ChainDateCalculator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ final class ChainDateCalculator: ChainDateCalculatorProtocol {
metadata: CrowdloanMetadata,
calendar: Calendar
) -> LeasingTimeInterval? {
let firstBlockNumber = firstPeriod * metadata.leasingPeriod
let lastBlockNumber = (lastPeriod + 1) * metadata.leasingPeriod
let firstBlockNumber = metadata.firstBlockNumber(of: firstPeriod)
let lastBlockNumber = metadata.firstBlockNumber(of: lastPeriod + 1)

let leasingTimeInterval = firstBlockNumber.secondsTo(
block: lastBlockNumber,
Expand Down Expand Up @@ -64,7 +64,7 @@ final class ChainDateCalculator: ChainDateCalculatorProtocol {
metadata: CrowdloanMetadata,
calendar: Calendar
) -> LeasingTimeInterval? {
let blockNumber = period * metadata.leasingPeriod
let blockNumber = metadata.firstBlockNumber(of: period)
let timeInterval = metadata.blockNumber.secondsTo(block: blockNumber, blockDuration: metadata.blockDuration)

guard let tillDate = calendar.date(
Expand Down
27 changes: 27 additions & 0 deletions novawallet/Common/Helpers/FilterImageProcessor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Foundation
import Kingfisher

final class FilterImageProcessor: ImageProcessor {
var identifier: String { proccessor.identifier }

func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
switch item {
case let .image(kFCrossPlatformImage):
guard filterClosure(kFCrossPlatformImage) else {
return kFCrossPlatformImage
}

return proccessor.process(item: item, options: options)
case .data:
return proccessor.process(item: item, options: options)
}
}

let filterClosure: (KFCrossPlatformImage) -> Bool
let proccessor: ImageProcessor

init(proccessor: ImageProcessor, filter: @escaping (KFCrossPlatformImage) -> Bool) {
self.proccessor = proccessor
filterClosure = filter
}
}
4 changes: 4 additions & 0 deletions novawallet/Common/Helpers/WidthScaleFitImageProcessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ final class WidthScaleFitProcessor: ImageProcessor {
func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
switch item {
case let .image(kFCrossPlatformImage):
guard kFCrossPlatformImage.size.width > 0 else {
return kFCrossPlatformImage
}

let height = (preferredWidth / kFCrossPlatformImage.size.width)
* kFCrossPlatformImage.size.height

Expand Down
2 changes: 2 additions & 0 deletions novawallet/Common/Model/KnownChainIds.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ import Foundation
enum KnowChainId {
static let kusama = "b0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe"
static let statemine = "48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a"
static let polkadot = "91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3"
static let acala = "fc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c"
}
88 changes: 88 additions & 0 deletions novawallet/Common/Model/RemoteNftModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,91 @@ struct RemoteNftModel: Equatable, Identifiable {
price = localModel.price
}
}

extension RemoteNftModel {
static func createFromRMRKV1(
_ remoteItem: RMRKNftV1,
ownerId: AccountId,
chainId: ChainModel.Id,
collection: RMRKV1Collection?
) -> RemoteNftModel {
let identifier = NftModel.rmrkv1Identifier(
for: chainId,
identifier: remoteItem.identifier
)

let metadata: Data?

if let metadataString = remoteItem.metadata {
metadata = metadataString.data(using: .utf8)
} else {
metadata = nil
}

let price = remoteItem.forsale.map(\.stringWithPointSeparator)

return RemoteNftModel(
identifier: identifier,
type: NftType.rmrkV1.rawValue,
chainId: chainId,
ownerId: ownerId,
collectionId: remoteItem.collectionId,
instanceId: remoteItem.instance,
metadata: metadata,
totalIssuance: collection?.max,
name: remoteItem.name,
label: remoteItem.serialNumber,
media: nil,
price: price
)
}

static func createFromRMRKV2(
_ remoteItem: RMRKNftV2,
ownerId: AccountId,
chainId: ChainModel.Id,
collection: RMRKV2Collection?
) -> RemoteNftModel {
let identifier = NftModel.rmrkv2Identifier(
for: chainId,
identifier: remoteItem.identifier
)

let metadata: Data?

if let metadataString = remoteItem.metadata {
metadata = metadataString.data(using: .utf8)
} else {
metadata = nil
}

let price = remoteItem.forsale.map(\.stringWithPointSeparator)

let imageUrl: String?

if let imageString = remoteItem.image {
if let parsingResult = DistributedUrlParser().parse(url: imageString) {
imageUrl = DistributedStorageOperationFactory.resolveUrl(from: parsingResult).absoluteString
} else {
imageUrl = imageString
}
} else {
imageUrl = nil
}

return RemoteNftModel(
identifier: identifier,
type: NftType.rmrkV2.rawValue,
chainId: chainId,
ownerId: ownerId,
collectionId: remoteItem.collectionId,
instanceId: remoteItem.identifier,
metadata: metadata,
totalIssuance: collection?.max,
name: remoteItem.symbol,
label: remoteItem.serialNumber,
media: imageUrl,
price: price
)
}
}
69 changes: 69 additions & 0 deletions novawallet/Common/Model/SearchMatch.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import Foundation

enum SearchMatch<T> {
case full(T)
case prefix(T)
case inclusion(T)

var item: T {
switch self {
case let .full(item):
return item
case let .prefix(item):
return item
case let .inclusion(item):
return item
}
}

var isFull: Bool {
switch self {
case .full:
return true
default:
return false
}
}
}

extension SearchMatch {
static func matchString<T>(for query: String, recordField: String, record: T) -> SearchMatch<T>? {
if let match = matchFullString(for: query, recordField: recordField, record: record) {
return match
}

if let match = matchPrefix(for: query, recordField: recordField, record: record) {
return match
}

if let match = matchInclusion(for: query, recordField: recordField, record: record) {
return match
}

return nil
}

static func matchFullString<T>(for query: String, recordField: String, record: T) -> SearchMatch<T>? {
isFullMatch(query: query.lowercased(), field: recordField.lowercased()) ? .full(record) : nil
}

static func isFullMatch(query: String, field: String) -> Bool {
field == query
}

static func matchPrefix<T>(for query: String, recordField: String, record: T) -> SearchMatch<T>? {
isPrefixMatch(query: query.lowercased(), field: recordField.lowercased()) ? .prefix(record) : nil
}

static func isPrefixMatch(query: String, field: String) -> Bool {
field.hasPrefix(query)
}

static func matchInclusion<T>(for query: String, recordField: String, record: T) -> SearchMatch<T>? {
isInclusionMatch(query: query.lowercased(), field: recordField.lowercased()) ? .inclusion(record) : nil
}

static func isInclusionMatch(query: String, field: String) -> Bool {
field.contains(query)
}
}
1 change: 1 addition & 0 deletions novawallet/Common/Model/SubstrateAlias.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ typealias BidderKey = UInt32
typealias BlockNumber = UInt32
typealias BlockTime = UInt64
typealias LeasingPeriod = UInt32
typealias LeasingOffset = UInt32
typealias Slot = UInt64
typealias SessionIndex = UInt32
typealias Moment = UInt32
Expand Down
Loading

0 comments on commit 502e06c

Please sign in to comment.