diff --git a/Scripts/ProcessIP2CountryData.swift b/Scripts/ProcessIP2CountryData.swift index e2161d08e..accfbaaca 100644 --- a/Scripts/ProcessIP2CountryData.swift +++ b/Scripts/ProcessIP2CountryData.swift @@ -26,7 +26,7 @@ let destinationFileName: String = "GeoLite2-Country-Blocks-IPv4" // Types struct IP2CountryCache { - var countryBlocksIPInt: [Int] = [] + var countryBlocksIPInt: [Int64] = [] var countryBlocksGeonameId: [String] = [] var countryLocationsLocaleCode: [String] = [] @@ -35,11 +35,11 @@ struct IP2CountryCache { } public enum IPv4 { - public static func toInt(_ ip: String) -> Int? { - let octets: [Int] = ip.split(separator: ".").compactMap { Int($0) } + public static func toInt(_ ip: String) -> Int64? { + let octets: [Int64] = ip.split(separator: ".").compactMap { Int64($0) } guard octets.count > 1 else { return nil } - var result: Int = 0 + var result: Int64 = 0 for i in stride(from: 3, through: 0, by: -1) { result += octets[ 3 - i ] << (i * 8) } @@ -67,6 +67,26 @@ class Processor { print("\r\(prefix)[\(bar)] \(Int(progress * 100))%", terminator: "") fflush(stdout) } + + static func parseCsvLine(_ line: String) -> [String] { + var result: [String] = [] + var currentField: String = "" + var inQuotedField: Bool = false + + for char in line { + if char == "," && !inQuotedField { + result.append(currentField) + currentField = "" + } else if char == "\"" { + inQuotedField.toggle() + } else { + currentField.append(char) + } + } + + result.append(currentField) + return result + } static func processFiles() { print("Searching For files") @@ -145,21 +165,19 @@ class Processor { lines[1...].enumerated().forEach { index, line in guard keepRunning else { return } - let values: [String] = line - .trimmingCharacters(in: .whitespacesAndNewlines) - .components(separatedBy: ",") + let values: [String] = parseCsvLine(line.trimmingCharacters(in: .whitespacesAndNewlines)) + let progress = (Double(index) / Double(lines.count)) + printProgressBar(prefix: countryBlockPrefix, progress: progress, total: (terminalWidth - 10)) guard values.count == 2, let ipNoSubnetMask: String = values[0].components(separatedBy: "/").first, - let ipAsInt: Int = IPv4.toInt(ipNoSubnetMask) + let ipAsInt: Int64 = IPv4.toInt(ipNoSubnetMask), + cache.countryBlocksGeonameId.last != values[1] else { return } cache.countryBlocksIPInt.append(ipAsInt) cache.countryBlocksGeonameId.append(values[1]) - - let progress = (Double(index) / Double(lines.count)) - printProgressBar(prefix: countryBlockPrefix, progress: progress, total: (terminalWidth - 10)) } guard keepRunning else { return } print("\r\u{1B}[2KProcessing country blocks completed ✅") @@ -178,9 +196,7 @@ class Processor { guard lines.count > 1 else { fatalError("Localised country file had no content") } lines[1...].enumerated().forEach { index, line in - let values: [String] = line - .trimmingCharacters(in: .whitespacesAndNewlines) - .components(separatedBy: ",") + let values: [String] = parseCsvLine(line.trimmingCharacters(in: .whitespacesAndNewlines)) guard values.count == 7 else { return } cache.countryLocationsLocaleCode.append(values[1]) @@ -198,7 +214,7 @@ class Processor { var outputData: Data = Data() var ipCount = Int32(cache.countryBlocksIPInt.count) outputData.append(Data(bytes: &ipCount, count: MemoryLayout.size)) - outputData.append(Data(bytes: cache.countryBlocksIPInt, count: cache.countryBlocksIPInt.count * MemoryLayout.size)) + outputData.append(Data(bytes: cache.countryBlocksIPInt, count: cache.countryBlocksIPInt.count * MemoryLayout.size)) let geonameIdData: Data = cache.countryBlocksGeonameId.joined(separator: "\0\0").data(using: .utf8)! var geonameIdCount = Int32(geonameIdData.count) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index a4a63e8af..9a4f421c1 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -804,8 +804,10 @@ extension ConversationVC: } func hideInputAccessoryView() { - self.inputAccessoryView?.isHidden = true - self.inputAccessoryView?.alpha = 0 + DispatchQueue.main.async { + self.inputAccessoryView?.isHidden = true + self.inputAccessoryView?.alpha = 0 + } } func showInputAccessoryView() { diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 2d8914cbb..499e35dbe 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -74,9 +74,11 @@ final class ConversationVC: BaseVC, LibSessionRespondingViewController, Conversa } override var inputAccessoryView: UIView? { - guard viewModel.threadData.canWrite else { return nil } - - return (isShowingSearchUI ? searchController.resultsBar : snInputView) + return ( + (viewModel.threadData.canWrite && isShowingSearchUI) ? + searchController.resultsBar : + snInputView + ) } /// The height of the visible part of the table view, i.e. the distance from the navigation bar (where the table view's origin is) @@ -750,6 +752,12 @@ final class ConversationVC: BaseVC, LibSessionRespondingViewController, Conversa viewModel.threadData.threadIsMessageRequest != updatedThreadData.threadIsMessageRequest || viewModel.threadData.threadRequiresApproval != updatedThreadData.threadRequiresApproval { + if updatedThreadData.canWrite { + self.showInputAccessoryView() + } else { + self.hideInputAccessoryView() + } + let messageRequestsViewWasVisible: Bool = (self.messageRequestFooterView.isHidden == false) UIView.animate(withDuration: 0.3) { [weak self] in diff --git a/Session/Media Viewing & Editing/ImagePickerController.swift b/Session/Media Viewing & Editing/ImagePickerController.swift index 3e642fc24..957d59079 100644 --- a/Session/Media Viewing & Editing/ImagePickerController.swift +++ b/Session/Media Viewing & Editing/ImagePickerController.swift @@ -30,6 +30,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat private var photoCollection: PhotoCollection private var photoCollectionContents: PhotoCollectionContents private let photoMediaSize = PhotoMediaSize() + private var firstSelectedIndexPath: IndexPath? var collectionViewFlowLayout: UICollectionViewFlowLayout var titleView: TitleView! @@ -212,6 +213,12 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat let cellSize = collectionViewFlowLayout.itemSize photoMediaSize.thumbnailSize = CGSize(width: cellSize.width * scale, height: cellSize.height * scale) + // When we select the first item we immediately deselect it so it doesn't look odd when pushing to the + // next screen, but this in turn looks odd if the user returns and the item is deselected + if let firstSelectedIndexPath: IndexPath = firstSelectedIndexPath { + collectionView.cellForItem(at: firstSelectedIndexPath)?.isSelected = true + } + if !hasEverAppeared { scrollToBottom(animated: false) } @@ -249,6 +256,13 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat DispatchQueue.main.async { // pre-layout collectionPicker for snappier response self.collectionPickerController.view.layoutIfNeeded() + + // We also need to actually inform the collectionView that the item should be selected (if we don't + // then the user won't be able to deselect it) + if let firstSelectedIndexPath: IndexPath = self.firstSelectedIndexPath { + self.collectionView.selectItem(at: firstSelectedIndexPath, animated: false, scrollPosition: .centeredHorizontally) + self.collectionView.cellForItem(at: firstSelectedIndexPath)?.isSelected = true + } } } @@ -489,9 +503,11 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat didSelectAsset: asset, attachmentPublisher: photoCollectionContents.outgoingAttachment(for: asset) ) + firstSelectedIndexPath = nil if !delegate.isInBatchSelectMode { // Don't show "selected" badge unless we're in batch mode + firstSelectedIndexPath = indexPath collectionView.deselectItem(at: indexPath, animated: false) delegate.imagePickerDidCompleteSelection(self) } @@ -511,6 +527,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat } delegate.imagePicker(self, didDeselectAsset: asset) + firstSelectedIndexPath = nil } override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { diff --git a/Session/Media Viewing & Editing/SendMediaNavigationController.swift b/Session/Media Viewing & Editing/SendMediaNavigationController.swift index 274bf0f85..b5434b26c 100644 --- a/Session/Media Viewing & Editing/SendMediaNavigationController.swift +++ b/Session/Media Viewing & Editing/SendMediaNavigationController.swift @@ -691,6 +691,7 @@ private class DoneButton: UIView { func updateCount() { guard let delegate = delegate else { return } + badge.themeBackgroundColor = (delegate.doneButtonCount > 0 ? .primary : .disabled) badgeLabel.text = numberFormatter.string(for: delegate.doneButtonCount) } @@ -729,11 +730,14 @@ private class DoneButton: UIView { } @objc func didTap(tapGesture: UITapGestureRecognizer) { + guard (delegate?.doneButtonCount ?? 0) > 0 else { return } + delegate?.doneButtonWasTapped(self) } override func touchesBegan(_ touches: Set, with event: UIEvent?) { guard + (delegate?.doneButtonCount ?? 0) > 0, isUserInteractionEnabled, let location: CGPoint = touches.first?.location(in: self), bounds.contains(location) diff --git a/Session/Meta/Countries/GeoLite2-Country-Blocks-IPv4 b/Session/Meta/Countries/GeoLite2-Country-Blocks-IPv4 index 4394c9dea..a6ad8d122 100644 Binary files a/Session/Meta/Countries/GeoLite2-Country-Blocks-IPv4 and b/Session/Meta/Countries/GeoLite2-Country-Blocks-IPv4 differ diff --git a/Session/Utilities/IP2Country.swift b/Session/Utilities/IP2Country.swift index 1630b54fa..59fdf72d5 100644 --- a/Session/Utilities/IP2Country.swift +++ b/Session/Utilities/IP2Country.swift @@ -8,6 +8,10 @@ import GRDB import SessionSnodeKit import SessionUtilitiesKit +private extension Log.Category { + static var ip2Country: Log.Category = "IP2Country" +} + public enum IP2Country { public static var isInitialized: Atomic = Atomic(false) private static var countryNamesCache: Atomic<[String: String]> = Atomic([:]) @@ -46,7 +50,7 @@ public enum IP2Country { /// (or `en` as default), then find the `geonameId` index from `countryLocationsGeonameId` using the same range, and that index /// should be retrieved from `countryLocationsCountryName` in order to get the country name struct IP2CountryCache { - var countryBlocksIPInt: [Int] = [] + var countryBlocksIPInt: [Int64] = [] var countryBlocksGeonameId: [String] = [] var countryLocationsLocaleCode: [String] = [] @@ -70,7 +74,14 @@ public enum IP2Country { var remainingData: Data = data.advanced(by: MemoryLayout.size) /// Extract the IPs - var countryBlockIpInts: [Int] = [Int](repeating: 0, count: Int(countryBlockIPCount)) + var countryBlockIpInts: [Int64] = [Int64](repeating: 0, count: Int(countryBlockIPCount)) + remainingData.withUnsafeBytes { buffer in + _ = countryBlockIpInts.withUnsafeMutableBytes { ipBuffer in + memcpy(ipBuffer.baseAddress, buffer.baseAddress, Int(countryBlockIPCount) * MemoryLayout.size) + } + } + + var countryBlockIpInts2: [Int] = [Int](repeating: 0, count: Int(countryBlockIPCount)) remainingData.withUnsafeBytes { buffer in _ = countryBlockIpInts.withUnsafeMutableBytes { ipBuffer in memcpy(ipBuffer.baseAddress, buffer.baseAddress, Int(countryBlockIPCount) * MemoryLayout.size) @@ -78,31 +89,55 @@ public enum IP2Country { } /// Extract arrays from the parts - func consumeStringArray(from targetData: inout Data) -> [String] { - var targetCount: Int32 = 0 - _ = withUnsafeMutableBytes(of: &targetCount) { countBuffer in - targetData.copyBytes(to: countBuffer, from: ...size) + func consumeStringArray(_ name: String, from targetData: inout Data) -> [String] { + /// The data should have a count, followed by actual data (so should have more data than an Int32 would take + guard targetData.count > MemoryLayout.size else { + Log.error(.ip2Country, "\(name) doesn't have enough data after the count.") + return [] } - /// Move past the count - targetData = targetData.advanced(by: MemoryLayout.size) + var targetCount: Int32 = targetData + .prefix(MemoryLayout.size) + .withUnsafeBytes { bytes -> Int32 in + guard + bytes.count >= MemoryLayout.size, + let baseAddress: UnsafePointer = bytes + .bindMemory(to: Int32.self) + .baseAddress + else { return 0 } + + return baseAddress.pointee + } + + /// Move past the count and extract the content data + targetData = targetData.dropFirst(MemoryLayout.size) + let contentData: Data = targetData.prefix(Int(targetCount)) guard - targetData.count >= targetCount, - let contentString: String = String(data: Data(targetData[.. targetData.count { + Log.error(.ip2Country, "\(name) suggested it had mare data then was actually available (\(targetCount) vs. \(targetData.count)).") + } /// Move past the data and return the result - targetData = targetData.advanced(by: Int(targetCount)) + targetData = targetData.dropFirst(Int(targetCount)) return contentString.components(separatedBy: "\0\0") } /// Move past the IP data - remainingData = remainingData.advanced(by: (Int(countryBlockIPCount) * MemoryLayout.size)) - let countryBlocksGeonameIds: [String] = consumeStringArray(from: &remainingData) - let countryLocaleCodes: [String] = consumeStringArray(from: &remainingData) - let countryGeonameIds: [String] = consumeStringArray(from: &remainingData) - let countryNames: [String] = consumeStringArray(from: &remainingData) + remainingData = remainingData.advanced(by: (Int(countryBlockIPCount) * MemoryLayout.size)) + let countryBlocksGeonameIds: [String] = consumeStringArray("CountryBlocks", from: &remainingData) + let countryLocaleCodes: [String] = consumeStringArray("LocaleCodes", from: &remainingData) + let countryGeonameIds: [String] = consumeStringArray("Geonames", from: &remainingData) + let countryNames: [String] = consumeStringArray("CountryNames", from: &remainingData) return IP2CountryCache( countryBlocksIPInt: countryBlockIpInts, @@ -151,7 +186,7 @@ public enum IP2Country { guard nameCache["\(ip)-\(currentLocale)"] == nil else { return } guard - let ipAsInt: Int = IPv4.toInt(ip), + let ipAsInt: Int64 = IPv4.toInt(ip), let countryBlockGeonameIdIndex: Int = cache.countryBlocksIPInt.firstIndex(where: { $0 > ipAsInt }).map({ $0 - 1 }), let localeStartIndex: Int = cache.countryLocationsLocaleCode.firstIndex(where: { $0 == currentLocale }), let countryNameIndex: Int = Array(cache.countryLocationsGeonameId[localeStartIndex...]).firstIndex(where: { geonameId in diff --git a/SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift b/SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift index dec044d86..e7fe2b82e 100644 --- a/SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift +++ b/SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift @@ -1140,11 +1140,11 @@ public class SignalAttachment: Equatable, Hashable { isConvertibleToContactShare.hash(into: &hasher) isVoiceMessage.hash(into: &hasher) - /// There was a crash in `AttachmentApprovalViewController when trying to generate the hash + /// There was a crash in `AttachmentApprovalViewController` when trying to generate the hash /// value to store in a dictionary, I'm guessing it's due to either `dataSource`, `cachedImage` or `cachedVideoPreview` /// so, instead of trying to hash them directly which involves unknown behaviours due to `NSObject` & `UIImage` types, this /// has been reworked to use primitives - dataSource.sourceFilename.hash(into: &hasher) + dataSource.uniqueId.hash(into: &hasher) cachedImage?.size.width.hash(into: &hasher) cachedImage?.size.height.hash(into: &hasher) cachedVideoPreview?.size.width.hash(into: &hasher) diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 2afe52fb5..167b95649 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -466,14 +466,12 @@ extension OpenGroupAPI { return true } - // Note: This might need to be updated in the future when we start tracking - // user permissions if changes to permissions don't trigger a change to - // the 'infoUpdates' return ( responseBody.activeUsers != existingOpenGroup.userCount || ( responseBody.details != nil && responseBody.details?.infoUpdates != existingOpenGroup.infoUpdates - ) + ) || + OpenGroup.Permissions(roomInfo: responseBody) != existingOpenGroup.permissions ) default: return true diff --git a/SessionUIKit/Style Guide/Themes/Theme+ClassicDark.swift b/SessionUIKit/Style Guide/Themes/Theme+ClassicDark.swift index ce5a62c53..b5e7ee9fe 100644 --- a/SessionUIKit/Style Guide/Themes/Theme+ClassicDark.swift +++ b/SessionUIKit/Style Guide/Themes/Theme+ClassicDark.swift @@ -65,7 +65,7 @@ internal enum Theme_ClassicDark: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerDark.withAlphaComponent(0.3), .sessionButton_destructiveBorder: .dangerDark, - .sessionButton_primaryFilledText: .classicDark0, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton @@ -186,7 +186,7 @@ internal enum Theme_ClassicDark: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerDark.opacity(0.3), .sessionButton_destructiveBorder: .dangerDark, - .sessionButton_primaryFilledText: .classicDark0, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton diff --git a/SessionUIKit/Style Guide/Themes/Theme+ClassicLight.swift b/SessionUIKit/Style Guide/Themes/Theme+ClassicLight.swift index 1feb658bb..a80872f54 100644 --- a/SessionUIKit/Style Guide/Themes/Theme+ClassicLight.swift +++ b/SessionUIKit/Style Guide/Themes/Theme+ClassicLight.swift @@ -18,7 +18,7 @@ internal enum Theme_ClassicLight: ThemeColors { .backgroundSecondary: .classicLight5, .textPrimary: .classicLight0, .textSecondary: .classicLight1, - .borderSeparator: .classicLight2, + .borderSeparator: .classicLight3, // Path .path_connected: .pathConnected, @@ -65,7 +65,7 @@ internal enum Theme_ClassicLight: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerLight.withAlphaComponent(0.3), .sessionButton_destructiveBorder: .dangerLight, - .sessionButton_primaryFilledText: .classicLight0, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton @@ -186,7 +186,7 @@ internal enum Theme_ClassicLight: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerLight.opacity(0.3), .sessionButton_destructiveBorder: .dangerLight, - .sessionButton_primaryFilledText: .classicLight0, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton diff --git a/SessionUIKit/Style Guide/Themes/Theme+OceanDark.swift b/SessionUIKit/Style Guide/Themes/Theme+OceanDark.swift index b05a49864..1e76a60e3 100644 --- a/SessionUIKit/Style Guide/Themes/Theme+OceanDark.swift +++ b/SessionUIKit/Style Guide/Themes/Theme+OceanDark.swift @@ -65,7 +65,7 @@ internal enum Theme_OceanDark: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerDark.withAlphaComponent(0.3), .sessionButton_destructiveBorder: .dangerDark, - .sessionButton_primaryFilledText: .oceanDark0, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton @@ -186,7 +186,7 @@ internal enum Theme_OceanDark: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerDark.opacity(0.3), .sessionButton_destructiveBorder: .dangerDark, - .sessionButton_primaryFilledText: .oceanDark0, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton diff --git a/SessionUIKit/Style Guide/Themes/Theme+OceanLight.swift b/SessionUIKit/Style Guide/Themes/Theme+OceanLight.swift index 93fa004fc..bd2d23cf5 100644 --- a/SessionUIKit/Style Guide/Themes/Theme+OceanLight.swift +++ b/SessionUIKit/Style Guide/Themes/Theme+OceanLight.swift @@ -65,7 +65,7 @@ internal enum Theme_OceanLight: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerLight.withAlphaComponent(0.3), .sessionButton_destructiveBorder: .dangerLight, - .sessionButton_primaryFilledText: .oceanLight1, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton @@ -186,7 +186,7 @@ internal enum Theme_OceanLight: ThemeColors { .sessionButton_destructiveBackground: .clear, .sessionButton_destructiveHighlight: .dangerLight.opacity(0.3), .sessionButton_destructiveBorder: .dangerLight, - .sessionButton_primaryFilledText: .oceanLight1, + .sessionButton_primaryFilledText: .black, .sessionButton_primaryFilledBackground: .primary, // SolidButton diff --git a/SessionUtilitiesKit/Media/DataSource.h b/SessionUtilitiesKit/Media/DataSource.h index 544800031..59b0bc5cb 100755 --- a/SessionUtilitiesKit/Media/DataSource.h +++ b/SessionUtilitiesKit/Media/DataSource.h @@ -10,6 +10,7 @@ NS_ASSUME_NONNULL_BEGIN @interface DataSource : NSObject @property (nonatomic, nullable) NSString *sourceFilename; +@property (nonatomic) NSUUID *uniqueId; // Should not be called unless necessary as it can involve an expensive read. - (NSData *)data; diff --git a/SessionUtilitiesKit/Media/DataSource.m b/SessionUtilitiesKit/Media/DataSource.m index dad3ed801..f673528c1 100755 --- a/SessionUtilitiesKit/Media/DataSource.m +++ b/SessionUtilitiesKit/Media/DataSource.m @@ -124,6 +124,7 @@ NS_ASSUME_NONNULL_BEGIN instance.dataValue = data; instance.fileExtension = fileExtension; instance.shouldDeleteOnDeallocation = YES; + instance.uniqueId = [NSUUID UUID]; return instance; } @@ -246,6 +247,7 @@ NS_ASSUME_NONNULL_BEGIN DataSourcePath *instance = [DataSourcePath new]; instance.filePath = fileUrl.path; instance.shouldDeleteOnDeallocation = shouldDeleteOnDeallocation; + instance.uniqueId = [NSUUID UUID]; return instance; } @@ -259,6 +261,7 @@ NS_ASSUME_NONNULL_BEGIN DataSourcePath *instance = [DataSourcePath new]; instance.filePath = filePath; instance.shouldDeleteOnDeallocation = shouldDeleteOnDeallocation; + instance.uniqueId = [NSUUID UUID]; return instance; } diff --git a/SessionUtilitiesKit/Networking/IPv4.swift b/SessionUtilitiesKit/Networking/IPv4.swift index b4c490ec6..90a79c073 100644 --- a/SessionUtilitiesKit/Networking/IPv4.swift +++ b/SessionUtilitiesKit/Networking/IPv4.swift @@ -5,11 +5,11 @@ import Foundation public enum IPv4 { - public static func toInt(_ ip: String) -> Int? { - let octets: [Int] = ip.split(separator: ".").compactMap { Int($0) } + public static func toInt(_ ip: String) -> Int64? { + let octets: [Int64] = ip.split(separator: ".").compactMap { Int64($0) } guard octets.count > 1 else { return nil } - var result: Int = 0 + var result: Int64 = 0 for i in stride(from: 3, through: 0, by: -1) { result += octets[ 3 - i ] << (i * 8) }