mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Added Watch reply preset settings
This commit is contained in:
parent
0d41a372c9
commit
95b6455f40
22
Images.xcassets/Settings/MenuIcons/Watch.imageset/Contents.json
vendored
Normal file
22
Images.xcassets/Settings/MenuIcons/Watch.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "SettingsWatchIcon@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "SettingsWatchIcon@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
BIN
Images.xcassets/Settings/MenuIcons/Watch.imageset/SettingsWatchIcon@2x.png
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/Watch.imageset/SettingsWatchIcon@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 925 B |
BIN
Images.xcassets/Settings/MenuIcons/Watch.imageset/SettingsWatchIcon@3x.png
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/Watch.imageset/SettingsWatchIcon@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 760 B |
@ -23,6 +23,12 @@
|
|||||||
0941A9A4210B0E2E00EBE194 /* OpenInAppIconResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0941A9A3210B0E2E00EBE194 /* OpenInAppIconResources.swift */; };
|
0941A9A4210B0E2E00EBE194 /* OpenInAppIconResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0941A9A3210B0E2E00EBE194 /* OpenInAppIconResources.swift */; };
|
||||||
0941A9A6210B822D00EBE194 /* OpenInOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0941A9A5210B822D00EBE194 /* OpenInOptions.swift */; };
|
0941A9A6210B822D00EBE194 /* OpenInOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0941A9A5210B822D00EBE194 /* OpenInOptions.swift */; };
|
||||||
0952D1752176DEB500194860 /* NotificationMuteSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0952D1742176DEB500194860 /* NotificationMuteSettingsController.swift */; };
|
0952D1752176DEB500194860 /* NotificationMuteSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0952D1742176DEB500194860 /* NotificationMuteSettingsController.swift */; };
|
||||||
|
0952D1772177FB5400194860 /* WatchPresetSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0952D1762177FB5400194860 /* WatchPresetSettings.swift */; };
|
||||||
|
096C98BA21787A5C00C211FF /* LegacyBridgeAudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C98B921787A5C00C211FF /* LegacyBridgeAudio.swift */; };
|
||||||
|
096C98BF21787C6700C211FF /* TGBridgeAudioEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 096C98BB21787C6600C211FF /* TGBridgeAudioEncoder.m */; };
|
||||||
|
096C98C021787C6700C211FF /* TGBridgeAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 096C98BC21787C6600C211FF /* TGBridgeAudioEncoder.h */; };
|
||||||
|
096C98C121787C6700C211FF /* TGBridgeAudioDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 096C98BD21787C6700C211FF /* TGBridgeAudioDecoder.h */; };
|
||||||
|
096C98C221787C6700C211FF /* TGBridgeAudioDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 096C98BE21787C6700C211FF /* TGBridgeAudioDecoder.mm */; };
|
||||||
09797873210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09797872210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift */; };
|
09797873210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09797872210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift */; };
|
||||||
0979787C210642CB0077D77F /* WebEmbedPlayerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787B210642CB0077D77F /* WebEmbedPlayerNode.swift */; };
|
0979787C210642CB0077D77F /* WebEmbedPlayerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787B210642CB0077D77F /* WebEmbedPlayerNode.swift */; };
|
||||||
0979787E210646C00077D77F /* YoutubeEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787D210646C00077D77F /* YoutubeEmbedImplementation.swift */; };
|
0979787E210646C00077D77F /* YoutubeEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787D210646C00077D77F /* YoutubeEmbedImplementation.swift */; };
|
||||||
@ -40,6 +46,8 @@
|
|||||||
09AE3823214C110900850BFD /* LegacySecureIdScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */; };
|
09AE3823214C110900850BFD /* LegacySecureIdScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */; };
|
||||||
09C3466D2167D63A00B76780 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C3466C2167D63A00B76780 /* Accessibility.swift */; };
|
09C3466D2167D63A00B76780 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C3466C2167D63A00B76780 /* Accessibility.swift */; };
|
||||||
09C500242142BA6400EF253E /* ItemListWebsiteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */; };
|
09C500242142BA6400EF253E /* ItemListWebsiteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */; };
|
||||||
|
09D304152173C0E900C00567 /* WatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D304142173C0E900C00567 /* WatchManager.swift */; };
|
||||||
|
09D304182173C15700C00567 /* WatchSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D304172173C15700C00567 /* WatchSettingsController.swift */; };
|
||||||
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
|
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
|
||||||
D007019C2029E8F2006B9E34 /* LegqacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.swift */; };
|
D007019C2029E8F2006B9E34 /* LegqacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.swift */; };
|
||||||
D007019E2029EFDD006B9E34 /* ICloudResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019D2029EFDD006B9E34 /* ICloudResources.swift */; };
|
D007019E2029EFDD006B9E34 /* ICloudResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019D2029EFDD006B9E34 /* ICloudResources.swift */; };
|
||||||
@ -1044,6 +1052,12 @@
|
|||||||
0941A9A3210B0E2E00EBE194 /* OpenInAppIconResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInAppIconResources.swift; sourceTree = "<group>"; };
|
0941A9A3210B0E2E00EBE194 /* OpenInAppIconResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInAppIconResources.swift; sourceTree = "<group>"; };
|
||||||
0941A9A5210B822D00EBE194 /* OpenInOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInOptions.swift; sourceTree = "<group>"; };
|
0941A9A5210B822D00EBE194 /* OpenInOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInOptions.swift; sourceTree = "<group>"; };
|
||||||
0952D1742176DEB500194860 /* NotificationMuteSettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationMuteSettingsController.swift; sourceTree = "<group>"; };
|
0952D1742176DEB500194860 /* NotificationMuteSettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationMuteSettingsController.swift; sourceTree = "<group>"; };
|
||||||
|
0952D1762177FB5400194860 /* WatchPresetSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WatchPresetSettings.swift; sourceTree = "<group>"; };
|
||||||
|
096C98B921787A5C00C211FF /* LegacyBridgeAudio.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyBridgeAudio.swift; sourceTree = "<group>"; };
|
||||||
|
096C98BB21787C6600C211FF /* TGBridgeAudioEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TGBridgeAudioEncoder.m; sourceTree = "<group>"; };
|
||||||
|
096C98BC21787C6600C211FF /* TGBridgeAudioEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGBridgeAudioEncoder.h; sourceTree = "<group>"; };
|
||||||
|
096C98BD21787C6700C211FF /* TGBridgeAudioDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGBridgeAudioDecoder.h; sourceTree = "<group>"; };
|
||||||
|
096C98BE21787C6700C211FF /* TGBridgeAudioDecoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TGBridgeAudioDecoder.mm; sourceTree = "<group>"; };
|
||||||
09797872210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageSettingsButtonItemNode.swift; sourceTree = "<group>"; };
|
09797872210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageSettingsButtonItemNode.swift; sourceTree = "<group>"; };
|
||||||
0979787B210642CB0077D77F /* WebEmbedPlayerNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebEmbedPlayerNode.swift; sourceTree = "<group>"; };
|
0979787B210642CB0077D77F /* WebEmbedPlayerNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebEmbedPlayerNode.swift; sourceTree = "<group>"; };
|
||||||
0979787D210646C00077D77F /* YoutubeEmbedImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeEmbedImplementation.swift; sourceTree = "<group>"; };
|
0979787D210646C00077D77F /* YoutubeEmbedImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeEmbedImplementation.swift; sourceTree = "<group>"; };
|
||||||
@ -1065,6 +1079,8 @@
|
|||||||
09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySecureIdScanController.swift; sourceTree = "<group>"; };
|
09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySecureIdScanController.swift; sourceTree = "<group>"; };
|
||||||
09C3466C2167D63A00B76780 /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = "<group>"; };
|
09C3466C2167D63A00B76780 /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = "<group>"; };
|
||||||
09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListWebsiteItem.swift; sourceTree = "<group>"; };
|
09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListWebsiteItem.swift; sourceTree = "<group>"; };
|
||||||
|
09D304142173C0E900C00567 /* WatchManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchManager.swift; sourceTree = "<group>"; };
|
||||||
|
09D304172173C15700C00567 /* WatchSettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchSettingsController.swift; sourceTree = "<group>"; };
|
||||||
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = "<group>"; };
|
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = "<group>"; };
|
||||||
D00219051DDD1C9E00BE708A /* ImageContainingNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageContainingNode.swift; sourceTree = "<group>"; };
|
D00219051DDD1C9E00BE708A /* ImageContainingNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageContainingNode.swift; sourceTree = "<group>"; };
|
||||||
D002A0D01E9B99F500A81812 /* SoftwareVideoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareVideoSource.swift; sourceTree = "<group>"; };
|
D002A0D01E9B99F500A81812 /* SoftwareVideoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareVideoSource.swift; sourceTree = "<group>"; };
|
||||||
@ -2213,6 +2229,18 @@
|
|||||||
name = "Open In";
|
name = "Open In";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0965C7152178738A007C94D0 /* Bridge Audio */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
096C98BD21787C6700C211FF /* TGBridgeAudioDecoder.h */,
|
||||||
|
096C98BE21787C6700C211FF /* TGBridgeAudioDecoder.mm */,
|
||||||
|
096C98BC21787C6600C211FF /* TGBridgeAudioEncoder.h */,
|
||||||
|
096C98BB21787C6600C211FF /* TGBridgeAudioEncoder.m */,
|
||||||
|
096C98B921787A5C00C211FF /* LegacyBridgeAudio.swift */,
|
||||||
|
);
|
||||||
|
name = "Bridge Audio";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
0979787F21065EAA0077D77F /* Web Embed */ = {
|
0979787F21065EAA0077D77F /* Web Embed */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -2245,6 +2273,14 @@
|
|||||||
name = "Web Embed";
|
name = "Web Embed";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
09D304162173C13500C00567 /* Watch */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
09D304172173C15700C00567 /* WatchSettingsController.swift */,
|
||||||
|
);
|
||||||
|
name = Watch;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D00C7CDA1E3776CA0080C3D5 /* Secret Preview */ = {
|
D00C7CDA1E3776CA0080C3D5 /* Secret Preview */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -2884,6 +2920,7 @@
|
|||||||
D07551891DDA4C7C0073E051 /* Legacy Components */ = {
|
D07551891DDA4C7C0073E051 /* Legacy Components */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0965C7152178738A007C94D0 /* Bridge Audio */,
|
||||||
D04BB2C61E48797500650E93 /* RMIntro */,
|
D04BB2C61E48797500650E93 /* RMIntro */,
|
||||||
D067B4AE211C916D00796039 /* Channel Intro */,
|
D067B4AE211C916D00796039 /* Channel Intro */,
|
||||||
D075518A1DDA4D7D0073E051 /* LegacyController.swift */,
|
D075518A1DDA4D7D0073E051 /* LegacyController.swift */,
|
||||||
@ -2999,6 +3036,7 @@
|
|||||||
D048B33A203C777500038D05 /* RenderedTotalUnreadCount.swift */,
|
D048B33A203C777500038D05 /* RenderedTotalUnreadCount.swift */,
|
||||||
D06ECFCA20B8448E00C576C2 /* ContactSynchronizationSettings.swift */,
|
D06ECFCA20B8448E00C576C2 /* ContactSynchronizationSettings.swift */,
|
||||||
D08A10BA211DF7A80077488B /* StickerSettings.swift */,
|
D08A10BA211DF7A80077488B /* StickerSettings.swift */,
|
||||||
|
0952D1762177FB5400194860 /* WatchPresetSettings.swift */,
|
||||||
);
|
);
|
||||||
name = Settings;
|
name = Settings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -4229,6 +4267,7 @@
|
|||||||
D0C9323A1E0B4AD40074F044 /* Data and Storage */,
|
D0C9323A1E0B4AD40074F044 /* Data and Storage */,
|
||||||
D0FA0AC31E7742EE005BB9B7 /* Stickers */,
|
D0FA0AC31E7742EE005BB9B7 /* Stickers */,
|
||||||
D05BFB4F1EA96EC100909D38 /* Themes */,
|
D05BFB4F1EA96EC100909D38 /* Themes */,
|
||||||
|
09D304162173C13500C00567 /* Watch */,
|
||||||
D0AF7C441ED84BB000CD8E0F /* Language Selection */,
|
D0AF7C441ED84BB000CD8E0F /* Language Selection */,
|
||||||
D0CB27D020C17A6D001ACF93 /* Terms of Service */,
|
D0CB27D020C17A6D001ACF93 /* Terms of Service */,
|
||||||
D01B279A1E39386C0022A4C0 /* SettingsController.swift */,
|
D01B279A1E39386C0022A4C0 /* SettingsController.swift */,
|
||||||
@ -4284,6 +4323,7 @@
|
|||||||
D0383ED5207D19BC00C45548 /* Emoji */,
|
D0383ED5207D19BC00C45548 /* Emoji */,
|
||||||
D0B69C3A20EBD8B3003632C7 /* Device Access */,
|
D0B69C3A20EBD8B3003632C7 /* Device Access */,
|
||||||
D01C7EFE1EF9D434008305F1 /* Device Contacts */,
|
D01C7EFE1EF9D434008305F1 /* Device Contacts */,
|
||||||
|
09D304142173C0E900C00567 /* WatchManager.swift */,
|
||||||
D0B844551DAC3AEE005F29E1 /* PresenceStrings.swift */,
|
D0B844551DAC3AEE005F29E1 /* PresenceStrings.swift */,
|
||||||
D08775081E3E59DE00A97350 /* PeerNotificationSoundStrings.swift */,
|
D08775081E3E59DE00A97350 /* PeerNotificationSoundStrings.swift */,
|
||||||
D0F69E931D6B8C9B0046BCD6 /* ProgressiveImage.swift */,
|
D0F69E931D6B8C9B0046BCD6 /* ProgressiveImage.swift */,
|
||||||
@ -4465,6 +4505,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0E9BA221F05577700F079A4 /* STPCard.h in Headers */,
|
D0E9BA221F05577700F079A4 /* STPCard.h in Headers */,
|
||||||
|
096C98C021787C6700C211FF /* TGBridgeAudioEncoder.h in Headers */,
|
||||||
D0E9BA591F055A2200F079A4 /* STPWeakStrongMacros.h in Headers */,
|
D0E9BA591F055A2200F079A4 /* STPWeakStrongMacros.h in Headers */,
|
||||||
D0E9BADE1F0574D800F079A4 /* STPBackendAPIAdapter.h in Headers */,
|
D0E9BADE1F0574D800F079A4 /* STPBackendAPIAdapter.h in Headers */,
|
||||||
D0E9BAD11F0573C000F079A4 /* STPToken.h in Headers */,
|
D0E9BAD11F0573C000F079A4 /* STPToken.h in Headers */,
|
||||||
@ -4495,6 +4536,7 @@
|
|||||||
D06F31E22135829B001A0F12 /* EDSunriseSet.h in Headers */,
|
D06F31E22135829B001A0F12 /* EDSunriseSet.h in Headers */,
|
||||||
D0E9BA531F0559DA00F079A4 /* STPImageLibrary+Private.h in Headers */,
|
D0E9BA531F0559DA00F079A4 /* STPImageLibrary+Private.h in Headers */,
|
||||||
D0E9BA601F055A4300F079A4 /* STPDelegateProxy.h in Headers */,
|
D0E9BA601F055A4300F079A4 /* STPDelegateProxy.h in Headers */,
|
||||||
|
096C98C121787C6700C211FF /* TGBridgeAudioDecoder.h in Headers */,
|
||||||
D0E9BADF1F0574D800F079A4 /* STPDispatchFunctions.h in Headers */,
|
D0E9BADF1F0574D800F079A4 /* STPDispatchFunctions.h in Headers */,
|
||||||
D0E9BACB1F05738600F079A4 /* STPAPIPostRequest.h in Headers */,
|
D0E9BACB1F05738600F079A4 /* STPAPIPostRequest.h in Headers */,
|
||||||
D0E9BA561F055A0B00F079A4 /* STPFormTextField.h in Headers */,
|
D0E9BA561F055A0B00F079A4 /* STPFormTextField.h in Headers */,
|
||||||
@ -4717,6 +4759,7 @@
|
|||||||
D0208ADC1FA346A4001F0D5F /* RaiseToListen.swift in Sources */,
|
D0208ADC1FA346A4001F0D5F /* RaiseToListen.swift in Sources */,
|
||||||
D0EB41F91F30E5B700838FE6 /* LegacyPeerAvatarPlaceholderDataSource.swift in Sources */,
|
D0EB41F91F30E5B700838FE6 /* LegacyPeerAvatarPlaceholderDataSource.swift in Sources */,
|
||||||
D0EC6CBB1EB9F58800EBF1C3 /* texture_helper.m in Sources */,
|
D0EC6CBB1EB9F58800EBF1C3 /* texture_helper.m in Sources */,
|
||||||
|
09D304182173C15700C00567 /* WatchSettingsController.swift in Sources */,
|
||||||
D0EC6CBC1EB9F58800EBF1C3 /* LegacyController.swift in Sources */,
|
D0EC6CBC1EB9F58800EBF1C3 /* LegacyController.swift in Sources */,
|
||||||
D0EC6CBD1EB9F58800EBF1C3 /* LegacyControllerNode.swift in Sources */,
|
D0EC6CBD1EB9F58800EBF1C3 /* LegacyControllerNode.swift in Sources */,
|
||||||
D079FCE91F06A76C0038FADE /* Notices.swift in Sources */,
|
D079FCE91F06A76C0038FADE /* Notices.swift in Sources */,
|
||||||
@ -4841,6 +4884,7 @@
|
|||||||
D0ACCB1A1EC5E0C20079D8BF /* CallControllerKeyPreviewNode.swift in Sources */,
|
D0ACCB1A1EC5E0C20079D8BF /* CallControllerKeyPreviewNode.swift in Sources */,
|
||||||
D0E9BA611F055A4300F079A4 /* STPDelegateProxy.m in Sources */,
|
D0E9BA611F055A4300F079A4 /* STPDelegateProxy.m in Sources */,
|
||||||
D0EC6CF91EB9F58800EBF1C3 /* MediaManager.swift in Sources */,
|
D0EC6CF91EB9F58800EBF1C3 /* MediaManager.swift in Sources */,
|
||||||
|
096C98BF21787C6700C211FF /* TGBridgeAudioEncoder.m in Sources */,
|
||||||
D01776B81F1D6FB30044446D /* RadialProgressContentNode.swift in Sources */,
|
D01776B81F1D6FB30044446D /* RadialProgressContentNode.swift in Sources */,
|
||||||
D0EC6CFA1EB9F58800EBF1C3 /* ManagedAudioSession.swift in Sources */,
|
D0EC6CFA1EB9F58800EBF1C3 /* ManagedAudioSession.swift in Sources */,
|
||||||
D0EB5ADF1F798033004E89B6 /* PeerMediaCollectionEmptyNode.swift in Sources */,
|
D0EB5ADF1F798033004E89B6 /* PeerMediaCollectionEmptyNode.swift in Sources */,
|
||||||
@ -4977,6 +5021,7 @@
|
|||||||
D0EC6D3F1EB9F58800EBF1C3 /* MediaNavigationAccessoryPanel.swift in Sources */,
|
D0EC6D3F1EB9F58800EBF1C3 /* MediaNavigationAccessoryPanel.swift in Sources */,
|
||||||
D0E9BA3B1F0558E800F079A4 /* NSString+Stripe.m in Sources */,
|
D0E9BA3B1F0558E800F079A4 /* NSString+Stripe.m in Sources */,
|
||||||
D0CE8CE51F6F354400AA2DB0 /* ChatTextInputAccessoryItem.swift in Sources */,
|
D0CE8CE51F6F354400AA2DB0 /* ChatTextInputAccessoryItem.swift in Sources */,
|
||||||
|
096C98BA21787A5C00C211FF /* LegacyBridgeAudio.swift in Sources */,
|
||||||
D0EC6D401EB9F58800EBF1C3 /* MediaNavigationAccessoryContainerNode.swift in Sources */,
|
D0EC6D401EB9F58800EBF1C3 /* MediaNavigationAccessoryContainerNode.swift in Sources */,
|
||||||
D0E266FD1F66706500BFC79F /* ChatBubbleVideoDecoration.swift in Sources */,
|
D0E266FD1F66706500BFC79F /* ChatBubbleVideoDecoration.swift in Sources */,
|
||||||
D0EC6D411EB9F58800EBF1C3 /* MediaNavigationAccessoryHeaderNode.swift in Sources */,
|
D0EC6D411EB9F58800EBF1C3 /* MediaNavigationAccessoryHeaderNode.swift in Sources */,
|
||||||
@ -5002,6 +5047,7 @@
|
|||||||
D0208ADA1FA34017001F0D5F /* DeviceProximityManager.m in Sources */,
|
D0208ADA1FA34017001F0D5F /* DeviceProximityManager.m in Sources */,
|
||||||
D04281FC200E61BC009DDE36 /* ChatRecentActionsInteraction.swift in Sources */,
|
D04281FC200E61BC009DDE36 /* ChatRecentActionsInteraction.swift in Sources */,
|
||||||
D0EC6D561EB9F58800EBF1C3 /* ChatHistoryNode.swift in Sources */,
|
D0EC6D561EB9F58800EBF1C3 /* ChatHistoryNode.swift in Sources */,
|
||||||
|
096C98C221787C6700C211FF /* TGBridgeAudioDecoder.mm in Sources */,
|
||||||
D0EC6D571EB9F58800EBF1C3 /* ChatHistoryListNode.swift in Sources */,
|
D0EC6D571EB9F58800EBF1C3 /* ChatHistoryListNode.swift in Sources */,
|
||||||
D0EC6D581EB9F58800EBF1C3 /* ChatHistoryGridNode.swift in Sources */,
|
D0EC6D581EB9F58800EBF1C3 /* ChatHistoryGridNode.swift in Sources */,
|
||||||
D0B2F76E2052B59F00D3BFB9 /* InviteContactsController.swift in Sources */,
|
D0B2F76E2052B59F00D3BFB9 /* InviteContactsController.swift in Sources */,
|
||||||
@ -5131,6 +5177,7 @@
|
|||||||
D0147BA7206E8B4F00E40378 /* SecureIdAuthAcceptNode.swift in Sources */,
|
D0147BA7206E8B4F00E40378 /* SecureIdAuthAcceptNode.swift in Sources */,
|
||||||
D0E8174E2011FC3800B82BBB /* ChatMessageEventLogPreviousDescriptionContentNode.swift in Sources */,
|
D0E8174E2011FC3800B82BBB /* ChatMessageEventLogPreviousDescriptionContentNode.swift in Sources */,
|
||||||
D0EC6D981EB9F58900EBF1C3 /* ChatMessageItemView.swift in Sources */,
|
D0EC6D981EB9F58900EBF1C3 /* ChatMessageItemView.swift in Sources */,
|
||||||
|
09D304152173C0E900C00567 /* WatchManager.swift in Sources */,
|
||||||
D039FB1921711B5D00BD1BAD /* PlatformVideoContent.swift in Sources */,
|
D039FB1921711B5D00BD1BAD /* PlatformVideoContent.swift in Sources */,
|
||||||
D0CAD8FD20AE467D00ACD96E /* PeerChannelMemberCategoriesContextsManager.swift in Sources */,
|
D0CAD8FD20AE467D00ACD96E /* PeerChannelMemberCategoriesContextsManager.swift in Sources */,
|
||||||
D073D2DB1FB61DA9009E1DA2 /* CallListSettings.swift in Sources */,
|
D073D2DB1FB61DA9009E1DA2 /* CallListSettings.swift in Sources */,
|
||||||
@ -5360,6 +5407,7 @@
|
|||||||
D0EC6E171EB9F58900EBF1C3 /* InstantPageTextStyleStack.swift in Sources */,
|
D0EC6E171EB9F58900EBF1C3 /* InstantPageTextStyleStack.swift in Sources */,
|
||||||
D0EC6E181EB9F58900EBF1C3 /* InstantPageTextItem.swift in Sources */,
|
D0EC6E181EB9F58900EBF1C3 /* InstantPageTextItem.swift in Sources */,
|
||||||
D01C06B51FBB7720001561AB /* ChatMediaInputSettingsItem.swift in Sources */,
|
D01C06B51FBB7720001561AB /* ChatMediaInputSettingsItem.swift in Sources */,
|
||||||
|
0952D1772177FB5400194860 /* WatchPresetSettings.swift in Sources */,
|
||||||
D091C7A61F8ECEA300D7DE13 /* SettingsThemeWallpaperNode.swift in Sources */,
|
D091C7A61F8ECEA300D7DE13 /* SettingsThemeWallpaperNode.swift in Sources */,
|
||||||
D0EC6E191EB9F58900EBF1C3 /* InstantPageAnchorItem.swift in Sources */,
|
D0EC6E191EB9F58900EBF1C3 /* InstantPageAnchorItem.swift in Sources */,
|
||||||
D05677531F4CA0D0001B723E /* InstantPagePeerReferenceNode.swift in Sources */,
|
D05677531F4CA0D0001B723E /* InstantPagePeerReferenceNode.swift in Sources */,
|
||||||
|
@ -311,8 +311,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if file.isAnimated {
|
if file.isAnimated {
|
||||||
strongSelf.fetchDisposable.set(fetchedMediaResource(postbox: account.postbox, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes)).start())
|
strongSelf.fetchDisposable.set(fetchedMediaResource(postbox: account.postbox, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes)).start())
|
||||||
} else {
|
} else {
|
||||||
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: manual).start())
|
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: manual).start())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, cancel: {
|
}, cancel: {
|
||||||
|
@ -26,6 +26,7 @@ private var telegramUIDeclaredEncodables: Void = {
|
|||||||
declareEncodable(CachedChannelAdminIds.self, f: { CachedChannelAdminIds(decoder: $0) })
|
declareEncodable(CachedChannelAdminIds.self, f: { CachedChannelAdminIds(decoder: $0) })
|
||||||
declareEncodable(StickerSettings.self, f: { StickerSettings(decoder: $0) })
|
declareEncodable(StickerSettings.self, f: { StickerSettings(decoder: $0) })
|
||||||
declareEncodable(InstantPagePresentationSettings.self, f: { InstantPagePresentationSettings(decoder: $0) })
|
declareEncodable(InstantPagePresentationSettings.self, f: { InstantPagePresentationSettings(decoder: $0) })
|
||||||
|
declareEncodable(WatchPresetSettings.self, f: { WatchPresetSettings(decoder: $0) })
|
||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import TelegramCore
|
|||||||
import Postbox
|
import Postbox
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
|
||||||
func freeMediaFileInteractiveFetched(account: Account, fileReference: FileMediaReference) -> Signal<FetchResourceSourceType, NoError> {
|
public func freeMediaFileInteractiveFetched(account: Account, fileReference: FileMediaReference) -> Signal<FetchResourceSourceType, NoError> {
|
||||||
return fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(fileReference.media.resource))
|
return fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(fileReference.media.resource))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ private func fetchCategoryForFile(_ file: TelegramMediaFile) -> FetchManagerCate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func messageMediaFileInteractiveFetched(account: Account, message: Message, file: TelegramMediaFile, userInitiated: Bool) -> Signal<Void, NoError> {
|
public func messageMediaFileInteractiveFetched(account: Account, message: Message, file: TelegramMediaFile, userInitiated: Bool) -> Signal<Void, NoError> {
|
||||||
return account.telegramApplicationContext.fetchManager.interactivelyFetched(category: fetchCategoryForFile(file), location: .chat(message.id.peerId), locationKey: .messageId(message.id), resourceReference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes), elevatedPriority: false, userInitiated: userInitiated)
|
return account.telegramApplicationContext.fetchManager.interactivelyFetched(category: fetchCategoryForFile(file), location: .chat(message.id.peerId), locationKey: .messageId(message.id), resourceReference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes), elevatedPriority: false, userInitiated: userInitiated)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ func messageMediaFileCancelInteractiveFetch(account: Account, messageId: Message
|
|||||||
account.telegramApplicationContext.fetchManager.cancelInteractiveFetches(category: fetchCategoryForFile(file), location: .chat(messageId.peerId), locationKey: .messageId(messageId), resource: file.resource)
|
account.telegramApplicationContext.fetchManager.cancelInteractiveFetches(category: fetchCategoryForFile(file), location: .chat(messageId.peerId), locationKey: .messageId(messageId), resource: file.resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
func messageMediaImageInteractiveFetched(account: Account, message: Message, image: TelegramMediaImage, resource: MediaResource) -> Signal<Void, NoError> {
|
public func messageMediaImageInteractiveFetched(account: Account, message: Message, image: TelegramMediaImage, resource: MediaResource) -> Signal<Void, NoError> {
|
||||||
return account.telegramApplicationContext.fetchManager.interactivelyFetched(category: .image, location: .chat(message.id.peerId), locationKey: .messageId(message.id), resourceReference: AnyMediaReference.message(message: MessageReference(message), media: image).resourceReference(resource), statsCategory: .image, elevatedPriority: false, userInitiated: true)
|
return account.telegramApplicationContext.fetchManager.interactivelyFetched(category: .image, location: .chat(message.id.peerId), locationKey: .messageId(message.id), resourceReference: AnyMediaReference.message(message: MessageReference(message), media: image).resourceReference(resource), statsCategory: .image, elevatedPriority: false, userInitiated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
TelegramUI/LegacyBridgeAudio.swift
Normal file
26
TelegramUI/LegacyBridgeAudio.swift
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
import TelegramUIPrivateModule
|
||||||
|
|
||||||
|
public func legacyDecodeOpusAudio(path: String, outputPath: String) -> Signal<String, NoError> {
|
||||||
|
return Signal { subscriber in
|
||||||
|
let decoder = TGBridgeAudioDecoder(url: URL(fileURLWithPath: path), outputUrl: URL(fileURLWithPath: outputPath))
|
||||||
|
decoder?.start(completion: {
|
||||||
|
subscriber.putNext(outputPath)
|
||||||
|
subscriber.putCompletion()
|
||||||
|
})
|
||||||
|
return EmptyDisposable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func legacyEncodeOpusAudio(path: String) -> Signal<(Data?, Int32), NoError> {
|
||||||
|
return Signal { subscriber in
|
||||||
|
let encoder = TGBridgeAudioEncoder(url: URL(fileURLWithPath: path))
|
||||||
|
encoder?.start(completion: { (dataItem, duration) in
|
||||||
|
subscriber.putNext((dataItem?.data(), duration))
|
||||||
|
subscriber.putCompletion()
|
||||||
|
})
|
||||||
|
return EmptyDisposable
|
||||||
|
}
|
||||||
|
}
|
@ -663,7 +663,7 @@ public func chatMessagePhotoInternal(photoData: Signal<(Data?, Data?, Bool), NoE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func chatMessagePhotoThumbnailDatas(account: Account, photoReference: ImageMediaReference) -> Signal<(Data?, Data?, Bool), NoError> {
|
private func chatMessagePhotoThumbnailDatas(account: Account, photoReference: ImageMediaReference, onlyFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
|
||||||
let fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0)
|
let fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0)
|
||||||
if let smallestRepresentation = smallestImageRepresentation(photoReference.media.representations), let largestRepresentation = photoReference.media.representationForDisplayAtSize(fullRepresentationSize) {
|
if let smallestRepresentation = smallestImageRepresentation(photoReference.media.representations), let largestRepresentation = photoReference.media.representationForDisplayAtSize(fullRepresentationSize) {
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ private enum ApplicationSpecificPreferencesKeyValues: Int32 {
|
|||||||
case experimentalUISettings = 11
|
case experimentalUISettings = 11
|
||||||
case contactSynchronizationSettings = 12
|
case contactSynchronizationSettings = 12
|
||||||
case stickerSettings = 13
|
case stickerSettings = 13
|
||||||
|
case watchPresetSettings = 14
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ApplicationSpecificPreferencesKeys {
|
public struct ApplicationSpecificPreferencesKeys {
|
||||||
@ -34,4 +35,5 @@ public struct ApplicationSpecificPreferencesKeys {
|
|||||||
public static let experimentalUISettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.experimentalUISettings.rawValue)
|
public static let experimentalUISettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.experimentalUISettings.rawValue)
|
||||||
public static let contactSynchronizationSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.contactSynchronizationSettings.rawValue)
|
public static let contactSynchronizationSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.contactSynchronizationSettings.rawValue)
|
||||||
public static let stickerSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.stickerSettings.rawValue)
|
public static let stickerSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.stickerSettings.rawValue)
|
||||||
|
public static let watchPresetSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.watchPresetSettings.rawValue)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ private final class SettingsItemIcons {
|
|||||||
static let appearance = UIImage(bundleImageName: "Settings/MenuIcons/Appearance")?.precomposed()
|
static let appearance = UIImage(bundleImageName: "Settings/MenuIcons/Appearance")?.precomposed()
|
||||||
static let language = UIImage(bundleImageName: "Settings/MenuIcons/Language")?.precomposed()
|
static let language = UIImage(bundleImageName: "Settings/MenuIcons/Language")?.precomposed()
|
||||||
|
|
||||||
static let secureId = UIImage(bundleImageName: "Settings/MenuIcons/Passport")?.precomposed()
|
static let passport = UIImage(bundleImageName: "Settings/MenuIcons/Passport")?.precomposed()
|
||||||
|
static let watch = UIImage(bundleImageName: "Settings/MenuIcons/Watch")?.precomposed()
|
||||||
|
|
||||||
static let support = UIImage(bundleImageName: "Settings/MenuIcons/Support")?.precomposed()
|
static let support = UIImage(bundleImageName: "Settings/MenuIcons/Support")?.precomposed()
|
||||||
static let faq = UIImage(bundleImageName: "Settings/MenuIcons/Faq")?.precomposed()
|
static let faq = UIImage(bundleImageName: "Settings/MenuIcons/Faq")?.precomposed()
|
||||||
@ -42,6 +43,7 @@ private struct SettingsItemArguments {
|
|||||||
let presentController: (ViewController) -> Void
|
let presentController: (ViewController) -> Void
|
||||||
let openLanguage: () -> Void
|
let openLanguage: () -> Void
|
||||||
let openPassport: () -> Void
|
let openPassport: () -> Void
|
||||||
|
let openWatch: () -> Void
|
||||||
let openSupport: () -> Void
|
let openSupport: () -> Void
|
||||||
let openFaq: () -> Void
|
let openFaq: () -> Void
|
||||||
let openEditing: () -> Void
|
let openEditing: () -> Void
|
||||||
@ -54,7 +56,7 @@ private enum SettingsSection: Int32 {
|
|||||||
case proxy
|
case proxy
|
||||||
case media
|
case media
|
||||||
case generalSettings
|
case generalSettings
|
||||||
case passport
|
case advanced
|
||||||
case help
|
case help
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +77,7 @@ private enum SettingsEntry: ItemListNodeEntry {
|
|||||||
case themes(PresentationTheme, UIImage?, String)
|
case themes(PresentationTheme, UIImage?, String)
|
||||||
case language(PresentationTheme, UIImage?, String, String)
|
case language(PresentationTheme, UIImage?, String, String)
|
||||||
case passport(PresentationTheme, UIImage?, String, String)
|
case passport(PresentationTheme, UIImage?, String, String)
|
||||||
|
case watch(PresentationTheme, UIImage?, String, String)
|
||||||
|
|
||||||
case askAQuestion(PresentationTheme, UIImage?, String)
|
case askAQuestion(PresentationTheme, UIImage?, String)
|
||||||
case faq(PresentationTheme, UIImage?, String)
|
case faq(PresentationTheme, UIImage?, String)
|
||||||
@ -89,8 +92,8 @@ private enum SettingsEntry: ItemListNodeEntry {
|
|||||||
return SettingsSection.media.rawValue
|
return SettingsSection.media.rawValue
|
||||||
case .notificationsAndSounds, .privacyAndSecurity, .dataAndStorage, .themes, .language:
|
case .notificationsAndSounds, .privacyAndSecurity, .dataAndStorage, .themes, .language:
|
||||||
return SettingsSection.generalSettings.rawValue
|
return SettingsSection.generalSettings.rawValue
|
||||||
case .passport:
|
case .passport, .watch :
|
||||||
return SettingsSection.passport.rawValue
|
return SettingsSection.advanced.rawValue
|
||||||
case .askAQuestion, .faq:
|
case .askAQuestion, .faq:
|
||||||
return SettingsSection.help.rawValue
|
return SettingsSection.help.rawValue
|
||||||
}
|
}
|
||||||
@ -124,10 +127,12 @@ private enum SettingsEntry: ItemListNodeEntry {
|
|||||||
return 11
|
return 11
|
||||||
case .passport:
|
case .passport:
|
||||||
return 12
|
return 12
|
||||||
case .askAQuestion:
|
case .watch:
|
||||||
return 13
|
return 13
|
||||||
case .faq:
|
case .askAQuestion:
|
||||||
return 14
|
return 14
|
||||||
|
case .faq:
|
||||||
|
return 15
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,6 +245,12 @@ private enum SettingsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case let .watch(lhsTheme, lhsImage, lhsText, lhsValue):
|
||||||
|
if case let .watch(rhsTheme, rhsImage, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsImage === rhsImage, lhsText == rhsText, lhsValue == rhsValue {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
case let .askAQuestion(lhsTheme, lhsImage, lhsText):
|
case let .askAQuestion(lhsTheme, lhsImage, lhsText):
|
||||||
if case let .askAQuestion(rhsTheme, rhsImage, rhsText) = rhs, lhsTheme === rhsTheme, lhsImage === rhsImage, lhsText == rhsText {
|
if case let .askAQuestion(rhsTheme, rhsImage, rhsText) = rhs, lhsTheme === rhsTheme, lhsImage === rhsImage, lhsText == rhsText {
|
||||||
return true
|
return true
|
||||||
@ -320,6 +331,10 @@ private enum SettingsEntry: ItemListNodeEntry {
|
|||||||
return ItemListDisclosureItem(theme: theme, icon: image, title: text, label: value, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
return ItemListDisclosureItem(theme: theme, icon: image, title: text, label: value, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||||
arguments.openPassport()
|
arguments.openPassport()
|
||||||
})
|
})
|
||||||
|
case let .watch(theme, image, text, value):
|
||||||
|
return ItemListDisclosureItem(theme: theme, icon: image, title: text, label: value, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||||
|
arguments.openWatch()
|
||||||
|
})
|
||||||
case let .askAQuestion(theme, image, text):
|
case let .askAQuestion(theme, image, text):
|
||||||
return ItemListDisclosureItem(theme: theme, icon: image, title: text, label: "", sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
return ItemListDisclosureItem(theme: theme, icon: image, title: text, label: "", sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||||
arguments.openSupport()
|
arguments.openSupport()
|
||||||
@ -351,7 +366,7 @@ private struct SettingsState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func settingsEntries(presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?, hasPassport: Bool) -> [SettingsEntry] {
|
private func settingsEntries(presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?, hasPassport: Bool, hasWatchApp: Bool) -> [SettingsEntry] {
|
||||||
var entries: [SettingsEntry] = []
|
var entries: [SettingsEntry] = []
|
||||||
|
|
||||||
if let peer = peerViewMainPeer(view) as? TelegramUser {
|
if let peer = peerViewMainPeer(view) as? TelegramUser {
|
||||||
@ -390,7 +405,10 @@ private func settingsEntries(presentationData: PresentationData, state: Settings
|
|||||||
entries.append(.language(presentationData.theme, SettingsItemIcons.language, presentationData.strings.Settings_AppLanguage, presentationData.strings.Localization_LanguageName))
|
entries.append(.language(presentationData.theme, SettingsItemIcons.language, presentationData.strings.Settings_AppLanguage, presentationData.strings.Localization_LanguageName))
|
||||||
|
|
||||||
if hasPassport {
|
if hasPassport {
|
||||||
entries.append(.passport(presentationData.theme, SettingsItemIcons.secureId, presentationData.strings.Settings_Passport, ""))
|
entries.append(.passport(presentationData.theme, SettingsItemIcons.passport, presentationData.strings.Settings_Passport, ""))
|
||||||
|
}
|
||||||
|
if hasWatchApp {
|
||||||
|
entries.append(.watch(presentationData.theme, SettingsItemIcons.watch, presentationData.strings.Settings_AppleWatch, ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.append(.askAQuestion(presentationData.theme, SettingsItemIcons.support, presentationData.strings.Settings_Support))
|
entries.append(.askAQuestion(presentationData.theme, SettingsItemIcons.support, presentationData.strings.Settings_Support))
|
||||||
@ -516,6 +534,9 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
|||||||
}, openPassport: {
|
}, openPassport: {
|
||||||
let controller = SecureIdAuthController(account: account, mode: .list)
|
let controller = SecureIdAuthController(account: account, mode: .list)
|
||||||
presentControllerImpl?(controller, nil)
|
presentControllerImpl?(controller, nil)
|
||||||
|
}, openWatch: {
|
||||||
|
let controller = watchSettingsController(account: account)
|
||||||
|
pushControllerImpl?(controller)
|
||||||
}, openSupport: {
|
}, openSupport: {
|
||||||
let supportPeer = Promise<PeerId?>()
|
let supportPeer = Promise<PeerId?>()
|
||||||
supportPeer.set(supportPeerId(account: account))
|
supportPeer.set(supportPeerId(account: account))
|
||||||
@ -654,8 +675,13 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
|||||||
}
|
}
|
||||||
updatePassport()
|
updatePassport()
|
||||||
|
|
||||||
let signal = combineLatest(account.telegramApplicationContext.presentationData, statePromise.get(), peerView, account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings]), combineLatest(account.viewTracker.featuredStickerPacks(), archivedPacks.get()), hasPassport.get())
|
let hasWatchApp = Promise<Bool>(false)
|
||||||
|> map { presentationData, state, view, preferences, featuredAndArchived, hasPassport -> (ItemListControllerState, (ItemListNodeState<SettingsEntry>, SettingsEntry.ItemGenerationArguments)) in
|
if let context = account.applicationContext as? TelegramApplicationContext, let watchManager = context.watchManager {
|
||||||
|
hasWatchApp.set(watchManager.watchAppInstalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
let signal = combineLatest(account.telegramApplicationContext.presentationData, statePromise.get(), peerView, account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings]), combineLatest(account.viewTracker.featuredStickerPacks(), archivedPacks.get()), combineLatest(hasPassport.get(), hasWatchApp.get()))
|
||||||
|
|> map { presentationData, state, view, preferences, featuredAndArchived, hasPassportAndWatch -> (ItemListControllerState, (ItemListNodeState<SettingsEntry>, SettingsEntry.ItemGenerationArguments)) in
|
||||||
let proxySettings: ProxySettings
|
let proxySettings: ProxySettings
|
||||||
if let value = preferences.values[PreferencesKeys.proxySettings] as? ProxySettings {
|
if let value = preferences.values[PreferencesKeys.proxySettings] as? ProxySettings {
|
||||||
proxySettings = value
|
proxySettings = value
|
||||||
@ -679,7 +705,9 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let listState = ItemListNodeState(entries: settingsEntries(presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, hasPassport: hasPassport), style: .blocks)
|
let (hasPassport, hasWatchApp) = hasPassportAndWatch
|
||||||
|
|
||||||
|
let listState = ItemListNodeState(entries: settingsEntries(presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, hasPassport: hasPassport, hasWatchApp: hasWatchApp), style: .blocks)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
} |> afterDisposed {
|
} |> afterDisposed {
|
||||||
|
@ -147,7 +147,7 @@ public func chatMessageSticker(account: Account, file: TelegramMediaFile, small:
|
|||||||
|
|
||||||
return signal |> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
return signal |> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||||
return { arguments in
|
return { arguments in
|
||||||
let context = DrawingContext(size: arguments.drawingSize, clear: true)
|
let context = DrawingContext(size: arguments.drawingSize, clear: arguments.emptyColor == nil)
|
||||||
|
|
||||||
let drawingRect = arguments.drawingRect
|
let drawingRect = arguments.drawingRect
|
||||||
let fittedSize = arguments.imageSize
|
let fittedSize = arguments.imageSize
|
||||||
@ -179,6 +179,10 @@ public func chatMessageSticker(account: Account, file: TelegramMediaFile, small:
|
|||||||
|
|
||||||
context.withFlippedContext { c in
|
context.withFlippedContext { c in
|
||||||
c.setBlendMode(.copy)
|
c.setBlendMode(.copy)
|
||||||
|
if let color = arguments.emptyColor {
|
||||||
|
c.fill(drawingRect)
|
||||||
|
}
|
||||||
|
|
||||||
if let blurredThumbnailImage = blurredThumbnailImage {
|
if let blurredThumbnailImage = blurredThumbnailImage {
|
||||||
c.interpolationQuality = .low
|
c.interpolationQuality = .low
|
||||||
c.draw(blurredThumbnailImage.cgImage!, in: fittedRect)
|
c.draw(blurredThumbnailImage.cgImage!, in: fittedRect)
|
||||||
|
@ -523,7 +523,7 @@ func storageUsageController(account: Account) -> ViewController {
|
|||||||
if !items.isEmpty {
|
if !items.isEmpty {
|
||||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize))").0, action: {
|
items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize))").0, action: {
|
||||||
if let statsPromise = statsPromise {
|
if let statsPromise = statsPromise {
|
||||||
var clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 })
|
let clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 })
|
||||||
//var clearSize: Int64 = 0
|
//var clearSize: Int64 = 0
|
||||||
|
|
||||||
var clearMediaIds = Set<MediaId>()
|
var clearMediaIds = Set<MediaId>()
|
||||||
|
8
TelegramUI/TGBridgeAudioDecoder.h
Normal file
8
TelegramUI/TGBridgeAudioDecoder.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface TGBridgeAudioDecoder : NSObject
|
||||||
|
|
||||||
|
- (instancetype)initWithURL:(NSURL *)url outputUrl:(NSURL *)outputURL;
|
||||||
|
- (void)startWithCompletion:(void (^)(void))completion;
|
||||||
|
|
||||||
|
@end
|
200
TelegramUI/TGBridgeAudioDecoder.mm
Normal file
200
TelegramUI/TGBridgeAudioDecoder.mm
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#import "TGBridgeAudioDecoder.h"
|
||||||
|
|
||||||
|
#import <AudioToolbox/AudioToolbox.h>
|
||||||
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
|
||||||
|
#import <SSignalKit/SSignalKit.h>
|
||||||
|
|
||||||
|
#import "opusfile.h"
|
||||||
|
#import "opusenc.h"
|
||||||
|
|
||||||
|
const NSInteger TGBridgeAudioDecoderInputSampleRate = 48000;
|
||||||
|
const NSInteger TGBridgeAudioDecoderResultSampleRate = 24000;
|
||||||
|
const NSUInteger TGBridgeAudioDecoderBufferSize = 32768;
|
||||||
|
|
||||||
|
#define checkResult(result,operation) (_checkResultLite((result),(operation),__FILE__,__LINE__))
|
||||||
|
|
||||||
|
struct TGAudioBuffer
|
||||||
|
{
|
||||||
|
NSUInteger capacity;
|
||||||
|
uint8_t *data;
|
||||||
|
NSUInteger size;
|
||||||
|
int64_t pcmOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline TGAudioBuffer *TGAudioBufferWithCapacity(NSUInteger capacity)
|
||||||
|
{
|
||||||
|
TGAudioBuffer *audioBuffer = (TGAudioBuffer *)malloc(sizeof(TGAudioBuffer));
|
||||||
|
audioBuffer->capacity = capacity;
|
||||||
|
audioBuffer->data = (uint8_t *)malloc(capacity);
|
||||||
|
audioBuffer->size = 0;
|
||||||
|
audioBuffer->pcmOffset = 0;
|
||||||
|
return audioBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TGAudioBufferDispose(TGAudioBuffer *audioBuffer)
|
||||||
|
{
|
||||||
|
if (audioBuffer != NULL)
|
||||||
|
{
|
||||||
|
free(audioBuffer->data);
|
||||||
|
free(audioBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _checkResultLite(OSStatus result, const char *operation, const char* file, int line)
|
||||||
|
{
|
||||||
|
if ( result != noErr )
|
||||||
|
{
|
||||||
|
NSLog(@"%s:%d: %s result %d %08X %4.4s\n", file, line, operation, (int)result, (int)result, (char*)&result);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface TGBridgeAudioDecoder ()
|
||||||
|
{
|
||||||
|
NSURL *_url;
|
||||||
|
NSURL *_resultURL;
|
||||||
|
|
||||||
|
OggOpusFile *_opusFile;
|
||||||
|
|
||||||
|
bool _finished;
|
||||||
|
bool _cancelled;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation TGBridgeAudioDecoder
|
||||||
|
|
||||||
|
- (instancetype)initWithURL:(NSURL *)url outputUrl:(NSURL *)outputUrl
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil)
|
||||||
|
{
|
||||||
|
_url = url;
|
||||||
|
|
||||||
|
int64_t randomId = 0;
|
||||||
|
arc4random_buf(&randomId, 8);
|
||||||
|
_resultURL = outputUrl;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startWithCompletion:(void (^)(void))completion
|
||||||
|
{
|
||||||
|
[[TGBridgeAudioDecoder processingQueue] dispatch:^
|
||||||
|
{
|
||||||
|
int error = OPUS_OK;
|
||||||
|
_opusFile = op_open_file(_url.path.UTF8String, &error);
|
||||||
|
if (_opusFile == NULL || error != OPUS_OK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioStreamBasicDescription sourceFormat;
|
||||||
|
sourceFormat.mSampleRate = TGBridgeAudioDecoderInputSampleRate;
|
||||||
|
sourceFormat.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
sourceFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
|
||||||
|
sourceFormat.mFramesPerPacket = 1;
|
||||||
|
sourceFormat.mChannelsPerFrame = 1;
|
||||||
|
sourceFormat.mBitsPerChannel = 16;
|
||||||
|
sourceFormat.mBytesPerPacket = 2;
|
||||||
|
sourceFormat.mBytesPerFrame = 2;
|
||||||
|
|
||||||
|
AudioStreamBasicDescription destFormat;
|
||||||
|
memset(&destFormat, 0, sizeof(destFormat));
|
||||||
|
destFormat.mChannelsPerFrame = sourceFormat.mChannelsPerFrame;
|
||||||
|
destFormat.mFormatID = kAudioFormatMPEG4AAC;
|
||||||
|
destFormat.mSampleRate = TGBridgeAudioDecoderResultSampleRate;
|
||||||
|
UInt32 size = sizeof(destFormat);
|
||||||
|
if (!checkResult(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &destFormat),
|
||||||
|
"AudioFormatGetProperty(kAudioFormatProperty_FormatInfo)"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtAudioFileRef destinationFile;
|
||||||
|
if (!checkResult(ExtAudioFileCreateWithURL((__bridge CFURLRef)_resultURL, kAudioFileM4AType, &destFormat, NULL, kAudioFileFlags_EraseFile, &destinationFile), "ExtAudioFileCreateWithURL"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkResult(ExtAudioFileSetProperty(destinationFile, kExtAudioFileProperty_ClientDataFormat, size, &sourceFormat),
|
||||||
|
"ExtAudioFileSetProperty(destinationFile, kExtAudioFileProperty_ClientDataFormat"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canResumeAfterInterruption = false;
|
||||||
|
AudioConverterRef converter;
|
||||||
|
size = sizeof(converter);
|
||||||
|
if (checkResult(ExtAudioFileGetProperty(destinationFile, kExtAudioFileProperty_AudioConverter, &size, &converter),
|
||||||
|
"ExtAudioFileGetProperty(kExtAudioFileProperty_AudioConverter;)"))
|
||||||
|
{
|
||||||
|
UInt32 canResume = 0;
|
||||||
|
size = sizeof(canResume);
|
||||||
|
if (AudioConverterGetProperty(converter, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume) == noErr)
|
||||||
|
canResumeAfterInterruption = canResume;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t srcBuffer[TGBridgeAudioDecoderBufferSize];
|
||||||
|
while (!_cancelled)
|
||||||
|
{
|
||||||
|
AudioBufferList bufferList;
|
||||||
|
bufferList.mNumberBuffers = 1;
|
||||||
|
bufferList.mBuffers[0].mNumberChannels = sourceFormat.mChannelsPerFrame;
|
||||||
|
bufferList.mBuffers[0].mDataByteSize = TGBridgeAudioDecoderBufferSize;
|
||||||
|
bufferList.mBuffers[0].mData = srcBuffer;
|
||||||
|
|
||||||
|
uint32_t writtenOutputBytes = 0;
|
||||||
|
while (writtenOutputBytes < TGBridgeAudioDecoderBufferSize)
|
||||||
|
{
|
||||||
|
int32_t readSamples = op_read(_opusFile, (opus_int16 *)(srcBuffer + writtenOutputBytes), (TGBridgeAudioDecoderBufferSize - writtenOutputBytes) / sourceFormat.mBytesPerFrame, NULL);
|
||||||
|
|
||||||
|
if (readSamples > 0)
|
||||||
|
writtenOutputBytes += readSamples * sourceFormat.mBytesPerFrame;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bufferList.mBuffers[0].mDataByteSize = writtenOutputBytes;
|
||||||
|
int32_t nFrames = writtenOutputBytes / sourceFormat.mBytesPerFrame;
|
||||||
|
|
||||||
|
if (nFrames == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
OSStatus status = ExtAudioFileWrite(destinationFile, nFrames, &bufferList);
|
||||||
|
if (status == kExtAudioFileError_CodecUnavailableInputConsumed)
|
||||||
|
{
|
||||||
|
//TGLog(@"1");
|
||||||
|
}
|
||||||
|
else if (status == kExtAudioFileError_CodecUnavailableInputNotConsumed)
|
||||||
|
{
|
||||||
|
//TGLog(@"2");
|
||||||
|
}
|
||||||
|
else if (!checkResult(status, "ExtAudioFileWrite"))
|
||||||
|
{
|
||||||
|
//TGLog(@"3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtAudioFileDispose(destinationFile);
|
||||||
|
|
||||||
|
if (completion != nil)
|
||||||
|
completion();
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SQueue *)processingQueue
|
||||||
|
{
|
||||||
|
static SQueue *queue = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^
|
||||||
|
{
|
||||||
|
static const char *queueSpecific = "org.telegram.opusAudioDecoderQueue";
|
||||||
|
dispatch_queue_t dispatchQueue = dispatch_queue_create("org.telegram.opusAudioDecoderQueue", DISPATCH_QUEUE_SERIAL);
|
||||||
|
dispatch_queue_set_specific(dispatchQueue, queueSpecific, (void *)queueSpecific, NULL);
|
||||||
|
queue = [SQueue wrapConcurrentNativeQueue:dispatchQueue];
|
||||||
|
});
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
11
TelegramUI/TGBridgeAudioEncoder.h
Normal file
11
TelegramUI/TGBridgeAudioEncoder.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@class TGDataItem;
|
||||||
|
@class TGLiveUploadActorData;
|
||||||
|
|
||||||
|
@interface TGBridgeAudioEncoder : NSObject
|
||||||
|
|
||||||
|
- (instancetype)initWithURL:(NSURL *)url;
|
||||||
|
- (void)startWithCompletion:(void (^)(TGDataItem *, int32_t))completion;
|
||||||
|
|
||||||
|
@end
|
211
TelegramUI/TGBridgeAudioEncoder.m
Normal file
211
TelegramUI/TGBridgeAudioEncoder.m
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
#import "TGBridgeAudioEncoder.h"
|
||||||
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
|
||||||
|
#import <SSignalKit/SSignalKit.h>
|
||||||
|
|
||||||
|
#import "opus.h"
|
||||||
|
#import "opusenc.h"
|
||||||
|
|
||||||
|
#import "TGDataItem.h"
|
||||||
|
|
||||||
|
const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
|
||||||
|
|
||||||
|
@interface TGBridgeAudioEncoder ()
|
||||||
|
{
|
||||||
|
AVAssetReader *_assetReader;
|
||||||
|
AVAssetReaderOutput *_readerOutput;
|
||||||
|
|
||||||
|
NSMutableData *_audioBuffer;
|
||||||
|
TGDataItem *_tempFileItem;
|
||||||
|
TGOggOpusWriter *_oggWriter;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation TGBridgeAudioEncoder
|
||||||
|
|
||||||
|
- (instancetype)initWithURL:(NSURL *)url
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil)
|
||||||
|
{
|
||||||
|
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
|
||||||
|
if (asset == nil || asset.tracks.count == 0)
|
||||||
|
{
|
||||||
|
//TGLog(@"Asset create fail");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
_assetReader = [[AVAssetReader alloc] initWithAsset:asset error:&error];
|
||||||
|
|
||||||
|
NSDictionary *outputSettings = @
|
||||||
|
{
|
||||||
|
AVFormatIDKey: @(kAudioFormatLinearPCM),
|
||||||
|
AVSampleRateKey: @(TGBridgeAudioEncoderSampleRate),
|
||||||
|
AVNumberOfChannelsKey: @1,
|
||||||
|
AVLinearPCMBitDepthKey: @16,
|
||||||
|
AVLinearPCMIsFloatKey: @false,
|
||||||
|
AVLinearPCMIsBigEndianKey: @false,
|
||||||
|
AVLinearPCMIsNonInterleaved: @false
|
||||||
|
};
|
||||||
|
|
||||||
|
_readerOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:asset.tracks audioSettings:outputSettings];
|
||||||
|
|
||||||
|
[_assetReader addOutput:_readerOutput];
|
||||||
|
|
||||||
|
_tempFileItem = [[TGDataItem alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[self cleanup];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cleanup
|
||||||
|
{
|
||||||
|
_oggWriter = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SQueue *)processingQueue
|
||||||
|
{
|
||||||
|
static SQueue *queue = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^
|
||||||
|
{
|
||||||
|
static const char *queueSpecific = "org.telegram.opusAudioEncoderQueue";
|
||||||
|
dispatch_queue_t dispatchQueue = dispatch_queue_create("org.telegram.opusAudioEncoderQueue", DISPATCH_QUEUE_SERIAL);
|
||||||
|
dispatch_queue_set_specific(dispatchQueue, queueSpecific, (void *)queueSpecific, NULL);
|
||||||
|
queue = [SQueue wrapConcurrentNativeQueue:dispatchQueue];
|
||||||
|
});
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startWithCompletion:(void (^)(TGDataItem *, int32_t))completion
|
||||||
|
{
|
||||||
|
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||||
|
|
||||||
|
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
||||||
|
{
|
||||||
|
_oggWriter = [[TGOggOpusWriter alloc] init];
|
||||||
|
if (![_oggWriter beginWithDataItem:_tempFileItem])
|
||||||
|
{
|
||||||
|
//TGLog(@"[TGBridgeAudioEncoder#%x error initializing ogg opus writer]", self);
|
||||||
|
[self cleanup];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_assetReader startReading];
|
||||||
|
|
||||||
|
while (_assetReader.status != AVAssetReaderStatusCompleted)
|
||||||
|
{
|
||||||
|
if (_assetReader.status == AVAssetReaderStatusReading)
|
||||||
|
{
|
||||||
|
CMSampleBufferRef nextBuffer = [_readerOutput copyNextSampleBuffer];
|
||||||
|
if (nextBuffer)
|
||||||
|
{
|
||||||
|
AudioBufferList abl;
|
||||||
|
CMBlockBufferRef blockBuffer;
|
||||||
|
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(nextBuffer, NULL, &abl, sizeof(abl), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer);
|
||||||
|
|
||||||
|
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
||||||
|
{
|
||||||
|
[self _processBuffer:&abl.mBuffers[0]];
|
||||||
|
|
||||||
|
CFRelease(nextBuffer);
|
||||||
|
CFRelease(blockBuffer);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TGDataItem *dataItemResult = nil;
|
||||||
|
NSTimeInterval durationResult = 0.0;
|
||||||
|
|
||||||
|
NSUInteger totalBytes = 0;
|
||||||
|
|
||||||
|
if (_assetReader.status == AVAssetReaderStatusCompleted)
|
||||||
|
{
|
||||||
|
if (_oggWriter != nil && [_oggWriter writeFrame:NULL frameByteCount:0])
|
||||||
|
{
|
||||||
|
dataItemResult = _tempFileItem;
|
||||||
|
durationResult = [_oggWriter encodedDuration];
|
||||||
|
totalBytes = [_oggWriter encodedBytes];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self cleanup];
|
||||||
|
}
|
||||||
|
|
||||||
|
//TGLog(@"[TGBridgeAudioEncoder#%x convert time: %f ms]", self, (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0);
|
||||||
|
|
||||||
|
if (completion != nil)
|
||||||
|
completion(dataItemResult, (int32_t)durationResult);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_processBuffer:(AudioBuffer const *)buffer
|
||||||
|
{
|
||||||
|
@autoreleasepool
|
||||||
|
{
|
||||||
|
if (_oggWriter == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static const int millisecondsPerPacket = 60;
|
||||||
|
static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 1000 * millisecondsPerPacket * 2;
|
||||||
|
|
||||||
|
unsigned char currentEncoderPacket[encoderPacketSizeInBytes];
|
||||||
|
|
||||||
|
int bufferOffset = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int currentEncoderPacketSize = 0;
|
||||||
|
|
||||||
|
while (currentEncoderPacketSize < encoderPacketSizeInBytes)
|
||||||
|
{
|
||||||
|
if (_audioBuffer.length != 0)
|
||||||
|
{
|
||||||
|
int takenBytes = MIN((int)_audioBuffer.length, encoderPacketSizeInBytes - currentEncoderPacketSize);
|
||||||
|
if (takenBytes != 0)
|
||||||
|
{
|
||||||
|
memcpy(currentEncoderPacket + currentEncoderPacketSize, _audioBuffer.bytes, takenBytes);
|
||||||
|
[_audioBuffer replaceBytesInRange:NSMakeRange(0, takenBytes) withBytes:NULL length:0];
|
||||||
|
currentEncoderPacketSize += takenBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bufferOffset < (int)buffer->mDataByteSize)
|
||||||
|
{
|
||||||
|
int takenBytes = MIN((int)buffer->mDataByteSize - bufferOffset, encoderPacketSizeInBytes - currentEncoderPacketSize);
|
||||||
|
if (takenBytes != 0)
|
||||||
|
{
|
||||||
|
memcpy(currentEncoderPacket + currentEncoderPacketSize, ((const char *)buffer->mData) + bufferOffset, takenBytes);
|
||||||
|
bufferOffset += takenBytes;
|
||||||
|
currentEncoderPacketSize += takenBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentEncoderPacketSize < encoderPacketSizeInBytes)
|
||||||
|
{
|
||||||
|
if (_audioBuffer == nil)
|
||||||
|
_audioBuffer = [[NSMutableData alloc] initWithCapacity:encoderPacketSizeInBytes];
|
||||||
|
[_audioBuffer appendBytes:currentEncoderPacket length:currentEncoderPacketSize];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_oggWriter writeFrame:currentEncoderPacket frameByteCount:(NSUInteger)currentEncoderPacketSize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -99,6 +99,8 @@ public final class TelegramApplicationContext {
|
|||||||
}
|
}
|
||||||
private var hasOngoingCallDisposable: Disposable?
|
private var hasOngoingCallDisposable: Disposable?
|
||||||
|
|
||||||
|
public var watchManager: WatchManager?
|
||||||
|
|
||||||
private var immediateExperimentalUISettingsValue = Atomic<ExperimentalUISettings>(value: ExperimentalUISettings.defaultSettings)
|
private var immediateExperimentalUISettingsValue = Atomic<ExperimentalUISettings>(value: ExperimentalUISettings.defaultSettings)
|
||||||
public var immediateExperimentalUISettings: ExperimentalUISettings {
|
public var immediateExperimentalUISettings: ExperimentalUISettings {
|
||||||
return self.immediateExperimentalUISettingsValue.with { $0 }
|
return self.immediateExperimentalUISettingsValue.with { $0 }
|
||||||
|
@ -28,4 +28,6 @@ module TelegramUIPrivateModule {
|
|||||||
header "../TGEmojiSuggestions.h"
|
header "../TGEmojiSuggestions.h"
|
||||||
header "../TGChannelIntroController.h"
|
header "../TGChannelIntroController.h"
|
||||||
header "../EDSunriseSet.h"
|
header "../EDSunriseSet.h"
|
||||||
|
header "../TGBridgeAudioDecoder.h"
|
||||||
|
header "../TGBridgeAudioEncoder.h"
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@ public struct TransformImageArguments: Equatable {
|
|||||||
public let boundingSize: CGSize
|
public let boundingSize: CGSize
|
||||||
public let intrinsicInsets: UIEdgeInsets
|
public let intrinsicInsets: UIEdgeInsets
|
||||||
public let resizeMode: TransformImageResizeMode
|
public let resizeMode: TransformImageResizeMode
|
||||||
public let emptyColor: UIColor
|
public let emptyColor: UIColor?
|
||||||
|
|
||||||
public init(corners: ImageCorners, imageSize: CGSize, boundingSize: CGSize, intrinsicInsets: UIEdgeInsets, resizeMode: TransformImageResizeMode = .fill(.black), emptyColor: UIColor = .white) {
|
public init(corners: ImageCorners, imageSize: CGSize, boundingSize: CGSize, intrinsicInsets: UIEdgeInsets, resizeMode: TransformImageResizeMode = .fill(.black), emptyColor: UIColor? = nil) {
|
||||||
self.corners = corners
|
self.corners = corners
|
||||||
self.imageSize = imageSize
|
self.imageSize = imageSize
|
||||||
self.boundingSize = boundingSize
|
self.boundingSize = boundingSize
|
||||||
|
36
TelegramUI/WatchManager.swift
Normal file
36
TelegramUI/WatchManager.swift
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
|
||||||
|
public final class WatchManagerArguments {
|
||||||
|
public let appInstalled: Signal<Bool, NoError>
|
||||||
|
public let navigateToMessageRequested: Signal<MessageId, NoError>
|
||||||
|
public let runningRequests: Signal<Bool, NoError>
|
||||||
|
|
||||||
|
public init(appInstalled: Signal<Bool, NoError>, navigateToMessageRequested: Signal<MessageId, NoError>, runningRequests: Signal<Bool, NoError>) {
|
||||||
|
self.appInstalled = appInstalled
|
||||||
|
self.navigateToMessageRequested = navigateToMessageRequested
|
||||||
|
self.runningRequests = runningRequests
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class WatchManager {
|
||||||
|
private let arguments: WatchManagerArguments?
|
||||||
|
|
||||||
|
public init(arguments: WatchManagerArguments?) {
|
||||||
|
self.arguments = arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
public var watchAppInstalled: Signal<Bool, NoError> {
|
||||||
|
return self.arguments?.appInstalled ?? .single(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var navigateToMessageRequested: Signal<MessageId, NoError> {
|
||||||
|
return self.arguments?.navigateToMessageRequested ?? .never()
|
||||||
|
}
|
||||||
|
|
||||||
|
public var runningRequests: Signal<Bool, NoError> {
|
||||||
|
return self.arguments?.runningRequests ?? .single(false)
|
||||||
|
}
|
||||||
|
}
|
68
TelegramUI/WatchPresetSettings.swift
Normal file
68
TelegramUI/WatchPresetSettings.swift
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import Foundation
|
||||||
|
import Postbox
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
public struct WatchPresetSettings: PreferencesEntry, Equatable {
|
||||||
|
public var customPresets: [String : String]
|
||||||
|
|
||||||
|
public static var defaultSettings: WatchPresetSettings {
|
||||||
|
return WatchPresetSettings(presets: [:])
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(presets: [String : String]) {
|
||||||
|
self.customPresets = presets
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(decoder: PostboxDecoder) {
|
||||||
|
let keys = decoder.decodeStringArrayForKey("presetKeys")
|
||||||
|
let values = decoder.decodeStringArrayForKey("presetValues")
|
||||||
|
if keys.count == values.count {
|
||||||
|
var presets: [String : String] = [:]
|
||||||
|
for i in 0 ..< keys.count {
|
||||||
|
presets[keys[i]] = values[i]
|
||||||
|
}
|
||||||
|
self.customPresets = presets
|
||||||
|
} else {
|
||||||
|
self.customPresets = [:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
|
let keys = self.customPresets.keys.sorted()
|
||||||
|
let values = keys.reduce([String]()) { (values, index) -> [String] in
|
||||||
|
var values = values
|
||||||
|
if let value = self.customPresets[index] {
|
||||||
|
values.append(value)
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
encoder.encodeStringArray(keys, forKey: "presetKeys")
|
||||||
|
encoder.encodeStringArray(values, forKey: "presetValues")
|
||||||
|
}
|
||||||
|
|
||||||
|
public func isEqual(to: PreferencesEntry) -> Bool {
|
||||||
|
if let to = to as? WatchPresetSettings {
|
||||||
|
return self == to
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: WatchPresetSettings, rhs: WatchPresetSettings) -> Bool {
|
||||||
|
return lhs.customPresets == rhs.customPresets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateWatchPresetSettingsInteractively(postbox: Postbox, _ f: @escaping (WatchPresetSettings) -> WatchPresetSettings) -> Signal<Void, NoError> {
|
||||||
|
return postbox.transaction { transaction -> Void in
|
||||||
|
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.watchPresetSettings, { entry in
|
||||||
|
let currentSettings: WatchPresetSettings
|
||||||
|
if let entry = entry as? WatchPresetSettings {
|
||||||
|
currentSettings = entry
|
||||||
|
} else {
|
||||||
|
currentSettings = WatchPresetSettings.defaultSettings
|
||||||
|
}
|
||||||
|
return f(currentSettings)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
148
TelegramUI/WatchSettingsController.swift
Normal file
148
TelegramUI/WatchSettingsController.swift
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import Foundation
|
||||||
|
import Display
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
|
||||||
|
private final class WatchSettingsControllerArguments {
|
||||||
|
let updatePreset: (String, String) -> Void
|
||||||
|
|
||||||
|
init(updatePreset: @escaping (String, String) -> Void) {
|
||||||
|
self.updatePreset = updatePreset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum WatchSettingsSection: Int32 {
|
||||||
|
case replyPresets
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum WatchSettingsControllerEntry: ItemListNodeEntry {
|
||||||
|
case replyPresetsHeader(PresentationTheme, String)
|
||||||
|
case replyPreset(PresentationTheme, String, String, String, Int32)
|
||||||
|
case replyPresetsInfo(PresentationTheme, String)
|
||||||
|
|
||||||
|
var section: ItemListSectionId {
|
||||||
|
switch self {
|
||||||
|
case .replyPresetsHeader, .replyPreset, .replyPresetsInfo:
|
||||||
|
return WatchSettingsSection.replyPresets.rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var stableId: Int32 {
|
||||||
|
switch self {
|
||||||
|
case .replyPresetsHeader:
|
||||||
|
return 0
|
||||||
|
case let .replyPreset(_, _, _, _, index):
|
||||||
|
return 1 + index
|
||||||
|
case .replyPresetsInfo:
|
||||||
|
return 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: WatchSettingsControllerEntry, rhs: WatchSettingsControllerEntry) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .replyPresetsHeader(lhsTheme, lhsText):
|
||||||
|
if case let .replyPresetsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
case let .replyPreset(lhsTheme, lhsIdentifier, lhsPlaceholder, lhsValue, lhsIndex):
|
||||||
|
if case let .replyPreset(rhsTheme, rhsIdentifier, rhsPlaceholder, rhsValue, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsIdentifier == rhsIdentifier, lhsPlaceholder == rhsPlaceholder, lhsValue == rhsValue, lhsIndex == rhsIndex {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
case let .replyPresetsInfo(lhsTheme, lhsText):
|
||||||
|
if case let .replyPresetsInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func <(lhs: WatchSettingsControllerEntry, rhs: WatchSettingsControllerEntry) -> Bool {
|
||||||
|
return lhs.stableId < rhs.stableId
|
||||||
|
}
|
||||||
|
|
||||||
|
func item(_ arguments: WatchSettingsControllerArguments) -> ListViewItem {
|
||||||
|
switch self {
|
||||||
|
case let .replyPresetsHeader(theme, text):
|
||||||
|
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||||
|
case let .replyPreset(theme, identifier, placeholder, value, _):
|
||||||
|
return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: ""), text: value, placeholder: placeholder, type: .regular(capitalization: true, autocorrection: true), spacing: 0.0, sectionId: self.section, textUpdated: { updatedText in
|
||||||
|
arguments.updatePreset(identifier, updatedText.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||||
|
}, action: {})
|
||||||
|
case let .replyPresetsInfo(theme, text):
|
||||||
|
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func watchSettingsControllerEntries(presentationData: PresentationData, customPresets: [String : String]) -> [WatchSettingsControllerEntry] {
|
||||||
|
var entries: [WatchSettingsControllerEntry] = []
|
||||||
|
|
||||||
|
let defaultSuggestions : [(Int32, String, String)] = [
|
||||||
|
(0, "OK", presentationData.strings.Watch_Suggestion_OK),
|
||||||
|
(1, "Thanks", presentationData.strings.Watch_Suggestion_Thanks),
|
||||||
|
(2, "WhatsUp", presentationData.strings.Watch_Suggestion_WhatsUp),
|
||||||
|
(3, "TalkLater", presentationData.strings.Watch_Suggestion_TalkLater),
|
||||||
|
(4, "CantTalk", presentationData.strings.Watch_Suggestion_CantTalk),
|
||||||
|
(5, "HoldOn", presentationData.strings.Watch_Suggestion_HoldOn),
|
||||||
|
(6, "BRB", presentationData.strings.Watch_Suggestion_BRB),
|
||||||
|
(7, "OnMyWay", presentationData.strings.Watch_Suggestion_OnMyWay)
|
||||||
|
]
|
||||||
|
|
||||||
|
entries.append(.replyPresetsHeader(presentationData.theme, presentationData.strings.AppleWatch_ReplyPresets))
|
||||||
|
for (index, identifier, placeholder) in defaultSuggestions {
|
||||||
|
entries.append(.replyPreset(presentationData.theme, identifier, placeholder, customPresets[identifier] ?? "", index))
|
||||||
|
}
|
||||||
|
entries.append(.replyPresetsInfo(presentationData.theme, presentationData.strings.AppleWatch_ReplyPresetsHelp))
|
||||||
|
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
public func watchSettingsController(account: Account) -> ViewController {
|
||||||
|
var pushControllerImpl: ((ViewController) -> Void)?
|
||||||
|
var presentControllerImpl: ((ViewController) -> Void)?
|
||||||
|
|
||||||
|
let updateDisposable = MetaDisposable()
|
||||||
|
let arguments = WatchSettingsControllerArguments(updatePreset: { identifier, text in
|
||||||
|
updateDisposable.set((.complete() |> delay(1.0, queue: Queue.mainQueue()) |> then(updateWatchPresetSettingsInteractively(postbox: account.postbox, { current in
|
||||||
|
var updatedPresets = current.customPresets
|
||||||
|
if !text.isEmpty {
|
||||||
|
updatedPresets[identifier] = text
|
||||||
|
} else {
|
||||||
|
updatedPresets.removeValue(forKey: identifier)
|
||||||
|
}
|
||||||
|
return WatchPresetSettings(presets: updatedPresets)
|
||||||
|
}))).start())
|
||||||
|
})
|
||||||
|
|
||||||
|
let watchPresetSettingsKey = ApplicationSpecificPreferencesKeys.watchPresetSettings
|
||||||
|
let preferences = account.postbox.preferencesView(keys: [watchPresetSettingsKey])
|
||||||
|
|
||||||
|
let signal = combineLatest(account.telegramApplicationContext.presentationData, preferences)
|
||||||
|
|> deliverOnMainQueue
|
||||||
|
|> map { presentationData, preferences -> (ItemListControllerState, (ItemListNodeState<WatchSettingsControllerEntry>, WatchSettingsControllerEntry.ItemGenerationArguments)) in
|
||||||
|
let settings = (preferences.values[watchPresetSettingsKey] as? WatchPresetSettings) ?? WatchPresetSettings.defaultSettings
|
||||||
|
|
||||||
|
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.AppleWatch_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||||
|
let listState = ItemListNodeState(entries: watchSettingsControllerEntries(presentationData: presentationData, customPresets: settings.customPresets), style: .blocks, animateChanges: false)
|
||||||
|
|
||||||
|
return (controllerState, (listState, arguments))
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = ItemListController(account: account, state: signal)
|
||||||
|
pushControllerImpl = { [weak controller] c in
|
||||||
|
(controller?.navigationController as? NavigationController)?.pushViewController(c)
|
||||||
|
}
|
||||||
|
presentControllerImpl = { [weak controller] c in
|
||||||
|
controller?.present(c, in: .window(.root))
|
||||||
|
}
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user