Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2019-08-17 01:15:25 +03:00
commit b7e0c3718e
58 changed files with 2940 additions and 152 deletions

View File

@ -100,22 +100,21 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|> mapToSignal { account -> Signal<Account?, NoError> in
if let account = account {
switch account {
case .upgrading:
return .complete()
case let .authorized(account):
account.shouldKeepOnlinePresence.set(.single(false))
return applicationSettings(accountManager: accountManager)
|> deliverOnMainQueue
|> map { settings -> Account in
accountCache = account
Logger.shared.logToFile = settings.logging.logToFile
Logger.shared.logToConsole = settings.logging.logToConsole
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
return account
}
case .unauthorized:
return .complete()
case .upgrading:
return .complete()
case let .authorized(account):
return applicationSettings(accountManager: accountManager)
|> deliverOnMainQueue
|> map { settings -> Account in
accountCache = account
Logger.shared.logToFile = settings.logging.logToFile
Logger.shared.logToConsole = settings.logging.logToConsole
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
return account
}
case .unauthorized:
return .complete()
}
} else {
return .single(nil)
@ -275,7 +274,9 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
@available(iOSApplicationExtension 11.0, *)
func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INSendMessageRecipientResolutionResult]) -> Void) {
if let peerId = intent.conversationIdentifier.flatMap(Int64.init) {
let signal = self.accountPromise.get()
let account = self.accountPromise.get()
let signal = account
|> introduceError(IntentHandlingError.self)
|> mapToSignal { account -> Signal<INPerson?, IntentHandlingError> in
if let account = account {
@ -402,8 +403,8 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
account.resetStateManagement()
let completion: Signal<Void, NoError> = account.stateManager.pollStateUpdateCompletion()
|> map { _ in
return Void()
|> map { _ in
return Void()
}
return (completion |> timeout(4.0, queue: Queue.mainQueue(), alternate: .single(Void())))
@ -482,7 +483,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
for (_, messageId) in maxMessageIdsToApply {
signals.append(applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0))
|> introduceError(IntentHandlingError.self))
|> introduceError(IntentHandlingError.self))
}
if signals.isEmpty {
@ -490,11 +491,11 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
} else {
account.shouldBeServiceTaskMaster.set(.single(.now))
return combineLatest(signals)
|> mapToSignal { _ -> Signal<Void, IntentHandlingError> in
return .complete()
}
|> afterDisposed {
account.shouldBeServiceTaskMaster.set(.single(.never))
|> mapToSignal { _ -> Signal<Void, IntentHandlingError> in
return .complete()
}
|> afterDisposed {
account.shouldBeServiceTaskMaster.set(.single(.never))
}
}
}
@ -573,34 +574,34 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
func handle(intent: INSearchCallHistoryIntent, completion: @escaping (INSearchCallHistoryIntentResponse) -> Void) {
self.actionDisposable.set((self.accountPromise.get()
|> take(1)
|> introduceError(IntentHandlingError.self)
|> mapToSignal { account -> Signal<[CallRecord], IntentHandlingError> in
guard let account = account else {
return .fail(.generic)
}
account.shouldBeServiceTaskMaster.set(.single(.now))
return missedCalls(account: account)
|> introduceError(IntentHandlingError.self)
|> afterDisposed {
account.shouldBeServiceTaskMaster.set(.single(.never))
}
|> take(1)
|> introduceError(IntentHandlingError.self)
|> mapToSignal { account -> Signal<[CallRecord], IntentHandlingError> in
guard let account = account else {
return .fail(.generic)
}
|> deliverOnMainQueue).start(next: { calls in
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
let response: INSearchCallHistoryIntentResponse
if #available(iOSApplicationExtension 11.0, *) {
response = INSearchCallHistoryIntentResponse(code: .success, userActivity: userActivity)
response.callRecords = calls.map { $0.intentCall }
} else {
response = INSearchCallHistoryIntentResponse(code: .continueInApp, userActivity: userActivity)
}
completion(response)
}, error: { _ in
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
let response = INSearchCallHistoryIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
completion(response)
}))
account.shouldBeServiceTaskMaster.set(.single(.now))
return missedCalls(account: account)
|> introduceError(IntentHandlingError.self)
|> afterDisposed {
account.shouldBeServiceTaskMaster.set(.single(.never))
}
}
|> deliverOnMainQueue).start(next: { calls in
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
let response: INSearchCallHistoryIntentResponse
if #available(iOSApplicationExtension 11.0, *) {
response = INSearchCallHistoryIntentResponse(code: .success, userActivity: userActivity)
response.callRecords = calls.map { $0.intentCall }
} else {
response = INSearchCallHistoryIntentResponse(code: .continueInApp, userActivity: userActivity)
}
completion(response)
}, error: { _ in
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
let response = INSearchCallHistoryIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
completion(response)
}))
}
}

View File

@ -372,6 +372,13 @@
location = "group:submodules/AvatarNode/AvatarNode_Xcode.xcodeproj">
</FileRef>
</Group>
<Group
location = "container:"
name = "Chat">
<FileRef
location = "group:submodules/ReactionSelectionNode/ReactionSelectionNode_Xcode.xcodeproj">
</FileRef>
</Group>
<FileRef
location = "group:submodules/LegacyComponents/LegacyComponents_Xcode.xcodeproj">
</FileRef>

View File

