mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +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",
|
"telegram_team_id",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
load("@build_bazel_rules_apple//apple:resources.bzl",
|
||||||
|
"swift_intent_library",
|
||||||
|
)
|
||||||
|
|
||||||
config_setting(
|
config_setting(
|
||||||
name = "debug",
|
name = "debug",
|
||||||
values = {
|
values = {
|
||||||
@ -1186,7 +1190,7 @@ swift_library(
|
|||||||
"//submodules/TelegramCore:TelegramCore",
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
"//submodules/SyncCore:SyncCore",
|
"//submodules/SyncCore:SyncCore",
|
||||||
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
|
"//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(
|
swift_library(
|
||||||
name = "IntentsExtensionLib",
|
name = "IntentsExtensionLib",
|
||||||
module_name = "IntentsExtensionLib",
|
module_name = "IntentsExtensionLib",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"SiriIntents/**/*.swift",
|
"SiriIntents/**/*.swift",
|
||||||
]),
|
]),
|
||||||
data = [
|
data = glob(["SiriIntents/*.lproj/Intents.intentdefinition"]),
|
||||||
#"SiriIntents/Intents.intentdefinition",
|
|
||||||
],
|
|
||||||
deps = [
|
deps = [
|
||||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
"//submodules/Postbox:Postbox",
|
"//submodules/Postbox:Postbox",
|
||||||
@ -1282,7 +1291,8 @@ swift_library(
|
|||||||
"//submodules/BuildConfig:BuildConfig",
|
"//submodules/BuildConfig:BuildConfig",
|
||||||
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
|
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
|
||||||
"//submodules/AppLockState:AppLockState",
|
"//submodules/AppLockState:AppLockState",
|
||||||
"//:GeneratedSources",
|
"//Telegram:GeneratedSources",
|
||||||
|
"//submodules/WidgetItems:WidgetItems",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import OpenSSLEncryptionProvider
|
|||||||
import AppLockState
|
import AppLockState
|
||||||
import UIKit
|
import UIKit
|
||||||
import GeneratedSources
|
import GeneratedSources
|
||||||
|
import WidgetItems
|
||||||
|
|
||||||
private var accountCache: Account?
|
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) {
|
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: [
|
let presentationData = WidgetPresentationData.getForExtension()
|
||||||
NSLocalizedDescriptionKey: "Open Telegram and enter passcode to edit widget."
|
|
||||||
|
let error = NSError(domain: presentationData.generalLockedTitle, code: 1, userInfo: [
|
||||||
|
NSLocalizedDescriptionKey: presentationData.generalLockedText
|
||||||
])
|
])
|
||||||
|
|
||||||
completion(nil, error)
|
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) {
|
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: [
|
let error = NSError(domain: "Locked", code: 1, userInfo: [
|
||||||
NSLocalizedDescriptionKey: "Open Telegram and enter passcode to edit widget."
|
NSLocalizedDescriptionKey: "Open Telegram and enter passcode to edit widget."
|
||||||
])
|
])
|
||||||
|
|||||||
@ -19,8 +19,6 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>INIntentCategory</key>
|
<key>INIntentCategory</key>
|
||||||
<string>information</string>
|
<string>information</string>
|
||||||
<key>INIntentDescription</key>
|
|
||||||
<string>Display the latest message from the most important chats.</string>
|
|
||||||
<key>INIntentDescriptionID</key>
|
<key>INIntentDescriptionID</key>
|
||||||
<string>jmsEbj</string>
|
<string>jmsEbj</string>
|
||||||
<key>INIntentEligibleForWidgets</key>
|
<key>INIntentEligibleForWidgets</key>
|
||||||
@ -137,8 +135,6 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>INIntentCategory</key>
|
<key>INIntentCategory</key>
|
||||||
<string>information</string>
|
<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>
|
<key>INIntentDescriptionID</key>
|
||||||
<string>DwL4WQ</string>
|
<string>DwL4WQ</string>
|
||||||
<key>INIntentEligibleForWidgets</key>
|
<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.AutoremoveTimerRemovedGroup" = "A group admin disabled the auto-delete timer";
|
||||||
"Conversation.AutoremoveTimerSetChannel" = "Messages in this channel will be automatically deleted after %1$@";
|
"Conversation.AutoremoveTimerSetChannel" = "Messages in this channel will be automatically deleted after %1$@";
|
||||||
"Conversation.AutoremoveTimerRemovedChannel" = "Messages in this channel will no longer be automatically deleted";
|
"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(\.widgetFamily) private var widgetFamily
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
let data: PeersWidgetData
|
let data: PeersWidgetData
|
||||||
|
let presentationData: WidgetPresentationData
|
||||||
|
|
||||||
private func linkForPeer(accountId: Int64, id: Int64) -> String {
|
private func linkForPeer(accountId: Int64, id: Int64) -> String {
|
||||||
switch self.widgetFamily {
|
switch self.widgetFamily {
|
||||||
@ -523,7 +524,6 @@ struct WidgetView: View {
|
|||||||
case let .peer(peer):
|
case let .peer(peer):
|
||||||
if let message = peer.peer.message {
|
if let message = peer.peer.message {
|
||||||
text = message.text
|
text = message.text
|
||||||
//TODO:localize
|
|
||||||
switch message.content {
|
switch message.content {
|
||||||
case .text:
|
case .text:
|
||||||
break
|
break
|
||||||
@ -531,19 +531,19 @@ struct WidgetView: View {
|
|||||||
if !message.text.isEmpty {
|
if !message.text.isEmpty {
|
||||||
text = "🖼 \(message.text)"
|
text = "🖼 \(message.text)"
|
||||||
} else {
|
} else {
|
||||||
text = "🖼 Photo"
|
text = "🖼 \(self.presentationData.messagePhoto)"
|
||||||
}
|
}
|
||||||
case .video:
|
case .video:
|
||||||
if !message.text.isEmpty {
|
if !message.text.isEmpty {
|
||||||
text = "📹 \(message.text)"
|
text = "📹 \(message.text)"
|
||||||
} else {
|
} else {
|
||||||
text = "📹 Video"
|
text = "📹 \(self.presentationData.messageVideo)"
|
||||||
}
|
}
|
||||||
case .gif:
|
case .gif:
|
||||||
if !message.text.isEmpty {
|
if !message.text.isEmpty {
|
||||||
text = "\(message.text)"
|
text = "\(message.text)"
|
||||||
} else {
|
} else {
|
||||||
text = "Gif"
|
text = "\(self.presentationData.messageAnimation)"
|
||||||
}
|
}
|
||||||
case let .file(file):
|
case let .file(file):
|
||||||
if !message.text.isEmpty {
|
if !message.text.isEmpty {
|
||||||
@ -559,31 +559,37 @@ struct WidgetView: View {
|
|||||||
} else if !music.artist.isEmpty {
|
} else if !music.artist.isEmpty {
|
||||||
text = music.artist
|
text = music.artist
|
||||||
} else {
|
} else {
|
||||||
text = "Music"
|
text = "Unknown Artist"
|
||||||
}
|
}
|
||||||
case .voiceMessage:
|
case .voiceMessage:
|
||||||
text = "🎤 Voice Message"
|
text = "🎤 \(self.presentationData.messageVoice)"
|
||||||
case .videoMessage:
|
case .videoMessage:
|
||||||
text = "Video Message"
|
text = "\(self.presentationData.messageVideoMessage)"
|
||||||
case let .sticker(sticker):
|
case let .sticker(sticker):
|
||||||
text = "\(sticker.altText) Sticker"
|
text = "\(sticker.altText) \(presentationData.messageSticker)"
|
||||||
case let .call(call):
|
case let .call(call):
|
||||||
if call.isVideo {
|
if call.isVideo {
|
||||||
text = "Video Call"
|
text = "\(self.presentationData.messageVideoCall)"
|
||||||
} else {
|
} else {
|
||||||
text = "Voice Call"
|
text = "\(self.presentationData.messageVoiceCall)"
|
||||||
}
|
}
|
||||||
case .mapLocation:
|
case .mapLocation:
|
||||||
text = "Location"
|
text = "\(self.presentationData.messageLocation)"
|
||||||
case let .game(game):
|
case let .game(game):
|
||||||
text = "🎮 \(game.title)"
|
text = "🎮 \(game.title)"
|
||||||
case let .poll(poll):
|
case let .poll(poll):
|
||||||
text = "📊 \(poll.title)"
|
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 let author = message.author {
|
||||||
if author.isMe {
|
if author.isMe {
|
||||||
text = "You: \(text)"
|
text = "\(presentationData.messageAuthorYou): \(text)"
|
||||||
} else {
|
} else {
|
||||||
text = "\(author.title): \(text)"
|
text = "\(author.title): \(text)"
|
||||||
}
|
}
|
||||||
@ -594,7 +600,7 @@ struct WidgetView: View {
|
|||||||
if index == 0 {
|
if index == 0 {
|
||||||
text = "☀️ 23 °C\n☁️ Passing Clouds"
|
text = "☀️ 23 °C\n☁️ Passing Clouds"
|
||||||
} else {
|
} else {
|
||||||
text = "😂 Sticker"
|
text = "😂 \(presentationData.messageSticker)"
|
||||||
text += "\n"
|
text += "\n"
|
||||||
}
|
}
|
||||||
case .placeholder:
|
case .placeholder:
|
||||||
@ -754,40 +760,38 @@ struct WidgetView: View {
|
|||||||
switch data {
|
switch data {
|
||||||
case let .peers(peersValue):
|
case let .peers(peersValue):
|
||||||
if peersValue.peers.isEmpty {
|
if peersValue.peers.isEmpty {
|
||||||
text = "Long tap to edit widget"
|
text = self.presentationData.widgetLongTapToEdit
|
||||||
} else {
|
} else {
|
||||||
let date = Date(timeIntervalSince1970: Double(peersValue.updateTimestamp))
|
let date = Date(timeIntervalSince1970: Double(peersValue.updateTimestamp))
|
||||||
let calendar = Calendar.current
|
let calendar = Calendar.current
|
||||||
//TODO:localize
|
|
||||||
if !calendar.isDate(Date(), inSameDayAs: date) {
|
if !calendar.isDate(Date(), inSameDayAs: date) {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .short
|
formatter.dateStyle = .short
|
||||||
formatter.timeStyle = .none
|
formatter.timeStyle = .none
|
||||||
text = "updated \(formatter.string(from: date))"
|
text = self.presentationData.widgetUpdatedAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||||
} else {
|
} else {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .none
|
formatter.dateStyle = .none
|
||||||
formatter.timeStyle = .short
|
formatter.timeStyle = .short
|
||||||
text = "updated at \(formatter.string(from: date))"
|
text = self.presentationData.widgetUpdatedTodayAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .preview:
|
case .preview:
|
||||||
let date = Date()
|
let date = Date()
|
||||||
let calendar = Calendar.current
|
let calendar = Calendar.current
|
||||||
//TODO:localize
|
|
||||||
if !calendar.isDate(Date(), inSameDayAs: date) {
|
if !calendar.isDate(Date(), inSameDayAs: date) {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .short
|
formatter.dateStyle = .short
|
||||||
formatter.timeStyle = .none
|
formatter.timeStyle = .none
|
||||||
text = "updated \(formatter.string(from: date))"
|
text = self.presentationData.widgetUpdatedAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||||
} else {
|
} else {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .none
|
formatter.dateStyle = .none
|
||||||
formatter.timeStyle = .short
|
formatter.timeStyle = .short
|
||||||
text = "updated at \(formatter.string(from: date))"
|
text = self.presentationData.widgetUpdatedTodayAt.replacingOccurrences(of: "{}", with: formatter.string(from: date))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
text = "Long tap to edit widget"
|
text = self.presentationData.widgetLongTapToEdit
|
||||||
}
|
}
|
||||||
|
|
||||||
return Text(text)
|
return Text(text)
|
||||||
@ -795,6 +799,17 @@ struct WidgetView: View {
|
|||||||
.foregroundColor(getUpdatedTextColor())
|
.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 {
|
func getSeparatorColor() -> Color {
|
||||||
switch colorScheme {
|
switch colorScheme {
|
||||||
case .light:
|
case .light:
|
||||||
@ -848,6 +863,7 @@ struct WidgetView: View {
|
|||||||
chatUpdateView(size: geometry.size)
|
chatUpdateView(size: geometry.size)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.background(Rectangle().foregroundColor(getBackgroundColor()))
|
||||||
.padding(0.0)
|
.padding(0.0)
|
||||||
.unredacted()
|
.unredacted()
|
||||||
}
|
}
|
||||||
@ -857,6 +873,7 @@ struct AvatarsWidgetView: View {
|
|||||||
@Environment(\.widgetFamily) private var widgetFamily
|
@Environment(\.widgetFamily) private var widgetFamily
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
let data: PeersWidgetData
|
let data: PeersWidgetData
|
||||||
|
let presentationData: WidgetPresentationData
|
||||||
|
|
||||||
func placeholder(geometry: GeometryProxy) -> some View {
|
func placeholder(geometry: GeometryProxy) -> some View {
|
||||||
return Spacer()
|
return Spacer()
|
||||||
@ -951,38 +968,6 @@ private let buildConfig: BuildConfig = {
|
|||||||
return 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 {
|
func getWidgetData(contents: SimpleEntry.Contents) -> PeersWidgetData {
|
||||||
switch contents {
|
switch contents {
|
||||||
case .recent:
|
case .recent:
|
||||||
@ -998,12 +983,14 @@ struct Static_Widget: Widget {
|
|||||||
private let kind: String = "Static_Widget"
|
private let kind: String = "Static_Widget"
|
||||||
|
|
||||||
public var body: some WidgetConfiguration {
|
public var body: some WidgetConfiguration {
|
||||||
|
let presentationData = WidgetPresentationData.getForExtension()
|
||||||
|
|
||||||
return IntentConfiguration(kind: kind, intent: SelectFriendsIntent.self, provider: Provider(), content: { entry in
|
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])
|
.supportedFamilies([.systemMedium])
|
||||||
.configurationDisplayName("Chats")
|
.configurationDisplayName(presentationData.widgetChatsGalleryTitle)
|
||||||
.description("Display the latest message from the most important chats.")
|
.description(presentationData.widgetChatsGalleryDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,12 +998,14 @@ struct Static_AvatarsWidget: Widget {
|
|||||||
private let kind: String = "Static_AvatarsWidget"
|
private let kind: String = "Static_AvatarsWidget"
|
||||||
|
|
||||||
public var body: some WidgetConfiguration {
|
public var body: some WidgetConfiguration {
|
||||||
|
let presentationData = WidgetPresentationData.getForExtension()
|
||||||
|
|
||||||
return IntentConfiguration(kind: kind, intent: SelectAvatarFriendsIntent.self, provider: AvatarsProvider(), content: { entry in
|
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])
|
.supportedFamilies([.systemMedium])
|
||||||
.configurationDisplayName("Shortcuts")
|
.configurationDisplayName(presentationData.widgetShortcutsGalleryTitle)
|
||||||
.description("Display shortcuts of your most important chats to always have quick access to them.")
|
.description(presentationData.widgetShortcutsGalleryDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -126,7 +126,7 @@ class ChatListFilterSettingsHeaderItemNode: ListViewItemNode {
|
|||||||
animationName = "MessageAutoRemove"
|
animationName = "MessageAutoRemove"
|
||||||
size = 260
|
size = 260
|
||||||
insetDifference = 120
|
insetDifference = 120
|
||||||
playbackMode = .count(2)
|
playbackMode = .once
|
||||||
additionalBottomInset = isHidden ? 8.0 : 16.0
|
additionalBottomInset = isHidden ? 8.0 : 16.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -112,9 +112,8 @@ private func peerAutoremoveSetupEntries(peer: Peer?, presentationData: Presentat
|
|||||||
|
|
||||||
resolvedValue = state.changedValue ?? defaultValue
|
resolvedValue = state.changedValue ?? defaultValue
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
entries.append(.header)
|
entries.append(.header)
|
||||||
entries.append(.timeHeader("AUTO-DELETE MESSAGES"))
|
entries.append(.timeHeader(presentationData.strings.AutoremoveSetup_TimeSectionHeader))
|
||||||
|
|
||||||
var availableValues: [Int32] = [
|
var availableValues: [Int32] = [
|
||||||
Int32.max,
|
Int32.max,
|
||||||
@ -127,9 +126,9 @@ private func peerAutoremoveSetupEntries(peer: Peer?, presentationData: Presentat
|
|||||||
}
|
}
|
||||||
entries.append(.timeValue(resolvedValue, availableValues))
|
entries.append(.timeValue(resolvedValue, availableValues))
|
||||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
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 {
|
} 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
|
return entries
|
||||||
@ -151,7 +150,6 @@ public func peerAutoremoveSetupScreen(context: AccountContext, peerId: PeerId, c
|
|||||||
statePromise.set(stateValue.modify { f($0) })
|
statePromise.set(stateValue.modify { f($0) })
|
||||||
}
|
}
|
||||||
|
|
||||||
var pushControllerImpl: ((ViewController) -> Void)?
|
|
||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
|
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
@ -238,8 +236,7 @@ public func peerAutoremoveSetupScreen(context: AccountContext, peerId: PeerId, c
|
|||||||
|
|
||||||
let isDebug = context.account.testingEnvironment
|
let isDebug = context.account.testingEnvironment
|
||||||
|
|
||||||
//TODO:localize
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.AutoremoveSetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Auto-Deletion"), 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)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: peerAutoremoveSetupEntries(peer: peer, presentationData: presentationData, isDebug: isDebug, defaultValue: defaultValue, state: state), style: .blocks)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
@ -254,8 +251,5 @@ public func peerAutoremoveSetupScreen(context: AccountContext, peerId: PeerId, c
|
|||||||
controller?.view.endEditing(true)
|
controller?.view.endEditing(true)
|
||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
}
|
}
|
||||||
pushControllerImpl = { [weak controller] c in
|
|
||||||
controller?.push(c)
|
|
||||||
}
|
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
|||||||
@ -193,11 +193,10 @@ class PeerRemoveTimeoutItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
let titleLayouts = zip(0 ..< makeTitleNodeLayouts.count, makeTitleNodeLayouts).map { index, makeLayout -> (TextNodeLayout, () -> TextNode) in
|
let titleLayouts = zip(0 ..< makeTitleNodeLayouts.count, makeTitleNodeLayouts).map { index, makeLayout -> (TextNodeLayout, () -> TextNode) in
|
||||||
let text: String
|
let text: String
|
||||||
//TODO:localize
|
|
||||||
if item.availableValues[index] == Int32.max {
|
if item.availableValues[index] == Int32.max {
|
||||||
text = "Never"
|
text = item.presentationData.strings.AutoremoveSetup_TimerValueNever
|
||||||
} else {
|
} 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)))
|
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
|
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)
|
let res = sqlite3_step(statement)
|
||||||
if res != SQLITE_ROW && res != SQLITE_DONE {
|
if res != SQLITE_ROW && res != SQLITE_DONE {
|
||||||
if res != SQLITE_MISUSE {
|
if let error = sqlite3_errmsg(handle), let str = NSString(utf8String: error) {
|
||||||
if let error = sqlite3_errmsg(handle), let str = NSString(utf8String: error) {
|
postboxLog("SQL error \(res): \(str) on step")
|
||||||
postboxLog("SQL error \(res): \(str) on step")
|
} else {
|
||||||
} else {
|
postboxLog("SQL error \(res) on step")
|
||||||
postboxLog("SQL error \(res) on step")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == SQLITE_CORRUPT {
|
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 {
|
func int32At(_ index: Int) -> Int32 {
|
||||||
@ -484,11 +490,20 @@ public final class SqliteValueBox: ValueBox {
|
|||||||
private func isEncrypted(_ database: Database) -> Bool {
|
private func isEncrypted(_ database: Database) -> Bool {
|
||||||
var statement: OpaquePointer? = nil
|
var statement: OpaquePointer? = nil
|
||||||
let status = sqlite3_prepare_v2(database.handle, "SELECT * FROM sqlite_master LIMIT 1", -1, &statement, 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 {
|
if status == SQLITE_NOTADB {
|
||||||
|
postboxLog("isEncrypted: status = SQLITE_NOTADB [\(self.databasePath)]")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let preparedStatement = SqlitePreparedStatement(statement: statement)
|
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()
|
preparedStatement.destroy()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -602,14 +617,14 @@ public final class SqliteValueBox: ValueBox {
|
|||||||
switch table.keyType {
|
switch table.keyType {
|
||||||
case .binary:
|
case .binary:
|
||||||
var resultCode: Bool
|
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 {
|
if table.compactValuesOnCreation {
|
||||||
createStatement += " WITHOUT ROWID"
|
createStatement += " WITHOUT ROWID"
|
||||||
}
|
}
|
||||||
resultCode = database.execute(createStatement)
|
resultCode = database.execute(createStatement)
|
||||||
assert(resultCode)
|
assert(resultCode)
|
||||||
case .int64:
|
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)
|
assert(resultCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,10 +633,10 @@ public final class SqliteValueBox: ValueBox {
|
|||||||
precondition(self.queue.isCurrent())
|
precondition(self.queue.isCurrent())
|
||||||
if let _ = self.fullTextTables[table.id] {
|
if let _ = self.fullTextTables[table.id] {
|
||||||
} else {
|
} 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)
|
precondition(resultCode)
|
||||||
self.fullTextTables[table.id] = table
|
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)
|
precondition(resultCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -211,7 +211,7 @@ swift_library(
|
|||||||
"//submodules/SlotMachineAnimationNode:SlotMachineAnimationNode",
|
"//submodules/SlotMachineAnimationNode:SlotMachineAnimationNode",
|
||||||
"//submodules/AnimatedNavigationStripeNode:AnimatedNavigationStripeNode",
|
"//submodules/AnimatedNavigationStripeNode:AnimatedNavigationStripeNode",
|
||||||
"//submodules/AudioBlob:AudioBlob",
|
"//submodules/AudioBlob:AudioBlob",
|
||||||
"//:GeneratedSources",
|
"//Telegram:GeneratedSources",
|
||||||
"//third-party/ZipArchive:ZipArchive",
|
"//third-party/ZipArchive:ZipArchive",
|
||||||
"//submodules/ChatImportUI:ChatImportUI",
|
"//submodules/ChatImportUI:ChatImportUI",
|
||||||
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
|
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -5626,9 +5626,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.presentAutoremoveSetup()
|
strongSelf.presentAutoremoveSetup()
|
||||||
} else if let currentAutoremoveTimeout = currentAutoremoveTimeout, let rect = strongSelf.chatDisplayNode.frameForInputPanelAccessoryButton(.messageAutoremoveTimeout(currentAutoremoveTimeout)) {
|
} else if let currentAutoremoveTimeout = currentAutoremoveTimeout, let rect = strongSelf.chatDisplayNode.frameForInputPanelAccessoryButton(.messageAutoremoveTimeout(currentAutoremoveTimeout)) {
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let intervalText = timeIntervalString(strings: strongSelf.presentationData.strings, value: currentAutoremoveTimeout)
|
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()
|
strongSelf.mediaRecordingModeTooltipController?.dismiss()
|
||||||
|
|
||||||
@ -7950,8 +7949,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
if chatPeer.canSetupAutoremoveTimeout(accountPeerId: strongSelf.context.account.peerId) {
|
if chatPeer.canSetupAutoremoveTimeout(accountPeerId: strongSelf.context.account.peerId) {
|
||||||
//TODO:localize
|
items.append(ActionSheetButtonItem(title: strongSelf.presentationInterfaceState.autoremoveTimeout == nil ? strongSelf.presentationData.strings.Conversation_AutoremoveActionEnable : strongSelf.presentationData.strings.Conversation_AutoremoveActionEdit, color: .accent, action: { [weak actionSheet] in
|
||||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationInterfaceState.autoremoveTimeout == nil ? "Enable Auto-Delete" : "Edit Auto-Delete Settings", color: .accent, action: { [weak actionSheet] in
|
|
||||||
guard let actionSheet = actionSheet else {
|
guard let actionSheet = actionSheet else {
|
||||||
return
|
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: [
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
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.chatDisplayNode.dismissInput()
|
||||||
strongSelf.present(actionSheet, in: .window(.root))
|
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):
|
case let .openChatInfo(expandAvatar):
|
||||||
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
||||||
|
|||||||
@ -50,8 +50,7 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
|
|||||||
canClear = true
|
canClear = true
|
||||||
} else if let peer = peer as? TelegramChannel {
|
} else if let peer = peer as? TelegramChannel {
|
||||||
if case .broadcast = peer.info {
|
if case .broadcast = peer.info {
|
||||||
//TODO:localize
|
title = strings.Conversation_ClearChannel
|
||||||
title = "Clear Channel"
|
|
||||||
}
|
}
|
||||||
if peer.hasPermission(.changeInfo) {
|
if peer.hasPermission(.changeInfo) {
|
||||||
canClear = true
|
canClear = true
|
||||||
|
|||||||
@ -256,7 +256,29 @@ final class WidgetDataContext {
|
|||||||
|
|
||||||
self.widgetPresentationDataDisposable = (presentationData
|
self.widgetPresentationDataDisposable = (presentationData
|
||||||
|> map { presentationData -> WidgetPresentationData in
|
|> 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
|
|> distinctUntilChanged).start(next: { value in
|
||||||
let path = widgetPresentationDataPath(rootPath: basePath)
|
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 {
|
enum CodingKeys: String, CodingKey {
|
||||||
case text
|
case text
|
||||||
case image
|
case image
|
||||||
@ -133,6 +141,7 @@ public struct WidgetDataPeer: Codable, Equatable {
|
|||||||
case mapLocation
|
case mapLocation
|
||||||
case game
|
case game
|
||||||
case poll
|
case poll
|
||||||
|
case autodeleteTimer
|
||||||
}
|
}
|
||||||
|
|
||||||
case text
|
case text
|
||||||
@ -148,6 +157,7 @@ public struct WidgetDataPeer: Codable, Equatable {
|
|||||||
case mapLocation(MapLocation)
|
case mapLocation(MapLocation)
|
||||||
case game(Game)
|
case game(Game)
|
||||||
case poll(Poll)
|
case poll(Poll)
|
||||||
|
case autodeleteTimer(AutodeleteTimer)
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
@ -177,6 +187,8 @@ public struct WidgetDataPeer: Codable, Equatable {
|
|||||||
self = .game(game)
|
self = .game(game)
|
||||||
} else if let poll = try? container.decode(Poll.self, forKey: .poll) {
|
} else if let poll = try? container.decode(Poll.self, forKey: .poll) {
|
||||||
self = .poll(poll)
|
self = .poll(poll)
|
||||||
|
} else if let autodeleteTimer = try? container.decode(AutodeleteTimer.self, forKey: .autodeleteTimer) {
|
||||||
|
self = .autodeleteTimer(autodeleteTimer)
|
||||||
} else {
|
} else {
|
||||||
throw DecodingError.generic
|
throw DecodingError.generic
|
||||||
}
|
}
|
||||||
@ -211,6 +223,8 @@ public struct WidgetDataPeer: Codable, Equatable {
|
|||||||
try container.encode(game, forKey: .game)
|
try container.encode(game, forKey: .game)
|
||||||
case let .poll(poll):
|
case let .poll(poll):
|
||||||
try container.encode(poll, forKey: .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 struct WidgetPresentationData: Codable, Equatable {
|
||||||
public var applicationLockedString: String
|
public var widgetChatsGalleryTitle: String
|
||||||
public var applicationStartRequiredString: String
|
public var widgetChatsGalleryDescription: String
|
||||||
public var widgetGalleryTitle: String
|
public var widgetShortcutsGalleryTitle: String
|
||||||
public var widgetGalleryDescription: String
|
public var widgetShortcutsGalleryDescription: String
|
||||||
|
|
||||||
public init(applicationLockedString: String, applicationStartRequiredString: String, widgetGalleryTitle: String, widgetGalleryDescription: String) {
|
public var widgetLongTapToEdit: String
|
||||||
self.applicationLockedString = applicationLockedString
|
public var widgetUpdatedTodayAt: String
|
||||||
self.applicationStartRequiredString = applicationStartRequiredString
|
public var widgetUpdatedAt: String
|
||||||
self.widgetGalleryTitle = widgetGalleryTitle
|
|
||||||
self.widgetGalleryDescription = widgetGalleryDescription
|
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 {
|
public func widgetPresentationDataPath(rootPath: String) -> String {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user