mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Update intents
This commit is contained in:
parent
9e7c9abceb
commit
933dcc17e7
10
BUILD.bazel
10
BUILD.bazel
@ -1,10 +0,0 @@
|
||||
|
||||
load("@build_bazel_rules_apple//apple:resources.bzl",
|
||||
"swift_intent_library",
|
||||
)
|
||||
|
||||
swift_intent_library(
|
||||
name = "GeneratedSources",
|
||||
src = "Intents.intentdefinition",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -32,6 +32,10 @@ load(
|
||||
"telegram_team_id",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_apple//apple:resources.bzl",
|
||||
"swift_intent_library",
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "debug",
|
||||
values = {
|
||||
@ -1186,7 +1190,7 @@ swift_library(
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/SyncCore:SyncCore",
|
||||
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
|
||||
"//:GeneratedSources",
|
||||
"//Telegram:GeneratedSources",
|
||||
],
|
||||
)
|
||||
|
||||
@ -1264,15 +1268,20 @@ plist_fragment(
|
||||
)
|
||||
)
|
||||
|
||||
swift_intent_library(
|
||||
name = "GeneratedSources",
|
||||
src = "SiriIntents/en.lproj/Intents.intentdefinition",
|
||||
module_name = "GeneratedSources",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
swift_library(
|
||||
name = "IntentsExtensionLib",
|
||||
module_name = "IntentsExtensionLib",
|
||||
srcs = glob([
|
||||
"SiriIntents/**/*.swift",
|
||||
]),
|
||||
data = [
|
||||
#"SiriIntents/Intents.intentdefinition",
|
||||
],
|
||||
data = glob(["SiriIntents/*.lproj/Intents.intentdefinition"]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
@ -1282,7 +1291,8 @@ swift_library(
|
||||
"//submodules/BuildConfig:BuildConfig",
|
||||
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
|
||||
"//submodules/AppLockState:AppLockState",
|
||||
"//:GeneratedSources",
|
||||
"//Telegram:GeneratedSources",
|
||||
"//submodules/WidgetItems:WidgetItems",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -10,6 +10,7 @@ import OpenSSLEncryptionProvider
|
||||
import AppLockState
|
||||
import UIKit
|
||||
import GeneratedSources
|
||||
import WidgetItems
|
||||
|
||||
private var accountCache: Account?
|
||||
|
||||
@ -771,8 +772,10 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) {
|
||||
let error = NSError(domain: "Locked", code: 1, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Open Telegram and enter passcode to edit widget."
|
||||
let presentationData = WidgetPresentationData.getForExtension()
|
||||
|
||||
let error = NSError(domain: presentationData.generalLockedTitle, code: 1, userInfo: [
|
||||
NSLocalizedDescriptionKey: presentationData.generalLockedText
|
||||
])
|
||||
|
||||
completion(nil, error)
|
||||
@ -937,7 +940,9 @@ private final class WidgetIntentHandler {
|
||||
}
|
||||
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) {
|
||||
//TODO:localize
|
||||
|
||||
let presentationData = WidgetPresentationData.getForExtension()
|
||||
|
||||
let error = NSError(domain: "Locked", code: 1, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Open Telegram and enter passcode to edit widget."
|
||||
])
|
||||
|
@ -19,8 +19,6 @@
|
||||
<dict>
|
||||
<key>INIntentCategory</key>
|
||||
<string>information</string>
|
||||
<key>INIntentDescription</key>
|
||||
<string>Display the latest message from the most important chats.</string>
|
||||
<key>INIntentDescriptionID</key>
|
||||
<string>jmsEbj</string>
|
||||
<key>INIntentEligibleForWidgets</key>
|
||||
@ -137,8 +135,6 @@
|
||||
<dict>
|
||||
<key>INIntentCategory</key>
|
||||
<string>information</string>
|
||||
<key>INIntentDescription</key>
|
||||
<string>"Display shortcuts of your most important chats to always have quick access to them.</string>
|
||||
<key>INIntentDescriptionID</key>
|
||||
<string>DwL4WQ</string>
|
||||
<key>INIntentEligibleForWidgets</key>
|
333
Telegram/SiriIntents/ru.lproj/Intents.intentdefinition
Normal file
333
Telegram/SiriIntents/ru.lproj/Intents.intentdefinition
Normal file
@ -0,0 +1,333 @@
|
||||
<?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>INEnums</key>
|
||||
<array/>
|
||||
<key>INIntentDefinitionModelVersion</key>
|
||||
<string>1.2</string>
|
||||
<key>INIntentDefinitionNamespace</key>
|
||||
<string>p74MWb</string>
|
||||
<key>INIntentDefinitionSystemVersion</key>
|
||||
<string>20C69</string>
|
||||
<key>INIntentDefinitionToolsBuildVersion</key>
|
||||
<string>12D4e</string>
|
||||
<key>INIntentDefinitionToolsVersion</key>
|
||||
<string>12.4</string>
|
||||
<key>INIntents</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentCategory</key>
|
||||
<string>information</string>
|
||||
<key>INIntentDescriptionID</key>
|
||||
<string>jmsEbj</string>
|
||||
<key>INIntentEligibleForWidgets</key>
|
||||
<true/>
|
||||
<key>INIntentIneligibleForSuggestions</key>
|
||||
<true/>
|
||||
<key>INIntentLastParameterTag</key>
|
||||
<integer>19</integer>
|
||||
<key>INIntentName</key>
|
||||
<string>SelectFriends</string>
|
||||
<key>INIntentParameters</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizeSize</key>
|
||||
<integer>1</integer>
|
||||
<key>INIntentParameterArraySizeSizeClass</key>
|
||||
<string>Small</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizeSize</key>
|
||||
<integer>2</integer>
|
||||
<key>INIntentParameterArraySizeSizeClass</key>
|
||||
<string>Medium</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizeSize</key>
|
||||
<integer>8</integer>
|
||||
<key>INIntentParameterArraySizeSizeClass</key>
|
||||
<string>Large</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentParameterConfigurable</key>
|
||||
<true/>
|
||||
<key>INIntentParameterDisplayName</key>
|
||||
<string>ВЫБЕРИТЕ ЧАТЫ</string>
|
||||
<key>INIntentParameterDisplayNameID</key>
|
||||
<string>WIf4LD</string>
|
||||
<key>INIntentParameterDisplayPriority</key>
|
||||
<integer>1</integer>
|
||||
<key>INIntentParameterFixedSizeArray</key>
|
||||
<integer>1</integer>
|
||||
<key>INIntentParameterName</key>
|
||||
<string>friends</string>
|
||||
<key>INIntentParameterObjectType</key>
|
||||
<string>Friend</string>
|
||||
<key>INIntentParameterObjectTypeNamespace</key>
|
||||
<string>p74MWb</string>
|
||||
<key>INIntentParameterPromptDialogs</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>Search</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>ORCbLf</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Configuration</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Primary</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentParameterRelationship</key>
|
||||
<dict>
|
||||
<key>INIntentParameterRelationshipPredicateName</key>
|
||||
<string>EnumHasExactValue</string>
|
||||
<key>INIntentParameterRelationshipPredicateValue</key>
|
||||
<string>custom</string>
|
||||
</dict>
|
||||
<key>INIntentParameterSupportsDynamicEnumeration</key>
|
||||
<true/>
|
||||
<key>INIntentParameterSupportsMultipleValues</key>
|
||||
<true/>
|
||||
<key>INIntentParameterSupportsSearch</key>
|
||||
<true/>
|
||||
<key>INIntentParameterTag</key>
|
||||
<integer>19</integer>
|
||||
<key>INIntentParameterType</key>
|
||||
<string>Object</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentResponse</key>
|
||||
<dict>
|
||||
<key>INIntentResponseCodes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentResponseCodeName</key>
|
||||
<string>success</string>
|
||||
<key>INIntentResponseCodeSuccess</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentResponseCodeName</key>
|
||||
<string>failure</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>INIntentTitle</key>
|
||||
<string>Чаты</string>
|
||||
<key>INIntentTitleID</key>
|
||||
<string>lMot0c</string>
|
||||
<key>INIntentType</key>
|
||||
<string>Custom</string>
|
||||
<key>INIntentVerb</key>
|
||||
<string>View</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentCategory</key>
|
||||
<string>information</string>
|
||||
<key>INIntentDescriptionID</key>
|
||||
<string>DwL4WQ</string>
|
||||
<key>INIntentEligibleForWidgets</key>
|
||||
<true/>
|
||||
<key>INIntentIneligibleForSuggestions</key>
|
||||
<true/>
|
||||
<key>INIntentLastParameterTag</key>
|
||||
<integer>19</integer>
|
||||
<key>INIntentName</key>
|
||||
<string>SelectAvatarFriends</string>
|
||||
<key>INIntentParameters</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizeSize</key>
|
||||
<integer>4</integer>
|
||||
<key>INIntentParameterArraySizeSizeClass</key>
|
||||
<string>Small</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizeSize</key>
|
||||
<integer>8</integer>
|
||||
<key>INIntentParameterArraySizeSizeClass</key>
|
||||
<string>Medium</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterArraySizeSize</key>
|
||||
<integer>16</integer>
|
||||
<key>INIntentParameterArraySizeSizeClass</key>
|
||||
<string>Large</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentParameterConfigurable</key>
|
||||
<true/>
|
||||
<key>INIntentParameterDisplayName</key>
|
||||
<string>ВЫБЕРИТЕ ЧАТЫ</string>
|
||||
<key>INIntentParameterDisplayNameID</key>
|
||||
<string>Jg5dYF</string>
|
||||
<key>INIntentParameterDisplayPriority</key>
|
||||
<integer>1</integer>
|
||||
<key>INIntentParameterFixedSizeArray</key>
|
||||
<integer>1</integer>
|
||||
<key>INIntentParameterName</key>
|
||||
<string>friends</string>
|
||||
<key>INIntentParameterObjectType</key>
|
||||
<string>Friend</string>
|
||||
<key>INIntentParameterObjectTypeNamespace</key>
|
||||
<string>p74MWb</string>
|
||||
<key>INIntentParameterPromptDialogs</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>Search</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>ORCbLf</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Configuration</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Primary</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentParameterRelationship</key>
|
||||
<dict>
|
||||
<key>INIntentParameterRelationshipPredicateName</key>
|
||||
<string>EnumHasExactValue</string>
|
||||
<key>INIntentParameterRelationshipPredicateValue</key>
|
||||
<string>custom</string>
|
||||
</dict>
|
||||
<key>INIntentParameterSupportsDynamicEnumeration</key>
|
||||
<true/>
|
||||
<key>INIntentParameterSupportsMultipleValues</key>
|
||||
<true/>
|
||||
<key>INIntentParameterSupportsSearch</key>
|
||||
<true/>
|
||||
<key>INIntentParameterTag</key>
|
||||
<integer>19</integer>
|
||||
<key>INIntentParameterType</key>
|
||||
<string>Object</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentResponse</key>
|
||||
<dict>
|
||||
<key>INIntentResponseCodes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentResponseCodeName</key>
|
||||
<string>success</string>
|
||||
<key>INIntentResponseCodeSuccess</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentResponseCodeName</key>
|
||||
<string>failure</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>INIntentTitle</key>
|
||||
<string>Шорткаты</string>
|
||||
<key>INIntentTitleID</key>
|
||||
<string>3Sbb7H</string>
|
||||
<key>INIntentType</key>
|
||||
<string>Custom</string>
|
||||
<key>INIntentVerb</key>
|
||||
<string>View</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INTypeDisplayName</key>
|
||||
<string>Chat</string>
|
||||
<key>INTypeDisplayNameID</key>
|
||||
<string>zsoXow</string>
|
||||
<key>INTypeLastPropertyTag</key>
|
||||
<integer>100</integer>
|
||||
<key>INTypeName</key>
|
||||
<string>Friend</string>
|
||||
<key>INTypeProperties</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>1</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>identifier</string>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>1</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>2</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>displayString</string>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>2</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>3</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>pronunciationHint</string>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>3</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>4</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>alternativeSpeakableMatches</string>
|
||||
<key>INTypePropertySupportsMultipleValues</key>
|
||||
<true/>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>4</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>SpeakableString</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypePropertyDisplayName</key>
|
||||
<string>Subtitle</string>
|
||||
<key>INTypePropertyDisplayNameID</key>
|
||||
<string>nNNpdC</string>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>5</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>subtitle</string>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>100</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -6102,3 +6102,31 @@ Sorry for the inconvenience.";
|
||||
"Conversation.AutoremoveTimerRemovedGroup" = "A group admin disabled the auto-delete timer";
|
||||
"Conversation.AutoremoveTimerSetChannel" = "Messages in this channel will be automatically deleted after %1$@";
|
||||
"Conversation.AutoremoveTimerRemovedChannel" = "Messages in this channel will no longer be automatically deleted";
|
||||
|
||||
"AutoremoveSetup.Title" = "Auto-Deletion";
|
||||
"AutoremoveSetup.TimeSectionHeader" = "AUTO-DELETE MESSAGES";
|
||||
"AutoremoveSetup.TimerInfoChannel" = "Automatically delete messages sent in this channel after a certain period of time.";
|
||||
"AutoremoveSetup.TimerInfoChat" = "Automatically delete messages sent in this chat after a certain period of time.";
|
||||
"AutoremoveSetup.TimerValueNever" = "Never";
|
||||
"AutoremoveSetup.TimerValueAfter" = "After %@";
|
||||
|
||||
"Conversation.ClearChannel" = "Clear Channel";
|
||||
|
||||
"Conversation.AutoremoveTimerSetToastText" = "Messages in this chat are automatically\ndeleted %@ after they have been sent.";
|
||||
"Conversation.AutoremoveActionEnable" = "Enable Auto-Delete";
|
||||
"Conversation.AutoremoveActionEdit" = "Edit Auto-Delete Settings";
|
||||
|
||||
"Widget.ChatsGalleryTitle" = "Chats";
|
||||
"Widget.ChatsGalleryDescription" = "Display the latest message from the most important chats.";
|
||||
"Widget.ShortcutsGalleryTitle" = "Shortcuts";
|
||||
"Widget.ShortcutsGalleryDescription" = "Display shortcuts of your most important chats to always have quick access to them.";
|
||||
|
||||
"Widget.MessageAutoremoveTimerUpdated" = "Auto-delete timer updated";
|
||||
"Widget.MessageAutoremoveTimerRemoved" = "Auto-delete timer disabled";
|
||||
|
||||
"Widget.LongTapToEdit" = "Tap or hold to edit widget.";
|
||||
"Widget.UpdatedTodayAt" = "Updated at {}";
|
||||
"Widget.UpdatedAt" = "Updated {}";
|
||||
|
||||
"Intents.ErrorLockedTitle" = "Locked";
|
||||
"Intents.ErrorLockedText" = "Open Telegram and enter passcode to edit widget.";
|
||||
|
@ -435,6 +435,7 @@ struct WidgetView: View {
|
||||
@Environment(\.widgetFamily) private var widgetFamily
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
let data: PeersWidgetData
|
||||
let presentationData: WidgetPresentationData
|
||||
|
||||
private func linkForPeer(accountId: Int64, id: Int64) -> String {
|
||||
switch self.widgetFamily {
|
||||
@ -523,7 +524,6 @@ struct WidgetView: View {
|
||||
case let .peer(peer):
|
||||
if let message = peer.peer.message {
|
||||
text = message.text
|
||||
//TODO:localize
|
||||
switch message.content {
|
||||
case .text:
|
||||
break
|
||||
@ -531,19 +531,19 @@ struct WidgetView: View {
|
||||
if !message.text.isEmpty {
|
||||
text = "🖼 \(message.text)"
|
||||
} else {
|
||||
text = "🖼 Photo"
|
||||
text = "🖼 \(self.presentationData.messagePhoto)"
|
||||
}
|
||||
case .video:
|
||||
if !message.text.isEmpty {
|
||||
text = "📹 \(message.text)"
|
||||
} else {
|
||||
text = "📹 Video"
|
||||
text = "📹 \(self.presentationData.messageVideo)"
|
||||
}
|
||||
case .gif:
|
||||
if !message.text.isEmpty {
|
||||
text = "\(message.text)"
|
||||
} else {
|
||||
text = "Gif"
|
||||
text = "\(self.presentationData.messageAnimation)"
|
||||
}
|
||||
case let .file(file):
|
||||
if !message.text.isEmpty {
|
||||
@ -559,31 +559,37 @@ struct WidgetView: View {
|
||||
} else if !music.artist.isEmpty {
|
||||
text = music.artist
|
||||
} else {
|
||||
text = "Music"
|
||||
text = "Unknown Artist"
|
||||
}
|
||||
case .voiceMessage:
|
||||
text = "🎤 Voice Message"
|
||||
text = "🎤 \(self.presentationData.messageVoice)"
|
||||
case .videoMessage:
|
||||
text = "Video Message"
|
||||
text = "\(self.presentationData.messageVideoMessage)"
|
||||
case let .sticker(sticker):
|
||||
text = "\(sticker.altText) Sticker"
|
||||
text = "\(sticker.altText) \(presentationData.messageSticker)"
|
||||
case let .call(call):
|
||||
if call.isVideo {
|
||||
text = "Video Call"
|
||||
text = "\(self.presentationData.messageVideoCall)"
|
||||
} else {
|
||||
text = "Voice Call"
|
||||
text = "\(self.presentationData.messageVoiceCall)"
|
||||
}
|
||||
case .mapLocation:
|
||||
text = "Location"
|
||||
text = "\(self.presentationData.messageLocation)"
|
||||
case let .game(game):
|
||||
text = "🎮 \(game.title)"
|
||||
case let .poll(poll):
|
||||
text = "📊 \(poll.title)"
|
||||
case let .autodeleteTimer(value):
|
||||
if value.value != nil {
|
||||
text = self.presentationData.autodeleteTimerUpdated
|
||||
} else {
|
||||
text = self.presentationData.autodeleteTimerRemoved
|
||||
}
|
||||
}
|
||||
|
||||
if let author = message.author {
|
||||
if author.isMe {
|
||||
text = "You: \(text)"
|
||||
text = "\(presentationData.messageAuthorYou): \(text)"
|
||||
} else {
|
||||
text = "\(author.title): \(text)"
|
||||
}
|
||||
@ -594,7 +600,7 @@ struct WidgetView: View {
|
||||
if index == 0 {
|
||||
text = "☀️ 23 °C\n☁️ Passing Clouds"
|
||||
} else {
|
||||
text = "😂 Sticker"
|
||||
text = "😂 \(presentationData.messageSticker)"
|
||||
text += "\n"
|
||||
}
|
||||
case .placeholder:
|
||||
@ -754,40 +760,38 @@ struct WidgetView: View {
|
||||
switch data {
|
||||
case let .peers(peersValue):
|
||||
if peersValue.peers.isEmpty {
|
||||
text = "Long tap to edit widget"
|
||||
text = self.presentationData.widgetLongTapToEdit
|
||||
} else {
|
||||
let date = Date(timeIntervalSince1970: Double(peersValue.updateTimestamp))
|
||||
let calendar = Calendar.current
|
||||
//TODO:localize
|
||||
if !calendar.isDate(Date(), inSameDayAs: date) {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .short
|
||||
formatter.timeStyle = .none
|
||||
text = "updated \(formatter.string(from: date))"
|
||||
text = self.presentationData.widgetUpdatedAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||
} else {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .none
|
||||
formatter.timeStyle = .short
|
||||
text = "updated at \(formatter.string(from: date))"
|
||||
text = self.presentationData.widgetUpdatedTodayAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||
}
|
||||
}
|
||||
case .preview:
|
||||
let date = Date()
|
||||
let calendar = Calendar.current
|
||||
//TODO:localize
|
||||
if !calendar.isDate(Date(), inSameDayAs: date) {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .short
|
||||
formatter.timeStyle = .none
|
||||
text = "updated \(formatter.string(from: date))"
|
||||
text = self.presentationData.widgetUpdatedAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||
} else {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .none
|
||||
formatter.timeStyle = .short
|
||||
text = "updated at \(formatter.string(from: date))"
|
||||
text = self.presentationData.widgetUpdatedTodayAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||
}
|
||||
default:
|
||||
text = "Long tap to edit widget"
|
||||
text = self.presentationData.widgetLongTapToEdit
|
||||
}
|
||||
|
||||
return Text(text)
|
||||
@ -795,6 +799,17 @@ struct WidgetView: View {
|
||||
.foregroundColor(getUpdatedTextColor())
|
||||
}
|
||||
|
||||
func getBackgroundColor() -> Color {
|
||||
switch colorScheme {
|
||||
case .light:
|
||||
return .white
|
||||
case .dark:
|
||||
return Color(.sRGB, red: 28.0 / 255.0, green: 28.0 / 255.0, blue: 30.0 / 255.0, opacity: 1.0)
|
||||
@unknown default:
|
||||
return .secondary
|
||||
}
|
||||
}
|
||||
|
||||
func getSeparatorColor() -> Color {
|
||||
switch colorScheme {
|
||||
case .light:
|
||||
@ -848,6 +863,7 @@ struct WidgetView: View {
|
||||
chatUpdateView(size: geometry.size)
|
||||
})
|
||||
})
|
||||
.background(Rectangle().foregroundColor(getBackgroundColor()))
|
||||
.padding(0.0)
|
||||
.unredacted()
|
||||
}
|
||||
@ -857,6 +873,7 @@ struct AvatarsWidgetView: View {
|
||||
@Environment(\.widgetFamily) private var widgetFamily
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
let data: PeersWidgetData
|
||||
let presentationData: WidgetPresentationData
|
||||
|
||||
func placeholder(geometry: GeometryProxy) -> some View {
|
||||
return Spacer()
|
||||
@ -951,38 +968,6 @@ private let buildConfig: BuildConfig = {
|
||||
return buildConfig
|
||||
}()
|
||||
|
||||
private extension WidgetPresentationData {
|
||||
static var `default` = WidgetPresentationData(
|
||||
applicationLockedString: "Unlock the app to use the widget",
|
||||
applicationStartRequiredString: "Open the app to use the widget",
|
||||
widgetGalleryTitle: "Telegram",
|
||||
widgetGalleryDescription: ""
|
||||
)
|
||||
}
|
||||
|
||||
private let presentationData: WidgetPresentationData = {
|
||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||
return WidgetPresentationData.default
|
||||
}
|
||||
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
|
||||
|
||||
let appGroupName = "group.\(baseAppBundleId)"
|
||||
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
||||
|
||||
guard let appGroupUrl = maybeAppGroupUrl else {
|
||||
return WidgetPresentationData.default
|
||||
}
|
||||
|
||||
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
||||
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: widgetPresentationDataPath(rootPath: rootPath))), let value = try? JSONDecoder().decode(WidgetPresentationData.self, from: data) {
|
||||
return value
|
||||
} else {
|
||||
return WidgetPresentationData.default
|
||||
}
|
||||
}()
|
||||
|
||||
func getWidgetData(contents: SimpleEntry.Contents) -> PeersWidgetData {
|
||||
switch contents {
|
||||
case .recent:
|
||||
@ -998,12 +983,14 @@ struct Static_Widget: Widget {
|
||||
private let kind: String = "Static_Widget"
|
||||
|
||||
public var body: some WidgetConfiguration {
|
||||
let presentationData = WidgetPresentationData.getForExtension()
|
||||
|
||||
return IntentConfiguration(kind: kind, intent: SelectFriendsIntent.self, provider: Provider(), content: { entry in
|
||||
WidgetView(data: getWidgetData(contents: entry.contents))
|
||||
WidgetView(data: getWidgetData(contents: entry.contents), presentationData: presentationData)
|
||||
})
|
||||
.supportedFamilies([.systemMedium])
|
||||
.configurationDisplayName("Chats")
|
||||
.description("Display the latest message from the most important chats.")
|
||||
.configurationDisplayName(presentationData.widgetChatsGalleryTitle)
|
||||
.description(presentationData.widgetChatsGalleryDescription)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1011,12 +998,14 @@ struct Static_AvatarsWidget: Widget {
|
||||
private let kind: String = "Static_AvatarsWidget"
|
||||
|
||||
public var body: some WidgetConfiguration {
|
||||
let presentationData = WidgetPresentationData.getForExtension()
|
||||
|
||||
return IntentConfiguration(kind: kind, intent: SelectAvatarFriendsIntent.self, provider: AvatarsProvider(), content: { entry in
|
||||
AvatarsWidgetView(data: getWidgetData(contents: entry.contents))
|
||||
AvatarsWidgetView(data: getWidgetData(contents: entry.contents), presentationData: presentationData)
|
||||
})
|
||||
.supportedFamilies([.systemMedium])
|
||||
.configurationDisplayName("Shortcuts")
|
||||
.description("Display shortcuts of your most important chats to always have quick access to them.")
|
||||
.configurationDisplayName(presentationData.widgetShortcutsGalleryTitle)
|
||||
.description(presentationData.widgetShortcutsGalleryDescription)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ class ChatListFilterSettingsHeaderItemNode: ListViewItemNode {
|
||||
animationName = "MessageAutoRemove"
|
||||
size = 260
|
||||
insetDifference = 120
|
||||
playbackMode = .count(2)
|
||||
playbackMode = .once
|
||||
additionalBottomInset = isHidden ? 8.0 : 16.0
|
||||
}
|
||||
|
||||
|
@ -112,9 +112,8 @@ private func peerAutoremoveSetupEntries(peer: Peer?, presentationData: Presentat
|
||||
|
||||
resolvedValue = state.changedValue ?? defaultValue
|
||||
|
||||
//TODO:localize
|
||||
entries.append(.header)
|
||||
entries.append(.timeHeader("AUTO-DELETE MESSAGES"))
|
||||
entries.append(.timeHeader(presentationData.strings.AutoremoveSetup_TimeSectionHeader))
|
||||
|
||||
var availableValues: [Int32] = [
|
||||
Int32.max,
|
||||
@ -127,9 +126,9 @@ private func peerAutoremoveSetupEntries(peer: Peer?, presentationData: Presentat
|
||||
}
|
||||
entries.append(.timeValue(resolvedValue, availableValues))
|
||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
entries.append(.timeComment("Automatically delete messages sent in this channel after a certain period of time."))
|
||||
entries.append(.timeComment(presentationData.strings.AutoremoveSetup_TimerInfoChannel))
|
||||
} else {
|
||||
entries.append(.timeComment("Automatically delete messages sent in this chat after a certain period of time."))
|
||||
entries.append(.timeComment(presentationData.strings.AutoremoveSetup_TimerInfoChat))
|
||||
}
|
||||
|
||||
return entries
|
||||
@ -151,7 +150,6 @@ public func peerAutoremoveSetupScreen(context: AccountContext, peerId: PeerId, c
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
var dismissImpl: (() -> Void)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
@ -238,8 +236,7 @@ public func peerAutoremoveSetupScreen(context: AccountContext, peerId: PeerId, c
|
||||
|
||||
let isDebug = context.account.testingEnvironment
|
||||
|
||||
//TODO:localize
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Auto-Deletion"), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.AutoremoveSetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: peerAutoremoveSetupEntries(peer: peer, presentationData: presentationData, isDebug: isDebug, defaultValue: defaultValue, state: state), style: .blocks)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
@ -254,8 +251,5 @@ public func peerAutoremoveSetupScreen(context: AccountContext, peerId: PeerId, c
|
||||
controller?.view.endEditing(true)
|
||||
controller?.dismiss()
|
||||
}
|
||||
pushControllerImpl = { [weak controller] c in
|
||||
controller?.push(c)
|
||||
}
|
||||
return controller
|
||||
}
|
||||
|
@ -193,11 +193,10 @@ class PeerRemoveTimeoutItemNode: ListViewItemNode, ItemListItemNode {
|
||||
|
||||
let titleLayouts = zip(0 ..< makeTitleNodeLayouts.count, makeTitleNodeLayouts).map { index, makeLayout -> (TextNodeLayout, () -> TextNode) in
|
||||
let text: String
|
||||
//TODO:localize
|
||||
if item.availableValues[index] == Int32.max {
|
||||
text = "Never"
|
||||
text = item.presentationData.strings.AutoremoveSetup_TimerValueNever
|
||||
} else {
|
||||
text = "After \(timeIntervalString(strings: item.presentationData.strings, value: item.availableValues[index]))"
|
||||
text = item.presentationData.strings.AutoremoveSetup_TimerValueAfter(timeIntervalString(strings: item.presentationData.strings, value: item.availableValues[index])).0
|
||||
}
|
||||
return makeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: text, font: Font.regular(13.0), textColor: item.presentationData.theme.list.itemSecondaryTextColor), maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: 100.0)))
|
||||
}
|
||||
|
@ -66,15 +66,17 @@ struct SqlitePreparedStatement {
|
||||
return res == SQLITE_ROW
|
||||
}
|
||||
|
||||
func tryStep(handle: OpaquePointer?, _ initial: Bool = false, path: String?) -> Bool {
|
||||
struct SqlError: Error {
|
||||
var code: Int32
|
||||
}
|
||||
|
||||
func tryStep(handle: OpaquePointer?, _ initial: Bool = false, path: String?) -> Result<Void, SqlError> {
|
||||
let res = sqlite3_step(statement)
|
||||
if res != SQLITE_ROW && res != SQLITE_DONE {
|
||||
if res != SQLITE_MISUSE {
|
||||
if let error = sqlite3_errmsg(handle), let str = NSString(utf8String: error) {
|
||||
postboxLog("SQL error \(res): \(str) on step")
|
||||
} else {
|
||||
postboxLog("SQL error \(res) on step")
|
||||
}
|
||||
if let error = sqlite3_errmsg(handle), let str = NSString(utf8String: error) {
|
||||
postboxLog("SQL error \(res): \(str) on step")
|
||||
} else {
|
||||
postboxLog("SQL error \(res) on step")
|
||||
}
|
||||
|
||||
if res == SQLITE_CORRUPT {
|
||||
@ -85,7 +87,11 @@ struct SqlitePreparedStatement {
|
||||
}
|
||||
}
|
||||
}
|
||||
return res == SQLITE_ROW || res == SQLITE_DONE
|
||||
if res == SQLITE_ROW || res == SQLITE_DONE {
|
||||
return .success(Void())
|
||||
} else {
|
||||
return .failure(SqlError(code: res))
|
||||
}
|
||||
}
|
||||
|
||||
func int32At(_ index: Int) -> Int32 {
|
||||
@ -484,11 +490,20 @@ public final class SqliteValueBox: ValueBox {
|
||||
private func isEncrypted(_ database: Database) -> Bool {
|
||||
var statement: OpaquePointer? = nil
|
||||
let status = sqlite3_prepare_v2(database.handle, "SELECT * FROM sqlite_master LIMIT 1", -1, &statement, nil)
|
||||
if statement == nil {
|
||||
postboxLog("isEncrypted: sqlite3_prepare_v2 status = \(status) [\(self.databasePath)]")
|
||||
return true
|
||||
}
|
||||
if status == SQLITE_NOTADB {
|
||||
postboxLog("isEncrypted: status = SQLITE_NOTADB [\(self.databasePath)]")
|
||||
return true
|
||||
}
|
||||
let preparedStatement = SqlitePreparedStatement(statement: statement)
|
||||
if !preparedStatement.tryStep(handle: database.handle, path: self.databasePath) {
|
||||
switch preparedStatement.tryStep(handle: database.handle, path: self.databasePath) {
|
||||
case .success:
|
||||
break
|
||||
case let .failure(error):
|
||||
postboxLog("isEncrypted: tryStep result is \(error.code) [\(self.databasePath)]")
|
||||
preparedStatement.destroy()
|
||||
return true
|
||||
}
|
||||
@ -602,14 +617,14 @@ public final class SqliteValueBox: ValueBox {
|
||||
switch table.keyType {
|
||||
case .binary:
|
||||
var resultCode: Bool
|
||||
var createStatement = "CREATE TABLE t\(table.id) (key BLOB PRIMARY KEY, value BLOB)"
|
||||
var createStatement = "CREATE TABLE IF NOT EXISTS t\(table.id) (key BLOB PRIMARY KEY, value BLOB)"
|
||||
if table.compactValuesOnCreation {
|
||||
createStatement += " WITHOUT ROWID"
|
||||
}
|
||||
resultCode = database.execute(createStatement)
|
||||
assert(resultCode)
|
||||
case .int64:
|
||||
let resultCode = database.execute("CREATE TABLE t\(table.id) (key INTEGER PRIMARY KEY, value BLOB)")
|
||||
let resultCode = database.execute("CREATE TABLE IF NOT EXISTS t\(table.id) (key INTEGER PRIMARY KEY, value BLOB)")
|
||||
assert(resultCode)
|
||||
}
|
||||
}
|
||||
@ -618,10 +633,10 @@ public final class SqliteValueBox: ValueBox {
|
||||
precondition(self.queue.isCurrent())
|
||||
if let _ = self.fullTextTables[table.id] {
|
||||
} else {
|
||||
var resultCode = self.database.execute("CREATE VIRTUAL TABLE ft\(table.id) USING fts5(collectionId, itemId, contents, tags)")
|
||||
var resultCode = self.database.execute("CREATE VIRTUAL TABLE IF NOT EXISTS ft\(table.id) USING fts5(collectionId, itemId, contents, tags)")
|
||||
precondition(resultCode)
|
||||
self.fullTextTables[table.id] = table
|
||||
resultCode = self.database.execute("INSERT INTO __meta_fulltext_tables(name) VALUES (\(table.id))")
|
||||
resultCode = self.database.execute("INSERT OR IGNORE INTO __meta_fulltext_tables(name) VALUES (\(table.id))")
|
||||
precondition(resultCode)
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -211,7 +211,7 @@ swift_library(
|
||||
"//submodules/SlotMachineAnimationNode:SlotMachineAnimationNode",
|
||||
"//submodules/AnimatedNavigationStripeNode:AnimatedNavigationStripeNode",
|
||||
"//submodules/AudioBlob:AudioBlob",
|
||||
"//:GeneratedSources",
|
||||
"//Telegram:GeneratedSources",
|
||||
"//third-party/ZipArchive:ZipArchive",
|
||||
"//submodules/ChatImportUI:ChatImportUI",
|
||||
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
|
||||
|
Binary file not shown.
Binary file not shown.
@ -5626,9 +5626,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.presentAutoremoveSetup()
|
||||
} else if let currentAutoremoveTimeout = currentAutoremoveTimeout, let rect = strongSelf.chatDisplayNode.frameForInputPanelAccessoryButton(.messageAutoremoveTimeout(currentAutoremoveTimeout)) {
|
||||
|
||||
//TODO:localize
|
||||
let intervalText = timeIntervalString(strings: strongSelf.presentationData.strings, value: currentAutoremoveTimeout)
|
||||
let text: String = "Messages in this chat are automatically\ndeleted \(intervalText) after they have been sent."
|
||||
let text: String = strongSelf.presentationData.strings.Conversation_AutoremoveTimerSetToastText(intervalText).0
|
||||
|
||||
strongSelf.mediaRecordingModeTooltipController?.dismiss()
|
||||
|
||||
@ -7950,8 +7949,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
if chatPeer.canSetupAutoremoveTimeout(accountPeerId: strongSelf.context.account.peerId) {
|
||||
//TODO:localize
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationInterfaceState.autoremoveTimeout == nil ? "Enable Auto-Delete" : "Edit Auto-Delete Settings", color: .accent, action: { [weak actionSheet] in
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationInterfaceState.autoremoveTimeout == nil ? strongSelf.presentationData.strings.Conversation_AutoremoveActionEnable : strongSelf.presentationData.strings.Conversation_AutoremoveActionEdit, color: .accent, action: { [weak actionSheet] in
|
||||
guard let actionSheet = actionSheet else {
|
||||
return
|
||||
}
|
||||
@ -7965,81 +7963,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/*if case .scheduledMessages = self.presentationInterfaceState.subject {
|
||||
|
||||
} else if canRemoveGlobally {
|
||||
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
beginClear(.forLocalPeer)
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationAction, action: {
|
||||
beginClear(.forEveryone)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}))
|
||||
} else {
|
||||
if !isClearCache {
|
||||
items.append(ActionSheetTextItem(title: text))
|
||||
}
|
||||
items.append(ActionSheetButtonItem(title: isClearCache ? self.presentationData.strings.Conversation_ClearCache : self.presentationData.strings.Conversation_ClearAll, color: isClearCache ? .accent : .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if isClearCache {
|
||||
strongSelf.navigationButtonAction(.clearCache)
|
||||
} else {
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationAction, action: {
|
||||
beginClear(.forLocalPeer)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if let peer = self.presentationInterfaceState.renderedPeer?.peer {
|
||||
var currentAutoremoveTimeout: Int32? = self.presentationInterfaceState.autoremoveTimeout
|
||||
var canSetupAutoremoveTimeout = false
|
||||
|
||||
if let _ = peer as? TelegramSecretChat {
|
||||
} else if let group = peer as? TelegramGroup {
|
||||
if case .creator = group.role {
|
||||
canSetupAutoremoveTimeout = true
|
||||
} else if case let .admin(rights, _) = group.role {
|
||||
if rights.flags.contains(.canDeleteMessages) {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
}
|
||||
} else if let user = self.presentationInterfaceState.renderedPeer?.peer as? TelegramUser {
|
||||
if user.id != self.context.account.peerId && user.botInfo == nil {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
} else if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel {
|
||||
if channel.hasPermission(.deleteAllMessages) {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
}
|
||||
|
||||
if canSetupAutoremoveTimeout {
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
@ -8050,163 +7973,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
})
|
||||
|
||||
/*if peerId == self.context.account.peerId {
|
||||
text = self.presentationData.strings.Conversation_ClearSelfHistory
|
||||
} else if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
text = self.presentationData.strings.Conversation_ClearSecretHistory
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
if let channel = peer.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
isClearCache = true
|
||||
text = self.presentationData.strings.Conversation_ClearCache
|
||||
} else {
|
||||
text = self.presentationData.strings.Conversation_ClearGroupHistory
|
||||
}
|
||||
} else {
|
||||
text = self.presentationData.strings.Conversation_ClearPrivateHistory
|
||||
}
|
||||
|
||||
let text: String
|
||||
if peerId == self.context.account.peerId {
|
||||
text = self.presentationData.strings.Conversation_ClearSelfHistory
|
||||
} else if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
text = self.presentationData.strings.Conversation_ClearSecretHistory
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
if let channel = peer.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
isClearCache = true
|
||||
text = self.presentationData.strings.Conversation_ClearCache
|
||||
} else {
|
||||
text = self.presentationData.strings.Conversation_ClearGroupHistory
|
||||
}
|
||||
} else {
|
||||
text = self.presentationData.strings.Conversation_ClearPrivateHistory
|
||||
}
|
||||
|
||||
var canRemoveGlobally = false
|
||||
let limitsConfiguration = self.context.currentLimitsConfiguration.with { $0 }
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser && peerId != self.context.account.peerId {
|
||||
if limitsConfiguration.maxMessageRevokeIntervalInPrivateChats == LimitsConfiguration.timeIntervalForever {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
}
|
||||
if let user = chatPeer as? TelegramUser, user.botInfo != nil {
|
||||
canRemoveGlobally = false
|
||||
}
|
||||
|
||||
|
||||
|
||||
let actionSheet = ActionSheetController(presentationData: self.presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
if case .scheduledMessages = self.presentationInterfaceState.subject {
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ScheduledMessages_ClearAllConfirmation, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationAction, action: {
|
||||
beginClear(.scheduledMessages)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}))
|
||||
} else if canRemoveGlobally {
|
||||
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
beginClear(.forLocalPeer)
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationAction, action: {
|
||||
beginClear(.forEveryone)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}))
|
||||
} else {
|
||||
if !isClearCache {
|
||||
items.append(ActionSheetTextItem(title: text))
|
||||
}
|
||||
items.append(ActionSheetButtonItem(title: isClearCache ? self.presentationData.strings.Conversation_ClearCache : self.presentationData.strings.Conversation_ClearAll, color: isClearCache ? .accent : .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if isClearCache {
|
||||
strongSelf.navigationButtonAction(.clearCache)
|
||||
} else {
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationAction, action: {
|
||||
beginClear(.forLocalPeer)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if let peer = self.presentationInterfaceState.renderedPeer?.peer {
|
||||
var currentAutoremoveTimeout: Int32? = self.presentationInterfaceState.autoremoveTimeout
|
||||
var canSetupAutoremoveTimeout = false
|
||||
|
||||
if let _ = peer as? TelegramSecretChat {
|
||||
} else if let group = peer as? TelegramGroup {
|
||||
if case .creator = group.role {
|
||||
canSetupAutoremoveTimeout = true
|
||||
} else if case let .admin(rights, _) = group.role {
|
||||
if rights.flags.contains(.canDeleteMessages) {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
}
|
||||
} else if let user = self.presentationInterfaceState.renderedPeer?.peer as? TelegramUser {
|
||||
if user.id != self.context.account.peerId && user.botInfo == nil {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
} else if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel {
|
||||
if channel.hasPermission(.deleteAllMessages) {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
}
|
||||
|
||||
if canSetupAutoremoveTimeout {
|
||||
//TODO:localize
|
||||
items.append(ActionSheetButtonItem(title: currentAutoremoveTimeout == nil ? "Enable Auto-Delete" : "Edit Auto-Delete Settings", color: .accent, action: { [weak self, weak actionSheet] in
|
||||
guard let actionSheet = actionSheet else {
|
||||
return
|
||||
}
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
actionSheet.dismissAnimated()
|
||||
|
||||
strongSelf.presentAutoremoveSetup()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
|
||||
self.chatDisplayNode.dismissInput()
|
||||
self.present(actionSheet, in: .window(.root))*/
|
||||
}
|
||||
case let .openChatInfo(expandAvatar):
|
||||
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
||||
|
@ -50,8 +50,7 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
|
||||
canClear = true
|
||||
} else if let peer = peer as? TelegramChannel {
|
||||
if case .broadcast = peer.info {
|
||||
//TODO:localize
|
||||
title = "Clear Channel"
|
||||
title = strings.Conversation_ClearChannel
|
||||
}
|
||||
if peer.hasPermission(.changeInfo) {
|
||||
canClear = true
|
||||
|
@ -256,7 +256,29 @@ final class WidgetDataContext {
|
||||
|
||||
self.widgetPresentationDataDisposable = (presentationData
|
||||
|> map { presentationData -> WidgetPresentationData in
|
||||
return WidgetPresentationData(applicationLockedString: presentationData.strings.Widget_ApplicationLocked, applicationStartRequiredString: presentationData.strings.Widget_ApplicationStartRequired, widgetGalleryTitle: presentationData.strings.Widget_GalleryTitle, widgetGalleryDescription: presentationData.strings.Widget_GalleryDescription)
|
||||
return WidgetPresentationData(
|
||||
widgetChatsGalleryTitle: presentationData.strings.Widget_ChatsGalleryTitle,
|
||||
widgetChatsGalleryDescription: presentationData.strings.Widget_ChatsGalleryDescription,
|
||||
widgetShortcutsGalleryTitle: presentationData.strings.Widget_ShortcutsGalleryTitle,
|
||||
widgetShortcutsGalleryDescription: presentationData.strings.Widget_ShortcutsGalleryDescription,
|
||||
widgetLongTapToEdit: presentationData.strings.Widget_LongTapToEdit,
|
||||
widgetUpdatedTodayAt: presentationData.strings.Widget_UpdatedTodayAt,
|
||||
widgetUpdatedAt: presentationData.strings.Widget_UpdatedAt,
|
||||
messageAuthorYou: presentationData.strings.DialogList_You,
|
||||
messagePhoto: presentationData.strings.Message_Photo,
|
||||
messageVideo: presentationData.strings.Message_Video,
|
||||
messageAnimation: presentationData.strings.Message_Animation,
|
||||
messageVoice: presentationData.strings.Message_Audio,
|
||||
messageVideoMessage: presentationData.strings.Message_VideoMessage,
|
||||
messageSticker: presentationData.strings.Message_Sticker,
|
||||
messageVoiceCall: presentationData.strings.Watch_Message_Call,
|
||||
messageVideoCall: presentationData.strings.Watch_Message_Call,
|
||||
messageLocation: presentationData.strings.Message_Location,
|
||||
autodeleteTimerUpdated: presentationData.strings.Widget_MessageAutoremoveTimerUpdated,
|
||||
autodeleteTimerRemoved: presentationData.strings.Widget_MessageAutoremoveTimerRemoved,
|
||||
generalLockedTitle: presentationData.strings.Intents_ErrorLockedTitle,
|
||||
generalLockedText: presentationData.strings.Intents_ErrorLockedText
|
||||
)
|
||||
}
|
||||
|> distinctUntilChanged).start(next: { value in
|
||||
let path = widgetPresentationDataPath(rootPath: basePath)
|
||||
|
@ -119,6 +119,14 @@ public struct WidgetDataPeer: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct AutodeleteTimer: Codable, Equatable {
|
||||
public var value: Int32?
|
||||
|
||||
public init(value: Int32?) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case text
|
||||
case image
|
||||
@ -133,6 +141,7 @@ public struct WidgetDataPeer: Codable, Equatable {
|
||||
case mapLocation
|
||||
case game
|
||||
case poll
|
||||
case autodeleteTimer
|
||||
}
|
||||
|
||||
case text
|
||||
@ -148,6 +157,7 @@ public struct WidgetDataPeer: Codable, Equatable {
|
||||
case mapLocation(MapLocation)
|
||||
case game(Game)
|
||||
case poll(Poll)
|
||||
case autodeleteTimer(AutodeleteTimer)
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
@ -177,6 +187,8 @@ public struct WidgetDataPeer: Codable, Equatable {
|
||||
self = .game(game)
|
||||
} else if let poll = try? container.decode(Poll.self, forKey: .poll) {
|
||||
self = .poll(poll)
|
||||
} else if let autodeleteTimer = try? container.decode(AutodeleteTimer.self, forKey: .autodeleteTimer) {
|
||||
self = .autodeleteTimer(autodeleteTimer)
|
||||
} else {
|
||||
throw DecodingError.generic
|
||||
}
|
||||
@ -211,6 +223,8 @@ public struct WidgetDataPeer: Codable, Equatable {
|
||||
try container.encode(game, forKey: .game)
|
||||
case let .poll(poll):
|
||||
try container.encode(poll, forKey: .poll)
|
||||
case let .autodeleteTimer(autodeleteTimer):
|
||||
try container.encode(autodeleteTimer, forKey: .autodeleteTimer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,17 +274,130 @@ public struct WidgetDataPeers: Codable, Equatable {
|
||||
}
|
||||
|
||||
public struct WidgetPresentationData: Codable, Equatable {
|
||||
public var applicationLockedString: String
|
||||
public var applicationStartRequiredString: String
|
||||
public var widgetGalleryTitle: String
|
||||
public var widgetGalleryDescription: String
|
||||
public var widgetChatsGalleryTitle: String
|
||||
public var widgetChatsGalleryDescription: String
|
||||
public var widgetShortcutsGalleryTitle: String
|
||||
public var widgetShortcutsGalleryDescription: String
|
||||
|
||||
public init(applicationLockedString: String, applicationStartRequiredString: String, widgetGalleryTitle: String, widgetGalleryDescription: String) {
|
||||
self.applicationLockedString = applicationLockedString
|
||||
self.applicationStartRequiredString = applicationStartRequiredString
|
||||
self.widgetGalleryTitle = widgetGalleryTitle
|
||||
self.widgetGalleryDescription = widgetGalleryDescription
|
||||
public var widgetLongTapToEdit: String
|
||||
public var widgetUpdatedTodayAt: String
|
||||
public var widgetUpdatedAt: String
|
||||
|
||||
public var messageAuthorYou: String
|
||||
public var messagePhoto: String
|
||||
public var messageVideo: String
|
||||
public var messageAnimation: String
|
||||
public var messageVoice: String
|
||||
public var messageVideoMessage: String
|
||||
public var messageSticker: String
|
||||
public var messageVoiceCall: String
|
||||
public var messageVideoCall: String
|
||||
public var messageLocation: String
|
||||
|
||||
public var autodeleteTimerUpdated: String
|
||||
public var autodeleteTimerRemoved: String
|
||||
|
||||
public var generalLockedTitle: String
|
||||
public var generalLockedText: String
|
||||
|
||||
public init(
|
||||
widgetChatsGalleryTitle: String,
|
||||
widgetChatsGalleryDescription: String,
|
||||
widgetShortcutsGalleryTitle: String,
|
||||
widgetShortcutsGalleryDescription: String,
|
||||
widgetLongTapToEdit: String,
|
||||
widgetUpdatedTodayAt: String,
|
||||
widgetUpdatedAt: String,
|
||||
messageAuthorYou: String,
|
||||
messagePhoto: String,
|
||||
messageVideo: String,
|
||||
messageAnimation: String,
|
||||
messageVoice: String,
|
||||
messageVideoMessage: String,
|
||||
messageSticker: String,
|
||||
messageVoiceCall: String,
|
||||
messageVideoCall: String,
|
||||
messageLocation: String,
|
||||
autodeleteTimerUpdated: String,
|
||||
autodeleteTimerRemoved: String,
|
||||
generalLockedTitle: String,
|
||||
generalLockedText: String
|
||||
) {
|
||||
self.widgetChatsGalleryTitle = widgetChatsGalleryTitle
|
||||
self.widgetChatsGalleryDescription = widgetChatsGalleryDescription
|
||||
self.widgetShortcutsGalleryTitle = widgetShortcutsGalleryTitle
|
||||
self.widgetShortcutsGalleryDescription = widgetShortcutsGalleryDescription
|
||||
self.widgetLongTapToEdit = widgetLongTapToEdit
|
||||
self.widgetUpdatedTodayAt = widgetUpdatedTodayAt
|
||||
self.widgetUpdatedAt = widgetUpdatedAt
|
||||
self.messageAuthorYou = messageAuthorYou
|
||||
self.messagePhoto = messagePhoto
|
||||
self.messageVideo = messageVideo
|
||||
self.messageAnimation = messageAnimation
|
||||
self.messageVoice = messageVoice
|
||||
self.messageVideoMessage = messageVideoMessage
|
||||
self.messageSticker = messageSticker
|
||||
self.messageVoiceCall = messageVoiceCall
|
||||
self.messageVideoCall = messageVideoCall
|
||||
self.messageLocation = messageLocation
|
||||
self.autodeleteTimerUpdated = autodeleteTimerUpdated
|
||||
self.autodeleteTimerRemoved = autodeleteTimerRemoved
|
||||
self.generalLockedTitle = generalLockedTitle
|
||||
self.generalLockedText = generalLockedText
|
||||
}
|
||||
|
||||
public static func getForExtension() -> WidgetPresentationData {
|
||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||
return WidgetPresentationData.default
|
||||
}
|
||||
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
|
||||
|
||||
let appGroupName = "group.\(baseAppBundleId)"
|
||||
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
||||
|
||||
guard let appGroupUrl = maybeAppGroupUrl else {
|
||||
return WidgetPresentationData.default
|
||||
}
|
||||
|
||||
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
||||
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: widgetPresentationDataPath(rootPath: rootPath))), let value = try? JSONDecoder().decode(WidgetPresentationData.self, from: data) {
|
||||
return value
|
||||
} else {
|
||||
return WidgetPresentationData.default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension WidgetPresentationData {
|
||||
static var `default` = WidgetPresentationData(
|
||||
widgetChatsGalleryTitle: "Chats",
|
||||
widgetChatsGalleryDescription: "Display the latest message from the most important chats.",
|
||||
widgetShortcutsGalleryTitle: "Shortcuts",
|
||||
widgetShortcutsGalleryDescription: "Display shortcuts of your most important chats to always have quick access to them.",
|
||||
widgetLongTapToEdit: "Tap or hold to edit widget.",
|
||||
widgetUpdatedTodayAt: "Updated at {}",
|
||||
widgetUpdatedAt: "Updated {}",
|
||||
messageAuthorYou: "You",
|
||||
messagePhoto: "Photo",
|
||||
messageVideo: "Video",
|
||||
messageAnimation: "GIF",
|
||||
messageVoice: "Voice Message",
|
||||
messageVideoMessage: "Video Message",
|
||||
messageSticker: "Sticker",
|
||||
messageVoiceCall: "Call",
|
||||
messageVideoCall: "Video Call",
|
||||
messageLocation: "Map",
|
||||
autodeleteTimerUpdated: "Auto-delete timer updated",
|
||||
autodeleteTimerRemoved: "Auto-delete timer disabled",
|
||||
generalLockedTitle: "Locked",
|
||||
generalLockedText: "Open Telegram and enter passcode to edit widget."
|
||||
)
|
||||
}
|
||||
|
||||
private func rootPathForBasePath(_ appGroupPath: String) -> String {
|
||||
return appGroupPath + "/telegram-data"
|
||||
}
|
||||
|
||||
public func widgetPresentationDataPath(rootPath: String) -> String {
|
||||
|
Loading…
x
Reference in New Issue
Block a user