@ -309,6 +309,9 @@ public final class AnimatedStickerNode: ASDisplayNode {
private let fetchDisposable = MetaDisposable()
private let eventsNode: AnimatedStickerNodeDisplayEvents
public var automaticallyLoadFirstFrame: Bool = false
public var playToCompletionOnStop: Bool = false
public var started: () -> Void = {}
private var reportedStarted = false
@ -320,6 +323,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
private var renderer: (AnimationRenderer & ASDisplayNode)?
private var isPlaying: Bool = false
private var canDisplayFirstFrame: Bool = false
private var playbackMode: AnimatedStickerPlaybackMode = .loop
private let playbackStatus = Promise<AnimatedStickerStatus>()
@ -394,6 +398,8 @@ public final class AnimatedStickerNode: ASDisplayNode {
}
if strongSelf.isPlaying {
strongSelf.play()
} else if strongSelf.canDisplayFirstFrame {
strongSelf.play(firstFrame: true)
}
}))
case .cached:
@ -403,6 +409,8 @@ public final class AnimatedStickerNode: ASDisplayNode {
strongSelf.cachedData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.mappedRead])
if strongSelf.isPlaying {
strongSelf.play()
} else if strongSelf.canDisplayFirstFrame {
strongSelf.play(firstFrame: true)
}
}
}))
@ -424,9 +432,16 @@ public final class AnimatedStickerNode: ASDisplayNode {
self.stop()
}
}
let canDisplayFirstFrame = self.automaticallyLoadFirstFrame && self.isDisplaying
if self.canDisplayFirstFrame != canDisplayFirstFrame {
self.canDisplayFirstFrame = canDisplayFirstFrame
if canDisplayFirstFrame {
self.play(firstFrame: true)
}
}
}
public func play() {
public func play(firstFrame: Bool = false) {
let directData = self.directData
let cachedData = self.cachedData
let queue = self.queue
@ -451,7 +466,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
let duration: Double = frameSource.frameRate > 0 ? Double(frameSource.frameCount) / Double(frameSource.frameRate) : 0
let frameRate = frameSource.frameRate
let timer = SwiftSignalKit.Timer(timeout: 1.0 / Double(frameRate), repeat: true, completion: {
let timer = SwiftSignalKit.Timer(timeout: 1.0 / Double(frameRate), repeat: !firstFrame, completion: {
let maybeFrame = frameQueue.syncWith { frameQueue in
return frameQueue.take()
}
@ -492,6 +507,9 @@ public final class AnimatedStickerNode: ASDisplayNode {
public func stop() {
self.reportedStarted = false
self.timer.swap(nil)?.invalidate()
if self.playToCompletionOnStop {
self.seekToStart()
}
}
public func seekToStart() {

View File

@ -11,6 +11,8 @@
D03E45742305CCD20049C28B /* Crc32.m in Sources */ = {isa = PBXBuildFile; fileRef = D03E45732305CCD20049C28B /* Crc32.m */; };
D03E45772305CCEC0049C28B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45762305CCEB0049C28B /* Foundation.framework */; };
D03E45792305CCF00049C28B /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45782305CCF00049C28B /* libz.tbd */; };
D03E46362306E0BB0049C28B /* crc32mac.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E46342306E0BB0049C28B /* crc32mac.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E463E2306E22E0049C28B /* Crc32.m in Sources */ = {isa = PBXBuildFile; fileRef = D03E45732305CCD20049C28B /* Crc32.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -20,6 +22,9 @@
D03E45732305CCD20049C28B /* Crc32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Crc32.m; sourceTree = "<group>"; };
D03E45762305CCEB0049C28B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D03E45782305CCF00049C28B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
D03E46322306E0BB0049C28B /* crc32mac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = crc32mac.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E46342306E0BB0049C28B /* crc32mac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32mac.h; sourceTree = "<group>"; };
D03E46352306E0BB0049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -32,6 +37,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E462F2306E0BB0049C28B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@ -40,6 +52,7 @@
children = (
D03E45682305CC310049C28B /* Info.plist */,
D03E45662305CC310049C28B /* Sources */,
D03E46332306E0BB0049C28B /* crc32mac */,
D03E45652305CC310049C28B /* Products */,
D03E45752305CCEB0049C28B /* Frameworks */,
);
@ -49,6 +62,7 @@
isa = PBXGroup;
children = (
D03E45642305CC310049C28B /* Crc32.framework */,
D03E46322306E0BB0049C28B /* crc32mac.framework */,
);
name = Products;
sourceTree = "<group>";
@ -71,6 +85,15 @@
name = Frameworks;
sourceTree = "<group>";
};
D03E46332306E0BB0049C28B /* crc32mac */ = {
isa = PBXGroup;
children = (
D03E46342306E0BB0049C28B /* crc32mac.h */,
D03E46352306E0BB0049C28B /* Info.plist */,
);
path = crc32mac;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -82,6 +105,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E462D2306E0BB0049C28B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D03E46362306E0BB0049C28B /* crc32mac.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
@ -103,6 +134,24 @@
productReference = D03E45642305CC310049C28B /* Crc32.framework */;
productType = "com.apple.product-type.framework";
};
D03E46312306E0BB0049C28B /* crc32mac */ = {
isa = PBXNativeTarget;
buildConfigurationList = D03E463B2306E0BB0049C28B /* Build configuration list for PBXNativeTarget "crc32mac" */;
buildPhases = (
D03E462D2306E0BB0049C28B /* Headers */,
D03E462E2306E0BB0049C28B /* Sources */,
D03E462F2306E0BB0049C28B /* Frameworks */,
D03E46302306E0BB0049C28B /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = crc32mac;
productName = crc32mac;
productReference = D03E46322306E0BB0049C28B /* crc32mac.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@ -116,6 +165,9 @@
D03E45632305CC310049C28B = {
CreatedOnToolsVersion = 10.3;
};
D03E46312306E0BB0049C28B = {
CreatedOnToolsVersion = 10.3;
};
};
};
buildConfigurationList = D03E455E2305CC310049C28B /* Build configuration list for PBXProject "Crc32_Xcode" */;
@ -131,6 +183,7 @@
projectRoot = "";
targets = (
D03E45632305CC310049C28B /* Crc32 */,
D03E46312306E0BB0049C28B /* crc32mac */,
);
};
/* End PBXProject section */
@ -143,6 +196,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E46302306E0BB0049C28B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -154,6 +214,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E462E2306E0BB0049C28B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D03E463E2306E22E0049C28B /* Crc32.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
@ -210,6 +278,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -266,6 +335,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -380,6 +450,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -462,6 +533,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -497,6 +569,316 @@
};
name = ReleaseHockeyappInternal;
};
D03E46372306E0BB0049C28B /* DebugAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = crc32mac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.crc32mac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = DebugAppStoreLLC;
};
D03E46382306E0BB0049C28B /* DebugHockeyapp */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = crc32mac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.crc32mac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = DebugHockeyapp;
};
D03E46392306E0BB0049C28B /* ReleaseAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = crc32mac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.crc32mac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = ReleaseAppStoreLLC;
};
D03E463A2306E0BB0049C28B /* ReleaseHockeyappInternal */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = crc32mac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.crc32mac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = ReleaseHockeyappInternal;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -522,6 +904,17 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = ReleaseAppStoreLLC;
};
D03E463B2306E0BB0049C28B /* Build configuration list for PBXNativeTarget "crc32mac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D03E46372306E0BB0049C28B /* DebugAppStoreLLC */,
D03E46382306E0BB0049C28B /* DebugHockeyapp */,
D03E46392306E0BB0049C28B /* ReleaseAppStoreLLC */,
D03E463A2306E0BB0049C28B /* ReleaseHockeyappInternal */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = ReleaseAppStoreLLC;
};
/* End XCConfigurationList section */
};
rootObject = D03E455B2305CC310049C28B /* Project object */;

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 Telegram Messenger LLP. All rights reserved.</string>
</dict>
</plist>

View File

@ -0,0 +1,9 @@
#import <Cocoa/Cocoa.h>
//! Project version number for crc32mac.
FOUNDATION_EXPORT double crc32macVersionNumber;
//! Project version string for crc32mac.
FOUNDATION_EXPORT const unsigned char crc32macVersionString[];
uint32_t Crc32(const void *bytes, int length);

View File

@ -130,7 +130,7 @@ public extension CALayer {
self.add(animationGroup, forKey: key)
}
public func animateKeyframes(values: [AnyObject], duration: Double, keyPath: String, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) {
public func animateKeyframes(values: [AnyObject], duration: Double, keyPath: String, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
let k = Float(UIView.animationDurationFactor())
var speed: Float = 1.0
if k != 0 && k != 1 {
@ -152,6 +152,7 @@ public extension CALayer {
animation.keyTimes = keyTimes
animation.speed = speed
animation.duration = duration
animation.isAdditive = additive
if let completion = completion {
animation.delegate = CALayerAnimationDelegate(animation: animation, completion: completion)
}

View File

@ -63,24 +63,29 @@ public enum ContainedViewLayoutTransition {
}
public extension ContainedViewLayoutTransition {
func updateFrame(node: ASDisplayNode, frame: CGRect, force: Bool = false, completion: ((Bool) -> Void)? = nil) {
func updateFrame(node: ASDisplayNode, frame: CGRect, force: Bool = false, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) {
if node.frame.equalTo(frame) && !force {
completion?(true)
} else {
switch self {
case .immediate:
node.frame = frame
case .immediate:
node.frame = frame
if let completion = completion {
completion(true)
}
case let .animated(duration, curve):
let previousFrame: CGRect
if beginWithCurrentState, let presentation = node.layer.presentation() {
previousFrame = presentation.frame
} else {
previousFrame = node.frame
}
node.frame = frame
node.layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, force: force, completion: { result in
if let completion = completion {
completion(true)
completion(result)
}
case let .animated(duration, curve):
let previousFrame = node.frame
node.frame = frame
node.layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, force: force, completion: { result in
if let completion = completion {
completion(result)
}
})
})
}
}
}
@ -147,7 +152,7 @@ public extension ContainedViewLayoutTransition {
}
}
func updatePosition(node: ASDisplayNode, position: CGPoint, completion: ((Bool) -> Void)? = nil) {
func updatePosition(node: ASDisplayNode, position: CGPoint, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) {
if node.position.equalTo(position) {
completion?(true)
} else {
@ -158,7 +163,12 @@ public extension ContainedViewLayoutTransition {
completion(true)
}
case let .animated(duration, curve):
let previousPosition = node.position
let previousPosition: CGPoint
if beginWithCurrentState {
previousPosition = node.layer.presentation()?.position ?? node.position
} else {
previousPosition = node.position
}
node.position = position
node.layer.animatePosition(from: previousPosition, to: position, duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, completion: { result in
if let completion = completion {
@ -498,7 +508,7 @@ public extension ContainedViewLayoutTransition {
}
}
func updateTransformScale(node: ASDisplayNode, scale: CGFloat, completion: ((Bool) -> Void)? = nil) {
func updateTransformScale(node: ASDisplayNode, scale: CGFloat, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) {
let t = node.layer.transform
let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13))
if currentScale.isEqual(to: scale) {
@ -515,8 +525,15 @@ public extension ContainedViewLayoutTransition {
completion(true)
}
case let .animated(duration, curve):
let previousScale: CGFloat
if beginWithCurrentState, let presentation = node.layer.presentation() {
let t = presentation.transform
previousScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13))
} else {
previousScale = currentScale
}
node.layer.transform = CATransform3DMakeScale(scale, scale, 1.0)
node.layer.animateScale(from: currentScale, to: scale, duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, completion: { result in
node.layer.animateScale(from: previousScale, to: scale, duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, completion: { result in
if let completion = completion {
completion(result)
}
@ -581,6 +598,47 @@ public extension ContainedViewLayoutTransition {
}
}
func updateSublayerTransformScaleAndOffset(node: ASDisplayNode, scale: CGFloat, offset: CGPoint, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) {
if !node.isNodeLoaded {
node.subnodeTransform = CATransform3DMakeScale(scale, scale, 1.0)
return
}
let t = node.layer.sublayerTransform
let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13))
let currentOffset = CGPoint(x: t.m41, y: t.m42)
if currentScale.isEqual(to: scale) && currentOffset == offset {
if let completion = completion {
completion(true)
}
return
}
let transform = CATransform3DTranslate(CATransform3DMakeScale(scale, scale, 1.0), offset.x, offset.y, 0.0)
switch self {
case .immediate:
node.layer.sublayerTransform = transform
if let completion = completion {
completion(true)
}
case let .animated(duration, curve):
let initialTransform: CATransform3D
if beginWithCurrentState, node.isNodeLoaded {
initialTransform = node.layer.presentation()?.sublayerTransform ?? t
} else {
initialTransform = t
}
node.layer.sublayerTransform = transform
node.layer.animate(from: NSValue(caTransform3D: initialTransform), to: NSValue(caTransform3D: node.layer.sublayerTransform), keyPath: "sublayerTransform", timingFunction: curve.timingFunction, duration: duration, delay: 0.0, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: true, additive: false, completion: {
result in
if let completion = completion {
completion(result)
}
})
}
}
func updateSublayerTransformScale(node: ASDisplayNode, scale: CGPoint, completion: ((Bool) -> Void)? = nil) {
if !node.isNodeLoaded {
node.subnodeTransform = CATransform3DMakeScale(scale.x, scale.y, 1.0)

View File

@ -5131,7 +5131,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -5211,7 +5211,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -5257,7 +5257,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5365,7 +5365,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -5439,7 +5439,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5513,7 +5513,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5588,7 +5588,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -5662,7 +5662,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5742,7 +5742,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -5816,7 +5816,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5890,7 +5890,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";

View File

@ -1,5 +1,9 @@
import Foundation
#if os(macOS)
import sqlciphermac
#else
import sqlcipher
#endif
public protocol PostboxCoding {
init(decoder: PostboxDecoder)

View File

@ -22,7 +22,11 @@
// THE SOFTWARE.
//
#if os(macOS)
import sqlciphermac
#else
import sqlcipher
#endif
public final class Database {
internal var handle: OpaquePointer? = nil

View File

@ -1,5 +1,9 @@
import Foundation
#if os(macOS)
import sqlciphermac
#else
import sqlcipher
#endif
public enum HashFunctions {
public static func murMurHash32(_ s: String) -> Int32 {

View File

@ -5,7 +5,11 @@ import SwiftSignalKit
import SwiftSignalKitMac
#endif
#if os(iOS)
import Crc32
#else
import crc32mac
#endif
private final class MediaBoxFileMap {
fileprivate(set) var sum: Int32

View File

@ -1,5 +1,9 @@
import Foundation
#if os(macOS)
import sqlciphermac
#else
import sqlcipher
#endif
private final class SqliteInterfaceStatement {
let statement: OpaquePointer?

View File

@ -1,5 +1,9 @@
import Foundation
#if os(macOS)
import sqlciphermac
#else
import sqlcipher
#endif
#if os(macOS)
import SwiftSignalKitMac
#else

View File

@ -1,5 +1,9 @@
import Foundation
#if os(macOS)
import sqlciphermac
#else
import sqlcipher
#endif
public enum StringIndexTokenTransliteration {
case none

View File

@ -77,9 +77,10 @@
D039FB1C21714D9800BD1BAD /* PeerPresencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D039FB1A21714D9800BD1BAD /* PeerPresencesView.swift */; };
D03BCCF81C73561C0097A291 /* Table.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03BCCF71C73561C0097A291 /* Table.swift */; };
D03E45572305C7C90049C28B /* sqlcipher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45562305C7C90049C28B /* sqlcipher.framework */; };
D03E457B2305CD000049C28B /* Crc32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E457A2305CD000049C28B /* Crc32.framework */; };
D03E457D2305CD090049C28B /* Crc32.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E457C2305CD090049C28B /* Crc32.framework */; };
D03E457F2305CD130049C28B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E457E2305CD130049C28B /* Foundation.framework */; };
D03E462C2306E01C0049C28B /* sqlciphermac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E462B2306E01C0049C28B /* sqlciphermac.framework */; };
D03E463D2306E0F60049C28B /* crc32mac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E463C2306E0F60049C28B /* crc32mac.framework */; };
D040CA6422665370007123CE /* PostboxUpgrade_23to24.swift in Sources */ = {isa = PBXBuildFile; fileRef = D040CA6322665370007123CE /* PostboxUpgrade_23to24.swift */; };
D040CA6522665370007123CE /* PostboxUpgrade_23to24.swift in Sources */ = {isa = PBXBuildFile; fileRef = D040CA6322665370007123CE /* PostboxUpgrade_23to24.swift */; };
D0439B3F2289F6300067E026 /* AccountManagerAtomicState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0439B3E2289F6300067E026 /* AccountManagerAtomicState.swift */; };
@ -444,6 +445,8 @@
D03E457A2305CD000049C28B /* Crc32.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Crc32.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E457C2305CD090049C28B /* Crc32.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Crc32.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E457E2305CD130049C28B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D03E462B2306E01C0049C28B /* sqlciphermac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = sqlciphermac.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E463C2306E0F60049C28B /* crc32mac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = crc32mac.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D040CA6322665370007123CE /* PostboxUpgrade_23to24.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostboxUpgrade_23to24.swift; sourceTree = "<group>"; };
D0439B3E2289F6300067E026 /* AccountManagerAtomicState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountManagerAtomicState.swift; sourceTree = "<group>"; };
D044CA291C617D39002160FF /* SeedConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeedConfiguration.swift; sourceTree = "<group>"; };
@ -613,7 +616,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D03E457B2305CD000049C28B /* Crc32.framework in Frameworks */,
D03E463D2306E0F60049C28B /* crc32mac.framework in Frameworks */,
D03E462C2306E01C0049C28B /* sqlciphermac.framework in Frameworks */,
D0B418611D7DFE95004562A4 /* SwiftSignalKitMac.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -692,6 +696,8 @@
D0B4185F1D7DFE95004562A4 /* Frameworks */ = {
isa = PBXGroup;
children = (
D03E463C2306E0F60049C28B /* crc32mac.framework */,
D03E462B2306E01C0049C28B /* sqlciphermac.framework */,
D03E457E2305CD130049C28B /* Foundation.framework */,
D03E457C2305CD090049C28B /* Crc32.framework */,
D03E457A2305CD000049C28B /* Crc32.framework */,

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1030"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0B418121D7DFAF2004562A4"
BuildableName = "PostboxMac.framework"
BlueprintName = "PostboxMac"
ReferencedContainer = "container:Postbox_Xcode.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "DebugHockeyapp"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "DebugHockeyapp"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0B418121D7DFAF2004562A4"
BuildableName = "PostboxMac.framework"
BlueprintName = "PostboxMac"
ReferencedContainer = "container:Postbox_Xcode.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "ReleaseHockeyapp"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0B418121D7DFAF2004562A4"
BuildableName = "PostboxMac.framework"
BlueprintName = "PostboxMac"
ReferencedContainer = "container:Postbox_Xcode.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "DebugHockeyapp">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "ReleaseHockeyapp"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
</plist>

View File

@ -0,0 +1,579 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
D03E45EA2305E3F30049C28B /* ReactionSelectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E45E82305E3F30049C28B /* ReactionSelectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E45F52305EB7C0049C28B /* ReactionSelectionNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E45F42305EB7C0049C28B /* ReactionSelectionNode.swift */; };
D03E45F82305EB880049C28B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45F72305EB880049C28B /* Foundation.framework */; };
D03E45FA2305EB8B0049C28B /* AsyncDisplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45F92305EB8B0049C28B /* AsyncDisplayKit.framework */; };
D03E45FC2305EB8E0049C28B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45FB2305EB8E0049C28B /* UIKit.framework */; };
D03E45FE2305EB910049C28B /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45FD2305EB910049C28B /* Display.framework */; };
D03E46002305EE710049C28B /* AnimationUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45FF2305EE710049C28B /* AnimationUI.framework */; };
D03E46022305EE750049C28B /* Postbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E46012305EE750049C28B /* Postbox.framework */; };
D03E46042305EE790049C28B /* TelegramCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E46032305EE790049C28B /* TelegramCore.framework */; };
D03E46082305EEDD0049C28B /* ReactionSelectionParentNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E46072305EEDD0049C28B /* ReactionSelectionParentNode.swift */; };
D03E460A2305EF900049C28B /* ReactionSwipeGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E46092305EF900049C28B /* ReactionSwipeGestureRecognizer.swift */; };
D03E460C2305EFD80049C28B /* ReactionGestureItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E460B2305EFD80049C28B /* ReactionGestureItem.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
D03E45E52305E3F30049C28B /* ReactionSelectionNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReactionSelectionNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E45E82305E3F30049C28B /* ReactionSelectionNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactionSelectionNode.h; sourceTree = "<group>"; };
D03E45E92305E3F30049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D03E45F42305EB7C0049C28B /* ReactionSelectionNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionSelectionNode.swift; sourceTree = "<group>"; };
D03E45F72305EB880049C28B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D03E45F92305EB8B0049C28B /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E45FB2305EB8E0049C28B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
D03E45FD2305EB910049C28B /* Display.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Display.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E45FF2305EE710049C28B /* AnimationUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AnimationUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E46012305EE750049C28B /* Postbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Postbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E46032305EE790049C28B /* TelegramCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TelegramCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E46072305EEDD0049C28B /* ReactionSelectionParentNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionSelectionParentNode.swift; sourceTree = "<group>"; };
D03E46092305EF900049C28B /* ReactionSwipeGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionSwipeGestureRecognizer.swift; sourceTree = "<group>"; };
D03E460B2305EFD80049C28B /* ReactionGestureItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionGestureItem.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D03E45E22305E3F30049C28B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D03E46042305EE790049C28B /* TelegramCore.framework in Frameworks */,
D03E46022305EE750049C28B /* Postbox.framework in Frameworks */,
D03E46002305EE710049C28B /* AnimationUI.framework in Frameworks */,
D03E45FE2305EB910049C28B /* Display.framework in Frameworks */,
D03E45FC2305EB8E0049C28B /* UIKit.framework in Frameworks */,
D03E45FA2305EB8B0049C28B /* AsyncDisplayKit.framework in Frameworks */,
D03E45F82305EB880049C28B /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D03E45DB2305E3F30049C28B = {
isa = PBXGroup;
children = (
D03E45E92305E3F30049C28B /* Info.plist */,
D03E45E72305E3F30049C28B /* Sources */,
D03E45E62305E3F30049C28B /* Products */,
D03E45F62305EB870049C28B /* Frameworks */,
);
sourceTree = "<group>";
};
D03E45E62305E3F30049C28B /* Products */ = {
isa = PBXGroup;
children = (
D03E45E52305E3F30049C28B /* ReactionSelectionNode.framework */,
);
name = Products;
sourceTree = "<group>";
};
D03E45E72305E3F30049C28B /* Sources */ = {
isa = PBXGroup;
children = (
D03E45F42305EB7C0049C28B /* ReactionSelectionNode.swift */,
D03E45E82305E3F30049C28B /* ReactionSelectionNode.h */,
D03E46072305EEDD0049C28B /* ReactionSelectionParentNode.swift */,
D03E46092305EF900049C28B /* ReactionSwipeGestureRecognizer.swift */,
D03E460B2305EFD80049C28B /* ReactionGestureItem.swift */,
);
path = Sources;
sourceTree = "<group>";
};
D03E45F62305EB870049C28B /* Frameworks */ = {
isa = PBXGroup;
children = (
D03E46032305EE790049C28B /* TelegramCore.framework */,
D03E46012305EE750049C28B /* Postbox.framework */,
D03E45FF2305EE710049C28B /* AnimationUI.framework */,
D03E45FD2305EB910049C28B /* Display.framework */,
D03E45FB2305EB8E0049C28B /* UIKit.framework */,
D03E45F92305EB8B0049C28B /* AsyncDisplayKit.framework */,
D03E45F72305EB880049C28B /* Foundation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D03E45E02305E3F30049C28B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D03E45EA2305E3F30049C28B /* ReactionSelectionNode.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
D03E45E42305E3F30049C28B /* ReactionSelectionNode */ = {
isa = PBXNativeTarget;
buildConfigurationList = D03E45ED2305E3F30049C28B /* Build configuration list for PBXNativeTarget "ReactionSelectionNode" */;
buildPhases = (
D03E45E02305E3F30049C28B /* Headers */,
D03E45E12305E3F30049C28B /* Sources */,
D03E45E22305E3F30049C28B /* Frameworks */,
D03E45E32305E3F30049C28B /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = ReactionSelectionNode;
productName = ReactionSelectionNode;
productReference = D03E45E52305E3F30049C28B /* ReactionSelectionNode.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D03E45DC2305E3F30049C28B /* Project object */ = {
isa = PBXProject;
attributes = {
DefaultBuildSystemTypeForWorkspace = Latest;
LastUpgradeCheck = 1030;
ORGANIZATIONNAME = "Telegram Messenger LLP";
TargetAttributes = {
D03E45E42305E3F30049C28B = {
CreatedOnToolsVersion = 10.3;
LastSwiftMigration = 1030;
};
};
};
buildConfigurationList = D03E45DF2305E3F30049C28B /* Build configuration list for PBXProject "ReactionSelectionNode_Xcode" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = D03E45DB2305E3F30049C28B;
productRefGroup = D03E45E62305E3F30049C28B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D03E45E42305E3F30049C28B /* ReactionSelectionNode */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D03E45E32305E3F30049C28B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D03E45E12305E3F30049C28B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D03E460A2305EF900049C28B /* ReactionSwipeGestureRecognizer.swift in Sources */,
D03E46082305EEDD0049C28B /* ReactionSelectionParentNode.swift in Sources */,
D03E460C2305EFD80049C28B /* ReactionGestureItem.swift in Sources */,
D03E45F52305EB7C0049C28B /* ReactionSelectionNode.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
D03E45EB2305E3F30049C28B /* DebugAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = DebugAppStoreLLC;
};
D03E45EC2305E3F30049C28B /* ReleaseAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = ReleaseAppStoreLLC;
};
D03E45EE2305E3F30049C28B /* DebugAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ReactionSelectionNode;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = DebugAppStoreLLC;
};
D03E45EF2305E3F30049C28B /* ReleaseAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ReactionSelectionNode;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = ReleaseAppStoreLLC;
};
D03E45F02305E4200049C28B /* DebugHockeyapp */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = DebugHockeyapp;
};
D03E45F12305E4200049C28B /* DebugHockeyapp */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ReactionSelectionNode;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = DebugHockeyapp;
};
D03E45F22305E4290049C28B /* ReleaseHockeyappInternal */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = ReleaseHockeyappInternal;
};
D03E45F32305E4290049C28B /* ReleaseHockeyappInternal */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ReactionSelectionNode;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = ReleaseHockeyappInternal;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D03E45DF2305E3F30049C28B /* Build configuration list for PBXProject "ReactionSelectionNode_Xcode" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D03E45EB2305E3F30049C28B /* DebugAppStoreLLC */,
D03E45F02305E4200049C28B /* DebugHockeyapp */,
D03E45EC2305E3F30049C28B /* ReleaseAppStoreLLC */,
D03E45F22305E4290049C28B /* ReleaseHockeyappInternal */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = ReleaseAppStoreLLC;
};
D03E45ED2305E3F30049C28B /* Build configuration list for PBXNativeTarget "ReactionSelectionNode" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D03E45EE2305E3F30049C28B /* DebugAppStoreLLC */,
D03E45F12305E4200049C28B /* DebugHockeyapp */,
D03E45EF2305E3F30049C28B /* ReleaseAppStoreLLC */,
D03E45F32305E4290049C28B /* ReleaseHockeyappInternal */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = ReleaseAppStoreLLC;
};
/* End XCConfigurationList section */
};
rootObject = D03E45DC2305E3F30049C28B /* Project object */;
}

