mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Added some more tests and cleaned up some warnings
Fixed the broken LibSessionSpec tests Added the libSessionSpec tests for GROUP_INFO and GROUP_MEMBERS
This commit is contained in:
parent
a48327f6f6
commit
67311f6d25
35 changed files with 1168 additions and 523 deletions
|
@ -27,7 +27,7 @@ extension ProjectState {
|
|||
"_SharedTestUtilities/", // Exclude shared test directory
|
||||
"external/" // External dependencies
|
||||
]
|
||||
static let excludedPhrases: Set<String> = [ "", " ", ",", ", ", "null" ]
|
||||
static let excludedPhrases: Set<String> = [ "", " ", ",", ", ", ".", "/", "\\n", "null" ]
|
||||
static let excludedUnlocalisedStringLineMatching: Set<MatchType> = [
|
||||
.contains(ProjectState.lintSuppression),
|
||||
.prefix("#import"),
|
||||
|
@ -38,12 +38,14 @@ extension ProjectState {
|
|||
.contains("print("),
|
||||
.contains("NSLog("),
|
||||
.contains("SNLog("),
|
||||
.contains("SNLogNotTests("),
|
||||
.contains("owsFailDebug("),
|
||||
.contains("#imageLiteral(resourceName:"),
|
||||
.contains("UIImage(named:"),
|
||||
.contains("UIImage(systemName:"),
|
||||
.contains("[UIImage imageNamed:"),
|
||||
.contains("UIFont(name:"),
|
||||
.contains(".dateFormat ="),
|
||||
.contains(".accessibilityLabel ="),
|
||||
.contains(".accessibilityValue ="),
|
||||
.contains(".accessibilityIdentifier ="),
|
||||
|
@ -51,6 +53,10 @@ extension ProjectState {
|
|||
.contains("accessibilityLabel:"),
|
||||
.contains("Accessibility(identifier:"),
|
||||
.contains("Accessibility(label:"),
|
||||
.contains("NSAttributedString.Key("),
|
||||
.contains("Notification.Name("),
|
||||
.contains("Notification.Key("),
|
||||
.contains("DispatchQueue("),
|
||||
.containsAnd("identifier:", .previousLine(numEarlier: 1, .contains("Accessibility("))),
|
||||
.containsAnd("label:", .previousLine(numEarlier: 1, .contains("Accessibility("))),
|
||||
.containsAnd("label:", .previousLine(numEarlier: 2, .contains("Accessibility("))),
|
||||
|
@ -58,7 +64,10 @@ extension ProjectState {
|
|||
.regex(".*static var databaseTableName: String"),
|
||||
.regex("Logger\\..*\\("),
|
||||
.regex("OWSLogger\\..*\\("),
|
||||
.regex("case .* = ")
|
||||
.regex("case .* = "),
|
||||
.regex("Error.*\\("),
|
||||
.regex("Crypto.*\\(id:"),
|
||||
.containsAnd("id:", .previousLine(numEarlier: 1, .regex("Crypto.*\\(")))
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -759,6 +759,8 @@
|
|||
FDA8EB10280F8238002B68E5 /* Codable+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EB0F280F8238002B68E5 /* Codable+Utilities.swift */; };
|
||||
FDAA16762AC28A3B00DDBF77 /* UserDefaultsType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDAA16752AC28A3B00DDBF77 /* UserDefaultsType.swift */; };
|
||||
FDAA167B2AC28E2F00DDBF77 /* SnodeRequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDAA167A2AC28E2F00DDBF77 /* SnodeRequestSpec.swift */; };
|
||||
FDAA167D2AC528A200DDBF77 /* Preferences+Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDAA167C2AC528A200DDBF77 /* Preferences+Sound.swift */; };
|
||||
FDAA167F2AC5290000DDBF77 /* Preferences+NotificationPreviewType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDAA167E2AC5290000DDBF77 /* Preferences+NotificationPreviewType.swift */; };
|
||||
FDAED05C2A7C6CE600091B25 /* MigrationRequirement.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDAED05B2A7C6CE600091B25 /* MigrationRequirement.swift */; };
|
||||
FDB4BBC72838B91E00B7C95D /* LinkPreviewError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB4BBC62838B91E00B7C95D /* LinkPreviewError.swift */; };
|
||||
FDB4BBC92839BEF000B7C95D /* ProfileManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB4BBC82839BEF000B7C95D /* ProfileManagerError.swift */; };
|
||||
|
@ -1978,6 +1980,8 @@
|
|||
FDA8EB0F280F8238002B68E5 /* Codable+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Codable+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FDAA16752AC28A3B00DDBF77 /* UserDefaultsType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsType.swift; sourceTree = "<group>"; };
|
||||
FDAA167A2AC28E2F00DDBF77 /* SnodeRequestSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnodeRequestSpec.swift; sourceTree = "<group>"; };
|
||||
FDAA167C2AC528A200DDBF77 /* Preferences+Sound.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Sound.swift"; sourceTree = "<group>"; };
|
||||
FDAA167E2AC5290000DDBF77 /* Preferences+NotificationPreviewType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+NotificationPreviewType.swift"; sourceTree = "<group>"; };
|
||||
FDAED05B2A7C6CE600091B25 /* MigrationRequirement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationRequirement.swift; sourceTree = "<group>"; };
|
||||
FDB4BBC62838B91E00B7C95D /* LinkPreviewError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewError.swift; sourceTree = "<group>"; };
|
||||
FDB4BBC82839BEF000B7C95D /* ProfileManagerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileManagerError.swift; sourceTree = "<group>"; };
|
||||
|
@ -3393,6 +3397,8 @@
|
|||
C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */,
|
||||
C38EF281255B6D84007E1867 /* OWSAudioSession.swift */,
|
||||
FDF0B75D280AAF35004C14C5 /* Preferences.swift */,
|
||||
FDAA167E2AC5290000DDBF77 /* Preferences+NotificationPreviewType.swift */,
|
||||
FDAA167C2AC528A200DDBF77 /* Preferences+Sound.swift */,
|
||||
C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */,
|
||||
C38EF306255B6DBE007E1867 /* OWSWindowManager.m */,
|
||||
FD09797327FAB3E200936362 /* ProfileManager.swift */,
|
||||
|
@ -6386,6 +6392,7 @@
|
|||
FD1D732E2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift in Sources */,
|
||||
FD432437299DEA38008A0213 /* TypeConversion+Utilities.swift in Sources */,
|
||||
FD2B4B042949887A00AB4848 /* QueryInterfaceRequest+Utilities.swift in Sources */,
|
||||
FDAA167F2AC5290000DDBF77 /* Preferences+NotificationPreviewType.swift in Sources */,
|
||||
FD09797027FA6FF300936362 /* Profile.swift in Sources */,
|
||||
FD245C56285065EA00B966DD /* SNProto.swift in Sources */,
|
||||
FD09798B27FD1CFE00936362 /* Capability.swift in Sources */,
|
||||
|
@ -6393,6 +6400,7 @@
|
|||
FD09798127FCFEE800936362 /* SessionThread.swift in Sources */,
|
||||
FD09C5EA282A1BB2000CE219 /* ThreadTypingIndicator.swift in Sources */,
|
||||
FDB5DADA2A95D839002C8721 /* GroupUpdateInfoChangeMessage.swift in Sources */,
|
||||
FDAA167D2AC528A200DDBF77 /* Preferences+Sound.swift in Sources */,
|
||||
FDF0B75E280AAF35004C14C5 /* Preferences.swift in Sources */,
|
||||
FDC4383827B3863200C60D73 /* VersionResponse.swift in Sources */,
|
||||
FDB5DAD42A9483F3002C8721 /* GroupUpdateInviteMessage.swift in Sources */,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#!/usr/bin/env xcrun swift
|
||||
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
// The way this works is:
|
||||
|
|
|
@ -115,10 +115,7 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
|
|||
customPadding: SessionCell.Padding(bottom: Values.verySmallSpacing)
|
||||
),
|
||||
onTap: { [weak self] in
|
||||
UserDefaults.standard.set(
|
||||
!UserDefaults.standard.bool(forKey: "isUsingFullAPNs"),
|
||||
forKey: "isUsingFullAPNs"
|
||||
)
|
||||
dependencies[defaults: .standard, key: .isUsingFullAPNs] = !dependencies[defaults: .standard, key: .isUsingFullAPNs]
|
||||
|
||||
// Force sync the push tokens on change
|
||||
SyncPushTokensJob.run(uploadOnlyIfStale: false)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// stringlint:disable
|
||||
|
||||
import WebRTC
|
||||
|
||||
extension RTCSignalingState : CustomStringConvertible {
|
||||
|
|
|
@ -6,7 +6,7 @@ import SessionUtilitiesKit
|
|||
|
||||
enum _017_DisappearingMessagesConfiguration: Migration {
|
||||
static let target: TargetMigrations.Identifier = .messagingKit
|
||||
static let identifier: String = "DisappearingMessagesWithTypes"
|
||||
static let identifier: String = "DisappearingMessagesWithTypes" // stringlint:disable
|
||||
static let needsConfigSync: Bool = false
|
||||
static let minExpectedRunDuration: TimeInterval = 0.1
|
||||
static var requirements: [MigrationRequirement] = [.sessionUtilStateLoaded]
|
||||
|
|
|
@ -6,7 +6,7 @@ import SessionUtilitiesKit
|
|||
|
||||
enum _018_GroupsRebuildChanges: Migration {
|
||||
static let target: TargetMigrations.Identifier = .messagingKit
|
||||
static let identifier: String = "GroupsRebuildChanges"
|
||||
static let identifier: String = "GroupsRebuildChanges" // stringlint:disable
|
||||
static let needsConfigSync: Bool = false
|
||||
static let minExpectedRunDuration: TimeInterval = 0.1
|
||||
static var requirements: [MigrationRequirement] = [.sessionUtilStateLoaded]
|
||||
|
|
|
@ -66,26 +66,8 @@ extension Capability.Variant {
|
|||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container: SingleValueDecodingContainer = try decoder.singleValueContainer()
|
||||
let valueString: String = try container.decode(String.self)
|
||||
|
||||
// FIXME: Remove this code
|
||||
// There was a point where we didn't have custom Codable handling for the Capability.Variant
|
||||
// which resulted in the data being encoded into the database as a JSON dict - this code catches
|
||||
// that case and extracts the standard string value so it can be processed the same as the
|
||||
// "proper" custom Codable logic)
|
||||
if valueString.starts(with: "{") {
|
||||
self = Capability.Variant(
|
||||
from: valueString
|
||||
.replacingOccurrences(of: "\":{}}", with: "")
|
||||
.replacingOccurrences(of: "\"}}", with: "")
|
||||
.replacingOccurrences(of: "{\"unsupported\":{\"_0\":\"", with: "")
|
||||
.replacingOccurrences(of: "{\"", with: "")
|
||||
)
|
||||
return
|
||||
}
|
||||
// FIXME: Remove this code ^^^
|
||||
|
||||
self = Capability.Variant(from: valueString)
|
||||
self = Capability.Variant(from: try container.decode(String.self))
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -3813,10 +3813,6 @@ extension SNProtoAttachmentPointer.SNProtoAttachmentPointerBuilder {
|
|||
case userProfile = 1
|
||||
case contacts = 2
|
||||
case convoInfoVolatile = 3
|
||||
case userGroups = 4
|
||||
case groupInfo = 5
|
||||
case groupMembers = 6
|
||||
case groupKeys = 7
|
||||
}
|
||||
|
||||
private class func SNProtoSharedConfigMessageKindWrap(_ value: SessionProtos_SharedConfigMessage.Kind) -> SNProtoSharedConfigMessageKind {
|
||||
|
@ -3824,10 +3820,6 @@ extension SNProtoAttachmentPointer.SNProtoAttachmentPointerBuilder {
|
|||
case .userProfile: return .userProfile
|
||||
case .contacts: return .contacts
|
||||
case .convoInfoVolatile: return .convoInfoVolatile
|
||||
case .userGroups: return .userGroups
|
||||
case .groupInfo: return .groupInfo
|
||||
case .groupMembers: return .groupMembers
|
||||
case .groupKeys: return .groupKeys
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3836,10 +3828,6 @@ extension SNProtoAttachmentPointer.SNProtoAttachmentPointerBuilder {
|
|||
case .userProfile: return .userProfile
|
||||
case .contacts: return .contacts
|
||||
case .convoInfoVolatile: return .convoInfoVolatile
|
||||
case .userGroups: return .userGroups
|
||||
case .groupInfo: return .groupInfo
|
||||
case .groupMembers: return .groupMembers
|
||||
case .groupKeys: return .groupKeys
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4314,22 +4302,22 @@ extension SNProtoGroupUpdateMessage.SNProtoGroupUpdateMessageBuilder {
|
|||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupUpdateInviteMessage) throws -> SNProtoGroupUpdateInviteMessage {
|
||||
guard proto.hasGroupIdentityPublicKey else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: groupIdentityPublicKey")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: groupIdentityPublicKey")
|
||||
}
|
||||
let groupIdentityPublicKey = proto.groupIdentityPublicKey
|
||||
|
||||
guard proto.hasName else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: name")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: name")
|
||||
}
|
||||
let name = proto.name
|
||||
|
||||
guard proto.hasMemberSubkey else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: memberSubkey")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: memberSubkey")
|
||||
}
|
||||
let memberSubkey = proto.memberSubkey
|
||||
|
||||
guard proto.hasMemberTag else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: memberTag")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: memberTag")
|
||||
}
|
||||
let memberTag = proto.memberTag
|
||||
|
||||
|
@ -4444,12 +4432,12 @@ extension SNProtoGroupUpdateInviteMessage.SNProtoGroupUpdateInviteMessageBuilder
|
|||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupUpdateDeleteMessage) throws -> SNProtoGroupUpdateDeleteMessage {
|
||||
guard proto.hasGroupIdentityPublicKey else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: groupIdentityPublicKey")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: groupIdentityPublicKey")
|
||||
}
|
||||
let groupIdentityPublicKey = proto.groupIdentityPublicKey
|
||||
|
||||
guard proto.hasEncryptedMemberSubkey else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: encryptedMemberSubkey")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: encryptedMemberSubkey")
|
||||
}
|
||||
let encryptedMemberSubkey = proto.encryptedMemberSubkey
|
||||
|
||||
|
@ -4602,7 +4590,7 @@ extension SNProtoGroupUpdateDeleteMessage.SNProtoGroupUpdateDeleteMessageBuilder
|
|||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupUpdateInfoChangeMessage) throws -> SNProtoGroupUpdateInfoChangeMessage {
|
||||
guard proto.hasType else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: type")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: type")
|
||||
}
|
||||
let type = SNProtoGroupUpdateInfoChangeMessageTypeWrap(proto.type)
|
||||
|
||||
|
@ -4738,7 +4726,7 @@ extension SNProtoGroupUpdateInfoChangeMessage.SNProtoGroupUpdateInfoChangeMessag
|
|||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupUpdateMemberChangeMessage) throws -> SNProtoGroupUpdateMemberChangeMessage {
|
||||
guard proto.hasType else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: type")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: type")
|
||||
}
|
||||
let type = SNProtoGroupUpdateMemberChangeMessageTypeWrap(proto.type)
|
||||
|
||||
|
@ -4844,12 +4832,12 @@ extension SNProtoGroupUpdateMemberChangeMessage.SNProtoGroupUpdateMemberChangeMe
|
|||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupUpdatePromoteMessage) throws -> SNProtoGroupUpdatePromoteMessage {
|
||||
guard proto.hasMemberPublicKey else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: memberPublicKey")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: memberPublicKey")
|
||||
}
|
||||
let memberPublicKey = proto.memberPublicKey
|
||||
|
||||
guard proto.hasEncryptedGroupIdentityPrivateKey else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: encryptedGroupIdentityPrivateKey")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: encryptedGroupIdentityPrivateKey")
|
||||
}
|
||||
let encryptedGroupIdentityPrivateKey = proto.encryptedGroupIdentityPrivateKey
|
||||
|
||||
|
@ -5052,7 +5040,7 @@ extension SNProtoGroupUpdateMemberLeftMessage.SNProtoGroupUpdateMemberLeftMessag
|
|||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupUpdateInviteResponseMessage) throws -> SNProtoGroupUpdateInviteResponseMessage {
|
||||
guard proto.hasIsApproved else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: isApproved")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: isApproved")
|
||||
}
|
||||
let isApproved = proto.isApproved
|
||||
|
||||
|
@ -5155,7 +5143,7 @@ extension SNProtoGroupUpdateInviteResponseMessage.SNProtoGroupUpdateInviteRespon
|
|||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupUpdatePromotionResponseMessage) throws -> SNProtoGroupUpdatePromotionResponseMessage {
|
||||
guard proto.hasEncryptedMemberPublicKey else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: encryptedMemberPublicKey")
|
||||
throw SNProtoError.invalidProtobuf(description: "\(String(describing: logTag)) missing required field: encryptedMemberPublicKey")
|
||||
}
|
||||
let encryptedMemberPublicKey = proto.encryptedMemberPublicKey
|
||||
|
||||
|
|
|
@ -1705,10 +1705,6 @@ struct SessionProtos_SharedConfigMessage {
|
|||
case userProfile // = 1
|
||||
case contacts // = 2
|
||||
case convoInfoVolatile // = 3
|
||||
case userGroups // = 4
|
||||
case groupInfo // = 5
|
||||
case groupMembers // = 6
|
||||
case groupKeys // = 7
|
||||
|
||||
init() {
|
||||
self = .userProfile
|
||||
|
@ -1719,10 +1715,6 @@ struct SessionProtos_SharedConfigMessage {
|
|||
case 1: self = .userProfile
|
||||
case 2: self = .contacts
|
||||
case 3: self = .convoInfoVolatile
|
||||
case 4: self = .userGroups
|
||||
case 5: self = .groupInfo
|
||||
case 6: self = .groupMembers
|
||||
case 7: self = .groupKeys
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
@ -1732,10 +1724,6 @@ struct SessionProtos_SharedConfigMessage {
|
|||
case .userProfile: return 1
|
||||
case .contacts: return 2
|
||||
case .convoInfoVolatile: return 3
|
||||
case .userGroups: return 4
|
||||
case .groupInfo: return 5
|
||||
case .groupMembers: return 6
|
||||
case .groupKeys: return 7
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3994,10 +3982,6 @@ extension SessionProtos_SharedConfigMessage.Kind: SwiftProtobuf._ProtoNameProvid
|
|||
1: .same(proto: "USER_PROFILE"),
|
||||
2: .same(proto: "CONTACTS"),
|
||||
3: .same(proto: "CONVO_INFO_VOLATILE"),
|
||||
4: .same(proto: "USER_GROUPS"),
|
||||
5: .same(proto: "GROUP_INFO"),
|
||||
6: .same(proto: "GROUP_MEMBERS"),
|
||||
7: .same(proto: "GROUP_KEYS"),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import SessionUtil
|
||||
|
@ -25,6 +27,7 @@ public extension SessionUtil {
|
|||
// MARK: - Config
|
||||
|
||||
enum Config {
|
||||
case invalid
|
||||
case object(UnsafeMutablePointer<config_object>)
|
||||
case groupKeys(
|
||||
UnsafeMutablePointer<config_group_keys>,
|
||||
|
@ -36,6 +39,7 @@ public extension SessionUtil {
|
|||
|
||||
var needsPush: Bool {
|
||||
switch self {
|
||||
case .invalid: return false
|
||||
case .object(let conf): return config_needs_push(conf)
|
||||
|
||||
case .groupKeys(let conf, _, _):
|
||||
|
@ -48,6 +52,7 @@ public extension SessionUtil {
|
|||
|
||||
var needsDump: Bool {
|
||||
switch self {
|
||||
case .invalid: return false
|
||||
case .object(let conf): return config_needs_dump(conf)
|
||||
case .groupKeys(let conf, _, _): return groups_keys_needs_dump(conf)
|
||||
}
|
||||
|
@ -55,6 +60,7 @@ public extension SessionUtil {
|
|||
|
||||
var lastError: String {
|
||||
switch self {
|
||||
case .invalid: return "Invalid"
|
||||
case .object(let conf): return String(cString: conf.pointee.last_error)
|
||||
case .groupKeys(let conf, _, _): return String(cString: conf.pointee.last_error)
|
||||
}
|
||||
|
@ -87,6 +93,7 @@ public extension SessionUtil {
|
|||
|
||||
func push(variant: ConfigDump.Variant) throws -> SessionUtil.PushData {
|
||||
switch self {
|
||||
case .invalid: throw SessionUtilError.invalidConfigObject
|
||||
case .object(let conf):
|
||||
var cPushData: UnsafeMutablePointer<config_push_data>!
|
||||
|
||||
|
@ -142,6 +149,7 @@ public extension SessionUtil {
|
|||
var cHash: [CChar] = hash.cArray.nullTerminated()
|
||||
|
||||
switch self {
|
||||
case .invalid: return
|
||||
case .object(let conf): return config_confirm_pushed(conf, seqNo, &cHash)
|
||||
case .groupKeys: return // No need to do anything here
|
||||
}
|
||||
|
@ -153,6 +161,7 @@ public extension SessionUtil {
|
|||
|
||||
try CExceptionHelper.performSafely {
|
||||
switch self {
|
||||
case .invalid: return
|
||||
case .object(let conf): config_dump(conf, &dumpResult, &dumpResultLen)
|
||||
case .groupKeys(let conf, _, _): groups_keys_dump(conf, &dumpResult, &dumpResultLen)
|
||||
}
|
||||
|
@ -168,6 +177,7 @@ public extension SessionUtil {
|
|||
|
||||
func currentHashes() -> [String] {
|
||||
switch self {
|
||||
case .invalid: return []
|
||||
case .object(let conf):
|
||||
guard let hashList: UnsafeMutablePointer<config_string_list> = config_current_hashes(conf) else {
|
||||
return []
|
||||
|
@ -200,7 +210,8 @@ public extension SessionUtil {
|
|||
|
||||
func merge(_ messages: [ConfigMessageReceiveJob.Details.MessageInfo]) throws -> Int64? {
|
||||
switch self {
|
||||
case .object(let conf):
|
||||
case .invalid: throw SessionUtilError.invalidConfigObject
|
||||
case .object(let conf):
|
||||
var mergeHashes: [UnsafePointer<CChar>?] = messages
|
||||
.map { message in message.serverHash.cArray.nullTerminated() }
|
||||
.unsafeCopy()
|
||||
|
@ -266,6 +277,7 @@ public extension SessionUtil {
|
|||
|
||||
try? CExceptionHelper.performSafely {
|
||||
switch self {
|
||||
case .invalid: return
|
||||
case .object(let conf): result = funcMap[variant].map { "\($0.size(conf)) \($0.info)" }
|
||||
case .groupKeys(let conf, _, _): result = "\(groups_keys_size(conf)) group keys"
|
||||
}
|
||||
|
@ -279,7 +291,7 @@ public extension SessionUtil {
|
|||
// MARK: - PushData
|
||||
|
||||
public extension SessionUtil {
|
||||
public struct PushData {
|
||||
struct PushData {
|
||||
let data: Data
|
||||
let seqNo: Int64
|
||||
let variant: ConfigDump.Variant
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import GRDB
|
||||
import SessionUtilitiesKit
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import DifferenceKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public extension Preferences {
|
||||
enum NotificationPreviewType: Int, CaseIterable, EnumIntSetting, Differentiable {
|
||||
public static var defaultPreviewType: NotificationPreviewType = .nameAndPreview
|
||||
|
||||
/// Notifications should include both the sender name and a preview of the message content
|
||||
case nameAndPreview
|
||||
|
||||
/// Notifications should include the sender name but no preview
|
||||
case nameNoPreview
|
||||
|
||||
/// Notifications should be a generic message
|
||||
case noNameNoPreview
|
||||
|
||||
public var name: String {
|
||||
switch self {
|
||||
case .nameAndPreview: return "NOTIFICATIONS_STYLE_CONTENT_OPTION_NAME_AND_CONTENT".localized()
|
||||
case .nameNoPreview: return "NOTIFICATIONS_STYLE_CONTENT_OPTION_NAME_ONLY".localized()
|
||||
case .noNameNoPreview: return "NOTIFICATIONS_STYLE_CONTENT_OPTION_NO_NAME_OR_CONTENT".localized()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
205
SessionMessagingKit/Utilities/Preferences+Sound.swift
Normal file
205
SessionMessagingKit/Utilities/Preferences+Sound.swift
Normal file
|
@ -0,0 +1,205 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import AudioToolbox
|
||||
import GRDB
|
||||
import DifferenceKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public extension Preferences {
|
||||
enum Sound: Int, Codable, DatabaseValueConvertible, EnumIntSetting, Differentiable {
|
||||
public static var defaultiOSIncomingRingtone: Sound = .opening
|
||||
public static var defaultNotificationSound: Sound = .note
|
||||
|
||||
// Don't store too many sounds in memory (Most users will only use 1 or 2 sounds anyway)
|
||||
private static let maxCachedSounds: Int = 4
|
||||
private static var cachedSystemSounds: Atomic<[String: (url: URL?, soundId: SystemSoundID)]> = Atomic([:])
|
||||
private static var cachedSystemSoundOrder: Atomic<[String]> = Atomic([])
|
||||
|
||||
// Values
|
||||
|
||||
case `default`
|
||||
|
||||
// Notification Sounds
|
||||
case aurora = 1000
|
||||
case bamboo
|
||||
case chord
|
||||
case circles
|
||||
case complete
|
||||
case hello
|
||||
case input
|
||||
case keys
|
||||
case note
|
||||
case popcorn
|
||||
case pulse
|
||||
case synth
|
||||
case signalClassic
|
||||
|
||||
// Ringtone Sounds
|
||||
case opening = 2000
|
||||
|
||||
// Calls
|
||||
case callConnecting = 3000
|
||||
case callOutboundRinging
|
||||
case callBusy
|
||||
case callFailure
|
||||
|
||||
// Other
|
||||
case messageSent = 4000
|
||||
case none
|
||||
|
||||
public static var notificationSounds: [Sound] {
|
||||
return [
|
||||
// None and Note (default) should be first.
|
||||
.none,
|
||||
.note,
|
||||
|
||||
.aurora,
|
||||
.bamboo,
|
||||
.chord,
|
||||
.circles,
|
||||
.complete,
|
||||
.hello,
|
||||
.input,
|
||||
.keys,
|
||||
.popcorn,
|
||||
.pulse,
|
||||
.synth
|
||||
]
|
||||
}
|
||||
|
||||
public var displayName: String {
|
||||
// TODO: Should we localize these sound names?
|
||||
switch self {
|
||||
case .`default`: return ""
|
||||
|
||||
// Notification Sounds
|
||||
case .aurora: return "Aurora"
|
||||
case .bamboo: return "Bamboo"
|
||||
case .chord: return "Chord"
|
||||
case .circles: return "Circles"
|
||||
case .complete: return "Complete"
|
||||
case .hello: return "Hello"
|
||||
case .input: return "Input"
|
||||
case .keys: return "Keys"
|
||||
case .note: return "Note"
|
||||
case .popcorn: return "Popcorn"
|
||||
case .pulse: return "Pulse"
|
||||
case .synth: return "Synth"
|
||||
case .signalClassic: return "Signal Classic"
|
||||
|
||||
// Ringtone Sounds
|
||||
case .opening: return "Opening"
|
||||
|
||||
// Calls
|
||||
case .callConnecting: return "Call Connecting"
|
||||
case .callOutboundRinging: return "Call Outboung Ringing"
|
||||
case .callBusy: return "Call Busy"
|
||||
case .callFailure: return "Call Failure"
|
||||
|
||||
// Other
|
||||
case .messageSent: return "Message Sent"
|
||||
case .none: return "SOUNDS_NONE".localized()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
public func filename(quiet: Bool = false) -> String? {
|
||||
switch self {
|
||||
case .`default`: return ""
|
||||
|
||||
// Notification Sounds
|
||||
case .aurora: return (quiet ? "aurora-quiet.aifc" : "aurora.aifc")
|
||||
case .bamboo: return (quiet ? "bamboo-quiet.aifc" : "bamboo.aifc")
|
||||
case .chord: return (quiet ? "chord-quiet.aifc" : "chord.aifc")
|
||||
case .circles: return (quiet ? "circles-quiet.aifc" : "circles.aifc")
|
||||
case .complete: return (quiet ? "complete-quiet.aifc" : "complete.aifc")
|
||||
case .hello: return (quiet ? "hello-quiet.aifc" : "hello.aifc")
|
||||
case .input: return (quiet ? "input-quiet.aifc" : "input.aifc")
|
||||
case .keys: return (quiet ? "keys-quiet.aifc" : "keys.aifc")
|
||||
case .note: return (quiet ? "note-quiet.aifc" : "note.aifc")
|
||||
case .popcorn: return (quiet ? "popcorn-quiet.aifc" : "popcorn.aifc")
|
||||
case .pulse: return (quiet ? "pulse-quiet.aifc" : "pulse.aifc")
|
||||
case .synth: return (quiet ? "synth-quiet.aifc" : "synth.aifc")
|
||||
case .signalClassic: return (quiet ? "classic-quiet.aifc" : "classic.aifc")
|
||||
|
||||
// Ringtone Sounds
|
||||
case .opening: return "Opening.m4r"
|
||||
|
||||
// Calls
|
||||
case .callConnecting: return "ringback_tone_ansi.caf"
|
||||
case .callOutboundRinging: return "ringback_tone_ansi.caf"
|
||||
case .callBusy: return "busy_tone_ansi.caf"
|
||||
case .callFailure: return "end_call_tone_cept.caf"
|
||||
|
||||
// Other
|
||||
case .messageSent: return "message_sent.aiff"
|
||||
case .none: return "silence.aiff"
|
||||
}
|
||||
}
|
||||
|
||||
public func soundUrl(quiet: Bool = false) -> URL? {
|
||||
guard let filename: String = filename(quiet: quiet) else { return nil }
|
||||
|
||||
let url: URL = URL(fileURLWithPath: filename)
|
||||
|
||||
return Bundle.main.url(
|
||||
forResource: url.deletingPathExtension().path,
|
||||
withExtension: url.pathExtension
|
||||
)
|
||||
}
|
||||
|
||||
public func notificationSound(isQuiet: Bool) -> UNNotificationSound {
|
||||
guard let filename: String = filename(quiet: isQuiet) else {
|
||||
SNLog("[Preferences.Sound] filename was unexpectedly nil")
|
||||
return UNNotificationSound.default
|
||||
}
|
||||
|
||||
return UNNotificationSound(named: UNNotificationSoundName(rawValue: filename))
|
||||
}
|
||||
|
||||
public static func systemSoundId(for sound: Sound, quiet: Bool) -> SystemSoundID {
|
||||
let cacheKey: String = "\(sound.rawValue):\(quiet ? 1 : 0)"
|
||||
|
||||
if let cachedSound: SystemSoundID = cachedSystemSounds.wrappedValue[cacheKey]?.soundId {
|
||||
return cachedSound
|
||||
}
|
||||
|
||||
let systemSound: (url: URL?, soundId: SystemSoundID) = (
|
||||
url: sound.soundUrl(quiet: quiet),
|
||||
soundId: SystemSoundID()
|
||||
)
|
||||
|
||||
cachedSystemSounds.mutate { cache in
|
||||
cachedSystemSoundOrder.mutate { order in
|
||||
if order.count > Sound.maxCachedSounds {
|
||||
cache.removeValue(forKey: order[0])
|
||||
order.remove(at: 0)
|
||||
}
|
||||
|
||||
order.append(cacheKey)
|
||||
}
|
||||
|
||||
cache[cacheKey] = systemSound
|
||||
}
|
||||
|
||||
return systemSound.soundId
|
||||
}
|
||||
|
||||
// MARK: - AudioPlayer
|
||||
|
||||
public static func audioPlayer(for sound: Sound, behavior: OWSAudioBehavior) -> OWSAudioPlayer? {
|
||||
guard let soundUrl: URL = sound.soundUrl(quiet: false) else { return nil }
|
||||
|
||||
let player = OWSAudioPlayer(mediaUrl: soundUrl, audioBehavior: behavior)
|
||||
|
||||
// These two cases should loop
|
||||
if sound == .callConnecting || sound == .callOutboundRinging {
|
||||
player.isLooping = true
|
||||
}
|
||||
|
||||
return player
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import AudioToolbox
|
||||
import GRDB
|
||||
import DifferenceKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public extension Setting.EnumKey {
|
||||
|
@ -99,223 +98,6 @@ public extension Setting.IntKey {
|
|||
}
|
||||
|
||||
public enum Preferences {
|
||||
public enum NotificationPreviewType: Int, CaseIterable, EnumIntSetting, Differentiable {
|
||||
public static var defaultPreviewType: NotificationPreviewType = .nameAndPreview
|
||||
|
||||
/// Notifications should include both the sender name and a preview of the message content
|
||||
case nameAndPreview
|
||||
|
||||
/// Notifications should include the sender name but no preview
|
||||
case nameNoPreview
|
||||
|
||||
/// Notifications should be a generic message
|
||||
case noNameNoPreview
|
||||
|
||||
public var name: String {
|
||||
switch self {
|
||||
case .nameAndPreview: return "NOTIFICATIONS_STYLE_CONTENT_OPTION_NAME_AND_CONTENT".localized()
|
||||
case .nameNoPreview: return "NOTIFICATIONS_STYLE_CONTENT_OPTION_NAME_ONLY".localized()
|
||||
case .noNameNoPreview: return "NOTIFICATIONS_STYLE_CONTENT_OPTION_NO_NAME_OR_CONTENT".localized()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Sound: Int, Codable, DatabaseValueConvertible, EnumIntSetting, Differentiable {
|
||||
public static var defaultiOSIncomingRingtone: Sound = .opening
|
||||
public static var defaultNotificationSound: Sound = .note
|
||||
|
||||
// Don't store too many sounds in memory (Most users will only use 1 or 2 sounds anyway)
|
||||
private static let maxCachedSounds: Int = 4
|
||||
private static var cachedSystemSounds: Atomic<[String: (url: URL?, soundId: SystemSoundID)]> = Atomic([:])
|
||||
private static var cachedSystemSoundOrder: Atomic<[String]> = Atomic([])
|
||||
|
||||
// Values
|
||||
|
||||
case `default`
|
||||
|
||||
// Notification Sounds
|
||||
case aurora = 1000
|
||||
case bamboo
|
||||
case chord
|
||||
case circles
|
||||
case complete
|
||||
case hello
|
||||
case input
|
||||
case keys
|
||||
case note
|
||||
case popcorn
|
||||
case pulse
|
||||
case synth
|
||||
case signalClassic
|
||||
|
||||
// Ringtone Sounds
|
||||
case opening = 2000
|
||||
|
||||
// Calls
|
||||
case callConnecting = 3000
|
||||
case callOutboundRinging
|
||||
case callBusy
|
||||
case callFailure
|
||||
|
||||
// Other
|
||||
case messageSent = 4000
|
||||
case none
|
||||
|
||||
public static var notificationSounds: [Sound] {
|
||||
return [
|
||||
// None and Note (default) should be first.
|
||||
.none,
|
||||
.note,
|
||||
|
||||
.aurora,
|
||||
.bamboo,
|
||||
.chord,
|
||||
.circles,
|
||||
.complete,
|
||||
.hello,
|
||||
.input,
|
||||
.keys,
|
||||
.popcorn,
|
||||
.pulse,
|
||||
.synth
|
||||
]
|
||||
}
|
||||
|
||||
public var displayName: String {
|
||||
// TODO: Should we localize these sound names?
|
||||
switch self {
|
||||
case .`default`: return ""
|
||||
|
||||
// Notification Sounds
|
||||
case .aurora: return "Aurora"
|
||||
case .bamboo: return "Bamboo"
|
||||
case .chord: return "Chord"
|
||||
case .circles: return "Circles"
|
||||
case .complete: return "Complete"
|
||||
case .hello: return "Hello"
|
||||
case .input: return "Input"
|
||||
case .keys: return "Keys"
|
||||
case .note: return "Note"
|
||||
case .popcorn: return "Popcorn"
|
||||
case .pulse: return "Pulse"
|
||||
case .synth: return "Synth"
|
||||
case .signalClassic: return "Signal Classic"
|
||||
|
||||
// Ringtone Sounds
|
||||
case .opening: return "Opening"
|
||||
|
||||
// Calls
|
||||
case .callConnecting: return "Call Connecting"
|
||||
case .callOutboundRinging: return "Call Outboung Ringing"
|
||||
case .callBusy: return "Call Busy"
|
||||
case .callFailure: return "Call Failure"
|
||||
|
||||
// Other
|
||||
case .messageSent: return "Message Sent"
|
||||
case .none: return "SOUNDS_NONE".localized()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
public func filename(quiet: Bool = false) -> String? {
|
||||
switch self {
|
||||
case .`default`: return ""
|
||||
|
||||
// Notification Sounds
|
||||
case .aurora: return (quiet ? "aurora-quiet.aifc" : "aurora.aifc")
|
||||
case .bamboo: return (quiet ? "bamboo-quiet.aifc" : "bamboo.aifc")
|
||||
case .chord: return (quiet ? "chord-quiet.aifc" : "chord.aifc")
|
||||
case .circles: return (quiet ? "circles-quiet.aifc" : "circles.aifc")
|
||||
case .complete: return (quiet ? "complete-quiet.aifc" : "complete.aifc")
|
||||
case .hello: return (quiet ? "hello-quiet.aifc" : "hello.aifc")
|
||||
case .input: return (quiet ? "input-quiet.aifc" : "input.aifc")
|
||||
case .keys: return (quiet ? "keys-quiet.aifc" : "keys.aifc")
|
||||
case .note: return (quiet ? "note-quiet.aifc" : "note.aifc")
|
||||
case .popcorn: return (quiet ? "popcorn-quiet.aifc" : "popcorn.aifc")
|
||||
case .pulse: return (quiet ? "pulse-quiet.aifc" : "pulse.aifc")
|
||||
case .synth: return (quiet ? "synth-quiet.aifc" : "synth.aifc")
|
||||
case .signalClassic: return (quiet ? "classic-quiet.aifc" : "classic.aifc")
|
||||
|
||||
// Ringtone Sounds
|
||||
case .opening: return "Opening.m4r"
|
||||
|
||||
// Calls
|
||||
case .callConnecting: return "ringback_tone_ansi.caf"
|
||||
case .callOutboundRinging: return "ringback_tone_ansi.caf"
|
||||
case .callBusy: return "busy_tone_ansi.caf"
|
||||
case .callFailure: return "end_call_tone_cept.caf"
|
||||
|
||||
// Other
|
||||
case .messageSent: return "message_sent.aiff"
|
||||
case .none: return "silence.aiff"
|
||||
}
|
||||
}
|
||||
|
||||
public func soundUrl(quiet: Bool = false) -> URL? {
|
||||
guard let filename: String = filename(quiet: quiet) else { return nil }
|
||||
|
||||
let url: URL = URL(fileURLWithPath: filename)
|
||||
|
||||
return Bundle.main.url(
|
||||
forResource: url.deletingPathExtension().path,
|
||||
withExtension: url.pathExtension
|
||||
)
|
||||
}
|
||||
|
||||
public func notificationSound(isQuiet: Bool) -> UNNotificationSound {
|
||||
guard let filename: String = filename(quiet: isQuiet) else {
|
||||
SNLog("[Preferences.Sound] filename was unexpectedly nil")
|
||||
return UNNotificationSound.default
|
||||
}
|
||||
|
||||
return UNNotificationSound(named: UNNotificationSoundName(rawValue: filename))
|
||||
}
|
||||
|
||||
public static func systemSoundId(for sound: Sound, quiet: Bool) -> SystemSoundID {
|
||||
let cacheKey: String = "\(sound.rawValue):\(quiet ? 1 : 0)"
|
||||
|
||||
if let cachedSound: SystemSoundID = cachedSystemSounds.wrappedValue[cacheKey]?.soundId {
|
||||
return cachedSound
|
||||
}
|
||||
|
||||
let systemSound: (url: URL?, soundId: SystemSoundID) = (
|
||||
url: sound.soundUrl(quiet: quiet),
|
||||
soundId: SystemSoundID()
|
||||
)
|
||||
|
||||
cachedSystemSounds.mutate { cache in
|
||||
cachedSystemSoundOrder.mutate { order in
|
||||
if order.count > Sound.maxCachedSounds {
|
||||
cache.removeValue(forKey: order[0])
|
||||
order.remove(at: 0)
|
||||
}
|
||||
|
||||
order.append(cacheKey)
|
||||
}
|
||||
|
||||
cache[cacheKey] = systemSound
|
||||
}
|
||||
|
||||
return systemSound.soundId
|
||||
}
|
||||
|
||||
// MARK: - AudioPlayer
|
||||
|
||||
public static func audioPlayer(for sound: Sound, behavior: OWSAudioBehavior) -> OWSAudioPlayer? {
|
||||
guard let soundUrl: URL = sound.soundUrl(quiet: false) else { return nil }
|
||||
|
||||
let player = OWSAudioPlayer(mediaUrl: soundUrl, audioBehavior: behavior)
|
||||
|
||||
// These two cases should loop
|
||||
if sound == .callConnecting || sound == .callOutboundRinging {
|
||||
player.isLooping = true
|
||||
}
|
||||
|
||||
return player
|
||||
}
|
||||
}
|
||||
|
||||
public static var isCallKitSupported: Bool {
|
||||
#if targetEnvironment(simulator)
|
||||
/// The iOS simulator doesn't support CallKit, when receiving a call on the simulator and routing it via CallKit it
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,11 +5,7 @@ import SessionUtil
|
|||
import SessionMessagingKit
|
||||
|
||||
extension SessionUtil.Config: Mocked {
|
||||
static var mockValue: SessionUtil.Config = {
|
||||
var config: config_object = config_object()
|
||||
|
||||
return .object(&config)
|
||||
}()
|
||||
static var mockValue: SessionUtil.Config = .invalid
|
||||
}
|
||||
|
||||
extension ConfigDump.Variant: Mocked {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
|
|
|
@ -4,7 +4,7 @@ import Foundation
|
|||
import GRDB
|
||||
|
||||
public class Dependencies {
|
||||
static let userInfoKey: CodingUserInfoKey = CodingUserInfoKey(rawValue: "io.oxen.dependencies.codingOptions")!
|
||||
static let userInfoKey: CodingUserInfoKey = CodingUserInfoKey(rawValue: "io.oxen.dependencies.codingOptions")! // stringlint:disable
|
||||
|
||||
private static var singletonInstances: Atomic<[Int: Any]> = Atomic([:])
|
||||
private static var cacheInstances: Atomic<[Int: MutableCacheType]> = Atomic([:])
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -210,8 +210,8 @@ typedef struct {
|
|||
// This should usually be 1.
|
||||
CGFloat depthBytes = (CGFloat)ceil(depthBits / 8.f);
|
||||
|
||||
/* The color model of the image such as "RGB", "CMYK", "Gray", or "Lab".
|
||||
* The value of this key is CFStringRef. */
|
||||
// The color model of the image such as "RGB", "CMYK", "Gray", or "Lab".
|
||||
// The value of this key is CFStringRef.
|
||||
NSString *colorModel = imageProperties[(__bridge NSString *)kCGImagePropertyColorModel];
|
||||
if (!colorModel) {
|
||||
return info;
|
||||
|
|
|
@ -179,7 +179,7 @@ internal extension HTTP.BatchResponse {
|
|||
|
||||
case let anyDict as [String: Any]:
|
||||
guard
|
||||
let resultsArray: [Data] = (anyDict["results"] as? [Any])?
|
||||
let resultsArray: [Data] = (anyDict["results"] as? [Any])? // stringlint:disable
|
||||
.compactMap({ try? JSONSerialization.data(withJSONObject: $0) }),
|
||||
(
|
||||
!requireAllResults ||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// stringlint:disable
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
|
Loading…
Reference in a new issue