mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
62449d35d3
5
.gitignore
vendored
5
.gitignore
vendored
@ -61,7 +61,4 @@ bazel-testlogs
|
|||||||
bazel-testlogs/*
|
bazel-testlogs/*
|
||||||
*/*.swp
|
*/*.swp
|
||||||
*.swp
|
*.swp
|
||||||
build-input/data
|
build-input/*
|
||||||
build-input/data/*
|
|
||||||
build-input/gen
|
|
||||||
build-input/gen/*
|
|
||||||
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -7,7 +7,7 @@
|
|||||||
url=https://github.com/bazelbuild/rules_apple.git
|
url=https://github.com/bazelbuild/rules_apple.git
|
||||||
[submodule "build-system/bazel-rules/rules_swift"]
|
[submodule "build-system/bazel-rules/rules_swift"]
|
||||||
path = build-system/bazel-rules/rules_swift
|
path = build-system/bazel-rules/rules_swift
|
||||||
url=https://github.com/ali-fareed/rules_swift.git
|
url=https://github.com/bazelbuild/rules_swift.git
|
||||||
[submodule "build-system/bazel-rules/apple_support"]
|
[submodule "build-system/bazel-rules/apple_support"]
|
||||||
path = build-system/bazel-rules/apple_support
|
path = build-system/bazel-rules/apple_support
|
||||||
url = https://github.com/bazelbuild/apple_support.git
|
url = https://github.com/bazelbuild/apple_support.git
|
||||||
@ -16,7 +16,7 @@ url=https://github.com/ali-fareed/rules_swift.git
|
|||||||
url = https://github.com/telegramdesktop/libtgvoip.git
|
url = https://github.com/telegramdesktop/libtgvoip.git
|
||||||
[submodule "build-system/tulsi"]
|
[submodule "build-system/tulsi"]
|
||||||
path = build-system/tulsi
|
path = build-system/tulsi
|
||||||
url=https://github.com/ali-fareed/tulsi.git
|
url=https://github.com/bazelbuild/tulsi.git
|
||||||
[submodule "submodules/TgVoipWebrtc/tgcalls"]
|
[submodule "submodules/TgVoipWebrtc/tgcalls"]
|
||||||
path = submodules/TgVoipWebrtc/tgcalls
|
path = submodules/TgVoipWebrtc/tgcalls
|
||||||
url=../tgcalls.git
|
url=../tgcalls.git
|
||||||
|
25
README.md
25
README.md
@ -20,23 +20,7 @@ There are several things we require from **all developers** for the moment.
|
|||||||
git clone --recursive -j8 https://github.com/TelegramMessenger/Telegram-iOS.git
|
git clone --recursive -j8 https://github.com/TelegramMessenger/Telegram-iOS.git
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Download Bazel 4.0.0
|
3. Adjust configuration parameters
|
||||||
|
|
||||||
```
|
|
||||||
mkdir -p $HOME/bazel-dist
|
|
||||||
cd $HOME/bazel-dist
|
|
||||||
curl -O -L https://github.com/bazelbuild/bazel/releases/download/4.0.0/bazel-4.0.0-darwin-x86_64
|
|
||||||
mv bazel-* bazel
|
|
||||||
```
|
|
||||||
|
|
||||||
Verify that it's working
|
|
||||||
|
|
||||||
```
|
|
||||||
chmod +x bazel
|
|
||||||
./bazel --version
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Adjust configuration parameters
|
|
||||||
|
|
||||||
```
|
```
|
||||||
mkdir -p $HOME/telegram-configuration
|
mkdir -p $HOME/telegram-configuration
|
||||||
@ -46,7 +30,7 @@ cp -R build-system/example-configuration/* $HOME/telegram-configuration/
|
|||||||
- Modify the values in `variables.bzl`
|
- Modify the values in `variables.bzl`
|
||||||
- Replace the provisioning profiles in `provisioning` with valid files
|
- Replace the provisioning profiles in `provisioning` with valid files
|
||||||
|
|
||||||
5. (Optional) Create a build cache directory to speed up rebuilds
|
4. (Optional) Create a build cache directory to speed up rebuilds
|
||||||
|
|
||||||
```
|
```
|
||||||
mkdir -p "$HOME/telegram-bazel-cache"
|
mkdir -p "$HOME/telegram-bazel-cache"
|
||||||
@ -56,7 +40,6 @@ mkdir -p "$HOME/telegram-bazel-cache"
|
|||||||
|
|
||||||
```
|
```
|
||||||
python3 build-system/Make/Make.py \
|
python3 build-system/Make/Make.py \
|
||||||
--bazel="$HOME/bazel-dist/bazel" \
|
|
||||||
--cacheDir="$HOME/telegram-bazel-cache" \
|
--cacheDir="$HOME/telegram-bazel-cache" \
|
||||||
build \
|
build \
|
||||||
--configurationPath="$HOME/telegram-configuration" \
|
--configurationPath="$HOME/telegram-configuration" \
|
||||||
@ -68,7 +51,6 @@ python3 build-system/Make/Make.py \
|
|||||||
|
|
||||||
```
|
```
|
||||||
python3 build-system/Make/Make.py \
|
python3 build-system/Make/Make.py \
|
||||||
--bazel="$HOME/bazel-dist/bazel" \
|
|
||||||
--cacheDir="$HOME/telegram-bazel-cache" \
|
--cacheDir="$HOME/telegram-bazel-cache" \
|
||||||
generateProject \
|
generateProject \
|
||||||
--configurationPath="$HOME/telegram-configuration" \
|
--configurationPath="$HOME/telegram-configuration" \
|
||||||
@ -78,7 +60,6 @@ python3 build-system/Make/Make.py \
|
|||||||
It is possible to generate a project that does not require any codesigning certificates to be installed: add `--disableProvisioningProfiles` flag:
|
It is possible to generate a project that does not require any codesigning certificates to be installed: add `--disableProvisioningProfiles` flag:
|
||||||
```
|
```
|
||||||
python3 build-system/Make/Make.py \
|
python3 build-system/Make/Make.py \
|
||||||
--bazel="$HOME/bazel-dist/bazel" \
|
|
||||||
--cacheDir="$HOME/telegram-bazel-cache" \
|
--cacheDir="$HOME/telegram-bazel-cache" \
|
||||||
generateProject \
|
generateProject \
|
||||||
--configurationPath="$HOME/telegram-configuration" \
|
--configurationPath="$HOME/telegram-configuration" \
|
||||||
@ -100,6 +81,8 @@ python3 build-system/Make/Make.py build --help
|
|||||||
python3 build-system/Make/Make.py generateProject --help
|
python3 build-system/Make/Make.py generateProject --help
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Bazel is automatically downloaded when running Make.py for the first time. If you wish to use your own build of Bazel, pass `--bazel=path-to-bazel`. If your Bazel version differs from that in `versions.json`, you may use `--overrideBazelVersion` to skip the version check.
|
||||||
|
|
||||||
Each release is built using specific Xcode and Bazel versions (see `versions.json`). The helper script checks the versions of installed software and reports an error if they don't match the ones specified in `versions.json`. There are flags that allow to bypass these checks:
|
Each release is built using specific Xcode and Bazel versions (see `versions.json`). The helper script checks the versions of installed software and reports an error if they don't match the ones specified in `versions.json`. There are flags that allow to bypass these checks:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
32
build-system/Make/BazelLocation.py
Normal file
32
build-system/Make/BazelLocation.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from BuildEnvironment import is_apple_silicon, resolve_executable, call_executable, BuildEnvironmentVersions
|
||||||
|
|
||||||
|
def locate_bazel(base_path):
|
||||||
|
versions = BuildEnvironmentVersions(base_path=os.getcwd())
|
||||||
|
if is_apple_silicon():
|
||||||
|
arch = 'darwin-arm64'
|
||||||
|
else:
|
||||||
|
arch = 'x86_64'
|
||||||
|
bazel_name = 'bazel-{version}-{arch}'.format(version=versions.bazel_version, arch=arch)
|
||||||
|
bazel_path = '{}/build-input/{}'.format(base_path, bazel_name)
|
||||||
|
|
||||||
|
if not os.path.isfile(bazel_path):
|
||||||
|
call_executable([
|
||||||
|
'curl',
|
||||||
|
'-L',
|
||||||
|
'https://github.com/bazelbuild/bazel/releases/download/{version}/{name}'.format(
|
||||||
|
version=versions.bazel_version,
|
||||||
|
name=bazel_name
|
||||||
|
),
|
||||||
|
'--output',
|
||||||
|
bazel_path
|
||||||
|
])
|
||||||
|
|
||||||
|
if not os.access(bazel_path, os.X_OK):
|
||||||
|
st = os.stat(bazel_path)
|
||||||
|
os.chmod(bazel_path, st.st_mode | stat.S_IEXEC)
|
||||||
|
|
||||||
|
return bazel_path
|
@ -93,18 +93,12 @@ def get_xcode_version():
|
|||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
class BuildEnvironment:
|
class BuildEnvironmentVersions:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
base_path,
|
base_path
|
||||||
bazel_path,
|
|
||||||
override_bazel_version,
|
|
||||||
override_xcode_version
|
|
||||||
):
|
):
|
||||||
self.base_path = os.path.expanduser(base_path)
|
configuration_path = os.path.join(base_path, 'versions.json')
|
||||||
self.bazel_path = os.path.expanduser(bazel_path)
|
|
||||||
|
|
||||||
configuration_path = os.path.join(self.base_path, 'versions.json')
|
|
||||||
with open(configuration_path) as file:
|
with open(configuration_path) as file:
|
||||||
configuration_dict = json.load(file)
|
configuration_dict = json.load(file)
|
||||||
if configuration_dict['app'] is None:
|
if configuration_dict['app'] is None:
|
||||||
@ -120,24 +114,41 @@ class BuildEnvironment:
|
|||||||
else:
|
else:
|
||||||
self.xcode_version = configuration_dict['xcode']
|
self.xcode_version = configuration_dict['xcode']
|
||||||
|
|
||||||
|
class BuildEnvironment:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
base_path,
|
||||||
|
bazel_path,
|
||||||
|
override_bazel_version,
|
||||||
|
override_xcode_version
|
||||||
|
):
|
||||||
|
self.base_path = os.path.expanduser(base_path)
|
||||||
|
self.bazel_path = os.path.expanduser(bazel_path)
|
||||||
|
|
||||||
|
versions = BuildEnvironmentVersions(base_path=self.base_path)
|
||||||
|
|
||||||
actual_bazel_version = get_bazel_version(self.bazel_path)
|
actual_bazel_version = get_bazel_version(self.bazel_path)
|
||||||
if actual_bazel_version != self.bazel_version:
|
if actual_bazel_version != versions.bazel_version:
|
||||||
if override_bazel_version:
|
if override_bazel_version:
|
||||||
print('Overriding the required bazel version {} with {} as reported by {}'.format(
|
print('Overriding the required bazel version {} with {} as reported by {}'.format(
|
||||||
self.bazel_version, actual_bazel_version, self.bazel_path))
|
versions.bazel_version, actual_bazel_version, self.bazel_path))
|
||||||
self.bazel_version = actual_bazel_version
|
self.bazel_version = actual_bazel_version
|
||||||
else:
|
else:
|
||||||
print('Required bazel version is "{}", but "{}"" is reported by {}'.format(
|
print('Required bazel version is "{}", but "{}"" is reported by {}'.format(
|
||||||
self.bazel_version, actual_bazel_version, self.bazel_path))
|
versions.bazel_version, actual_bazel_version, self.bazel_path))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
actual_xcode_version = get_xcode_version()
|
actual_xcode_version = get_xcode_version()
|
||||||
if actual_xcode_version != self.xcode_version:
|
if actual_xcode_version != versions.xcode_version:
|
||||||
if override_xcode_version:
|
if override_xcode_version:
|
||||||
print('Overriding the required Xcode version {} with {} as reported by \'xcode-select -p\''.format(
|
print('Overriding the required Xcode version {} with {} as reported by \'xcode-select -p\''.format(
|
||||||
self.xcode_version, actual_xcode_version, self.bazel_path))
|
versions.xcode_version, actual_xcode_version, self.bazel_path))
|
||||||
self.xcode_version = actual_xcode_version
|
versions.xcode_version = actual_xcode_version
|
||||||
else:
|
else:
|
||||||
print('Required Xcode version is {}, but {} is reported by \'xcode-select -p\''.format(
|
print('Required Xcode version is {}, but {} is reported by \'xcode-select -p\''.format(
|
||||||
self.xcode_version, actual_xcode_version, self.bazel_path))
|
versions.xcode_version, actual_xcode_version, self.bazel_path))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
self.app_version = versions.app_version
|
||||||
|
self.xcode_version = versions.xcode_version
|
||||||
|
self.bazel_version = versions.bazel_version
|
||||||
|
@ -7,15 +7,15 @@ import sys
|
|||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from BuildEnvironment import is_apple_silicon, resolve_executable, call_executable, BuildEnvironment
|
from BuildEnvironment import resolve_executable, call_executable, BuildEnvironment
|
||||||
from ProjectGeneration import generate
|
from ProjectGeneration import generate
|
||||||
|
from BazelLocation import locate_bazel
|
||||||
|
|
||||||
class BazelCommandLine:
|
class BazelCommandLine:
|
||||||
def __init__(self, bazel_path, override_bazel_version, override_xcode_version, bazel_user_root):
|
def __init__(self, bazel, override_bazel_version, override_xcode_version, bazel_user_root):
|
||||||
self.build_environment = BuildEnvironment(
|
self.build_environment = BuildEnvironment(
|
||||||
base_path=os.getcwd(),
|
base_path=os.getcwd(),
|
||||||
bazel_path=bazel_path,
|
bazel_path=bazel,
|
||||||
override_bazel_version=override_bazel_version,
|
override_bazel_version=override_bazel_version,
|
||||||
override_xcode_version=override_xcode_version
|
override_xcode_version=override_xcode_version
|
||||||
)
|
)
|
||||||
@ -27,6 +27,9 @@ class BazelCommandLine:
|
|||||||
self.configuration_args = None
|
self.configuration_args = None
|
||||||
self.configuration_path = None
|
self.configuration_path = None
|
||||||
self.split_submodules = False
|
self.split_submodules = False
|
||||||
|
self.custom_target = None
|
||||||
|
self.continue_on_error = False
|
||||||
|
self.enable_sandbox = False
|
||||||
|
|
||||||
self.common_args = [
|
self.common_args = [
|
||||||
# https://docs.bazel.build/versions/master/command-line-reference.html
|
# https://docs.bazel.build/versions/master/command-line-reference.html
|
||||||
@ -314,9 +317,9 @@ class BazelCommandLine:
|
|||||||
call_executable(combined_arguments)
|
call_executable(combined_arguments)
|
||||||
|
|
||||||
|
|
||||||
def clean(arguments):
|
def clean(bazel, arguments):
|
||||||
bazel_command_line = BazelCommandLine(
|
bazel_command_line = BazelCommandLine(
|
||||||
bazel_path=arguments.bazel,
|
bazel=bazel,
|
||||||
override_bazel_version=arguments.overrideBazelVersion,
|
override_bazel_version=arguments.overrideBazelVersion,
|
||||||
override_xcode_version=arguments.overrideXcodeVersion,
|
override_xcode_version=arguments.overrideXcodeVersion,
|
||||||
bazel_user_root=arguments.bazelUserRoot
|
bazel_user_root=arguments.bazelUserRoot
|
||||||
@ -355,9 +358,9 @@ def resolve_configuration(bazel_command_line: BazelCommandLine, arguments):
|
|||||||
raise Exception('Neither configurationPath nor configurationGenerator are set')
|
raise Exception('Neither configurationPath nor configurationGenerator are set')
|
||||||
|
|
||||||
|
|
||||||
def generate_project(arguments):
|
def generate_project(bazel, arguments):
|
||||||
bazel_command_line = BazelCommandLine(
|
bazel_command_line = BazelCommandLine(
|
||||||
bazel_path=arguments.bazel,
|
bazel=bazel,
|
||||||
override_bazel_version=arguments.overrideBazelVersion,
|
override_bazel_version=arguments.overrideBazelVersion,
|
||||||
override_xcode_version=arguments.overrideXcodeVersion,
|
override_xcode_version=arguments.overrideXcodeVersion,
|
||||||
bazel_user_root=arguments.bazelUserRoot
|
bazel_user_root=arguments.bazelUserRoot
|
||||||
@ -401,9 +404,9 @@ def generate_project(arguments):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def build(arguments):
|
def build(bazel, arguments):
|
||||||
bazel_command_line = BazelCommandLine(
|
bazel_command_line = BazelCommandLine(
|
||||||
bazel_path=arguments.bazel,
|
bazel=bazel,
|
||||||
override_bazel_version=arguments.overrideBazelVersion,
|
override_bazel_version=arguments.overrideBazelVersion,
|
||||||
override_xcode_version=arguments.overrideXcodeVersion,
|
override_xcode_version=arguments.overrideXcodeVersion,
|
||||||
bazel_user_root=arguments.bazelUserRoot
|
bazel_user_root=arguments.bazelUserRoot
|
||||||
@ -463,7 +466,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--bazel',
|
'--bazel',
|
||||||
required=True,
|
required=False,
|
||||||
help='Use custom bazel binary',
|
help='Use custom bazel binary',
|
||||||
metavar='path'
|
metavar='path'
|
||||||
)
|
)
|
||||||
@ -596,7 +599,8 @@ if __name__ == '__main__':
|
|||||||
'--disableParallelSwiftmoduleGeneration',
|
'--disableParallelSwiftmoduleGeneration',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
default=False,
|
default=False,
|
||||||
help='Generate .swiftmodule files in parallel to building modules, can speed up compilation on multi-core systems.'
|
help='Generate .swiftmodule files in parallel to building modules, can speed up compilation on multi-core '
|
||||||
|
'systems. '
|
||||||
)
|
)
|
||||||
buildParser.add_argument(
|
buildParser.add_argument(
|
||||||
'--target',
|
'--target',
|
||||||
@ -629,13 +633,19 @@ if __name__ == '__main__':
|
|||||||
if args.commandName is None:
|
if args.commandName is None:
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
bazel_path = None
|
||||||
|
if args.bazel is None:
|
||||||
|
bazel_path = locate_bazel(base_path=os.getcwd())
|
||||||
|
else:
|
||||||
|
bazel_path = args.bazel
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if args.commandName == 'clean':
|
if args.commandName == 'clean':
|
||||||
clean(arguments=args)
|
clean(bazel=bazel_path, arguments=args)
|
||||||
elif args.commandName == 'generateProject':
|
elif args.commandName == 'generateProject':
|
||||||
generate_project(arguments=args)
|
generate_project(bazel=bazel_path, arguments=args)
|
||||||
elif args.commandName == 'build':
|
elif args.commandName == 'build':
|
||||||
build(arguments=args)
|
build(bazel=bazel_path, arguments=args)
|
||||||
else:
|
else:
|
||||||
raise Exception('Unknown command')
|
raise Exception('Unknown command')
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
@ -5,7 +5,7 @@ set -e
|
|||||||
BUILD_TELEGRAM_VERSION="1"
|
BUILD_TELEGRAM_VERSION="1"
|
||||||
|
|
||||||
MACOS_VERSION="11"
|
MACOS_VERSION="11"
|
||||||
XCODE_VERSION="13.1"
|
XCODE_VERSION="13.2.1"
|
||||||
GUEST_SHELL="bash"
|
GUEST_SHELL="bash"
|
||||||
|
|
||||||
VM_BASE_NAME="macos$(echo $MACOS_VERSION | sed -e 's/\.'/_/g)_Xcode$(echo $XCODE_VERSION | sed -e 's/\.'/_/g)"
|
VM_BASE_NAME="macos$(echo $MACOS_VERSION | sed -e 's/\.'/_/g)_Xcode$(echo $XCODE_VERSION | sed -e 's/\.'/_/g)"
|
||||||
|
@ -548,7 +548,11 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
self.contentContainerNode.contentNode = .reference(node: referenceNode)
|
self.contentContainerNode.contentNode = .reference(node: referenceNode)
|
||||||
self.contentAreaInScreenSpace = transitionInfo.contentAreaInScreenSpace
|
self.contentAreaInScreenSpace = transitionInfo.contentAreaInScreenSpace
|
||||||
self.customPosition = transitionInfo.customPosition
|
self.customPosition = transitionInfo.customPosition
|
||||||
let projectedFrame = convertFrame(referenceNode.view.bounds, from: referenceNode.view, to: self.view)
|
var projectedFrame = convertFrame(referenceNode.view.bounds, from: referenceNode.view, to: self.view)
|
||||||
|
projectedFrame.origin.x += transitionInfo.insets.left
|
||||||
|
projectedFrame.size.width -= transitionInfo.insets.left + transitionInfo.insets.right
|
||||||
|
projectedFrame.origin.y += transitionInfo.insets.top
|
||||||
|
projectedFrame.size.width -= transitionInfo.insets.top + transitionInfo.insets.bottom
|
||||||
self.originalProjectedContentViewFrame = (projectedFrame, projectedFrame)
|
self.originalProjectedContentViewFrame = (projectedFrame, projectedFrame)
|
||||||
}
|
}
|
||||||
case let .extracted(source):
|
case let .extracted(source):
|
||||||
@ -1463,7 +1467,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
|
|
||||||
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
|
||||||
let actionsSideInset: CGFloat = layout.safeInsets.left + 11.0
|
let actionsSideInset: CGFloat = layout.safeInsets.left + 12.0
|
||||||
var contentTopInset: CGFloat = max(11.0, layout.statusBarHeight ?? 0.0)
|
var contentTopInset: CGFloat = max(11.0, layout.statusBarHeight ?? 0.0)
|
||||||
|
|
||||||
if let _ = self.reactionContextNode {
|
if let _ = self.reactionContextNode {
|
||||||
@ -2025,11 +2029,13 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
public final class ContextControllerReferenceViewInfo {
|
public final class ContextControllerReferenceViewInfo {
|
||||||
public let referenceNode: ContextReferenceContentNode
|
public let referenceNode: ContextReferenceContentNode
|
||||||
public let contentAreaInScreenSpace: CGRect
|
public let contentAreaInScreenSpace: CGRect
|
||||||
|
public let insets: UIEdgeInsets
|
||||||
public let customPosition: CGPoint?
|
public let customPosition: CGPoint?
|
||||||
|
|
||||||
public init(referenceNode: ContextReferenceContentNode, contentAreaInScreenSpace: CGRect, customPosition: CGPoint? = nil) {
|
public init(referenceNode: ContextReferenceContentNode, contentAreaInScreenSpace: CGRect, insets: UIEdgeInsets = UIEdgeInsets(), customPosition: CGPoint? = nil) {
|
||||||
self.referenceNode = referenceNode
|
self.referenceNode = referenceNode
|
||||||
self.contentAreaInScreenSpace = contentAreaInScreenSpace
|
self.contentAreaInScreenSpace = contentAreaInScreenSpace
|
||||||
|
self.insets = insets
|
||||||
self.customPosition = customPosition
|
self.customPosition = customPosition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1086,44 +1086,46 @@ public class TextNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var headIndent: CGFloat = 0.0
|
var headIndent: CGFloat = 0.0
|
||||||
attributedString.enumerateAttributes(in: NSMakeRange(brokenLineRange.location, brokenLineRange.length), options: []) { attributes, range, _ in
|
if brokenLineRange.location >= 0 && brokenLineRange.length > 0 && brokenLineRange.location + brokenLineRange.length <= attributedString.length {
|
||||||
if attributes[NSAttributedString.Key(rawValue: "TelegramSpoiler")] != nil || attributes[NSAttributedString.Key(rawValue: "Attribute__Spoiler")] != nil {
|
attributedString.enumerateAttributes(in: NSMakeRange(brokenLineRange.location, brokenLineRange.length), options: []) { attributes, range, _ in
|
||||||
var ascent: CGFloat = 0.0
|
if attributes[NSAttributedString.Key(rawValue: "TelegramSpoiler")] != nil || attributes[NSAttributedString.Key(rawValue: "Attribute__Spoiler")] != nil {
|
||||||
var descent: CGFloat = 0.0
|
var ascent: CGFloat = 0.0
|
||||||
CTLineGetTypographicBounds(coreTextLine, &ascent, &descent, nil)
|
var descent: CGFloat = 0.0
|
||||||
|
CTLineGetTypographicBounds(coreTextLine, &ascent, &descent, nil)
|
||||||
var startIndex: Int?
|
|
||||||
var currentIndex: Int?
|
var startIndex: Int?
|
||||||
|
var currentIndex: Int?
|
||||||
let nsString = (attributedString.string as NSString)
|
|
||||||
nsString.enumerateSubstrings(in: range, options: .byComposedCharacterSequences) { substring, range, _, _ in
|
let nsString = (attributedString.string as NSString)
|
||||||
if let substring = substring, substring.rangeOfCharacter(from: .whitespacesAndNewlines) != nil {
|
nsString.enumerateSubstrings(in: range, options: .byComposedCharacterSequences) { substring, range, _, _ in
|
||||||
if let currentStartIndex = startIndex {
|
if let substring = substring, substring.rangeOfCharacter(from: .whitespacesAndNewlines) != nil {
|
||||||
startIndex = nil
|
if let currentStartIndex = startIndex {
|
||||||
let endIndex = range.location
|
startIndex = nil
|
||||||
addSpoilerWord(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex)
|
let endIndex = range.location
|
||||||
|
addSpoilerWord(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex)
|
||||||
|
}
|
||||||
|
} else if startIndex == nil {
|
||||||
|
startIndex = range.location
|
||||||
}
|
}
|
||||||
} else if startIndex == nil {
|
currentIndex = range.location + range.length
|
||||||
startIndex = range.location
|
|
||||||
}
|
}
|
||||||
currentIndex = range.location + range.length
|
|
||||||
|
if let currentStartIndex = startIndex, let currentIndex = currentIndex {
|
||||||
|
startIndex = nil
|
||||||
|
let endIndex = currentIndex
|
||||||
|
addSpoilerWord(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex, rightInset: truncated ? 12.0 : 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
addSpoiler(line: coreTextLine, ascent: ascent, descent: descent, startIndex: range.location, endIndex: range.location + range.length)
|
||||||
|
} else if let _ = attributes[NSAttributedString.Key.strikethroughStyle] {
|
||||||
|
let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil))
|
||||||
|
let upperX = ceil(CTLineGetOffsetForStringIndex(coreTextLine, range.location + range.length, nil))
|
||||||
|
let x = lowerX < upperX ? lowerX : upperX
|
||||||
|
strikethroughs.append(TextNodeStrikethrough(range: range, frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: fontLineHeight)))
|
||||||
|
} else if let paragraphStyle = attributes[NSAttributedString.Key.paragraphStyle] as? NSParagraphStyle {
|
||||||
|
headIndent = paragraphStyle.headIndent
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let currentStartIndex = startIndex, let currentIndex = currentIndex {
|
|
||||||
startIndex = nil
|
|
||||||
let endIndex = currentIndex
|
|
||||||
addSpoilerWord(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex, rightInset: truncated ? 12.0 : 0.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
addSpoiler(line: coreTextLine, ascent: ascent, descent: descent, startIndex: range.location, endIndex: range.location + range.length)
|
|
||||||
} else if let _ = attributes[NSAttributedString.Key.strikethroughStyle] {
|
|
||||||
let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil))
|
|
||||||
let upperX = ceil(CTLineGetOffsetForStringIndex(coreTextLine, range.location + range.length, nil))
|
|
||||||
let x = lowerX < upperX ? lowerX : upperX
|
|
||||||
strikethroughs.append(TextNodeStrikethrough(range: range, frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: fontLineHeight)))
|
|
||||||
} else if let paragraphStyle = attributes[NSAttributedString.Key.paragraphStyle] as? NSParagraphStyle {
|
|
||||||
headIndent = paragraphStyle.headIndent
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
#if !os(macOS)
|
||||||
import UIKit
|
import UIKit
|
||||||
|
#else
|
||||||
|
import AppKit
|
||||||
|
#endif
|
||||||
import CoreMedia
|
import CoreMedia
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import FFMpegBinding
|
import FFMpegBinding
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
#if !os(macOS)
|
||||||
import UIKit
|
import UIKit
|
||||||
|
#else
|
||||||
|
import AppKit
|
||||||
|
#endif
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Postbox
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
|
32
submodules/OpenSSLEncryptionProvider/Package.swift
Normal file
32
submodules/OpenSSLEncryptionProvider/Package.swift
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// swift-tools-version:5.5
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "OpenSSLEncryption",
|
||||||
|
platforms: [
|
||||||
|
.macOS(.v10_11)
|
||||||
|
],
|
||||||
|
products: [
|
||||||
|
.library(
|
||||||
|
name: "OpenSSLEncryption",
|
||||||
|
targets: ["OpenSSLEncryption"]),
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "OpenSSLEncryption",
|
||||||
|
dependencies: [],
|
||||||
|
path: ".",
|
||||||
|
exclude: ["BUILD"],
|
||||||
|
publicHeadersPath: "PublicHeaders",
|
||||||
|
cSettings: [
|
||||||
|
.headerSearchPath("PublicHeaders"),
|
||||||
|
.unsafeFlags([
|
||||||
|
"-I../../../../core-xprojects/openssl/build/openssl/include",
|
||||||
|
"-I../EncryptionProvider/PublicHeaders"
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
)
|
@ -610,7 +610,7 @@ struct AccountFinalState {
|
|||||||
struct AccountReplayedFinalState {
|
struct AccountReplayedFinalState {
|
||||||
let state: AccountFinalState
|
let state: AccountFinalState
|
||||||
let addedIncomingMessageIds: [MessageId]
|
let addedIncomingMessageIds: [MessageId]
|
||||||
let addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)]
|
let addedReactionEvents: [(reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)]
|
||||||
let wasScheduledMessageIds: [MessageId]
|
let wasScheduledMessageIds: [MessageId]
|
||||||
let addedSecretMessageIds: [MessageId]
|
let addedSecretMessageIds: [MessageId]
|
||||||
let deletedMessageIds: [DeletedMessageId]
|
let deletedMessageIds: [DeletedMessageId]
|
||||||
@ -628,7 +628,7 @@ struct AccountReplayedFinalState {
|
|||||||
|
|
||||||
struct AccountFinalStateEvents {
|
struct AccountFinalStateEvents {
|
||||||
let addedIncomingMessageIds: [MessageId]
|
let addedIncomingMessageIds: [MessageId]
|
||||||
let addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)]
|
let addedReactionEvents: [(reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)]
|
||||||
let wasScheduledMessageIds:[MessageId]
|
let wasScheduledMessageIds:[MessageId]
|
||||||
let deletedMessageIds: [DeletedMessageId]
|
let deletedMessageIds: [DeletedMessageId]
|
||||||
let updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]]
|
let updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]]
|
||||||
@ -651,7 +651,7 @@ struct AccountFinalStateEvents {
|
|||||||
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
||||||
self.addedIncomingMessageIds = addedIncomingMessageIds
|
self.addedIncomingMessageIds = addedIncomingMessageIds
|
||||||
self.addedReactionEvents = addedReactionEvents
|
self.addedReactionEvents = addedReactionEvents
|
||||||
self.wasScheduledMessageIds = wasScheduledMessageIds
|
self.wasScheduledMessageIds = wasScheduledMessageIds
|
||||||
|
@ -4,6 +4,43 @@ import SwiftSignalKit
|
|||||||
import TelegramApi
|
import TelegramApi
|
||||||
import MtProtoKit
|
import MtProtoKit
|
||||||
|
|
||||||
|
private func reactionGeneratedEvent(_ previousReactions: ReactionsMessageAttribute?, _ updatedReactions: ReactionsMessageAttribute?, message: Message, transaction: Transaction) -> (reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)? {
|
||||||
|
|
||||||
|
if let updatedReactions = updatedReactions, !message.flags.contains(.Incoming), message.id.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
|
let prev = previousReactions?.reactions ?? []
|
||||||
|
|
||||||
|
let updated = updatedReactions.reactions.filter { value in
|
||||||
|
return !prev.contains(where: {
|
||||||
|
$0.value == value.value && $0.count == value.count
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let myUpdated = updatedReactions.reactions.filter { value in
|
||||||
|
return value.isSelected
|
||||||
|
}.first
|
||||||
|
let myPrevious = prev.filter { value in
|
||||||
|
return value.isSelected
|
||||||
|
}.first
|
||||||
|
|
||||||
|
let previousCount = prev.reduce(0, {
|
||||||
|
$0 + $1.count
|
||||||
|
})
|
||||||
|
let updatedCount = updatedReactions.reactions.reduce(0, {
|
||||||
|
$0 + $1.count
|
||||||
|
})
|
||||||
|
|
||||||
|
let newReaction = updated.filter {
|
||||||
|
!$0.isSelected
|
||||||
|
}.first?.value
|
||||||
|
|
||||||
|
if !updated.isEmpty && myUpdated == myPrevious, updatedCount >= previousCount, let value = newReaction {
|
||||||
|
if let reactionAuthor = transaction.getPeer(message.id.peerId) {
|
||||||
|
return (reactionAuthor: reactionAuthor, reaction: value, message: message, timestamp: Int32(Date().timeIntervalSince1970))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private func peerIdsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set<PeerId> {
|
private func peerIdsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set<PeerId> {
|
||||||
var peerIds = Set<PeerId>()
|
var peerIds = Set<PeerId>()
|
||||||
@ -2430,7 +2467,7 @@ func replayFinalState(
|
|||||||
}
|
}
|
||||||
var wasScheduledMessageIds:[MessageId] = []
|
var wasScheduledMessageIds:[MessageId] = []
|
||||||
var addedIncomingMessageIds: [MessageId] = []
|
var addedIncomingMessageIds: [MessageId] = []
|
||||||
var addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)] = []
|
var addedReactionEvents: [(reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)] = []
|
||||||
|
|
||||||
if !wasOperationScheduledMessageIds.isEmpty {
|
if !wasOperationScheduledMessageIds.isEmpty {
|
||||||
let existingIds = transaction.filterStoredMessageIds(Set(wasOperationScheduledMessageIds))
|
let existingIds = transaction.filterStoredMessageIds(Set(wasOperationScheduledMessageIds))
|
||||||
@ -2670,6 +2707,7 @@ func replayFinalState(
|
|||||||
invalidateGroupStats.insert(Namespaces.PeerGroup.archive)
|
invalidateGroupStats.insert(Namespaces.PeerGroup.archive)
|
||||||
}
|
}
|
||||||
case let .EditMessage(id, message):
|
case let .EditMessage(id, message):
|
||||||
|
var generatedEvent: (reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)?
|
||||||
transaction.updateMessage(id, update: { previousMessage in
|
transaction.updateMessage(id, update: { previousMessage in
|
||||||
var updatedFlags = message.flags
|
var updatedFlags = message.flags
|
||||||
var updatedLocalTags = message.localTags
|
var updatedLocalTags = message.localTags
|
||||||
@ -2681,8 +2719,21 @@ func replayFinalState(
|
|||||||
} else {
|
} else {
|
||||||
updatedFlags.remove(.Incoming)
|
updatedFlags.remove(.Incoming)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let peers: [PeerId:Peer] = previousMessage.peers.reduce([:], { current, value in
|
||||||
|
var current = current
|
||||||
|
current[value.0] = value.1
|
||||||
|
return current
|
||||||
|
})
|
||||||
|
|
||||||
|
if let message = locallyRenderedMessage(message: message, peers: peers) {
|
||||||
|
generatedEvent = reactionGeneratedEvent(previousMessage.reactionsAttribute, message.reactionsAttribute, message: message, transaction: transaction)
|
||||||
|
}
|
||||||
return .update(message.withUpdatedLocalTags(updatedLocalTags).withUpdatedFlags(updatedFlags))
|
return .update(message.withUpdatedLocalTags(updatedLocalTags).withUpdatedFlags(updatedFlags))
|
||||||
})
|
})
|
||||||
|
if let generatedEvent = generatedEvent {
|
||||||
|
addedReactionEvents.append(generatedEvent)
|
||||||
|
}
|
||||||
case let .UpdateMessagePoll(pollId, apiPoll, results):
|
case let .UpdateMessagePoll(pollId, apiPoll, results):
|
||||||
if let poll = transaction.getMedia(pollId) as? TelegramMediaPoll {
|
if let poll = transaction.getMedia(pollId) as? TelegramMediaPoll {
|
||||||
var updatedPoll = poll
|
var updatedPoll = poll
|
||||||
@ -3229,14 +3280,14 @@ func replayFinalState(
|
|||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
case let .UpdateMessageReactions(messageId, reactions, eventTimestamp):
|
case let .UpdateMessageReactions(messageId, reactions, _):
|
||||||
var generatedEvent: (reactionAuthor: Peer, message: Message, timestamp: Int32)?
|
|
||||||
transaction.updateMessage(messageId, update: { currentMessage in
|
transaction.updateMessage(messageId, update: { currentMessage in
|
||||||
var updatedReactions = ReactionsMessageAttribute(apiReactions: reactions)
|
var updatedReactions = ReactionsMessageAttribute(apiReactions: reactions)
|
||||||
|
|
||||||
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
||||||
var attributes = currentMessage.attributes
|
var attributes = currentMessage.attributes
|
||||||
var previousReactions: ReactionsMessageAttribute?
|
var previousReactions: ReactionsMessageAttribute?
|
||||||
|
let _ = previousReactions
|
||||||
var added = false
|
var added = false
|
||||||
loop: for j in 0 ..< attributes.count {
|
loop: for j in 0 ..< attributes.count {
|
||||||
if let attribute = attributes[j] as? ReactionsMessageAttribute {
|
if let attribute = attributes[j] as? ReactionsMessageAttribute {
|
||||||
@ -3254,45 +3305,9 @@ func replayFinalState(
|
|||||||
if !added {
|
if !added {
|
||||||
attributes.append(updatedReactions)
|
attributes.append(updatedReactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let eventTimestamp = eventTimestamp, !currentMessage.flags.contains(.Incoming), let chatPeer = currentMessage.peers[currentMessage.id.peerId] {
|
|
||||||
let _ = chatPeer
|
|
||||||
|
|
||||||
var previousCount = 0
|
|
||||||
if let previousReactions = previousReactions {
|
|
||||||
for reaction in previousReactions.reactions {
|
|
||||||
previousCount += Int(reaction.count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var updatedCount = 0
|
|
||||||
for reaction in updatedReactions.reactions {
|
|
||||||
updatedCount += Int(reaction.count)
|
|
||||||
}
|
|
||||||
|
|
||||||
if updatedCount > previousCount {
|
|
||||||
if let topPeer = updatedReactions.recentPeers.last {
|
|
||||||
var wasPresentBefore = false
|
|
||||||
if let previousReactions = previousReactions {
|
|
||||||
for recentPeer in previousReactions.recentPeers {
|
|
||||||
if recentPeer.peerId == topPeer.peerId {
|
|
||||||
wasPresentBefore = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !wasPresentBefore, let reactionAuthor = transaction.getPeer(topPeer.peerId), transaction.isPeerContact(peerId: topPeer.peerId) {
|
|
||||||
generatedEvent = (reactionAuthor: reactionAuthor, message: currentMessage.withUpdatedAttributes(attributes), timestamp: eventTimestamp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||||
})
|
})
|
||||||
if let generatedEvent = generatedEvent {
|
|
||||||
addedReactionEvents.append(generatedEvent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,8 +105,8 @@ public final class AccountStateManager {
|
|||||||
return self.notificationMessagesPipe.signal()
|
return self.notificationMessagesPipe.signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
private let reactionNotificationsPipe = ValuePipe<[(reactionAuthor: Peer, message: Message)]>()
|
private let reactionNotificationsPipe = ValuePipe<[(reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)]>()
|
||||||
public var reactionNotifications: Signal<[(reactionAuthor: Peer, message: Message)], NoError> {
|
public var reactionNotifications: Signal<[(reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)], NoError> {
|
||||||
return self.reactionNotificationsPipe.signal()
|
return self.reactionNotificationsPipe.signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,16 +746,15 @@ public final class AccountStateManager {
|
|||||||
|
|
||||||
let timestamp = Int32(Date().timeIntervalSince1970)
|
let timestamp = Int32(Date().timeIntervalSince1970)
|
||||||
let minReactionTimestamp = timestamp - 20
|
let minReactionTimestamp = timestamp - 20
|
||||||
let reactionEvents = events.addedReactionEvents.compactMap { event -> (reactionAuthor: Peer, message: Message)? in
|
let reactionEvents = events.addedReactionEvents.compactMap { event -> (reactionAuthor: Peer, reaction: String, message: Message, timestamp: Int32)? in
|
||||||
if event.timestamp >= minReactionTimestamp {
|
if event.timestamp >= minReactionTimestamp {
|
||||||
return (event.reactionAuthor, event.message)
|
return (event.reactionAuthor, event.reaction, event.message, event.timestamp)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !reactionEvents.isEmpty {
|
self.reactionNotificationsPipe.putNext(reactionEvents)
|
||||||
self.reactionNotificationsPipe.putNext(reactionEvents)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !events.displayAlerts.isEmpty {
|
if !events.displayAlerts.isEmpty {
|
||||||
self.displayAlertsPipe.putNext(events.displayAlerts)
|
self.displayAlertsPipe.putNext(events.displayAlerts)
|
||||||
|
@ -19,6 +19,7 @@ public func updateMessageReactionsInteractively(account: Account, messageId: Mes
|
|||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes.append(PendingReactionsMessageAttribute(accountPeerId: account.peerId, value: reaction))
|
attributes.append(PendingReactionsMessageAttribute(accountPeerId: account.peerId, value: reaction))
|
||||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||||
})
|
})
|
||||||
@ -245,7 +246,9 @@ public extension EngineMessageReactionListContext.State {
|
|||||||
}
|
}
|
||||||
for recentPeer in reactionsAttribute.recentPeers {
|
for recentPeer in reactionsAttribute.recentPeers {
|
||||||
if let peer = message.peers[recentPeer.peerId] {
|
if let peer = message.peers[recentPeer.peerId] {
|
||||||
items.append(EngineMessageReactionListContext.Item(peer: EnginePeer(peer), reaction: recentPeer.value))
|
if reaction == nil || recentPeer.value == reaction {
|
||||||
|
items.append(EngineMessageReactionListContext.Item(peer: EnginePeer(peer), reaction: recentPeer.value))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,6 +340,8 @@ public final class EngineMessageReactionListContext {
|
|||||||
|
|
||||||
if initialState.canLoadMore {
|
if initialState.canLoadMore {
|
||||||
self.loadMore()
|
self.loadMore()
|
||||||
|
} else {
|
||||||
|
self.statePromise.set(.single(self.state))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ public struct ProxyServerSettings: Codable, Equatable, Hashable {
|
|||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(self.host)
|
hasher.combine(self.host)
|
||||||
|
hasher.combine(self.port)
|
||||||
hasher.combine(self.connection)
|
hasher.combine(self.connection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,6 @@ public struct MessageReaction: Equatable, PostboxCoding {
|
|||||||
public var isSelected: Bool
|
public var isSelected: Bool
|
||||||
|
|
||||||
public init(value: String, count: Int32, isSelected: Bool) {
|
public init(value: String, count: Int32, isSelected: Bool) {
|
||||||
var value = value
|
|
||||||
|
|
||||||
if value == "❤️" {
|
|
||||||
value = "❤"
|
|
||||||
}
|
|
||||||
|
|
||||||
self.value = value
|
self.value = value
|
||||||
self.count = count
|
self.count = count
|
||||||
self.isSelected = isSelected
|
self.isSelected = isSelected
|
||||||
|
@ -322,6 +322,19 @@ public extension Message {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
var hasReactions: Bool {
|
||||||
|
for attribute in self.attributes {
|
||||||
|
if let attribute = attribute as? ReactionsMessageAttribute {
|
||||||
|
return !attribute.reactions.isEmpty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for attribute in self.attributes {
|
||||||
|
if let attribute = attribute as? PendingReactionsMessageAttribute {
|
||||||
|
return attribute.value != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var textEntitiesAttribute: TextEntitiesMessageAttribute? {
|
var textEntitiesAttribute: TextEntitiesMessageAttribute? {
|
||||||
for attribute in self.attributes {
|
for attribute in self.attributes {
|
||||||
|
@ -8374,7 +8374,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}))
|
}))
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: strongSelf, sourceNode: backButtonNode, insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 4.0, right: 0.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: strongSelf, sourceNode: backButtonNode, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||||
strongSelf.presentInGlobalOverlay(contextController)
|
strongSelf.presentInGlobalOverlay(contextController)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -14564,15 +14564,17 @@ private final class ChatControllerContextReferenceContentSource: ContextReferenc
|
|||||||
private let controller: ViewController
|
private let controller: ViewController
|
||||||
private let sourceNode: ContextReferenceContentNode
|
private let sourceNode: ContextReferenceContentNode
|
||||||
private let insets: UIEdgeInsets
|
private let insets: UIEdgeInsets
|
||||||
|
private let contentInsets: UIEdgeInsets
|
||||||
|
|
||||||
init(controller: ViewController, sourceNode: ContextReferenceContentNode, insets: UIEdgeInsets) {
|
init(controller: ViewController, sourceNode: ContextReferenceContentNode, insets: UIEdgeInsets, contentInsets: UIEdgeInsets = UIEdgeInsets()) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.sourceNode = sourceNode
|
self.sourceNode = sourceNode
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
|
self.contentInsets = contentInsets
|
||||||
}
|
}
|
||||||
|
|
||||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||||
return ContextControllerReferenceViewInfo(referenceNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds.inset(by: insets))
|
return ContextControllerReferenceViewInfo(referenceNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds.inset(by: self.insets), insets: self.contentInsets)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,19 @@
|
|||||||
|
|
||||||
|
config_setting(
|
||||||
|
name = "debug_build",
|
||||||
|
values = {
|
||||||
|
"compilation_mode": "dbg",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
optimization_flags = select({
|
||||||
|
":debug_build": [
|
||||||
|
"-O2",
|
||||||
|
"-DNDEBUG",
|
||||||
|
],
|
||||||
|
"//conditions:default": ["-DNDEBUG"],
|
||||||
|
})
|
||||||
|
|
||||||
objc_library(
|
objc_library(
|
||||||
name = "TgVoipWebrtc",
|
name = "TgVoipWebrtc",
|
||||||
enable_modules = True,
|
enable_modules = True,
|
||||||
@ -55,8 +70,7 @@ objc_library(
|
|||||||
"-DRTC_ENABLE_VP9",
|
"-DRTC_ENABLE_VP9",
|
||||||
"-DTGVOIP_NAMESPACE=tgvoip_webrtc",
|
"-DTGVOIP_NAMESPACE=tgvoip_webrtc",
|
||||||
"-std=c++14",
|
"-std=c++14",
|
||||||
#"-DWEBRTC_DISABLE_H265",
|
] + optimization_flags,
|
||||||
],
|
|
||||||
includes = [
|
includes = [
|
||||||
"PublicHeaders",
|
"PublicHeaders",
|
||||||
],
|
],
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit b2c7f2f226a6c17a587b5fb421963a503855a2b6
|
Subproject commit 955e51f15ba1b2e35a910064388e5c0737032bb7
|
32
third-party/webrtc/BUILD
vendored
32
third-party/webrtc/BUILD
vendored
@ -11,8 +11,7 @@ config_setting(
|
|||||||
optimization_flags = select({
|
optimization_flags = select({
|
||||||
":debug_build": [
|
":debug_build": [
|
||||||
"-O2",
|
"-O2",
|
||||||
#"-DNDEBUG",
|
"-DNDEBUG",
|
||||||
#"-DRTC_DCHECK_IS_ON",
|
|
||||||
],
|
],
|
||||||
"//conditions:default": ["-DNDEBUG"],
|
"//conditions:default": ["-DNDEBUG"],
|
||||||
})
|
})
|
||||||
@ -684,7 +683,6 @@ webrtc_sources = [
|
|||||||
"api/video_codecs/video_decoder.cc",
|
"api/video_codecs/video_decoder.cc",
|
||||||
"api/video_codecs/video_decoder_software_fallback_wrapper.cc",
|
"api/video_codecs/video_decoder_software_fallback_wrapper.cc",
|
||||||
"api/video_codecs/video_encoder.cc",
|
"api/video_codecs/video_encoder.cc",
|
||||||
"api/video_codecs/video_encoder_config.cc",
|
|
||||||
"api/video_codecs/video_encoder_software_fallback_wrapper.cc",
|
"api/video_codecs/video_encoder_software_fallback_wrapper.cc",
|
||||||
"api/video_codecs/vp8_frame_config.cc",
|
"api/video_codecs/vp8_frame_config.cc",
|
||||||
"api/video_codecs/vp8_temporal_layers.cc",
|
"api/video_codecs/vp8_temporal_layers.cc",
|
||||||
@ -1286,12 +1284,10 @@ webrtc_sources = [
|
|||||||
"modules/video_coding/codecs/multiplex/multiplex_encoded_image_packer.cc",
|
"modules/video_coding/codecs/multiplex/multiplex_encoded_image_packer.cc",
|
||||||
"modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc",
|
"modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc",
|
||||||
"modules/video_coding/decoder_database.cc",
|
"modules/video_coding/decoder_database.cc",
|
||||||
"modules/video_coding/decoding_state.cc",
|
|
||||||
"modules/video_coding/encoded_frame.cc",
|
"modules/video_coding/encoded_frame.cc",
|
||||||
"modules/video_coding/event_wrapper.cc",
|
|
||||||
"modules/video_coding/fec_controller_default.cc",
|
"modules/video_coding/fec_controller_default.cc",
|
||||||
"modules/video_coding/frame_buffer.cc",
|
|
||||||
"modules/video_coding/frame_buffer2.cc",
|
"modules/video_coding/frame_buffer2.cc",
|
||||||
|
"modules/video_coding/frame_buffer3.cc",
|
||||||
"modules/video_coding/frame_dependencies_calculator.cc",
|
"modules/video_coding/frame_dependencies_calculator.cc",
|
||||||
"modules/video_coding/frame_object.cc",
|
"modules/video_coding/frame_object.cc",
|
||||||
"modules/video_coding/generic_decoder.cc",
|
"modules/video_coding/generic_decoder.cc",
|
||||||
@ -1300,16 +1296,12 @@ webrtc_sources = [
|
|||||||
"modules/video_coding/histogram.cc",
|
"modules/video_coding/histogram.cc",
|
||||||
"modules/video_coding/include/video_codec_interface.cc",
|
"modules/video_coding/include/video_codec_interface.cc",
|
||||||
"modules/video_coding/inter_frame_delay.cc",
|
"modules/video_coding/inter_frame_delay.cc",
|
||||||
"modules/video_coding/jitter_buffer.cc",
|
|
||||||
"modules/video_coding/jitter_estimator.cc",
|
"modules/video_coding/jitter_estimator.cc",
|
||||||
"modules/video_coding/loss_notification_controller.cc",
|
"modules/video_coding/loss_notification_controller.cc",
|
||||||
"modules/video_coding/media_opt_util.cc",
|
"modules/video_coding/media_opt_util.cc",
|
||||||
"modules/video_coding/packet.cc",
|
|
||||||
"modules/video_coding/packet_buffer.cc",
|
"modules/video_coding/packet_buffer.cc",
|
||||||
"modules/video_coding/receiver.cc",
|
|
||||||
"modules/video_coding/rtp_frame_reference_finder.cc",
|
"modules/video_coding/rtp_frame_reference_finder.cc",
|
||||||
"modules/video_coding/rtt_filter.cc",
|
"modules/video_coding/rtt_filter.cc",
|
||||||
"modules/video_coding/session_info.cc",
|
|
||||||
"modules/video_coding/timestamp_map.cc",
|
"modules/video_coding/timestamp_map.cc",
|
||||||
"modules/video_coding/timing.cc",
|
"modules/video_coding/timing.cc",
|
||||||
"modules/video_coding/unique_timestamp_counter.cc",
|
"modules/video_coding/unique_timestamp_counter.cc",
|
||||||
@ -1324,8 +1316,6 @@ webrtc_sources = [
|
|||||||
"modules/video_coding/utility/vp9_uncompressed_header_parser.cc",
|
"modules/video_coding/utility/vp9_uncompressed_header_parser.cc",
|
||||||
"modules/video_coding/video_codec_initializer.cc",
|
"modules/video_coding/video_codec_initializer.cc",
|
||||||
"modules/video_coding/video_coding_defines.cc",
|
"modules/video_coding/video_coding_defines.cc",
|
||||||
"modules/video_coding/video_coding_impl.cc",
|
|
||||||
"modules/video_coding/video_receiver.cc",
|
|
||||||
"modules/video_coding/video_receiver2.cc",
|
"modules/video_coding/video_receiver2.cc",
|
||||||
"modules/video_coding/codecs/vp8/default_temporal_layers.cc",
|
"modules/video_coding/codecs/vp8/default_temporal_layers.cc",
|
||||||
"modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc",
|
"modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc",
|
||||||
@ -1522,7 +1512,6 @@ webrtc_sources = [
|
|||||||
"video/stream_synchronization.cc",
|
"video/stream_synchronization.cc",
|
||||||
"video/transport_adapter.cc",
|
"video/transport_adapter.cc",
|
||||||
"video/video_quality_observer.cc",
|
"video/video_quality_observer.cc",
|
||||||
"video/video_receive_stream.cc",
|
|
||||||
"video/video_send_stream.cc",
|
"video/video_send_stream.cc",
|
||||||
"video/video_send_stream_impl.cc",
|
"video/video_send_stream_impl.cc",
|
||||||
"video/video_source_sink_controller.cc",
|
"video/video_source_sink_controller.cc",
|
||||||
@ -2466,7 +2455,6 @@ webrtc_sources = [
|
|||||||
"video/stream_synchronization.h",
|
"video/stream_synchronization.h",
|
||||||
"video/transport_adapter.h",
|
"video/transport_adapter.h",
|
||||||
"video/video_quality_observer.h",
|
"video/video_quality_observer.h",
|
||||||
"video/video_receive_stream.h",
|
|
||||||
"video/video_send_stream_impl.h",
|
"video/video_send_stream_impl.h",
|
||||||
"video/video_source_sink_controller.h",
|
"video/video_source_sink_controller.h",
|
||||||
"video/video_stream_decoder_impl.h",
|
"video/video_stream_decoder_impl.h",
|
||||||
@ -2959,6 +2947,19 @@ webrtc_sources = [
|
|||||||
"modules/video_coding/h265_vps_sps_pps_tracker.cc",
|
"modules/video_coding/h265_vps_sps_pps_tracker.cc",
|
||||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc",
|
"modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc",
|
||||||
"common_video/h265/h265_bitstream_parser.cc",
|
"common_video/h265/h265_bitstream_parser.cc",
|
||||||
|
"api/video_codecs/video_encoder_config.cc",
|
||||||
|
"video/frame_cadence_adapter.cc",
|
||||||
|
"modules/video_coding/codecs/h265/include/h265_globals.h",
|
||||||
|
"video/frame_cadence_adapter.h",
|
||||||
|
"common_video/h265/h265_common.h",
|
||||||
|
"modules/video_coding/h265_vps_sps_pps_tracker.h",
|
||||||
|
"common_video/h265/h265_pps_parser.h",
|
||||||
|
"modules/video_coding/frame_buffer3.h",
|
||||||
|
"common_video/h265/h265_bitstream_parser.h",
|
||||||
|
"modules/rtp_rtcp/source/video_rtp_depacketizer_h265.h",
|
||||||
|
"common_video/h265/h265_sps_parser.h",
|
||||||
|
"modules/rtp_rtcp/source/rtp_format_h265.h",
|
||||||
|
"common_video/h265/h265_vps_parser.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
ios_objc_sources = [
|
ios_objc_sources = [
|
||||||
@ -3225,6 +3226,9 @@ ios_sources = [
|
|||||||
"objc/native/src/network_monitor_observer.h",
|
"objc/native/src/network_monitor_observer.h",
|
||||||
"objc/components/video_codec/RTCCodecSpecificInfoH265.mm",
|
"objc/components/video_codec/RTCCodecSpecificInfoH265.mm",
|
||||||
"objc/components/video_codec/RTCH265ProfileLevelId.mm",
|
"objc/components/video_codec/RTCH265ProfileLevelId.mm",
|
||||||
|
"objc/components/video_codec/RTCCodecSpecificInfoH265+Private.h",
|
||||||
|
"objc/components/video_codec/RTCH265ProfileLevelId.h",
|
||||||
|
"objc/components/video_codec/RTCCodecSpecificInfoH265.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
common_arm_specific_sources = [webrtc_source_dir + "/" + path for path in [
|
common_arm_specific_sources = [webrtc_source_dir + "/" + path for path in [
|
||||||
|
2
third-party/webrtc/webrtc
vendored
2
third-party/webrtc/webrtc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 9cd0a24a2e450bcc731fbce6f3fe0fb516c75bc2
|
Subproject commit 4f09932cfdda8c8a432e8e5ace32c9ae840f6201
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"app": "8.4.1",
|
"app": "8.4.1",
|
||||||
"bazel": "4.0.0",
|
"bazel": "5.0.0",
|
||||||
"xcode": "13.1"
|
"xcode": "13.2.1"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user