View File

@ -0,0 +1,23 @@
import Foundation
import Postbox
import TelegramCore
public struct ReactionGestureItemValue {
public var value: String
public var text: String
public var file: TelegramMediaFile
public init(value: String, text: String, file: TelegramMediaFile) {
self.value = value
self.text = text
self.file = file
}
}
public final class ReactionGestureItem {
public let value: ReactionGestureItemValue
public init(value: ReactionGestureItemValue) {
self.value = value
}
}

View File

@ -0,0 +1,19 @@
//
// ReactionSelectionNode.h
// ReactionSelectionNode
//
// Created by Peter on 8/15/19.
// Copyright © 2019 Telegram Messenger LLP. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for ReactionSelectionNode.
FOUNDATION_EXPORT double ReactionSelectionNodeVersionNumber;
//! Project version string for ReactionSelectionNode.
FOUNDATION_EXPORT const unsigned char ReactionSelectionNodeVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <ReactionSelectionNode/PublicHeader.h>

View File

@ -0,0 +1,344 @@
import Foundation
import AsyncDisplayKit
import AnimationUI
import Display
import Postbox
import TelegramCore
private let shadowBlur: CGFloat = 8.0
private let minimizedReactionSize: CGFloat = 30.0
private let maximizedReactionSize: CGFloat = 60.0
private func generateBubbleImage(foreground: UIColor, diameter: CGFloat) -> UIImage? {
return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(foreground.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter)))
})?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0))
}
private func generateBubbleShadowImage(shadow: UIColor, diameter: CGFloat) -> UIImage? {
return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.setShadow(offset: CGSize(), blur: shadowBlur, color: shadow.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter)))
context.setShadow(offset: CGSize(), blur: 1.0, color: shadow.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter)))
context.setFillColor(UIColor.clear.cgColor)
context.setBlendMode(.copy)
context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter)))
})?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0))
}
private final class ReactionNode: ASDisplayNode {
let reaction: ReactionGestureItem
private let animationNode: AnimatedStickerNode
var isMaximized: Bool?
private let intrinsicSize: CGSize
private let intrinsicOffset: CGPoint
init(account: Account, reaction: ReactionGestureItem) {
self.reaction = reaction
self.animationNode = AnimatedStickerNode()
self.animationNode.automaticallyLoadFirstFrame = true
self.animationNode.playToCompletionOnStop = true
//self.animationNode.backgroundColor = .lightGray
var intrinsicSize = CGSize(width: maximizedReactionSize + 18.0, height: maximizedReactionSize + 18.0)
switch reaction.value.value {
case "😳":
intrinsicSize.width += 8.0
intrinsicSize.height += 8.0
self.intrinsicOffset = CGPoint(x: 0.0, y: -4.0)
case "👍":
intrinsicSize.width += 20.0
intrinsicSize.height += 20.0
self.intrinsicOffset = CGPoint(x: 0.0, y: 4.0)
default:
self.intrinsicOffset = CGPoint(x: 0.0, y: 0.0)
}
self.intrinsicSize = intrinsicSize
super.init()
//self.backgroundColor = .green
self.addSubnode(self.animationNode)
self.animationNode.visibility = true
self.animationNode.setup(account: account, resource: reaction.value.file.resource, width: Int(self.intrinsicSize.width) * 2, height: Int(self.intrinsicSize.height) * 2, mode: .direct)
self.animationNode.updateLayout(size: self.intrinsicSize)
self.animationNode.frame = CGRect(origin: CGPoint(), size: self.intrinsicSize)
}
func updateLayout(size: CGSize, scale: CGFloat, transition: ContainedViewLayoutTransition) {
transition.updatePosition(node: self.animationNode, position: CGPoint(x: size.width / 2.0 + self.intrinsicOffset.x * scale, y: size.height / 2.0 + self.intrinsicOffset.y * scale), beginWithCurrentState: true)
transition.updateTransformScale(node: self.animationNode, scale: scale, beginWithCurrentState: true)
}
func updateIsAnimating(_ isAnimating: Bool, animated: Bool) {
if isAnimating {
self.animationNode.visibility = true
} else {
self.animationNode.visibility = false
}
}
}
final class ReactionSelectionNode: ASDisplayNode {
private let backgroundNode: ASImageNode
private let backgroundShadowNode: ASImageNode
private let bubbleNodes: [(ASImageNode, ASImageNode)]
private let reactionNodes: [ReactionNode]
private var hasSelectedNode = false
private let hapticFeedback = HapticFeedback()
public init(account: Account, reactions: [ReactionGestureItem]) {
self.backgroundNode = ASImageNode()
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.displayWithoutProcessing = true
self.backgroundNode.image = generateBubbleImage(foreground: .white, diameter: 42.0)
self.backgroundShadowNode = ASImageNode()
self.backgroundShadowNode.displaysAsynchronously = false
self.backgroundShadowNode.displayWithoutProcessing = true
self.backgroundShadowNode.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: 42.0)
self.bubbleNodes = (0 ..< 2).map { i -> (ASImageNode, ASImageNode) in
let imageNode = ASImageNode()
imageNode.image = generateBubbleImage(foreground: .white, diameter: CGFloat(i + 1) * 8.0)
imageNode.displaysAsynchronously = false
imageNode.displayWithoutProcessing = true
let shadowNode = ASImageNode()
shadowNode.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: CGFloat(i + 1) * 8.0)
shadowNode.displaysAsynchronously = false
shadowNode.displayWithoutProcessing = true
return (imageNode, shadowNode)
}
self.reactionNodes = reactions.map { reaction -> ReactionNode in
return ReactionNode(account: account, reaction: reaction)
}
super.init()
self.bubbleNodes.forEach { _, shadow in
self.addSubnode(shadow)
}
self.addSubnode(self.backgroundShadowNode)
self.bubbleNodes.forEach { foreground, _ in
self.addSubnode(foreground)
}
self.addSubnode(self.backgroundNode)
self.reactionNodes.forEach(self.addSubnode(_:))
}
func updateLayout(constrainedSize: CGSize, startingPoint: CGPoint, offsetFromStart: CGFloat, isInitial: Bool) {
let backgroundHeight: CGFloat = 42.0
let reactionSpacing: CGFloat = 6.0
let minimizedReactionVerticalInset: CGFloat = floor((backgroundHeight - minimizedReactionSize) / 2.0)
let contentWidth: CGFloat = CGFloat(self.reactionNodes.count - 1) * (minimizedReactionSize) + maximizedReactionSize + CGFloat(self.reactionNodes.count + 1) * reactionSpacing
var backgroundFrame = CGRect(origin: CGPoint(x: -shadowBlur, y: -shadowBlur), size: CGSize(width: contentWidth + shadowBlur * 2.0, height: backgroundHeight + shadowBlur * 2.0))
backgroundFrame = backgroundFrame.offsetBy(dx: startingPoint.x - contentWidth + backgroundHeight / 2.0 - 52.0, dy: startingPoint.y - backgroundHeight - 16.0)
self.backgroundNode.frame = backgroundFrame
self.backgroundShadowNode.frame = backgroundFrame
let anchorMinX = backgroundFrame.minX + shadowBlur + backgroundHeight / 2.0
let anchorMaxX = backgroundFrame.maxX - shadowBlur - backgroundHeight / 2.0
let anchorX = max(anchorMinX, min(anchorMaxX, offsetFromStart))
var reactionX: CGFloat = backgroundFrame.minX + shadowBlur + reactionSpacing
if offsetFromStart > backgroundFrame.maxX - shadowBlur {
self.hasSelectedNode = false
} else {
self.hasSelectedNode = true
}
var maximizedIndex = Int(((anchorX - anchorMinX) / (anchorMaxX - anchorMinX)) * CGFloat(self.reactionNodes.count))
maximizedIndex = max(0, min(self.reactionNodes.count - 1, maximizedIndex))
for i in 0 ..< self.reactionNodes.count {
let isMaximized = i == maximizedIndex
let reactionSize: CGFloat
if isMaximized {
reactionSize = maximizedReactionSize
} else {
reactionSize = minimizedReactionSize
}
let transition: ContainedViewLayoutTransition
if isInitial {
transition = .immediate
} else {
transition = .animated(duration: 0.18, curve: .easeInOut)
}
if self.reactionNodes[i].isMaximized != isMaximized {
self.reactionNodes[i].isMaximized = isMaximized
self.reactionNodes[i].updateIsAnimating(isMaximized, animated: !isInitial)
if isMaximized && !isInitial {
self.hapticFeedback.tap()
}
}
var reactionFrame = CGRect(origin: CGPoint(x: reactionX, y: backgroundFrame.maxY - shadowBlur - minimizedReactionVerticalInset - reactionSize), size: CGSize(width: reactionSize, height: reactionSize))
if isMaximized {
reactionFrame.origin.x -= 9.0
reactionFrame.size.width += 18.0
}
self.reactionNodes[i].updateLayout(size: reactionFrame.size, scale: reactionFrame.size.width / (maximizedReactionSize + 18.0), transition: transition)
transition.updateFrame(node: self.reactionNodes[i], frame: reactionFrame, beginWithCurrentState: true)
reactionX += reactionSize + reactionSpacing
}
let mainBubbleFrame = CGRect(origin: CGPoint(x: anchorX - 8.0 - shadowBlur, y: backgroundFrame.maxY - shadowBlur - 8.0 - shadowBlur), size: CGSize(width: 16.0 + shadowBlur * 2.0, height: 16.0 + shadowBlur * 2.0))
self.bubbleNodes[1].0.frame = mainBubbleFrame
self.bubbleNodes[1].1.frame = mainBubbleFrame
let secondaryBubbleFrame = CGRect(origin: CGPoint(x: mainBubbleFrame.midX - 9.0 - (8.0 + shadowBlur * 2.0) / 2.0, y: mainBubbleFrame.midY + 12.0 - (8.0 + shadowBlur * 2.0) / 2.0), size: CGSize(width: 8.0 + shadowBlur * 2.0, height: 8.0 + shadowBlur * 2.0))
self.bubbleNodes[0].0.frame = secondaryBubbleFrame
self.bubbleNodes[0].1.frame = secondaryBubbleFrame
}
func animateIn() {
self.bubbleNodes[1].0.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
self.bubbleNodes[1].1.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
self.bubbleNodes[0].0.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
self.bubbleNodes[0].1.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
let backgroundOffset = CGPoint(x: (self.backgroundNode.frame.width - shadowBlur) / 2.0 - 42.0, y: (self.backgroundNode.frame.height - shadowBlur) / 2.0)
let damping: CGFloat = 100.0
for i in 0 ..< self.reactionNodes.count {
let animationOffset: Double = 1.0 - Double(i) / Double(self.reactionNodes.count - 1)
var nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.maxX - shadowBlur) / 2.0 - 42.0, y: self.reactionNodes[i].frame.minY - self.backgroundNode.frame.maxY - shadowBlur)
nodeOffset.x = -nodeOffset.x
nodeOffset.y = 30.0
self.reactionNodes[i].layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5 + animationOffset * 0.08, initialVelocity: 0.0, damping: damping)
self.reactionNodes[i].layer.animateSpring(from: NSValue(cgPoint: nodeOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true)
}
self.backgroundNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, damping: damping)
self.backgroundNode.layer.animateSpring(from: NSValue(cgPoint: backgroundOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true)
self.backgroundShadowNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, damping: damping)
self.backgroundShadowNode.layer.animateSpring(from: NSValue(cgPoint: backgroundOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true)
}
func animateOut(into targetNode: ASImageNode?, hideTarget: Bool, completion: @escaping () -> Void) {
self.hapticFeedback.prepareTap()
var completedContainer = false
var completedTarget = true
let intermediateCompletion: () -> Void = {
if completedContainer && completedTarget {
completion()
}
}
if let targetNode = targetNode {
for i in 0 ..< self.reactionNodes.count {
if let isMaximized = self.reactionNodes[i].isMaximized, isMaximized {
if let snapshotView = self.reactionNodes[i].view.snapshotContentTree() {
let targetSnapshotView = UIImageView()
targetSnapshotView.image = targetNode.image
targetSnapshotView.frame = self.view.convert(targetNode.bounds, from: targetNode.view)
self.reactionNodes[i].isHidden = true
self.view.addSubview(targetSnapshotView)
self.view.addSubview(snapshotView)
completedTarget = false
let targetPosition = self.view.convert(targetNode.bounds.center, from: targetNode.view)
let duration: Double = 0.3
if hideTarget {
targetNode.isHidden = true
}
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false)
targetSnapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
targetSnapshotView.layer.animateScale(from: snapshotView.bounds.width / targetSnapshotView.bounds.width, to: 0.5, duration: 0.3, removeOnCompletion: false)
let sourcePoint = snapshotView.center
let midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0, y: sourcePoint.y - 30.0)
let x1 = sourcePoint.x
let y1 = sourcePoint.y
let x2 = midPoint.x
let y2 = midPoint.y
let x3 = targetPosition.x
let y3 = targetPosition.y
let a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / ((x1 - x2) * (x1 - x3) * (x2 - x3))
let b = (x1 * x1 * (y2 - y3) + x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1)) / ((x1 - x2) * (x1 - x3) * (x2 - x3))
let c = (x2 * x2 * (x3 * y1 - x1 * y3) + x2 * (x1 * x1 * y3 - x3 * x3 * y1) + x1 * x3 * (x3 - x1) * y2) / ((x1 - x2) * (x1 - x3) * (x2 - x3))
var keyframes: [AnyObject] = []
for i in 0 ..< 10 {
let k = CGFloat(i) / CGFloat(10 - 1)
let x = sourcePoint.x * (1.0 - k) + targetPosition.x * k
let y = a * x * x + b * x + c
keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y)))
}
snapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.hapticFeedback.tap()
}
completedTarget = true
if hideTarget {
targetNode.isHidden = false
targetNode.layer.animateSpring(from: 0.5 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, initialVelocity: 0.0, damping: 90.0)
}
intermediateCompletion()
})
targetSnapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false)
snapshotView.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 0.5) / snapshotView.bounds.width, duration: 0.3, removeOnCompletion: false)
}
break
}
}
}
self.backgroundNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
self.backgroundShadowNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
self.backgroundShadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
completedContainer = true
intermediateCompletion()
})
for (node, shadow) in self.bubbleNodes {
node.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
node.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
shadow.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
shadow.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
for i in 0 ..< self.reactionNodes.count {
self.reactionNodes[i].layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
self.reactionNodes[i].layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
}
func selectedReaction() -> ReactionGestureItem? {
if !self.hasSelectedNode {
return nil
}
for i in 0 ..< self.reactionNodes.count {
if let isMaximized = self.reactionNodes[i].isMaximized, isMaximized {
return self.reactionNodes[i].reaction
}
}
return nil
}
}

View File

@ -0,0 +1,81 @@
import Foundation
import AsyncDisplayKit
import Display
import Postbox
import TelegramCore
public final class ReactionSelectionParentNode: ASDisplayNode {
private let account: Account
private var currentNode: ReactionSelectionNode?
private var currentLocation: (CGPoint, CGFloat)?
private var validLayout: (size: CGSize, insets: UIEdgeInsets)?
public init(account: Account) {
self.account = account
super.init()
}
func displayReactions(_ reactions: [ReactionGestureItem], at point: CGPoint) {
if let currentNode = self.currentNode {
currentNode.removeFromSupernode()
self.currentNode = nil
}
let reactionNode = ReactionSelectionNode(account: self.account, reactions: reactions)
self.addSubnode(reactionNode)
self.currentNode = reactionNode
self.currentLocation = (point, point.x)
if let (size, insets) = self.validLayout {
self.update(size: size, insets: insets, isInitial: true)
reactionNode.animateIn()
}
}
func selectedReaction() -> ReactionGestureItem? {
if let currentNode = self.currentNode {
return currentNode.selectedReaction()
}
return nil
}
func dismissReactions(into targetNode: ASImageNode?, hideTarget: Bool) {
if let currentNode = self.currentNode {
currentNode.animateOut(into: targetNode, hideTarget: hideTarget, completion: { [weak currentNode] in
currentNode?.removeFromSupernode()
})
self.currentNode = nil
}
}
func updateReactionsAnchor(point: CGPoint) {
if let (currentPoint, _) = self.currentLocation {
self.currentLocation = (currentPoint, point.x)
if let (size, insets) = self.validLayout {
self.update(size: size, insets: insets, isInitial: false)
}
}
}
public func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, insets)
self.update(size: size, insets: insets, isInitial: false)
}
private func update(size: CGSize, insets: UIEdgeInsets, isInitial: Bool) {
if let currentNode = self.currentNode, let (point, offset) = currentLocation {
currentNode.updateLayout(constrainedSize: size, startingPoint: point, offsetFromStart: offset, isInitial: isInitial)
currentNode.frame = CGRect(origin: CGPoint(), size: size)
}
}
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return nil
}
}

View File

@ -0,0 +1,141 @@
import Foundation
import UIKit
import Display
public final class ReactionSwipeGestureRecognizer: UIPanGestureRecognizer {
private var validatedGesture = false
private var firstLocation: CGPoint = CGPoint()
private var currentReactions: [ReactionGestureItem] = []
private var isActivated = false
private var isAwaitingCompletion = false
private weak var currentContainer: ReactionSelectionParentNode?
public var availableReactions: (() -> [ReactionGestureItem])?
public var getReactionContainer: (() -> ReactionSelectionParentNode?)?
public var updateOffset: ((CGFloat, Bool) -> Void)?
public var completed: ((ReactionGestureItem?) -> Void)?
public var displayReply: ((CGFloat) -> Void)?
public var activateReply: (() -> Void)?
override public init(target: Any?, action: Selector?) {
super.init(target: target, action: action)
self.maximumNumberOfTouches = 1
}
override public func reset() {
super.reset()
self.validatedGesture = false
self.currentReactions = []
self.isActivated = false
self.isAwaitingCompletion = false
}
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
if let availableReactions = self.availableReactions?(), !availableReactions.isEmpty {
self.currentReactions = availableReactions
let touch = touches.first!
self.firstLocation = touch.location(in: nil)
} else {
self.state = .failed
}
}
override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
if self.isAwaitingCompletion {
return
}
guard let _ = self.view else {
return
}
guard let location = touches.first?.location(in: nil) else {
return
}
var translation = CGPoint(x: location.x - self.firstLocation.x, y: location.y - self.firstLocation.y)
let absTranslationX: CGFloat = abs(translation.x)
let absTranslationY: CGFloat = abs(translation.y)
var updatedOffset = false
if !self.validatedGesture {
if translation.x > 0.0 {
self.state = .failed
} else if absTranslationY > 2.0 && absTranslationY > absTranslationX * 2.0 {
self.state = .failed
} else if absTranslationX > 2.0 && absTranslationY * 2.0 < absTranslationX {
self.validatedGesture = true
self.firstLocation = location
translation = CGPoint()
self.updateOffset?(0.0, false)
updatedOffset = true
}
}
if self.validatedGesture {
if !updatedOffset {
self.updateOffset?(-min(0.0, translation.x), false)
}
if !self.isActivated {
if absTranslationX > 40.0 {
self.isActivated = true
self.displayReply?(-min(0.0, translation.x))
if !self.currentReactions.isEmpty, let reactionContainer = self.getReactionContainer?() {
self.currentContainer = reactionContainer
let reactionContainerLocation = reactionContainer.view.convert(location, from: nil)
reactionContainer.displayReactions(self.currentReactions, at: reactionContainerLocation)
}
}
} else {
if let reactionContainer = self.currentContainer {
let reactionContainerLocation = reactionContainer.view.convert(location, from: nil)
reactionContainer.updateReactionsAnchor(point: reactionContainerLocation)
}
}
super.touchesMoved(touches, with: event)
}
}
override public func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
if self.isAwaitingCompletion {
return
}
guard let location = touches.first?.location(in: nil) else {
return
}
if self.validatedGesture {
let translation = CGPoint(x: location.x - self.firstLocation.x, y: location.y - self.firstLocation.y)
if let reaction = self.currentContainer?.selectedReaction() {
self.completed?(reaction)
self.isAwaitingCompletion = true
} else {
if translation.x < -40.0 {
self.currentContainer?.dismissReactions(into: nil, hideTarget: false)
self.activateReply?()
self.state = .ended
} else {
self.currentContainer?.dismissReactions(into: nil, hideTarget: false)
self.completed?(nil)
self.state = .cancelled
super.touchesEnded(touches, with: event)
}
}
} else {
self.currentContainer?.dismissReactions(into: nil, hideTarget: false)
self.state = .cancelled
super.touchesEnded(touches, with: event)
}
}
public func complete(into targetNode: ASImageNode?, hideTarget: Bool) {
if self.isAwaitingCompletion {
self.currentContainer?.dismissReactions(into: targetNode, hideTarget: hideTarget)
self.state = .ended
}
}
}

View File

@ -1017,6 +1017,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return self?.navigationController as? NavigationController
}, chatControllerNode: { [weak self] in
return self?.chatDisplayNode
}, reactionContainerNode: { [weak self] in
return self?.chatDisplayNode.reactionContainerNode
}, presentGlobalOverlayController: { [weak self] controller, arguments in
self?.presentInGlobalOverlay(controller, with: arguments)
}, callPeer: { [weak self] peerId in
@ -1523,6 +1525,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
window.rootViewController?.present(controller, animated: true)
}
}
}, updateMessageReaction: { [weak self] messageId, reaction in
guard let strongSelf = self else {
return
}
let _ = updateMessageReactionsInteractively(postbox: strongSelf.context.account.postbox, messageId: messageId, reactions: [reaction]).start()
}, requestMessageUpdate: { [weak self] id in
if let strongSelf = self {
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)

View File

@ -7,6 +7,7 @@ import Display
import TelegramUIPreferences
import AccountContext
import TextSelectionNode
import ReactionSelectionNode
struct ChatInterfaceHighlightedState: Equatable {
let messageStableId: UInt32
@ -73,6 +74,7 @@ public final class ChatControllerInteraction {
let presentController: (ViewController, Any?) -> Void
let navigationController: () -> NavigationController?
let chatControllerNode: () -> ASDisplayNode?
let reactionContainerNode: () -> ReactionSelectionParentNode?
let presentGlobalOverlayController: (ViewController, Any?) -> Void
let callPeer: (PeerId) -> Void
let longTap: (ChatControllerInteractionLongTapAction, Message?) -> Void
@ -92,6 +94,7 @@ public final class ChatControllerInteraction {
let sendScheduledMessagesNow: ([MessageId]) -> Void
let editScheduledMessagesTime: ([MessageId]) -> Void
let performTextSelectionAction: (UInt32, String, TextSelectionAction) -> Void
let updateMessageReaction: (MessageId, String) -> Void
let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void
@ -106,7 +109,7 @@ public final class ChatControllerInteraction {
var searchTextHighightState: String?
var seenOneTimeAnimatedMedia = Set<MessageId>()
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
self.openMessage = openMessage
self.openPeer = openPeer
self.openPeerMention = openPeerMention
@ -134,6 +137,7 @@ public final class ChatControllerInteraction {
self.presentController = presentController
self.navigationController = navigationController
self.chatControllerNode = chatControllerNode
self.reactionContainerNode = reactionContainerNode
self.presentGlobalOverlayController = presentGlobalOverlayController
self.callPeer = callPeer
self.longTap = longTap
@ -153,6 +157,7 @@ public final class ChatControllerInteraction {
self.sendScheduledMessagesNow = sendScheduledMessagesNow
self.editScheduledMessagesTime = editScheduledMessagesTime
self.performTextSelectionAction = performTextSelectionAction
self.updateMessageReaction = updateMessageReaction
self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
@ -170,6 +175,8 @@ public final class ChatControllerInteraction {
return nil
}, chatControllerNode: {
return nil
}, reactionContainerNode: {
return nil
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in
}, canSetupReply: { _ in
return false
@ -185,6 +192,7 @@ public final class ChatControllerInteraction {
}, sendScheduledMessagesNow: { _ in
}, editScheduledMessagesTime: { _ in
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -10,6 +10,7 @@ import TelegramUIPreferences
import TextFormat
import AccountContext
import TelegramNotices
import ReactionSelectionNode
private final class ChatControllerNodeView: UITracingLayerView, WindowInputAccessoryHeightProvider, PreviewingHostView {
var inputAccessoryHeight: (() -> CGFloat)?
@ -76,6 +77,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let backgroundNode: WallpaperbackgroundNode
let historyNode: ChatHistoryListNode
let reactionContainerNode: ReactionSelectionParentNode
let historyNodeContainer: ASDisplayNode
let loadingNode: ChatLoadingNode
private var emptyNode: ChatEmptyNode?
@ -209,6 +211,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.historyNode.rotated = true
self.historyNodeContainer = ASDisplayNode()
self.historyNodeContainer.addSubnode(self.historyNode)
self.reactionContainerNode = ReactionSelectionParentNode(account: context.account)
self.historyNodeContainer.addSubnode(self.reactionContainerNode)
self.loadingNode = ChatLoadingNode(theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper)
self.inputPanelBackgroundNode = ASDisplayNode()
@ -839,6 +845,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
transition.updateFrame(node: emptyNode, frame: contentBounds)
}
transition.updateFrame(node: self.reactionContainerNode, frame: contentBounds)
self.reactionContainerNode.updateLayout(size: contentBounds.size, insets: UIEdgeInsets(), transition: transition)
var contentBottomInset: CGFloat = inputPanelsHeight + 4.0
if let scrollContainerNode = self.scrollContainerNode {

View File

@ -462,9 +462,22 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .minimal)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, false, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude))
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .minimal, reactionCount: dateReactionCount)
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, false, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions)
var viaBotApply: (TextNodeLayout, () -> TextNode)?
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?

View File

@ -314,7 +314,20 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings, reactionCount: dateReactionCount)
var webpageGalleryMediaCount: Int?
for media in message.media {
@ -534,7 +547,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
}
}
statusSizeAndApply = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, textConstrainedSize)
statusSizeAndApply = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions)
}
default:
break
@ -1023,4 +1036,11 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? {
return self.contentImageNode?.playMediaWithSound()
}
func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -172,4 +172,8 @@ class ChatMessageBubbleContentNode: ASDisplayNode {
func updateIsExtractedToContextPreview(_ value: Bool) {
}
func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
return nil
}
}

View File

@ -16,6 +16,7 @@ import MosaicLayout
import TextSelectionNode
import PlatformRestrictionMatching
import Emoji
import ReactionSelectionNode
private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(Message, AnyClass)] {
var result: [(Message, AnyClass)] = []
@ -178,6 +179,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
private var appliedForwardInfo: (Peer?, String?)?
private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer?
private var reactionRecognizer: ReactionSwipeGestureRecognizer?
private var awaitingAppliedReaction: String?
override var visibility: ListViewItemNodeVisibility {
didSet {
@ -365,7 +369,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
self.tapRecognizer = recognizer
self.view.addGestureRecognizer(recognizer)
let replyRecognizer = ChatSwipeToReplyRecognizer(target: self, action: #selector(self.swipeToReplyGesture(_:)))
/*let replyRecognizer = ChatSwipeToReplyRecognizer(target: self, action: #selector(self.swipeToReplyGesture(_:)))
replyRecognizer.shouldBegin = { [weak self] in
if let strongSelf = self, let item = strongSelf.item {
if strongSelf.selectionNode != nil {
@ -387,7 +391,128 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
return false
}
self.view.addGestureRecognizer(replyRecognizer)
self.view.addGestureRecognizer(replyRecognizer)*/
let reactionRecognizer = ReactionSwipeGestureRecognizer(target: nil, action: nil)
self.reactionRecognizer = reactionRecognizer
reactionRecognizer.availableReactions = { [weak self] in
guard let strongSelf = self, let item = strongSelf.item else {
return []
}
if strongSelf.selectionNode != nil {
return []
}
for media in item.content.firstMessage.media {
if let _ = media as? TelegramMediaExpiredContent {
return []
}
else if let media = media as? TelegramMediaAction {
if case .phoneCall = media.action {
} else {
return []
}
}
}
if !item.controllerInteraction.canSetupReply(item.message) {
//return []
}
let reactions: [(String, String)] = [
("😒", "Sad"),
("😳", "Surprised"),
//("🥳", "Fun"),
("👍", "Like"),
("", "Love"),
]
var result: [ReactionGestureItem] = []
for (value, text) in reactions {
if let file = item.associatedData.animatedEmojiStickers[value]?.file {
result.append(ReactionGestureItem(value: ReactionGestureItemValue(value: value, text: text, file: file)))
}
}
return result
}
reactionRecognizer.getReactionContainer = { [weak self] in
return self?.item?.controllerInteraction.reactionContainerNode()
}
reactionRecognizer.updateOffset = { [weak self] offset, animated in
guard let strongSelf = self else {
return
}
var bounds = strongSelf.bounds
bounds.origin.x = offset
strongSelf.bounds = bounds
if animated {
strongSelf.layer.animateBoundsOriginXAdditive(from: -offset, to: 0.0, duration: 0.1, mediaTimingFunction: CAMediaTimingFunction(name: .easeOut))
}
if let swipeToReplyNode = strongSelf.swipeToReplyNode {
swipeToReplyNode.alpha = max(0.0, min(1.0, abs(offset / 40.0)))
}
}
reactionRecognizer.activateReply = { [weak self] in
guard let strongSelf = self, let item = strongSelf.item else {
return
}
var bounds = strongSelf.bounds
let offset = bounds.origin.x
bounds.origin.x = 0.0
strongSelf.bounds = bounds
if !offset.isZero {
strongSelf.layer.animateBoundsOriginXAdditive(from: offset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring)
}
if let swipeToReplyNode = strongSelf.swipeToReplyNode {
strongSelf.swipeToReplyNode = nil
swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in
swipeToReplyNode?.removeFromSupernode()
})
swipeToReplyNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
}
item.controllerInteraction.setupReply(item.message.id)
}
reactionRecognizer.displayReply = { [weak self] offset in
guard let strongSelf = self, let item = strongSelf.item else {
return
}
if strongSelf.swipeToReplyNode == nil {
if strongSelf.swipeToReplyFeedback == nil {
strongSelf.swipeToReplyFeedback = HapticFeedback()
}
strongSelf.swipeToReplyFeedback?.tap()
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonFillColor, wallpaper: item.presentationData.theme.wallpaper), strokeColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonStrokeColor, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper))
strongSelf.swipeToReplyNode = swipeToReplyNode
strongSelf.insertSubnode(swipeToReplyNode, belowSubnode: strongSelf.messageAccessibilityArea)
swipeToReplyNode.frame = CGRect(origin: CGPoint(x: strongSelf.bounds.size.width, y: floor((strongSelf.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0))
swipeToReplyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12)
swipeToReplyNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
}
}
reactionRecognizer.completed = { [weak self] reaction in
guard let strongSelf = self else {
return
}
if let item = strongSelf.item, let reaction = reaction {
strongSelf.awaitingAppliedReaction = reaction.value.value
item.controllerInteraction.updateMessageReaction(item.message.id, reaction.value.value)
} else {
strongSelf.reactionRecognizer?.complete(into: nil, hideTarget: false)
var bounds = strongSelf.bounds
let offset = bounds.origin.x
bounds.origin.x = 0.0
strongSelf.bounds = bounds
if !offset.isZero {
strongSelf.layer.animateBoundsOriginXAdditive(from: offset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring)
}
if let swipeToReplyNode = strongSelf.swipeToReplyNode {
strongSelf.swipeToReplyNode = nil
swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in
swipeToReplyNode?.removeFromSupernode()
})
swipeToReplyNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
}
}
}
self.view.addGestureRecognizer(reactionRecognizer)
}
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
@ -444,7 +569,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
forwardInfoLayout: (ChatPresentationData, PresentationStrings, ChatMessageForwardInfoType, Peer?, String?, CGSize) -> (CGSize, () -> ChatMessageForwardInfoNode),
replyInfoLayout: (ChatPresentationData, PresentationStrings, AccountContext, ChatMessageReplyInfoType, Message, CGSize) -> (CGSize, () -> ChatMessageReplyInfoNode),
actionButtonsLayout: (AccountContext, ChatPresentationThemeData, PresentationStrings, ReplyMarkupMessageAttribute, Message, CGFloat) -> (minWidth: CGFloat, layout: (CGFloat) -> (CGSize, (Bool) -> ChatMessageActionButtonsNode)),
mosaicStatusLayout: (AccountContext, ChatPresentationData, Bool, Int?, String, ChatMessageDateAndStatusType, CGSize) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode),
mosaicStatusLayout: (AccountContext, ChatPresentationData, Bool, Int?, String, ChatMessageDateAndStatusType, CGSize, [MessageReaction]) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode),
currentShareButtonNode: HighlightableButtonNode?,
layoutConstants: ChatMessageItemLayoutConstants,
currentItem: ChatMessageItem?,
@ -888,7 +1013,20 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount)
let statusType: ChatMessageDateAndStatusType
if message.effectivelyIncoming(item.context.account.peerId) {
@ -903,7 +1041,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
}
mosaicStatusSizeAndApply = mosaicStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: 200.0, height: CGFloat.greatestFiniteMagnitude))
mosaicStatusSizeAndApply = mosaicStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: 200.0, height: CGFloat.greatestFiniteMagnitude), dateReactions)
}
}
@ -1775,6 +1913,35 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
strongSelf.updateSearchTextHighlightState()
if let awaitingAppliedReaction = strongSelf.awaitingAppliedReaction {
var bounds = strongSelf.bounds
let offset = bounds.origin.x
bounds.origin.x = 0.0
strongSelf.bounds = bounds
if !offset.isZero {
strongSelf.layer.animateBoundsOriginXAdditive(from: offset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring)
}
if let swipeToReplyNode = strongSelf.swipeToReplyNode {
strongSelf.swipeToReplyNode = nil
swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in
swipeToReplyNode?.removeFromSupernode()
})
swipeToReplyNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
}
strongSelf.awaitingAppliedReaction = nil
var targetNode: ASImageNode?
var hideTarget = false
for contentNode in strongSelf.contentNodes {
if let (reactionNode, count) = contentNode.reactionTargetNode(value: awaitingAppliedReaction) {
targetNode = reactionNode
hideTarget = count == 1
break
}
}
strongSelf.reactionRecognizer?.complete(into: targetNode, hideTarget: hideTarget)
}
}
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {
@ -2504,7 +2671,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
@objc func swipeToReplyGesture(_ recognizer: ChatSwipeToReplyRecognizer) {
switch recognizer.state {
/*switch recognizer.state {
case .began:
self.currentSwipeToReplyTranslation = 0.0
if self.swipeToReplyFeedback == nil {
@ -2563,7 +2730,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
default:
break
}
}*/
}
private var absoluteRect: (CGRect, CGSize)?

View File

@ -128,7 +128,7 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
buttonImage = PresentationResourcesChat.chatBubbleOutgoingCallButtonImage(item.presentationData.theme.theme)
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: 0)
let statusText: String
if let callDuration = callDuration, callDuration > 1 {
@ -214,4 +214,8 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
return .none
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
return nil
}
}

View File

@ -149,7 +149,20 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount)
let statusType: ChatMessageDateAndStatusType?
switch position {
@ -173,7 +186,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
var statusApply: ((Bool) -> Void)?
if let statusType = statusType {
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude))
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions)
statusSize = size
statusApply = apply
}
@ -330,4 +343,11 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
let _ = item.controllerInteraction.openMessage(item.message, .default)
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -2,6 +2,7 @@ import Foundation
import UIKit
import AsyncDisplayKit
import Postbox
import TelegramCore
import Display
import SwiftSignalKit
import TelegramPresentationData
@ -104,6 +105,28 @@ enum ChatMessageDateAndStatusType: Equatable {
}
}
private let reactionSize: CGFloat = 18.0
private final class StatusReactionNode: ASImageNode {
let value: String
var count: Int
init(value: String, count: Int) {
self.value = value
self.count = count
super.init()
self.image = generateImage(CGSize(width: reactionSize, height: reactionSize), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
UIGraphicsPushContext(context)
let string = NSAttributedString(string: value, font: Font.regular(11.0), textColor: .black)
string.draw(at: CGPoint(x: 1.0, y: 3.0))
UIGraphicsPopContext()
})
}
}
class ChatMessageDateAndStatusNode: ASDisplayNode {
private var backgroundNode: ASImageNode?
private var checkSentNode: ASImageNode?
@ -112,6 +135,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
private var clockMinNode: ASImageNode?
private let dateNode: TextNode
private var impressionIcon: ASImageNode?
private var reactionNodes: [StatusReactionNode] = []
private var type: ChatMessageDateAndStatusType?
private var theme: ChatPresentationThemeData?
@ -128,7 +152,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
self.addSubnode(self.dateNode)
}
func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize) -> (CGSize, (Bool) -> Void) {
func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction]) -> (CGSize, (Bool) -> Void) {
let dateLayout = TextNode.asyncLayout(self.dateNode)
var checkReadNode = self.checkReadNode
@ -142,11 +166,11 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
let currentType = self.type
let currentTheme = self.theme
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize in
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions in
let dateColor: UIColor
var backgroundImage: UIImage?
var outgoingStatus: ChatMessageDateAndStatusOutgoingType?
let leftInset: CGFloat
var leftInset: CGFloat
let loadedCheckFullImage: UIImage?
let loadedCheckPartialImage: UIImage?
@ -372,6 +396,12 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
backgroundInsets = UIEdgeInsets(top: 2.0, left: 7.0, bottom: 2.0, right: 7.0)
}
var reactionInset: CGFloat = 0.0
if !reactions.isEmpty {
reactionInset = 1.0 + CGFloat(reactions.count) * reactionSize
}
leftInset += reactionInset
let layoutSize = CGSize(width: leftInset + impressionWidth + date.size.width + statusWidth + backgroundInsets.left + backgroundInsets.right, height: date.size.height + backgroundInsets.top + backgroundInsets.bottom)
return (layoutSize, { [weak self] animated in
@ -423,7 +453,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
} else if themeUpdated {
clockFrameNode.image = clockFrameImage
}
clockFrameNode.position = CGPoint(x: backgroundInsets.left + clockPosition.x, y: backgroundInsets.top + clockPosition.y)
clockFrameNode.position = CGPoint(x: backgroundInsets.left + clockPosition.x + reactionInset, y: backgroundInsets.top + clockPosition.y)
if let clockFrameNode = strongSelf.clockFrameNode {
maybeAddRotationAnimation(clockFrameNode.layer, duration: 6.0)
}
@ -440,7 +470,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
} else if themeUpdated {
clockMinNode.image = clockMinImage
}
clockMinNode.position = CGPoint(x: backgroundInsets.left + clockPosition.x, y: backgroundInsets.top + clockPosition.y)
clockMinNode.position = CGPoint(x: backgroundInsets.left + clockPosition.x + reactionInset, y: backgroundInsets.top + clockPosition.y)
if let clockMinNode = strongSelf.clockMinNode {
maybeAddRotationAnimation(clockMinNode.layer, duration: 1.0)
}
@ -465,7 +495,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
animateSentNode = animated
}
checkSentNode.isHidden = false
checkSentNode.frame = checkSentFrame.offsetBy(dx: backgroundInsets.left, dy: backgroundInsets.top)
checkSentNode.frame = checkSentFrame.offsetBy(dx: backgroundInsets.left + reactionInset, dy: backgroundInsets.top)
} else {
checkSentNode.isHidden = true
}
@ -485,7 +515,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
animateReadNode = animated
}
checkReadNode.isHidden = false
checkReadNode.frame = checkReadFrame.offsetBy(dx: backgroundInsets.left, dy: backgroundInsets.top)
checkReadNode.frame = checkReadFrame.offsetBy(dx: backgroundInsets.left + reactionInset, dy: backgroundInsets.top)
} else {
checkReadNode.isHidden = true
}
@ -502,22 +532,47 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
strongSelf.checkSentNode = nil
strongSelf.checkReadNode = nil
}
var reactionOffset: CGFloat = leftInset - reactionInset + backgroundInsets.left
for i in 0 ..< reactions.count {
let node: StatusReactionNode
if strongSelf.reactionNodes.count > i, strongSelf.reactionNodes[i].value == reactions[i].value {
node = strongSelf.reactionNodes[i]
node.count = Int(reactions[i].count)
} else {
node = StatusReactionNode(value: reactions[i].value, count: Int(reactions[i].count))
if strongSelf.reactionNodes.count > i {
strongSelf.reactionNodes[i].removeFromSupernode()
strongSelf.reactionNodes[i] = node
} else {
strongSelf.reactionNodes.append(node)
}
}
if node.supernode == nil {
strongSelf.addSubnode(node)
}
node.frame = CGRect(origin: CGPoint(x: reactionOffset, y: backgroundInsets.top + 1.0 + offset - 3.0), size: CGSize(width: reactionSize, height: reactionSize))
reactionOffset += reactionSize
}
for _ in reactions.count ..< strongSelf.reactionNodes.count {
strongSelf.reactionNodes.removeLast().removeFromSupernode()
}
}
})
}
}
static func asyncLayout(_ node: ChatMessageDateAndStatusNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode) {
static func asyncLayout(_ node: ChatMessageDateAndStatusNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction]) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode) {
let currentLayout = node?.asyncLayout()
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize in
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions in
let resultNode: ChatMessageDateAndStatusNode
let resultSizeAndApply: (CGSize, (Bool) -> Void)
if let node = node, let currentLayout = currentLayout {
resultNode = node
resultSizeAndApply = currentLayout(context, presentationData, edited, impressionCount, dateText, type, constrainedSize)
resultSizeAndApply = currentLayout(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions)
} else {
resultNode = ChatMessageDateAndStatusNode()
resultSizeAndApply = resultNode.asyncLayout()(context, presentationData, edited, impressionCount, dateText, type, constrainedSize)
resultSizeAndApply = resultNode.asyncLayout()(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions)
}
return (resultSizeAndApply.0, { animated in
@ -526,4 +581,13 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
})
}
}
func reactionNode(value: String) -> (ASImageNode, Int)? {
for node in self.reactionNodes {
if node.value == value {
return (node, node.count)
}
}
return nil
}
}

View File

@ -117,4 +117,8 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.interactiveFileNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
return self.interactiveFileNode.reactionTargetNode(value: value)
}
}

View File

@ -132,4 +132,8 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode {
}
return self.contentNode.transitionNode(media: media)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
return self.contentNode.reactionTargetNode(value: value)
}
}

View File

@ -276,9 +276,22 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let (size, apply) = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, constrainedSize)
let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings, reactionCount: dateReactionCount)
let (size, apply) = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, constrainedSize, dateReactions)
statusSize = size
statusApply = apply
}
@ -927,4 +940,11 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
self.playerUpdateTimer?.invalidate()
self.playerUpdateTimer = nil
}
func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -246,23 +246,31 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
}
}
let edited = false
var edited = false
let sentViaBot = false
var viewCount: Int? = nil
for attribute in item.message.attributes {
if let _ = attribute as? EditedMessageAttribute {
// edited = true
if let attribute = attribute as? EditedMessageAttribute {
edited = !attribute.isHidden
} else if let attribute = attribute as? ViewCountMessageAttribute {
viewCount = attribute.count
}// else if let _ = attribute as? InlineBotMessageAttribute {
// sentViaBot = true
// }
}
}
// if let author = item.message.author as? TelegramUser, author.botInfo != nil {
// sentViaBot = true
// }
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular, reactionCount: dateReactionCount)
let maxDateAndStatusWidth: CGFloat
if case .bubble = statusDisplayType {
@ -270,7 +278,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} else {
maxDateAndStatusWidth = width - videoFrame.midX - 85.0
}
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited && !sentViaBot, viewCount, dateText, statusType, CGSize(width: max(1.0, maxDateAndStatusWidth), height: CGFloat.greatestFiniteMagnitude))
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited && !sentViaBot, viewCount, dateText, statusType, CGSize(width: max(1.0, maxDateAndStatusWidth), height: CGFloat.greatestFiniteMagnitude), dateReactions)
var contentSize = imageSize
var dateAndStatusOverflow = false

View File

@ -135,4 +135,8 @@ final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContentNode {
}
return self.contentNode.transitionNode(media: media)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
return self.contentNode.reactionTargetNode(value: value)
}
}

View File

@ -181,13 +181,26 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
}
}
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
if let selectedMedia = selectedMedia {
if selectedMedia.liveBroadcastingTimeout != nil {
edited = false
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount)
let statusType: ChatMessageDateAndStatusType?
switch position {
@ -225,7 +238,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
var statusApply: ((Bool) -> Void)?
if let statusType = statusType {
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude))
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions)
statusSize = size
statusApply = apply
}
@ -455,4 +468,11 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
}
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -164,7 +164,20 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount)
let statusType: ChatMessageDateAndStatusType?
switch position {
@ -192,7 +205,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
var statusApply: ((Bool) -> Void)?
if let statusType = statusType {
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: imageSize.width - 30.0, height: CGFloat.greatestFiniteMagnitude))
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: imageSize.width - 30.0, height: CGFloat.greatestFiniteMagnitude), dateReactions)
statusSize = size
statusApply = apply
}
@ -359,4 +372,11 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
return false
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -596,7 +596,20 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount)
let statusType: ChatMessageDateAndStatusType?
switch position {
@ -620,7 +633,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
var statusApply: ((Bool) -> Void)?
if let statusType = statusType {
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize)
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions)
statusSize = size
statusApply = apply
}
@ -942,4 +955,11 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
return .none
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -59,7 +59,20 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount)
let statusType: ChatMessageDateAndStatusType?
switch position {
@ -83,7 +96,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
var statusApply: ((Bool) -> Void)?
if let statusType = statusType {
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize)
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions)
statusSize = size
statusApply = apply
}
@ -95,7 +108,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
let textFont = item.presentationData.messageFont
let forceStatusNewline = false
let attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont)
let attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor.withAlphaComponent(0.7), linkColor: messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont)
var cutout: TextNodeCutout?
if let statusSize = statusSize, !forceStatusNewline {
@ -230,4 +243,11 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
self.textNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
self.statusNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -265,9 +265,22 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude))
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular, reactionCount: dateReactionCount)
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions)
var viaBotApply: (TextNodeLayout, () -> TextNode)?
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?

View File

@ -106,7 +106,20 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings)
var dateReactions: [MessageReaction] = []
var dateReactionCount = 0
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
for reaction in reactionsAttribute.reactions {
if reaction.isSelected {
dateReactions.insert(reaction, at: 0)
} else {
dateReactions.append(reaction)
}
dateReactionCount += Int(reaction.count)
}
}
let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount)
let statusType: ChatMessageDateAndStatusType?
switch position {
@ -130,7 +143,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
var statusApply: ((Bool) -> Void)?
if let statusType = statusType {
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize)
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions)
statusSize = size
statusApply = apply
}
@ -158,20 +171,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
rawText = item.presentationData.strings.Conversation_UnsupportedMediaPlaceholder
messageEntities = [MessageTextEntity(range: 0..<rawText.count, type: .Italic)]
} else {
var reactionsString = ""
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty {
reactionsString += "\n\nReactions:"
for reaction in reactionsAttribute.reactions {
reactionsString += "\n[\(reaction.value)"
if reaction.isSelected {
reactionsString += ""
}
reactionsString += "]"
}
}
rawText = item.message.text + reactionsString
rawText = item.message.text
for attribute in item.message.attributes {
if let attribute = attribute as? TextEntitiesMessageAttribute {
@ -540,4 +540,11 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
})
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}
return nil
}
}

View File

@ -487,4 +487,8 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
let contentNodeFrame = self.contentNode.frame
self.contentNode.updateTouchesAtPoint(point.flatMap { $0.offsetBy(dx: -contentNodeFrame.minX, dy: -contentNodeFrame.minY) })
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
return self.contentNode.reactionTargetNode(value: value)
}
}

View File

@ -236,6 +236,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
return self?.getNavigationController()
}, chatControllerNode: { [weak self] in
return self
}, reactionContainerNode: {
return nil
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in }, longTap: { [weak self] action, message in
if let strongSelf = self {
switch action {
@ -408,6 +410,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, sendScheduledMessagesNow: { _ in
}, editScheduledMessagesTime: { _ in
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,

View File

@ -90,6 +90,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
return nil
}, chatControllerNode: {
return nil
}, reactionContainerNode: {
return nil
}, presentGlobalOverlayController: { _, _ in
}, callPeer: { _ in
}, longTap: { _, _ in
@ -110,6 +112,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, sendScheduledMessagesNow: { _ in
}, editScheduledMessagesTime: { _ in
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))

View File

@ -219,6 +219,8 @@ public class PeerMediaCollectionController: TelegramBaseController {
return nil
}, chatControllerNode: {
return nil
}, reactionContainerNode: {
return nil
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in
}, longTap: { [weak self] content, _ in
if let strongSelf = self {
@ -284,6 +286,7 @@ public class PeerMediaCollectionController: TelegramBaseController {
}, sendScheduledMessagesNow: { _ in
}, editScheduledMessagesTime: { _ in
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -11,7 +11,7 @@ enum MessageTimestampStatusFormat {
case minimal
}
func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular) -> String {
func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular, reactionCount: Int) -> String {
let timestamp: Int32
if let scheduleTime = message.scheduleTime {
timestamp = scheduleTime

View File

@ -195,6 +195,7 @@
D03E449E2305B6A00049C28B /* WatchBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E449D2305B6A00049C28B /* WatchBridge.framework */; };
D03E44E22305BC900049C28B /* LegacyDataImport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E44E12305BC900049C28B /* LegacyDataImport.framework */; };
D03E45252305C07A0049C28B /* ShareItems.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E45242305C07A0049C28B /* ShareItems.framework */; };
D03E46102305FD360049C28B /* ReactionSelectionNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E460F2305FD360049C28B /* ReactionSelectionNode.framework */; };
D04203152037162700490EA5 /* MediaInputPaneTrendingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04203142037162700490EA5 /* MediaInputPaneTrendingItem.swift */; };
D04281F4200E5AB0009DDE36 /* ChatRecentActionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04281F3200E5AB0009DDE36 /* ChatRecentActionsController.swift */; };
D04281F6200E5AC2009DDE36 /* ChatRecentActionsControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04281F5200E5AC2009DDE36 /* ChatRecentActionsControllerNode.swift */; };
@ -915,6 +916,7 @@
D03E449D2305B6A00049C28B /* WatchBridge.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = WatchBridge.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E44E12305BC900049C28B /* LegacyDataImport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LegacyDataImport.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E45242305C07A0049C28B /* ShareItems.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ShareItems.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E460F2305FD360049C28B /* ReactionSelectionNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ReactionSelectionNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E5E081E55C49C0029569A /* DebugAccountsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugAccountsController.swift; sourceTree = "<group>"; };
D04203142037162700490EA5 /* MediaInputPaneTrendingItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInputPaneTrendingItem.swift; sourceTree = "<group>"; };
D04281F3200E5AB0009DDE36 /* ChatRecentActionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatRecentActionsController.swift; sourceTree = "<group>"; };
@ -1377,6 +1379,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D03E46102305FD360049C28B /* ReactionSelectionNode.framework in Frameworks */,
D03E45252305C07A0049C28B /* ShareItems.framework in Frameworks */,
D03E44E22305BC900049C28B /* LegacyDataImport.framework in Frameworks */,
D03E449E2305B6A00049C28B /* WatchBridge.framework in Frameworks */,
@ -2085,6 +2088,7 @@
D08D45281D5E340200A7428A /* Frameworks */ = {
isa = PBXGroup;
children = (
D03E460F2305FD360049C28B /* ReactionSelectionNode.framework */,
D03E45242305C07A0049C28B /* ShareItems.framework */,
D03E44E12305BC900049C28B /* LegacyDataImport.framework */,
D03E449D2305B6A00049C28B /* WatchBridge.framework */,

View File

@ -29,6 +29,7 @@
D03E44982305B6810049C28B /* StickerResources.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E44972305B6810049C28B /* StickerResources.framework */; };
D03E449A2305B6850049C28B /* PhotoResources.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E44992305B6850049C28B /* PhotoResources.framework */; };
D03E449C2305B6910049C28B /* LegacyComponents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E449B2305B6910049C28B /* LegacyComponents.framework */; };
D03E4641230750150049C28B /* LegacyUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E4640230750150049C28B /* LegacyUI.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -56,6 +57,7 @@
D03E44972305B6810049C28B /* StickerResources.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = StickerResources.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E44992305B6850049C28B /* PhotoResources.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PhotoResources.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E449B2305B6910049C28B /* LegacyComponents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LegacyComponents.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E4640230750150049C28B /* LegacyUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LegacyUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -63,6 +65,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D03E4641230750150049C28B /* LegacyUI.framework in Frameworks */,
D03E449C2305B6910049C28B /* LegacyComponents.framework in Frameworks */,
D03E449A2305B6850049C28B /* PhotoResources.framework in Frameworks */,
D03E44982305B6810049C28B /* StickerResources.framework in Frameworks */,
@ -119,6 +122,7 @@
D03E447C2305B6170049C28B /* Frameworks */ = {
isa = PBXGroup;
children = (
D03E4640230750150049C28B /* LegacyUI.framework */,
D03E449B2305B6910049C28B /* LegacyComponents.framework */,
D03E44992305B6850049C28B /* PhotoResources.framework */,
D03E44972305B6810049C28B /* StickerResources.framework */,

View File

@ -34,7 +34,11 @@
#define SQLITE3_H
#include <stdarg.h> /* Needed for the definition of va_list */
#if TARGET_OS_IOS
#include <sqlcipher/sqlcipher_config.h>
#else
#include <sqlciphermac/sqlcipher_config.h>
#endif
/*
** Make sure we can call this stuff from C++.

View File

@ -17,7 +17,12 @@
*/
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#if TARGET_OS_IOS
#include <sqlcipher/sqlite3.h>
#else
#include <sqlciphermac/sqlite3.h>
#endif
/*
** The following structure holds pointers to all of the SQLite API

View File

@ -15,6 +15,13 @@
D03E45542305C7600049C28B /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E454E2305C7600049C28B /* SQLite-Bridging.h */; };
D03E45552305C7600049C28B /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E454F2305C7600049C28B /* fts3_tokenizer.h */; };
D03E45592305C8090049C28B /* sqlcipher_config.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E45582305C8090049C28B /* sqlcipher_config.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E461A2306DF740049C28B /* sqlciphermac.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E46182306DF740049C28B /* sqlciphermac.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E46202306DF830049C28B /* sqlcipher_config.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E45582305C8090049C28B /* sqlcipher_config.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E46212306DF8A0049C28B /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E454F2305C7600049C28B /* fts3_tokenizer.h */; };
D03E46222306DF8D0049C28B /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E454E2305C7600049C28B /* SQLite-Bridging.h */; };
D03E46232306DF920049C28B /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E454C2305C75F0049C28B /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E46252306DF9A0049C28B /* sqlite3ext.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E454D2305C7600049C28B /* sqlite3ext.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E46262306DFA00049C28B /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = D03E454B2305C75F0049C28B /* sqlite3.c */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -28,6 +35,9 @@
D03E454E2305C7600049C28B /* SQLite-Bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SQLite-Bridging.h"; sourceTree = "<group>"; };
D03E454F2305C7600049C28B /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fts3_tokenizer.h; sourceTree = "<group>"; };
D03E45582305C8090049C28B /* sqlcipher_config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sqlcipher_config.h; sourceTree = "<group>"; };
D03E46162306DF740049C28B /* sqlciphermac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlciphermac.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E46182306DF740049C28B /* sqlciphermac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sqlciphermac.h; sourceTree = "<group>"; };
D03E46192306DF740049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -38,6 +48,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E46132306DF740049C28B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@ -46,6 +63,7 @@
children = (
D03E453F2305C6E40049C28B /* Info.plist */,
D03E453D2305C6E40049C28B /* Sources */,
D03E46172306DF740049C28B /* sqlciphermac */,
D03E453C2305C6E40049C28B /* Products */,
);
sourceTree = "<group>";
@ -54,6 +72,7 @@
isa = PBXGroup;
children = (
D03E453B2305C6E40049C28B /* sqlcipher.framework */,
D03E46162306DF740049C28B /* sqlciphermac.framework */,
);
name = Products;
sourceTree = "<group>";
@ -73,6 +92,15 @@
path = Sources;
sourceTree = "<group>";
};
D03E46172306DF740049C28B /* sqlciphermac */ = {
isa = PBXGroup;
children = (
D03E46182306DF740049C28B /* sqlciphermac.h */,
D03E46192306DF740049C28B /* Info.plist */,
);
path = sqlciphermac;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -89,6 +117,19 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E46112306DF740049C28B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D03E46222306DF8D0049C28B /* SQLite-Bridging.h in Headers */,
D03E46252306DF9A0049C28B /* sqlite3ext.h in Headers */,
D03E46212306DF8A0049C28B /* fts3_tokenizer.h in Headers */,
D03E46202306DF830049C28B /* sqlcipher_config.h in Headers */,
D03E461A2306DF740049C28B /* sqlciphermac.h in Headers */,
D03E46232306DF920049C28B /* sqlite3.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
@ -110,6 +151,24 @@
productReference = D03E453B2305C6E40049C28B /* sqlcipher.framework */;
productType = "com.apple.product-type.framework";
};
D03E46152306DF740049C28B /* sqlciphermac */ = {
isa = PBXNativeTarget;
buildConfigurationList = D03E461F2306DF740049C28B /* Build configuration list for PBXNativeTarget "sqlciphermac" */;
buildPhases = (
D03E46112306DF740049C28B /* Headers */,
D03E46122306DF740049C28B /* Sources */,
D03E46132306DF740049C28B /* Frameworks */,
D03E46142306DF740049C28B /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = sqlciphermac;
productName = sqlciphermac;
productReference = D03E46162306DF740049C28B /* sqlciphermac.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@ -123,6 +182,9 @@
D03E453A2305C6E40049C28B = {
CreatedOnToolsVersion = 10.3;
};
D03E46152306DF740049C28B = {
CreatedOnToolsVersion = 10.3;
};
};
};
buildConfigurationList = D03E45352305C6E40049C28B /* Build configuration list for PBXProject "sqlcipher_Xcode" */;
@ -138,6 +200,7 @@
projectRoot = "";
targets = (
D03E453A2305C6E40049C28B /* sqlcipher */,
D03E46152306DF740049C28B /* sqlciphermac */,
);
};
/* End PBXProject section */
@ -150,6 +213,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E46142306DF740049C28B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -162,6 +232,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D03E46122306DF740049C28B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D03E46262306DFA00049C28B /* sqlite3.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
@ -218,6 +296,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -274,6 +353,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -402,6 +482,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -491,6 +572,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -533,6 +615,344 @@
};
name = ReleaseHockeyappInternal;
};
D03E461B2306DF740049C28B /* DebugAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = sqlciphermac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = (
"-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
"-DNDEBUG",
);
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.sqlciphermac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = DebugAppStoreLLC;
};
D03E461C2306DF740049C28B /* DebugHockeyapp */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = sqlciphermac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = (
"-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
"-DNDEBUG",
);
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.sqlciphermac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = DebugHockeyapp;
};
D03E461D2306DF740049C28B /* ReleaseAppStoreLLC */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = sqlciphermac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (
"-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
"-DNDEBUG",
);
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.sqlciphermac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = ReleaseAppStoreLLC;
};
D03E461E2306DF740049C28B /* ReleaseHockeyappInternal */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = sqlciphermac/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (
"-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_DEFAULT_MEMSTATUS=0",
"-DNDEBUG",
);
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.sqlciphermac;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = ReleaseHockeyappInternal;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -558,6 +978,17 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = ReleaseAppStoreLLC;
};
D03E461F2306DF740049C28B /* Build configuration list for PBXNativeTarget "sqlciphermac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D03E461B2306DF740049C28B /* DebugAppStoreLLC */,
D03E461C2306DF740049C28B /* DebugHockeyapp */,
D03E461D2306DF740049C28B /* ReleaseAppStoreLLC */,
D03E461E2306DF740049C28B /* ReleaseHockeyappInternal */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = ReleaseAppStoreLLC;
};
/* End XCConfigurationList section */
};
rootObject = D03E45322305C6E40049C28B /* Project object */;

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 Telegram Messenger LLP. All rights reserved.</string>
</dict>
</plist>

View File

@ -0,0 +1,13 @@
#import <Cocoa/Cocoa.h>
//! Project version number for sqlciphermac.
FOUNDATION_EXPORT double sqlciphermacVersionNumber;
//! Project version string for sqlciphermac.
FOUNDATION_EXPORT const unsigned char sqlciphermacVersionString[];
#import <sqlciphermac/sqlcipher_config.h>
#import <sqlciphermac/sqlite3.h>
#import <sqlciphermac/sqlite3ext.h>