diff --git a/Makefile b/Makefile
deleted file mode 100644
index 68ac34a879..0000000000
--- a/Makefile
+++ /dev/null
@@ -1,159 +0,0 @@
-.PHONY : kill_xcode clean bazel_app_debug_arm64 bazel_app_debug_sim_arm64 bazel_app_arm64 bazel_app_armv7 bazel_app check_sandbox_debug_build bazel_project bazel_project_noextensions
-
-APP_VERSION="7.3"
-CORE_COUNT=$(shell sysctl -n hw.logicalcpu)
-CORE_COUNT_MINUS_ONE=$(shell expr ${CORE_COUNT} \- 1)
-
-BAZEL=$(shell which bazel)
-
-ifneq ($(BAZEL_HTTP_CACHE_URL),)
- export BAZEL_CACHE_FLAGS=\
- --remote_cache="$(BAZEL_HTTP_CACHE_URL)" --experimental_remote_downloader="$(BAZEL_HTTP_CACHE_URL)"
-else ifneq ($(BAZEL_CACHE_DIR),)
- export BAZEL_CACHE_FLAGS=\
- --disk_cache="${BAZEL_CACHE_DIR}"
-endif
-
-ifneq ($(BAZEL_KEEP_GOING),)
- export BAZEL_KEEP_GOING_FLAGS=\
- -k
-else ifneq ($(BAZEL_CACHE_DIR),)
- export BAZEL_KEEP_GOING_FLAGS=
-endif
-
-BAZEL_COMMON_FLAGS=\
- --announce_rc \
- --features=swift.use_global_module_cache \
- --features=swift.split_derived_files_generation \
- --features=swift.skip_function_bodies_for_derived_files \
- --jobs=${CORE_COUNT} \
- ${BAZEL_KEEP_GOING_FLAGS} \
-
-BAZEL_DEBUG_FLAGS=\
- --features=swift.enable_batch_mode \
- --swiftcopt=-j${CORE_COUNT_MINUS_ONE} \
- --experimental_guard_against_concurrent_changes \
-
-BAZEL_SANDBOX_FLAGS=\
- --strategy=Genrule=sandboxed \
- --spawn_strategy=sandboxed \
- --strategy=SwiftCompile=sandboxed \
-
-# --num-threads 0 forces swiftc to generate one object file per module; it:
-# 1. resolves issues with the linker caused by swift-objc mixing.
-# 2. makes the resulting binaries significantly smaller (up to 9% for this project).
-BAZEL_OPT_FLAGS=\
- --features=swift.opt_uses_wmo \
- --features=swift.opt_uses_osize \
- --swiftcopt='-num-threads' --swiftcopt='0' \
- --features=dead_strip \
- --objc_enable_binary_stripping \
- --apple_bitcode=watchos=embedded \
-
-kill_xcode:
- killall Xcode || true
-
-clean:
- "${BAZEL}" clean --expunge
-
-bazel_app_debug_arm64:
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="0" \
- build-system/prepare-build.sh Telegram distribution
- "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_DEBUG_FLAGS} \
- -c dbg \
- --ios_multi_cpus=arm64 \
- --watchos_cpus=armv7k,arm64_32 \
- --verbose_failures
-
-bazel_app_debug_sim_arm64:
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="0" \
- build-system/prepare-build.sh Telegram distribution
- "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_DEBUG_FLAGS} \
- -c dbg \
- --ios_multi_cpus=sim_arm64 \
- --watchos_cpus=armv7k,arm64_32 \
- --verbose_failures
-
-bazel_app_arm64:
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="0" \
- build-system/prepare-build.sh Telegram distribution
- "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_OPT_FLAGS} \
- -c opt \
- --ios_multi_cpus=arm64 \
- --watchos_cpus=armv7k,arm64_32 \
- --apple_generate_dsym \
- --output_groups=+dsyms \
- --verbose_failures
-
-bazel_app_armv7:
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="0" \
- build-system/prepare-build.sh Telegram distribution
- "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_OPT_FLAGS} \
- -c opt \
- --ios_multi_cpus=armv7 \
- --watchos_cpus=armv7k,arm64_32 \
- --apple_generate_dsym \
- --output_groups=+dsyms \
- --verbose_failures
-
-bazel_app:
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="0" \
- build-system/prepare-build.sh Telegram distribution
- "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_OPT_FLAGS} \
- -c opt \
- --ios_multi_cpus=armv7,arm64 \
- --watchos_cpus=armv7k,arm64_32 \
- --apple_generate_dsym \
- --output_groups=+dsyms \
- --verbose_failures
-
-check_sandbox_debug_build:
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="0" \
- build-system/prepare-build.sh Telegram distribution
- "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_DEBUG_FLAGS} ${BAZEL_SANDBOX_FLAGS} \
- -c opt \
- --ios_multi_cpus=arm64 \
- --watchos_cpus=armv7k,arm64_32 \
- --apple_generate_dsym \
- --output_groups=+dsyms \
- --verbose_failures
-
-bazel_project: kill_xcode
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="0" \
- build-system/prepare-build.sh Telegram development
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- build-system/generate-xcode-project.sh Telegram
-
-bazel_project_noextensions: kill_xcode
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- TELEGRAM_DISABLE_EXTENSIONS="1" \
- build-system/prepare-build.sh Telegram development
- APP_VERSION="${APP_VERSION}" \
- BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
- BAZEL_HTTP_CACHE_URL="${BAZEL_HTTP_CACHE_URL}" \
- build-system/generate-xcode-project.sh Telegram
diff --git a/README.md b/README.md
index 621c3cef60..344a62325c 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,96 @@
# Telegram iOS Source Code Compilation Guide
-1. Install the brew package manager, if you havenโt already.
-2. Install the packages yasm, cmake:
-```
-brew install yasm cmake
-```
-3. Clone the project from GitHub:
+We welcome all developers to use our API and source code to create applications on our platform.
+There are several things we require from **all developers** for the moment.
+
+# Creating your Telegram Application
+
+1. [**Obtain your own api_id**](https://core.telegram.org/api/obtaining_api_id) for your application.
+2. Please **do not** use the name Telegram for your app โ or make sure your users understand that it is unofficial.
+3. Kindly **do not** use our standard logo (white paper plane in a blue circle) as your app's logo.
+3. Please study our [**security guidelines**](https://core.telegram.org/mtproto/security_guidelines) and take good care of your users' data and privacy.
+4. Please remember to publish **your** code too in order to comply with the licences.
+
+# Compilation Guide
+
+1. Install Xcode (directly from https://developer.apple.com/download/more or using the App Store).
+2. Clone the project from GitHub:
```
git clone --recursive https://github.com/TelegramMessenger/Telegram-iOS.git
```
-4. Open Telegram-iOS.workspace.
-5. Open the Telegram-iOS-Fork scheme.
-6. Start the compilation process.
-7. To run the app on your device, you will need to set the correct values for the signature, .entitlements files and package IDs in accordance with your developer account values.
+
+3. Download Bazel 3.7.0
+
+```
+mkdir -p $HOME/bazel-dist
+cd $HOME/bazel-dist
+curl -O -L https://github.com/bazelbuild/bazel/releases/download/3.7.0/bazel-3.7.0-darwin-x86_64
+mv bazel-3.7.0* bazel
+```
+
+Verify that it's working
+
+```
+chmod +x bazel
+./bazel --version
+```
+
+4. Adjust configuration parameters
+
+```
+mkdir -p $HOME/telegram-configuration
+cp -R build-system/example-configuration/* $HOME/telegram-configuration/
+```
+
+- Modify the values in `variables.bzl`
+- Replace the provisioning profiles in `provisioning` with valid files
+
+5. (Optional) Create a build cache directory to speed up rebuilds
+
+```
+mkdir -p "$HOME/telegram-bazel-cache"
+```
+
+5. Build the app
+
+```
+python3 build-system/Make/Make.py \
+ --bazel="$HOME/bazel-dist/bazel" \
+ --cacheDir="$HOME/telegram-bazel-cache" \
+ build \
+ --configurationPath="$HOME/telegram-configuration" \
+ --buildNumber=100001 \
+ --configuration=release_universal
+```
+
+6. (Optional) Generate an Xcode project
+
+```
+python3 build-system/Make/Make.py \
+ --bazel="$HOME/bazel-dist/bazel" \
+ --cacheDir="$HOME/telegram-bazel-cache" \
+ generateProject \
+ --configurationPath="$HOME/telegram-configuration" \
+ --disableExtensions
+```
+
+Tip: use `--disableExtensions` when developing to speed up development by not building application extensions.
+
+
+# Tips
+
+Bazel is used to build the app. To simplify the development setup a helper script is provided (`build-system/Make/Make.py`). See help:
+
+```
+python3 build-system/Make/Make.py --help
+python3 build-system/Make/Make.py build --help
+python3 build-system/Make/Make.py generateProject --help
+```
+
+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:
+
+```
+python3 build-system/Make/Make.py --overrideBazelVersion build ... # Don't check the version of Bazel
+python3 build-system/Make/Make.py --overrideXcodeVersion build ... # Don't check the version of Xcode
+```
diff --git a/Telegram/BUILD b/Telegram/BUILD
index d570c88f26..415ee8cc3f 100644
--- a/Telegram/BUILD
+++ b/Telegram/BUILD
@@ -1,3 +1,7 @@
+load("@bazel_skylib//rules:common_settings.bzl",
+ "bool_flag",
+)
+
load("@build_bazel_rules_apple//apple:ios.bzl",
"ios_application",
"ios_extension",
@@ -18,13 +22,10 @@ load("//build-system/bazel-utils:plist_fragment.bzl",
)
load(
- "//build-input/data:variables.bzl",
- "telegram_build_number",
- "telegram_version",
+ "@build_configuration//:variables.bzl",
"telegram_bundle_id",
"telegram_aps_environment",
"telegram_team_id",
- "telegram_disable_extensions",
)
config_setting(
@@ -34,6 +35,19 @@ config_setting(
},
)
+bool_flag(
+ name = "disableExtensions",
+ build_setting_default = False,
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
+ name = "disableExtensionsSetting",
+ flag_values = {
+ ":disableExtensions": "True",
+ },
+)
+
genrule(
name = "empty",
outs = ["empty.swift"],
@@ -190,14 +204,20 @@ swift_library(
)
plist_fragment(
- name = "AdditionalInfoPlist",
+ name = "BuildNumberInfoPlist",
extension = "plist",
template =
"""
- CFBundleShortVersionString
- {telegram_version}
CFBundleVersion
- {telegram_build_number}
+ {buildNumber}
+ """
+)
+
+plist_fragment(
+ name = "UrlTypesInfoPlist",
+ extension = "plist",
+ template =
+ """
CFBundleURLTypes
@@ -210,16 +230,6 @@ plist_fragment(
telegram
-
- CFBundleTypeRole
- Viewer
- CFBundleURLName
- {telegram_bundle_id}.ton
- CFBundleURLSchemes
-
- ton
-
-
CFBundleTypeRole
Viewer
@@ -232,8 +242,6 @@ plist_fragment(
""".format(
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
telegram_bundle_id = telegram_bundle_id,
)
)
@@ -371,13 +379,8 @@ plist_fragment(
template =
"""
CFBundleShortVersionString
- {telegram_version}
- CFBundleVersion
- {telegram_build_number}
- """.format(
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
- )
+ {telegramVersion}
+ """
)
plist_fragment(
@@ -478,11 +481,12 @@ watchos_extension(
infoplists = [
":WatchExtensionInfoPlist",
":VersionInfoPlist",
+ ":BuildNumberInfoPlist",
":AppNameInfoPlist",
":WatchExtensionNSExtensionInfoPlist",
],
minimum_os_version = "5.0",
- provisioning_profile = "//build-input/data/provisioning-profiles:WatchExtension.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:WatchExtension.mobileprovision",
resources = [
":TelegramWatchExtensionResources",
],
@@ -505,11 +509,12 @@ watchos_application(
infoplists = [
":WatchAppInfoPlist",
":VersionInfoPlist",
+ "BuildNumberInfoPlist",
":AppNameInfoPlist",
":WatchAppCompanionInfoPlist",
],
minimum_os_version = "5.0",
- provisioning_profile = "//build-input/data/provisioning-profiles:WatchApp.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:WatchApp.mobileprovision",
resources = [
":TelegramWatchAppResources",
":TelegramWatchAppAssets",
@@ -528,20 +533,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.MtProtoKit
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
MtProtoKit
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -556,6 +555,8 @@ ios_framework(
],
infoplists = [
":MtProtoKitInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
minimum_os_version = "9.0",
ipa_post_processor = strip_framework,
@@ -571,20 +572,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.SwiftSignalKit
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
SwiftSignalKit
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -599,6 +594,8 @@ ios_framework(
],
infoplists = [
":SwiftSignalKitInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
minimum_os_version = "9.0",
ipa_post_processor = strip_framework,
@@ -614,20 +611,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.Postbox
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
Postbox
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -642,6 +633,8 @@ ios_framework(
],
infoplists = [
":PostboxInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
frameworks = [
":SwiftSignalKitFramework",
@@ -660,20 +653,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.TelegramApi
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
TelegramApi
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -688,6 +675,8 @@ ios_framework(
],
infoplists = [
":TelegramApiInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
minimum_os_version = "9.0",
ipa_post_processor = strip_framework,
@@ -703,20 +692,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.SyncCore
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
SyncCore
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -731,6 +714,8 @@ ios_framework(
],
infoplists = [
":SyncCoreInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
frameworks = [
":SwiftSignalKitFramework",
@@ -750,20 +735,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.TelegramCore
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
TelegramCore
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -778,13 +757,14 @@ ios_framework(
],
infoplists = [
":TelegramCoreInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
frameworks = [
":MtProtoKitFramework",
":SwiftSignalKitFramework",
":PostboxFramework",
":SyncCoreFramework",
- #":TelegramApiFramework",
],
minimum_os_version = "9.0",
ipa_post_processor = strip_framework,
@@ -800,20 +780,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.AsyncDisplayKit
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
AsyncDisplayKit
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -828,6 +802,8 @@ ios_framework(
],
infoplists = [
":AsyncDisplayKitInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
minimum_os_version = "9.0",
ipa_post_processor = strip_framework,
@@ -843,20 +819,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.Display
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
Display
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -914,6 +884,8 @@ ios_framework(
],
infoplists = [
":DisplayInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
frameworks = [
":SwiftSignalKitFramework",
@@ -933,20 +905,14 @@ plist_fragment(
"""
CFBundleIdentifier
{telegram_bundle_id}.TelegramUI
- CFBundleVersion
- {telegram_build_number}
CFBundleDevelopmentRegion
en
CFBundleName
TelegramUI
- CFBundleShortVersionString
- {telegram_version}
CFBundlePackageType
FMWK
""".format(
telegram_bundle_id = telegram_bundle_id,
- telegram_version = telegram_version,
- telegram_build_number = telegram_build_number,
)
)
@@ -961,12 +927,13 @@ ios_framework(
],
infoplists = [
":TelegramUIInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
],
frameworks = [
":MtProtoKitFramework",
":SwiftSignalKitFramework",
":PostboxFramework",
- #":TelegramApiFramework",
":SyncCoreFramework",
":TelegramCoreFramework",
":AsyncDisplayKitFramework",
@@ -1052,10 +1019,11 @@ ios_extension(
infoplists = [
":ShareInfoPlist",
":VersionInfoPlist",
+ ":BuildNumberInfoPlist",
":AppNameInfoPlist",
],
minimum_os_version = "9.0",
- provisioning_profile = "//build-input/data/provisioning-profiles:Share.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:Share.mobileprovision",
deps = [":ShareExtensionLib"],
frameworks = [
":TelegramUIFramework"
@@ -1120,10 +1088,11 @@ ios_extension(
infoplists = [
":NotificationContentInfoPlist",
":VersionInfoPlist",
+ ":BuildNumberInfoPlist",
":AppNameInfoPlist",
],
minimum_os_version = "10.0",
- provisioning_profile = "//build-input/data/provisioning-profiles:NotificationContent.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:NotificationContent.mobileprovision",
deps = [":NotificationContentExtensionLib"],
frameworks = [
":TelegramUIFramework"
@@ -1157,25 +1126,35 @@ plist_fragment(
)
)
+swift_library(
+ name = "GeneratedSources",
+ module_name = "GeneratedSources",
+ srcs = glob([
+ "Generated/**/*.swift",
+ ]),
+ visibility = ["//visibility:public"],
+)
+
swift_library(
name = "WidgetExtensionLib",
module_name = "WidgetExtensionLib",
srcs = glob([
"WidgetKitWidget/**/*.swift",
- "Generated/**/*.swift",
]),
data = [
"SiriIntents/Intents.intentdefinition",
],
deps = [
"//submodules/BuildConfig:BuildConfig",
- "//submodules/WidgetItems:WidgetItems",
+ "//submodules/WidgetItems:WidgetItems_iOS14",
+ "//submodules/WidgetItemsUtils:WidgetItemsUtils",
"//submodules/AppLockState:AppLockState",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore",
"//submodules/SyncCore:SyncCore",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
+ ":GeneratedSources",
],
)
@@ -1191,11 +1170,12 @@ ios_extension(
infoplists = [
":WidgetInfoPlist",
":VersionInfoPlist",
+ ":BuildNumberInfoPlist",
":AppNameInfoPlist",
],
minimum_os_version = "14.0",
provides_main = True,
- provisioning_profile = "//build-input/data/provisioning-profiles:Widget.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:Widget.mobileprovision",
deps = [":WidgetExtensionLib"],
frameworks = [
":SwiftSignalKitFramework",
@@ -1251,7 +1231,6 @@ swift_library(
module_name = "IntentsExtensionLib",
srcs = glob([
"SiriIntents/**/*.swift",
- "Generated/**/*.swift",
]),
data = [
"SiriIntents/Intents.intentdefinition",
@@ -1265,6 +1244,7 @@ swift_library(
"//submodules/BuildConfig:BuildConfig",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
"//submodules/AppLockState:AppLockState",
+ ":GeneratedSources",
],
)
@@ -1280,16 +1260,16 @@ ios_extension(
infoplists = [
":IntentsInfoPlist",
":VersionInfoPlist",
+ ":BuildNumberInfoPlist",
":AppNameInfoPlist",
],
minimum_os_version = "10.0",
- provisioning_profile = "//build-input/data/provisioning-profiles:Intents.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:Intents.mobileprovision",
deps = [":IntentsExtensionLib"],
frameworks = [
":SwiftSignalKitFramework",
":PostboxFramework",
":TelegramCoreFramework",
- #":TelegramApiFramework",
":SyncCoreFramework",
],
)
@@ -1331,17 +1311,16 @@ ios_extension(
infoplists = [
":NotificationServiceInfoPlist",
":VersionInfoPlist",
+ ":BuildNumberInfoPlist",
":AppNameInfoPlist",
],
minimum_os_version = "10.0",
- provisioning_profile = "//build-input/data/provisioning-profiles:NotificationService.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:NotificationService.mobileprovision",
deps = ["//Telegram/NotificationService:NotificationServiceExtensionLib"],
frameworks = [
":MtProtoKitFramework",
":SwiftSignalKitFramework",
":PostboxFramework",
- #":TelegramApiFramework",
- #":SyncCoreFramework",
],
)
@@ -1522,11 +1501,13 @@ ios_application(
),
families = ["iphone", "ipad"],
minimum_os_version = "9.0",
- provisioning_profile = "//build-input/data/provisioning-profiles:Telegram.mobileprovision",
+ provisioning_profile = "@build_configuration//provisioning:Telegram.mobileprovision",
entitlements = ":TelegramEntitlements.entitlements",
infoplists = [
":TelegramInfoPlist",
- ":AdditionalInfoPlist",
+ ":BuildNumberInfoPlist",
+ ":VersionInfoPlist",
+ ":UrlTypesInfoPlist",
],
ipa_post_processor = ":AddAlternateIcons",
resources = [
@@ -1547,14 +1528,16 @@ ios_application(
strings = [
":AppStringResources",
],
- extensions = [
- ] if telegram_disable_extensions else [
- ":ShareExtension",
- ":NotificationContentExtension",
- ":NotificationServiceExtension",
- ":IntentsExtension",
- ":WidgetExtension",
- ],
+ extensions = select({
+ ":disableExtensionsSetting": [],
+ "//conditions:default": [
+ ":ShareExtension",
+ ":NotificationContentExtension",
+ ":NotificationServiceExtension",
+ ":IntentsExtension",
+ ":WidgetExtension",
+ ],
+ }),
watch_application = ":TelegramWatchApp",
deps = [
":Main",
diff --git a/Telegram/SiriIntents/IntentHandler.swift b/Telegram/SiriIntents/IntentHandler.swift
index 41ac71b129..8ef09e3458 100644
--- a/Telegram/SiriIntents/IntentHandler.swift
+++ b/Telegram/SiriIntents/IntentHandler.swift
@@ -9,6 +9,7 @@ import Contacts
import OpenSSLEncryptionProvider
import AppLockState
import UIKit
+import GeneratedSources
private var accountCache: Account?
diff --git a/Telegram/WidgetKitWidget/TodayViewController.swift b/Telegram/WidgetKitWidget/TodayViewController.swift
index 1afe3bb85a..2a02c2d21c 100644
--- a/Telegram/WidgetKitWidget/TodayViewController.swift
+++ b/Telegram/WidgetKitWidget/TodayViewController.swift
@@ -13,6 +13,9 @@ import Postbox
import SyncCore
import TelegramCore
import OpenSSLEncryptionProvider
+import WidgetItemsUtils
+
+import GeneratedSources
private var installedSharedLogger = false
@@ -156,9 +159,16 @@ struct Provider: IntentTimelineProvider {
)
}
+ var mappedMessage: WidgetDataPeer.Message?
+ if let index = transaction.getTopPeerMessageIndex(peerId: peer.id) {
+ if let message = transaction.getMessage(index.id) {
+ mappedMessage = WidgetDataPeer.Message(message: message)
+ }
+ }
+
peers.append(WidgetDataPeer(id: peer.id.toInt64(), name: name, lastName: lastName, letters: peer.displayLetters, avatarPath: smallestImageRepresentation(peer.profileImageRepresentations).flatMap { representation in
return postbox.mediaBox.resourcePath(representation.resource)
- }, badge: badge))
+ }, badge: badge, message: mappedMessage))
}
}
return WidgetDataPeers(accountPeerId: widgetPeers.accountPeerId, peers: peers)
@@ -195,12 +205,13 @@ struct AvatarItemView: View {
var accountPeerId: Int64
var peer: WidgetDataPeer
var itemSize: CGFloat
+ var displayBadge: Bool = true
var body: some View {
return ZStack {
Image(uiImage: avatarImage(accountPeerId: accountPeerId, peer: peer, size: CGSize(width: itemSize, height: itemSize)))
.clipShape(Circle())
- if let badge = peer.badge, badge.count > 0 {
+ if displayBadge, let badge = peer.badge, badge.count > 0 {
Text("\(badge.count)")
.font(Font.system(size: 16.0))
.multilineTextAlignment(.center)
@@ -219,6 +230,7 @@ struct AvatarItemView: View {
struct WidgetView: View {
@Environment(\.widgetFamily) private var widgetFamily
+ @Environment(\.colorScheme) private var colorScheme
let data: PeersWidgetData
func placeholder(geometry: GeometryProxy) -> some View {
@@ -329,12 +341,150 @@ struct WidgetView: View {
}
}
- var body: some View {
+ var body1: some View {
ZStack {
peerViews()
}
.padding(0.0)
}
+
+ func chatTopLine(_ peer: WidgetDataPeer) -> some View {
+ let dateText: String
+ if let message = peer.message {
+ dateText = DateFormatter.localizedString(from: Date(timeIntervalSince1970: Double(message.timestamp)), dateStyle: .none, timeStyle: .short)
+ } else {
+ dateText = ""
+ }
+ return HStack(alignment: .center, spacing: 0.0, content: {
+ Text(peer.name).font(Font.system(size: 16.0, weight: .medium, design: .default)).foregroundColor(.primary)
+ Spacer()
+ Text(dateText).font(Font.system(size: 14.0, weight: .regular, design: .default)).foregroundColor(.secondary)
+ })
+ }
+
+ func chatBottomLine(_ peer: WidgetDataPeer) -> some View {
+ var text = peer.message?.text ?? ""
+ if let message = peer.message {
+ //TODO:localize
+ switch message.content {
+ case .text:
+ break
+ case .image:
+ text = "๐ผ Photo"
+ case .video:
+ text = "๐น Video"
+ case .gif:
+ text = "Gif"
+ case let .file(file):
+ text = "๐ \(file.name)"
+ case let .music(music):
+ if !music.title.isEmpty && !music.artist.isEmpty {
+ text = "\(music.artist) โ \(music.title)"
+ } else if !music.title.isEmpty {
+ text = music.title
+ } else if !music.artist.isEmpty {
+ text = music.artist
+ } else {
+ text = "Music"
+ }
+ case .voiceMessage:
+ text = "๐ค Voice Message"
+ case .videoMessage:
+ text = "Video Message"
+ case let .sticker(sticker):
+ text = "\(sticker.altText) Sticker"
+ case let .call(call):
+ if call.isVideo {
+ text = "Video Call"
+ } else {
+ text = "Voice Call"
+ }
+ case .mapLocation:
+ text = "Location"
+ case let .game(game):
+ text = "๐ฎ \(game.title)"
+ case let .poll(poll):
+ text = "๐ \(poll.title)"
+ }
+ }
+
+ var hasBadge = false
+ if let badge = peer.badge, badge.count > 0 {
+ hasBadge = true
+ }
+
+ return HStack(alignment: .center, spacing: hasBadge ? 6.0 : 0.0, content: {
+ Text(text).lineLimit(nil).font(Font.system(size: 15.0, weight: .regular, design: .default)).foregroundColor(.secondary).multilineTextAlignment(.leading).frame(maxHeight: .infinity, alignment: .topLeading)
+ Spacer()
+ if let badge = peer.badge, badge.count > 0 {
+ VStack {
+ Spacer()
+ Text("\(badge.count)")
+ .font(Font.system(size: 14.0))
+ .multilineTextAlignment(.center)
+ .foregroundColor(.white)
+ .padding(.horizontal, 4.0)
+ .background(
+ RoundedRectangle(cornerRadius: 10)
+ .fill(badge.isMuted ? Color.gray : Color.blue)
+ .frame(minWidth: 20, idealWidth: 20, maxWidth: .infinity, minHeight: 20, idealHeight: 20, maxHeight: 20.0, alignment: .center)
+ )
+ .padding(EdgeInsets(top: 0.0, leading: 0.0, bottom: 6.0, trailing: 3.0))
+ }
+ }
+ })
+ }
+
+ func chatContent(_ peer: WidgetDataPeer) -> some View {
+ return VStack(alignment: .leading, spacing: 2.0, content: {
+ chatTopLine(peer)
+ chatBottomLine(peer).frame(maxHeight: .infinity)
+ })
+ }
+
+ func chatContentView(_ index: Int) -> AnyView {
+ let peers: WidgetDataPeers
+ switch data {
+ case let .peers(peersValue):
+ peers = peersValue
+ if peers.peers.count <= index {
+ return AnyView(Spacer())
+ }
+ default:
+ return AnyView(Spacer())
+ }
+
+ return AnyView(
+ Link(destination: URL(string: linkForPeer(id: peers.peers[index].id))!, label: {
+ HStack(alignment: .center, spacing: 0.0, content: {
+ AvatarItemView(accountPeerId: peers.accountPeerId, peer: peers.peers[index], itemSize: 60.0, displayBadge: false).frame(width: 60.0, height: 60.0, alignment: .leading).padding(EdgeInsets(top: 0.0, leading: 10.0, bottom: 0.0, trailing: 10.0))
+ chatContent(peers.peers[index]).frame(maxWidth: .infinity).padding(EdgeInsets(top: 10.0, leading: 0.0, bottom: 10.0, trailing: 10.0))
+ })
+ })
+ )
+ }
+
+ func getSeparatorColor() -> Color {
+ switch colorScheme {
+ case .light:
+ return Color(.sRGB, red: 200.0 / 255.0, green: 199.0 / 255.0, blue: 204.0 / 255.0, opacity: 1.0)
+ case .dark:
+ return Color(.sRGB, red: 61.0 / 255.0, green: 61.0 / 255.0, blue: 64.0 / 255.0, opacity: 1.0)
+ @unknown default:
+ return .secondary
+ }
+ }
+
+ var body: some View {
+ GeometryReader(content: { geometry in
+ ZStack {
+ chatContentView(0).position(x: geometry.size.width / 2.0, y: geometry.size.height / 4.0).frame(width: geometry.size.width, height: geometry.size.height / 2.0, alignment: .leading)
+ chatContentView(1).position(x: geometry.size.width / 2.0, y: geometry.size.height / 2.0 + geometry.size.height / 4.0).frame(width: geometry.size.width, height: geometry.size.height / 2.0, alignment: .leading)
+ Rectangle().foregroundColor(getSeparatorColor()).position(x: geometry.size.width / 2.0, y: geometry.size.height / 4.0).frame(width: geometry.size.width, height: 0.33, alignment: .leading)
+ }
+ })
+ .padding(0.0)
+ }
}
private let buildConfig: BuildConfig = {
@@ -429,7 +579,7 @@ struct Static_Widget: Widget {
return IntentConfiguration(kind: kind, intent: SelectFriendsIntent.self, provider: Provider(), content: { entry in
WidgetView(data: getWidgetData(contents: entry.contents))
})
- .supportedFamilies([.systemSmall, .systemMedium])
+ .supportedFamilies([.systemMedium])
.configurationDisplayName(presentationData.widgetGalleryTitle)
.description(presentationData.widgetGalleryDescription)
}
diff --git a/build-system/Make/BuildEnvironment.py b/build-system/Make/BuildEnvironment.py
new file mode 100644
index 0000000000..aa889367f2
--- /dev/null
+++ b/build-system/Make/BuildEnvironment.py
@@ -0,0 +1,148 @@
+import json
+import os
+import platform
+import subprocess
+
+
+def is_apple_silicon():
+ if platform.processor() == 'arm':
+ return True
+ else:
+ return False
+
+
+def get_clean_env():
+ clean_env = os.environ.copy()
+ clean_env['PATH'] = '/usr/bin:/bin:/usr/sbin:/sbin'
+ return clean_env
+
+
+def resolve_executable(program):
+ def is_executable(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+ for path in get_clean_env()["PATH"].split(os.pathsep):
+ executable_file = os.path.join(path, program)
+ if is_executable(executable_file):
+ return executable_file
+ return None
+
+
+def run_executable_with_output(path, arguments):
+ executable_path = resolve_executable(path)
+ if executable_path is None:
+ raise Exception('Could not resolve {} to a valid executable file'.format(path))
+
+ process = subprocess.Popen(
+ [executable_path] + arguments,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ env=get_clean_env()
+ )
+ output_data, _ = process.communicate()
+ output_string = output_data.decode('utf-8')
+ return output_string
+
+
+def call_executable(arguments, use_clean_environment=True, check_result=True):
+ executable_path = resolve_executable(arguments[0])
+ if executable_path is None:
+ raise Exception('Could not resolve {} to a valid executable file'.format(arguments[0]))
+
+ if use_clean_environment:
+ resolved_env = get_clean_env()
+ else:
+ resolved_env = os.environ
+
+ resolved_arguments = [executable_path] + arguments[1:]
+
+ if check_result:
+ subprocess.check_call(resolved_arguments, env=resolved_env)
+ else:
+ subprocess.call(resolved_arguments, env=resolved_env)
+
+
+def get_bazel_version(bazel_path):
+ command_result = run_executable_with_output(bazel_path, ['--version']).strip('\n')
+ if not command_result.startswith('bazel '):
+ raise Exception('{} is not a valid bazel binary'.format(bazel_path))
+ command_result = command_result.replace('bazel ', '')
+ return command_result
+
+
+def get_xcode_version():
+ xcode_path = run_executable_with_output('xcode-select', ['-p']).strip('\n')
+ if not os.path.isdir(xcode_path):
+ print('The path reported by \'xcode-select -p\' does not exist')
+ exit(1)
+
+ plist_path = '{}/../Info.plist'.format(xcode_path)
+
+ info_plist_lines = run_executable_with_output('plutil', [
+ '-p', plist_path
+ ]).split('\n')
+
+ pattern = 'CFBundleShortVersionString" => '
+ for line in info_plist_lines:
+ index = line.find(pattern)
+ if index != -1:
+ version = line[index + len(pattern):].strip('"')
+ return version
+
+ print('Could not parse the Xcode version from {}'.format(plist_path))
+ exit(1)
+
+
+class BuildEnvironment:
+ def __init__(
+ self,
+ base_path,
+ bazel_path,
+ bazel_x86_64_path,
+ override_bazel_version,
+ override_xcode_version
+ ):
+ self.base_path = os.path.expanduser(base_path)
+ self.bazel_path = os.path.expanduser(bazel_path)
+ if bazel_x86_64_path is not None:
+ self.bazel_x86_64_path = os.path.expanduser(bazel_x86_64_path)
+ else:
+ self.bazel_x86_64_path = None
+
+ configuration_path = os.path.join(self.base_path, 'versions.json')
+ with open(configuration_path) as file:
+ configuration_dict = json.load(file)
+ if configuration_dict['app'] is None:
+ raise Exception('Missing app version in {}'.format(configuration_path))
+ else:
+ self.app_version = configuration_dict['app']
+ if configuration_dict['bazel'] is None:
+ raise Exception('Missing bazel version in {}'.format(configuration_path))
+ else:
+ self.bazel_version = configuration_dict['bazel']
+ if configuration_dict['xcode'] is None:
+ raise Exception('Missing xcode version in {}'.format(configuration_path))
+ else:
+ self.xcode_version = configuration_dict['xcode']
+
+ actual_bazel_version = get_bazel_version(self.bazel_path)
+ if actual_bazel_version != self.bazel_version:
+ if override_bazel_version:
+ print('Overriding the required bazel version {} with {} as reported by {}'.format(
+ self.bazel_version, actual_bazel_version, self.bazel_path))
+ self.bazel_version = actual_bazel_version
+ else:
+ print('Required bazel version is "{}", but "{}"" is reported by {}'.format(
+ self.bazel_version, actual_bazel_version, self.bazel_path))
+ exit(1)
+
+ actual_xcode_version = get_xcode_version()
+ if actual_xcode_version != self.xcode_version:
+ if override_xcode_version:
+ print('Overriding the required Xcode version {} with {} as reported by \'xcode-select -p\''.format(
+ self.xcode_version, actual_xcode_version, self.bazel_path))
+ self.xcode_version = actual_xcode_version
+ else:
+ print('Required Xcode version is {}, but {} is reported by \'xcode-select -p\''.format(
+ self.xcode_version, actual_xcode_version, self.bazel_path))
+ exit(1)
diff --git a/build-system/Make/Make.py b/build-system/Make/Make.py
new file mode 100644
index 0000000000..8c12101cfd
--- /dev/null
+++ b/build-system/Make/Make.py
@@ -0,0 +1,484 @@
+#!/bin/python3
+
+import argparse
+import os
+import shlex
+import sys
+import tempfile
+import subprocess
+
+from BuildEnvironment import is_apple_silicon, resolve_executable, call_executable, BuildEnvironment
+from ProjectGeneration import generate
+
+
+class BazelCommandLine:
+ def __init__(self, bazel_path, bazel_x86_64_path, override_bazel_version, override_xcode_version):
+ self.build_environment = BuildEnvironment(
+ base_path=os.getcwd(),
+ bazel_path=bazel_path,
+ bazel_x86_64_path=bazel_x86_64_path,
+ override_bazel_version=override_bazel_version,
+ override_xcode_version=override_xcode_version
+ )
+ self.remote_cache = None
+ self.cache_dir = None
+ self.additional_args = None
+ self.build_number = None
+ self.configuration_args = None
+ self.configuration_path = None
+
+ self.common_args = [
+ # https://docs.bazel.build/versions/master/command-line-reference.html
+ # Ask bazel to print the actual resolved command line options.
+ '--announce_rc',
+
+ # https://github.com/bazelbuild/rules_swift
+ # If enabled, Swift compilation actions will use the same global Clang module
+ # cache used by Objective-C compilation actions. This is disabled by default
+ # because under some circumstances Clang module cache corruption can cause the
+ # Swift compiler to crash (sometimes when switching configurations or syncing a
+ # repository), but disabling it also causes a noticeable build time regression
+ # so it can be explicitly re-enabled by users who are not affected by those
+ # crashes.
+ '--features=swift.use_global_module_cache',
+
+ # https://docs.bazel.build/versions/master/command-line-reference.html
+ # Print the subcommand details in case of failure.
+ '--verbose_failures',
+ ]
+
+ self.common_build_args = [
+ # https://github.com/bazelbuild/rules_swift
+ # If enabled and whole module optimisation is being used, the `*.swiftdoc`,
+ # `*.swiftmodule` and `*-Swift.h` are generated with a separate action
+ # rather than as part of the compilation.
+ '--features=swift.split_derived_files_generation',
+
+ # https://github.com/bazelbuild/rules_swift
+ # If enabled the skip function bodies frontend flag is passed when using derived
+ # files generation.
+ '--features=swift.skip_function_bodies_for_derived_files',
+
+ # Set the number of parallel processes to match the available CPU core count.
+ '--jobs={}'.format(os.cpu_count()),
+ ]
+
+ self.common_debug_args = [
+ # https://github.com/bazelbuild/rules_swift
+ # If enabled, Swift compilation actions will use batch mode by passing
+ # `-enable-batch-mode` to `swiftc`. This is a new compilation mode as of
+ # Swift 4.2 that is intended to speed up non-incremental non-WMO builds by
+ # invoking a smaller number of frontend processes and passing them batches of
+ # source files.
+ '--features=swift.enable_batch_mode',
+
+ # https://docs.bazel.build/versions/master/command-line-reference.html
+ # Set the number of parallel jobs per module to saturate the available CPU resources.
+ '--swiftcopt=-j{}'.format(os.cpu_count() - 1),
+ ]
+
+ self.common_release_args = [
+ # https://github.com/bazelbuild/rules_swift
+ # Enable whole module optimization.
+ '--features=swift.opt_uses_wmo',
+
+ # https://github.com/bazelbuild/rules_swift
+ # Use -Osize instead of -O when building swift modules.
+ '--features=swift.opt_uses_osize',
+
+ # --num-threads 0 forces swiftc to generate one object file per module; it:
+ # 1. resolves issues with the linker caused by the swift-objc mixing.
+ # 2. makes the resulting binaries significantly smaller (up to 9% for this project).
+ '--swiftcopt=-num-threads', '--swiftcopt=0',
+
+ # Strip unsused code.
+ '--features=dead_strip',
+ '--objc_enable_binary_stripping',
+
+ # Always embed bitcode into Watch binaries. This is required by the App Store.
+ '--apple_bitcode=watchos=embedded',
+ ]
+
+ def add_remote_cache(self, host):
+ self.remote_cache = host
+
+ def add_cache_dir(self, path):
+ self.cache_dir = path
+
+ def add_additional_args(self, additional_args):
+ self.additional_args = additional_args
+
+ def set_build_number(self, build_number):
+ self.build_number = build_number
+
+ def set_configuration_path(self, path):
+ self.configuration_path = path
+
+ def set_configuration(self, configuration):
+ if configuration == 'debug_arm64':
+ self.configuration_args = [
+ # bazel debug build configuration
+ '-c', 'dbg',
+
+ # Build single-architecture binaries. It is almost 2 times faster is 32-bit support is not required.
+ '--ios_multi_cpus=arm64',
+
+ # Always build universal Watch binaries.
+ '--watchos_cpus=armv7k,arm64_32'
+ ] + self.common_debug_args
+ elif configuration == 'release_arm64':
+ self.configuration_args = [
+ # bazel optimized build configuration
+ '-c', 'opt',
+
+ # Build single-architecture binaries. It is almost 2 times faster is 32-bit support is not required.
+ '--ios_multi_cpus=arm64',
+
+ # Always build universal Watch binaries.
+ '--watchos_cpus=armv7k,arm64_32',
+
+ # Generate DSYM files when building.
+ '--apple_generate_dsym',
+
+ # Require DSYM files as build output.
+ '--output_groups=+dsyms'
+ ] + self.common_release_args
+ elif configuration == 'release_universal':
+ self.configuration_args = [
+ # bazel optimized build configuration
+ '-c', 'opt',
+
+ # Build universal binaries.
+ '--ios_multi_cpus=armv7,arm64',
+
+ # Always build universal Watch binaries.
+ '--watchos_cpus=armv7k,arm64_32',
+
+ # Generate DSYM files when building.
+ '--apple_generate_dsym',
+
+ # Require DSYM files as build output.
+ '--output_groups=+dsyms'
+ ] + self.common_release_args
+ else:
+ raise Exception('Unknown configuration {}'.format(configuration))
+
+ def invoke_clean(self):
+ combined_arguments = [
+ self.build_environment.bazel_path,
+ 'clean',
+ '--expunge'
+ ]
+
+ print('TelegramBuild: running {}'.format(combined_arguments))
+ call_executable(combined_arguments)
+
+ def get_define_arguments(self):
+ return [
+ '--define=buildNumber={}'.format(self.build_number),
+ '--define=telegramVersion={}'.format(self.build_environment.app_version)
+ ]
+
+ def get_project_generation_arguments(self):
+ combined_arguments = []
+ combined_arguments += self.common_args
+ combined_arguments += self.common_debug_args
+ combined_arguments += self.get_define_arguments()
+
+ if self.remote_cache is not None:
+ combined_arguments += [
+ '--remote_cache={}'.format(self.remote_cache),
+ '--experimental_remote_downloader={}'.format(self.remote_cache)
+ ]
+ elif self.cache_dir is not None:
+ combined_arguments += [
+ '--disk_cache={path}'.format(path=self.cache_dir)
+ ]
+
+ return combined_arguments
+
+ def invoke_build(self):
+ combined_arguments = [
+ self.build_environment.bazel_path,
+ 'build',
+ 'Telegram/Telegram'
+ ]
+
+ if self.configuration_path is None:
+ raise Exception('configuration_path is not defined')
+
+ combined_arguments += [
+ '--override_repository=build_configuration={}'.format(self.configuration_path)
+ ]
+
+ combined_arguments += self.common_args
+ combined_arguments += self.common_build_args
+ combined_arguments += self.get_define_arguments()
+
+ if self.remote_cache is not None:
+ combined_arguments += [
+ '--remote_cache={}'.format(self.remote_cache),
+ '--experimental_remote_downloader={}'.format(self.remote_cache)
+ ]
+ elif self.cache_dir is not None:
+ combined_arguments += [
+ '--disk_cache={path}'.format(path=self.cache_dir)
+ ]
+
+ combined_arguments += self.configuration_args
+
+ print('TelegramBuild: running')
+ print(subprocess.list2cmdline(combined_arguments))
+ call_executable(combined_arguments)
+
+
+def clean(arguments):
+ bazel_command_line = BazelCommandLine(
+ bazel_path=arguments.bazel,
+ bazel_x86_64_path=None,
+ override_bazel_version=arguments.overrideBazelVersion,
+ override_xcode_version=arguments.overrideXcodeVersion
+ )
+
+ bazel_command_line.invoke_clean()
+
+
+def resolve_configuration(bazel_command_line: BazelCommandLine, arguments):
+ if arguments.configurationGenerator is not None:
+ configuration_generator_arguments = shlex.split(arguments.configurationGenerator)
+
+ configuration_generator_executable = resolve_executable(configuration_generator_arguments[0])
+
+ if configuration_generator_executable is None:
+ print('{} is not a valid executable'.format(configuration_generator_arguments[0]))
+ exit(1)
+
+ temp_configuration_path = tempfile.mkdtemp()
+
+ resolved_configuration_generator_arguments = [configuration_generator_executable]
+ resolved_configuration_generator_arguments += configuration_generator_arguments[1:]
+ resolved_configuration_generator_arguments += [temp_configuration_path]
+
+ call_executable(resolved_configuration_generator_arguments, use_clean_environment=False)
+
+ print('TelegramBuild: using generated configuration in {}'.format(temp_configuration_path))
+ bazel_command_line.set_configuration_path(temp_configuration_path)
+ elif arguments.configurationPath is not None:
+ absolute_configuration_path = os.path.abspath(arguments.configurationPath)
+ if not os.path.isdir(absolute_configuration_path):
+ print('Error: {} does not exist'.format(absolute_configuration_path))
+ exit(1)
+ bazel_command_line.set_configuration_path(absolute_configuration_path)
+ else:
+ raise Exception('Neither configurationPath nor configurationGenerator are set')
+
+
+def generate_project(arguments):
+ bazel_x86_64_path = None
+ if is_apple_silicon():
+ bazel_x86_64_path = arguments.bazel_x86_64
+
+ bazel_command_line = BazelCommandLine(
+ bazel_path=arguments.bazel,
+ bazel_x86_64_path=bazel_x86_64_path,
+ override_bazel_version=arguments.overrideBazelVersion,
+ override_xcode_version=arguments.overrideXcodeVersion
+ )
+
+ if arguments.cacheDir is not None:
+ bazel_command_line.add_cache_dir(arguments.cacheDir)
+ elif arguments.cacheHost is not None:
+ bazel_command_line.add_remote_cache(arguments.cacheHost)
+
+ resolve_configuration(bazel_command_line, arguments)
+
+ bazel_command_line.set_build_number(arguments.buildNumber)
+
+ disable_extensions = False
+ if arguments.disableExtensions is not None:
+ disable_extensions = arguments.disableExtensions
+
+ call_executable(['killall', 'Xcode'], check_result=False)
+
+ generate(
+ build_environment=bazel_command_line.build_environment,
+ disable_extensions=disable_extensions,
+ configuration_path=bazel_command_line.configuration_path,
+ bazel_app_arguments=bazel_command_line.get_project_generation_arguments()
+ )
+
+
+def build(arguments):
+ bazel_command_line = BazelCommandLine(
+ bazel_path=arguments.bazel,
+ bazel_x86_64_path=None,
+ override_bazel_version=arguments.overrideBazelVersion,
+ override_xcode_version=arguments.overrideXcodeVersion
+ )
+
+ if arguments.cacheDir is not None:
+ bazel_command_line.add_cache_dir(arguments.cacheDir)
+ elif arguments.cacheHost is not None:
+ bazel_command_line.add_remote_cache(arguments.cacheHost)
+
+ resolve_configuration(bazel_command_line, arguments)
+
+ bazel_command_line.set_configuration(arguments.configuration)
+ bazel_command_line.set_build_number(arguments.buildNumber)
+
+ bazel_command_line.invoke_build()
+
+
+def add_project_and_build_common_arguments(current_parser: argparse.ArgumentParser):
+ group = current_parser.add_mutually_exclusive_group(required=True)
+ group.add_argument(
+ '--configurationPath',
+ help='''
+ Path to a folder containing build configuration and provisioning profiles.
+ See build-system/example-configuration for an example.
+ ''',
+ metavar='path'
+ )
+ group.add_argument(
+ '--configurationGenerator',
+ help='''
+ A command line invocation that will dynamically generate the configuration data
+ (project constants and provisioning profiles).
+ The expression will be parsed according to the shell parsing rules into program and arguments parts.
+ The program will be then invoked with the given arguments plus the path to the output directory.
+ See build-system/generate-configuration.sh for an example.
+ Example: --configurationGenerator="sh ~/my_script.sh argument1"
+ ''',
+ metavar='command'
+ )
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(prog='Make')
+
+ parser.add_argument(
+ '--verbose',
+ action='store_true',
+ default=False,
+ help='Print debug info'
+ )
+
+ parser.add_argument(
+ '--bazel',
+ required=True,
+ help='Use custom bazel binary',
+ metavar='path'
+ )
+
+ parser.add_argument(
+ '--overrideBazelVersion',
+ action='store_true',
+ help='Override bazel version with the actual version reported by the bazel binary'
+ )
+
+ parser.add_argument(
+ '--overrideXcodeVersion',
+ action='store_true',
+ help='Override xcode version with the actual version reported by \'xcode-select -p\''
+ )
+
+ parser.add_argument(
+ '--bazelArguments',
+ required=False,
+ help='Add additional arguments to all bazel invocations.',
+ metavar='arguments'
+ )
+
+ cacheTypeGroup = parser.add_mutually_exclusive_group()
+ cacheTypeGroup.add_argument(
+ '--cacheHost',
+ required=False,
+ help='Use remote build artifact cache to speed up rebuilds (See https://github.com/buchgr/bazel-remote).',
+ metavar='http://host:9092'
+ )
+ cacheTypeGroup.add_argument(
+ '--cacheDir',
+ required=False,
+ help='Cache build artifacts in a local directory to speed up rebuilds.',
+ metavar='path'
+ )
+
+ subparsers = parser.add_subparsers(dest='commandName', help='Commands')
+
+ cleanParser = subparsers.add_parser(
+ 'clean', help='''
+ Clean local bazel cache. Does not affect files cached remotely (via --cacheHost=...) or
+ locally in an external directory ('--cacheDir=...')
+ '''
+ )
+
+ generateProjectParser = subparsers.add_parser('generateProject', help='Generate Xcode project')
+ if is_apple_silicon():
+ generateProjectParser.add_argument(
+ '--bazel_x86_64',
+ required=True,
+ help='A standalone bazel x86_64 binary is required to generate a project on Apple Silicon.',
+ metavar='path'
+ )
+ generateProjectParser.add_argument(
+ '--buildNumber',
+ required=False,
+ type=int,
+ default=10000,
+ help='Build number.',
+ metavar='number'
+ )
+ add_project_and_build_common_arguments(generateProjectParser)
+ generateProjectParser.add_argument(
+ '--disableExtensions',
+ action='store_true',
+ default=False,
+ help='''
+ The generated project will not include app extensions.
+ This allows Xcode to properly index the source code.
+ '''
+ )
+
+ buildParser = subparsers.add_parser('build', help='Build the app')
+ buildParser.add_argument(
+ '--buildNumber',
+ required=True,
+ type=int,
+ help='Build number.',
+ metavar='number'
+ )
+ add_project_and_build_common_arguments(buildParser)
+ buildParser.add_argument(
+ '--configuration',
+ choices=[
+ 'debug_arm64',
+ 'release_arm64',
+ 'release_universal'
+ ],
+ required=True,
+ help='Build configuration'
+ )
+
+ if len(sys.argv) < 2:
+ parser.print_help()
+ sys.exit(1)
+
+ args = parser.parse_args()
+
+ if args.verbose:
+ print(args)
+
+ if args.commandName is None:
+ exit(0)
+
+ try:
+ if args.commandName == 'clean':
+ clean(arguments=args)
+ elif args.commandName == 'generateProject':
+ generate_project(arguments=args)
+ elif args.commandName == 'build':
+ build(arguments=args)
+ else:
+ raise Exception('Unknown command')
+ except KeyboardInterrupt:
+ pass
diff --git a/build-system/Make/ProjectGeneration.py b/build-system/Make/ProjectGeneration.py
new file mode 100644
index 0000000000..dab2520e34
--- /dev/null
+++ b/build-system/Make/ProjectGeneration.py
@@ -0,0 +1,155 @@
+import json
+import os
+import shutil
+
+from BuildEnvironment import is_apple_silicon, call_executable, BuildEnvironment
+
+
+def remove_directory(path):
+ if os.path.isdir(path):
+ shutil.rmtree(path)
+
+
+def generate(build_environment: BuildEnvironment, disable_extensions, configuration_path, bazel_app_arguments):
+ project_path = os.path.join(build_environment.base_path, 'build-input/gen/project')
+ app_target = 'Telegram'
+
+ '''
+ TULSI_APP="build-input/gen/project/Tulsi.app"
+ TULSI="$TULSI_APP/Contents/MacOS/Tulsi"
+
+ rm -rf "$GEN_DIRECTORY/${APP_TARGET}.tulsiproj"
+ rm -rf "$TULSI_APP"
+ '''
+
+ os.makedirs(project_path, exist_ok=True)
+ remove_directory('{}/Tulsi.app'.format(project_path))
+ remove_directory('{project}/{target}.tulsiproj'.format(project=project_path, target=app_target))
+
+ tulsi_path = os.path.join(project_path, 'Tulsi.app/Contents/MacOS/Tulsi')
+
+ if is_apple_silicon():
+ tulsi_build_bazel_path = build_environment.bazel_x86_64_path
+ if tulsi_build_bazel_path is None or not os.path.isfile(tulsi_build_bazel_path):
+ print('Could not find a valid bazel x86_64 binary at {}'.format(tulsi_build_bazel_path))
+ exit(1)
+ else:
+ tulsi_build_bazel_path = build_environment.bazel_path
+
+ current_dir = os.getcwd()
+ os.chdir(os.path.join(build_environment.base_path, 'build-system/tulsi'))
+ call_executable([
+ tulsi_build_bazel_path,
+ 'build', '//:tulsi',
+ '--xcode_version={}'.format(build_environment.xcode_version),
+ '--use_top_level_targets_for_symlinks',
+ '--verbose_failures'
+ ])
+ os.chdir(current_dir)
+
+ bazel_wrapper_path = os.path.abspath('build-input/gen/project/bazel')
+
+ bazel_wrapper_arguments = []
+ bazel_wrapper_arguments += ['--override_repository=build_configuration={}'.format(configuration_path)]
+ if disable_extensions and False:
+ bazel_wrapper_arguments += ['--//Telegram:disableExtensions']
+
+ with open(bazel_wrapper_path, 'wb') as bazel_wrapper:
+ bazel_wrapper.write('''#!/bin/sh
+{bazel} "$@" {arguments}
+'''.format(
+ bazel=build_environment.bazel_path,
+ arguments=' '.join(bazel_wrapper_arguments)
+ ).encode('utf-8'))
+
+ call_executable(['chmod', '+x', bazel_wrapper_path])
+
+ call_executable([
+ 'unzip', '-oq',
+ 'build-system/tulsi/bazel-bin/tulsi.zip',
+ '-d', project_path
+ ])
+
+ user_defaults_path = os.path.expanduser('~/Library/Preferences/com.google.Tulsi.plist')
+ if os.path.isfile(user_defaults_path):
+ os.unlink(user_defaults_path)
+
+ with open(user_defaults_path, 'wb') as user_defaults:
+ user_defaults.write('''
+
+
+
+
+ defaultBazelURL
+ {}
+
+
+'''.format(bazel_wrapper_path).encode('utf-8'))
+
+ bazel_build_arguments = []
+ bazel_build_arguments += ['--override_repository=build_configuration={}'.format(configuration_path)]
+ if disable_extensions:
+ bazel_build_arguments += ['--//Telegram:disableExtensions']
+
+ call_executable([
+ tulsi_path,
+ '--',
+ '--verbose',
+ '--create-tulsiproj', app_target,
+ '--workspaceroot', './',
+ '--bazel', bazel_wrapper_path,
+ '--outputfolder', project_path,
+ '--target', '{target}:{target}'.format(target=app_target),
+ '--build-options', ' '.join(bazel_build_arguments)
+ ])
+
+ additional_arguments = []
+ additional_arguments += ['--override_repository=build_configuration={}'.format(configuration_path)]
+ additional_arguments += bazel_app_arguments
+ if disable_extensions:
+ additional_arguments += ['--//Telegram:disableExtensions']
+
+ additional_arguments_string = ' '.join(additional_arguments)
+
+ tulsi_config_path = 'build-input/gen/project/{target}.tulsiproj/Configs/{target}.tulsigen'.format(target=app_target)
+ with open(tulsi_config_path, 'rb') as tulsi_config:
+ tulsi_config_json = json.load(tulsi_config)
+ for category in ['BazelBuildOptionsDebug', 'BazelBuildOptionsRelease']:
+ tulsi_config_json['optionSet'][category]['p'] += ' {}'.format(additional_arguments_string)
+ tulsi_config_json['sourceFilters'] = [
+ 'Telegram/...',
+ 'submodules/...',
+ 'third-party/...'
+ ]
+ with open(tulsi_config_path, 'wb') as tulsi_config:
+ tulsi_config.write(json.dumps(tulsi_config_json, indent=2).encode('utf-8'))
+
+ call_executable([
+ tulsi_path,
+ '--',
+ '--verbose',
+ '--genconfig', '{project}/{target}.tulsiproj:{target}'.format(project=project_path, target=app_target),
+ '--bazel', bazel_wrapper_path,
+ '--outputfolder', project_path,
+ '--no-open-xcode'
+ ])
+
+ xcodeproj_path = '{project}/{target}.xcodeproj'.format(project=project_path, target=app_target)
+
+ bazel_build_settings_path = '{}/.tulsi/Scripts/bazel_build_settings.py'.format(xcodeproj_path)
+
+ with open(bazel_build_settings_path, 'rb') as bazel_build_settings:
+ bazel_build_settings_contents = bazel_build_settings.read().decode('utf-8')
+ bazel_build_settings_contents = bazel_build_settings_contents.replace(
+ 'BUILD_SETTINGS = BazelBuildSettings(',
+ 'import os\nBUILD_SETTINGS = BazelBuildSettings('
+ )
+ bazel_build_settings_contents = bazel_build_settings_contents.replace(
+ '\'--cpu=ios_arm64\'',
+ '\'--cpu=ios_arm64\'.replace(\'ios_arm64\', \'ios_sim_arm64\' if os.environ.get(\'EFFECTIVE_PLATFORM_NAME\') '
+ '== \'-iphonesimulator\' else \'ios_arm64\')'
+ )
+ with open(bazel_build_settings_path, 'wb') as bazel_build_settings:
+ bazel_build_settings.write(bazel_build_settings_contents.encode('utf-8'))
+
+ call_executable(['open', xcodeproj_path])
diff --git a/build-system/bazel_version b/build-system/bazel_version
deleted file mode 100644
index 7c69a55dbb..0000000000
--- a/build-system/bazel_version
+++ /dev/null
@@ -1 +0,0 @@
-3.7.0
diff --git a/build-input/BUILD b/build-system/example-configuration/BUILD
similarity index 100%
rename from build-input/BUILD
rename to build-system/example-configuration/BUILD
diff --git a/build-system/example-configuration/WORKSPACE b/build-system/example-configuration/WORKSPACE
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/build-system/example-configuration/provisioning/BUILD b/build-system/example-configuration/provisioning/BUILD
new file mode 100644
index 0000000000..9abb88a19d
--- /dev/null
+++ b/build-system/example-configuration/provisioning/BUILD
@@ -0,0 +1,11 @@
+
+exports_files([
+ "Intents.mobileprovision",
+ "NotificationContent.mobileprovision",
+ "NotificationService.mobileprovision",
+ "Share.mobileprovision",
+ "Telegram.mobileprovision",
+ "WatchApp.mobileprovision",
+ "WatchExtension.mobileprovision",
+ "Widget.mobileprovision",
+])
diff --git a/build-system/example-configuration/provisioning/Intents.mobileprovision b/build-system/example-configuration/provisioning/Intents.mobileprovision
new file mode 100644
index 0000000000..8cb484f943
Binary files /dev/null and b/build-system/example-configuration/provisioning/Intents.mobileprovision differ
diff --git a/build-system/example-configuration/provisioning/NotificationContent.mobileprovision b/build-system/example-configuration/provisioning/NotificationContent.mobileprovision
new file mode 100644
index 0000000000..bd054573e9
Binary files /dev/null and b/build-system/example-configuration/provisioning/NotificationContent.mobileprovision differ
diff --git a/build-system/example-configuration/provisioning/NotificationService.mobileprovision b/build-system/example-configuration/provisioning/NotificationService.mobileprovision
new file mode 100644
index 0000000000..663bd68b69
Binary files /dev/null and b/build-system/example-configuration/provisioning/NotificationService.mobileprovision differ
diff --git a/build-system/example-configuration/provisioning/Share.mobileprovision b/build-system/example-configuration/provisioning/Share.mobileprovision
new file mode 100644
index 0000000000..e49de2d713
Binary files /dev/null and b/build-system/example-configuration/provisioning/Share.mobileprovision differ
diff --git a/build-system/example-configuration/provisioning/Telegram.mobileprovision b/build-system/example-configuration/provisioning/Telegram.mobileprovision
new file mode 100644
index 0000000000..1592674339
Binary files /dev/null and b/build-system/example-configuration/provisioning/Telegram.mobileprovision differ
diff --git a/build-system/example-configuration/provisioning/WatchApp.mobileprovision b/build-system/example-configuration/provisioning/WatchApp.mobileprovision
new file mode 100644
index 0000000000..2b0558a240
Binary files /dev/null and b/build-system/example-configuration/provisioning/WatchApp.mobileprovision differ
diff --git a/build-system/example-configuration/provisioning/WatchExtension.mobileprovision b/build-system/example-configuration/provisioning/WatchExtension.mobileprovision
new file mode 100644
index 0000000000..ba9ce392ff
Binary files /dev/null and b/build-system/example-configuration/provisioning/WatchExtension.mobileprovision differ
diff --git a/build-system/example-configuration/provisioning/Widget.mobileprovision b/build-system/example-configuration/provisioning/Widget.mobileprovision
new file mode 100644
index 0000000000..37de9fe5aa
Binary files /dev/null and b/build-system/example-configuration/provisioning/Widget.mobileprovision differ
diff --git a/build-system/example-configuration/variables.bzl b/build-system/example-configuration/variables.bzl
new file mode 100644
index 0000000000..a89c790a17
--- /dev/null
+++ b/build-system/example-configuration/variables.bzl
@@ -0,0 +1,10 @@
+telegram_bundle_id = "ph.telegra.Telegraph"
+telegram_api_id = "8"
+telegram_api_hash = "7245de8e747a0d6fbe11f7cc14fcc0bb"
+telegram_team_id = "C67CF9S4VU"
+telegram_app_center_id = "0"
+telegram_is_internal_build = "false"
+telegram_is_appstore_build = "true"
+telegram_appstore_id = "0"
+telegram_app_specific_url_scheme = "tg"
+telegram_aps_environment = "production"
diff --git a/build-system/example-generate-configuration b/build-system/example-generate-configuration
new file mode 100755
index 0000000000..79217d6514
--- /dev/null
+++ b/build-system/example-generate-configuration
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ ! -d "$1" ]; then
+ exit 1
+fi
+
+cp -R build-system/example-configuration/* "$1/"
diff --git a/build-system/manage-developer-portal-app.sh b/build-system/manage-developer-portal-app.sh
deleted file mode 100644
index 60e21c1381..0000000000
--- a/build-system/manage-developer-portal-app.sh
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/bin/bash
-
-set -e
-
-FASTLANE="$(which fastlane)"
-
-EXPECTED_VARIABLES=(\
- APPLE_ID \
- BASE_BUNDLE_ID \
- APP_NAME \
- TEAM_ID \
- PROVISIONING_DIRECTORY \
-)
-
-MISSING_VARIABLES="0"
-for VARIABLE_NAME in ${EXPECTED_VARIABLES[@]}; do
- if [ "${!VARIABLE_NAME}" = "" ]; then
- echo "$VARIABLE_NAME not defined"
- MISSING_VARIABLES="1"
- fi
-done
-if [ "$MISSING_VARIABLES" == "1" ]; then
- exit 1
-fi
-
-if [ ! -d "$PROVISIONING_DIRECTORY" ]; then
- echo "Directory $PROVISIONING_DIRECTORY does not exist"
- exit 1
-fi
-
-BASE_DIR=$(mktemp -d)
-FASTLANE_DIR="$BASE_DIR/fastlane"
-mkdir "$FASTLANE_DIR"
-FASTFILE="$FASTLANE_DIR/Fastfile"
-
-touch "$FASTFILE"
-
-CREDENTIALS=(\
- --username "$APPLE_ID" \
- --team_id "$TEAM_ID" \
-)
-export FASTLANE_SKIP_UPDATE_CHECK=1
-
-APP_EXTENSIONS=(\
- Share \
- SiriIntents \
- NotificationContent \
- NotificationService \
- Widget \
-)
-
-echo "lane :manage_app do" >> "$FASTFILE"
-echo " produce(" >> "$FASTFILE"
-echo " username: '$APPLE_ID'," >> "$FASTFILE"
-echo " app_identifier: '${BASE_BUNDLE_ID}'," >> "$FASTFILE"
-echo " app_name: '$APP_NAME'," >> "$FASTFILE"
-echo " language: 'English'," >> "$FASTFILE"
-echo " app_version: '1.0'," >> "$FASTFILE"
-echo " team_id: '$TEAM_ID'," >> "$FASTFILE"
-echo " skip_itc: true," >> "$FASTFILE"
-echo " )" >> "$FASTFILE"
-
-echo " produce(" >> "$FASTFILE"
-echo " username: '$APPLE_ID'," >> "$FASTFILE"
-echo " app_identifier: '${BASE_BUNDLE_ID}.watchkitapp'," >> "$FASTFILE"
-echo " app_name: '$APP_NAME Watch App'," >> "$FASTFILE"
-echo " language: 'English'," >> "$FASTFILE"
-echo " app_version: '1.0'," >> "$FASTFILE"
-echo " team_id: '$TEAM_ID'," >> "$FASTFILE"
-echo " skip_itc: true," >> "$FASTFILE"
-echo " )" >> "$FASTFILE"
-
-echo " produce(" >> "$FASTFILE"
-echo " username: '$APPLE_ID'," >> "$FASTFILE"
-echo " app_identifier: '${BASE_BUNDLE_ID}.watchkitapp.watchkitextension'," >> "$FASTFILE"
-echo " app_name: '$APP_NAME Watch App Extension'," >> "$FASTFILE"
-echo " language: 'English'," >> "$FASTFILE"
-echo " app_version: '1.0'," >> "$FASTFILE"
-echo " team_id: '$TEAM_ID'," >> "$FASTFILE"
-echo " skip_itc: true," >> "$FASTFILE"
-echo " )" >> "$FASTFILE"
-
-for EXTENSION in ${APP_EXTENSIONS[@]}; do
- echo " produce(" >> "$FASTFILE"
- echo " username: '$APPLE_ID'," >> "$FASTFILE"
- echo " app_identifier: '${BASE_BUNDLE_ID}.${EXTENSION}'," >> "$FASTFILE"
- echo " app_name: '${APP_NAME} ${EXTENSION}'," >> "$FASTFILE"
- echo " language: 'English'," >> "$FASTFILE"
- echo " app_version: '1.0'," >> "$FASTFILE"
- echo " team_id: '$TEAM_ID'," >> "$FASTFILE"
- echo " skip_itc: true," >> "$FASTFILE"
- echo " )" >> "$FASTFILE"
-done
-
-echo "end" >> "$FASTFILE"
-
-pushd "$BASE_DIR"
-
-fastlane cert ${CREDENTIALS[@]} --development
-
-fastlane manage_app
-
-fastlane produce group -g "group.$BASE_BUNDLE_ID" -n "$APP_NAME Group" ${CREDENTIALS[@]}
-
-fastlane produce enable_services -a "$BASE_BUNDLE_ID" ${CREDENTIALS[@]} \
- --app-group \
- --push-notification \
- --sirikit
-
-fastlane produce associate_group -a "$BASE_BUNDLE_ID" "group.$BASE_BUNDLE_ID" ${CREDENTIALS[@]}
-for EXTENSION in ${APP_EXTENSIONS[@]}; do
- fastlane produce enable_services -a "${BASE_BUNDLE_ID}.${EXTENSION}" ${CREDENTIALS[@]} \
- --app-group
-
- fastlane produce associate_group -a "${BASE_BUNDLE_ID}.${EXTENSION}" "group.$BASE_BUNDLE_ID" ${CREDENTIALS[@]}
-done
-
-for DEVELOPMENT_FLAG in "--development"; do
- fastlane sigh -a "$BASE_BUNDLE_ID" ${CREDENTIALS[@]} -o "$PROVISIONING_DIRECTORY" $DEVELOPMENT_FLAG \
- --skip_install
- for EXTENSION in ${APP_EXTENSIONS[@]}; do
- fastlane sigh -a "${BASE_BUNDLE_ID}.${EXTENSION}" ${CREDENTIALS[@]} -o "$PROVISIONING_DIRECTORY" $DEVELOPMENT_FLAG \
- --skip_install
- done
-done
-
-popd
-
-rm -rf "$BASE_DIR"
diff --git a/build-system/tulsi b/build-system/tulsi
index b965114f31..734518e85d 160000
--- a/build-system/tulsi
+++ b/build-system/tulsi
@@ -1 +1 @@
-Subproject commit b965114f31a464185318c71ef3d0c1538d0c52de
+Subproject commit 734518e85d769de070b5a78b234080d9580ae625
diff --git a/build-system/xcode_version b/build-system/xcode_version
deleted file mode 100644
index 5807e59269..0000000000
--- a/build-system/xcode_version
+++ /dev/null
@@ -1 +0,0 @@
-12.2
diff --git a/buildbox/build-telegram.sh b/buildbox/build-telegram.sh
index 38a7bf6fd8..c1e4905153 100644
--- a/buildbox/build-telegram.sh
+++ b/buildbox/build-telegram.sh
@@ -5,7 +5,7 @@ set -e
BUILD_TELEGRAM_VERSION="1"
MACOS_VERSION="10.15"
-XCODE_VERSION="12.2"
+XCODE_VERSION="12.3"
GUEST_SHELL="bash"
VM_BASE_NAME="macos$(echo $MACOS_VERSION | sed -e 's/\.'/_/g)_Xcode$(echo $XCODE_VERSION | sed -e 's/\.'/_/g)"
@@ -58,7 +58,7 @@ cp "$BAZEL" "tools/bazel"
BUILD_CONFIGURATION="$1"
if [ "$BUILD_CONFIGURATION" == "hockeyapp" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental-2" ]; then
- CODESIGNING_SUBPATH="transient-data/codesigning"
+ CODESIGNING_SUBPATH="transient-data/telegram-codesigning/codesigning"
CODESIGNING_TEAMS_SUBPATH="transient-data/teams"
elif [ "$BUILD_CONFIGURATION" == "appstore" ]; then
CODESIGNING_SUBPATH="transient-data/codesigning"
@@ -90,28 +90,25 @@ fi
BASE_DIR=$(pwd)
if [ "$BUILD_CONFIGURATION" == "hockeyapp" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental-2" ] || [ "$BUILD_CONFIGURATION" == "appstore" ]; then
- if [ ! `which setup-telegram-build.sh` ]; then
- echo "setup-telegram-build.sh not found in PATH $PATH"
+ if [ ! `which generate-configuration.sh` ]; then
+ echo "generate-configuration.sh not found in PATH $PATH"
exit 1
fi
- if [ ! `which setup-codesigning.sh` ]; then
- echo "setup-codesigning.sh not found in PATH $PATH"
- exit 1
- fi
- source `which setup-telegram-build.sh`
- setup_telegram_build "$BUILD_CONFIGURATION" "$BASE_DIR/$BUILDBOX_DIR/transient-data"
- source `which setup-codesigning.sh`
-
- CODESIGNING_CONFIGURATION="$BUILD_CONFIGURATION"
- if [ "$BUILD_CONFIGURATION" == "appcenter-experimental" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental-2" ]; then
- CODESIGNING_CONFIGURATION="hockeyapp"
- fi
- setup_codesigning "$CODESIGNING_CONFIGURATION" "$BASE_DIR/$BUILDBOX_DIR/transient-data"
- if [ "$SETUP_TELEGRAM_BUILD_VERSION" != "$BUILD_TELEGRAM_VERSION" ]; then
- echo "setup-telegram-build.sh script version doesn't match"
- exit 1
- fi
+ mkdir -p "$BASE_DIR/$BUILDBOX_DIR/transient-data/telegram-codesigning"
+ mkdir -p "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
+
+ case "$BUILD_CONFIGURATION" in
+ "hockeyapp")
+ generate-configuration.sh internal release "$BASE_DIR/$BUILDBOX_DIR/transient-data/telegram-codesigning" "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
+ ;;
+
+ *)
+ echo "Unknown build configuration $BUILD_CONFIGURATION"
+ exit 1
+ ;;
+ esac
+
if [ "$BUILD_CONFIGURATION" == "appstore" ]; then
if [ -z "$TELEGRAM_BUILD_APPSTORE_PASSWORD" ]; then
echo "TELEGRAM_BUILD_APPSTORE_PASSWORD is not set"
@@ -186,13 +183,14 @@ elif [ "$BUILD_MACHINE" == "macOS" ]; then
fi
scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -pr "$BUILDBOX_DIR/$CODESIGNING_SUBPATH" telegram@"$VM_IP":codesigning_data
-scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -pr "$BUILDBOX_DIR/$CODESIGNING_TEAMS_SUBPATH" telegram@"$VM_IP":codesigning_teams
+scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -pr "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration" telegram@"$VM_IP":telegram-configuration
+#scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -pr "$BUILDBOX_DIR/$CODESIGNING_TEAMS_SUBPATH" telegram@"$VM_IP":codesigning_teams
-if [ "$BUILD_CONFIGURATION" == "verify" ]; then
- ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null telegram@"$VM_IP" -o ServerAliveInterval=60 -t "mkdir -p telegram-ios-shared/fastlane; echo '' > telegram-ios-shared/fastlane/Fastfile"
-else
- scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -pr "$BUILDBOX_DIR/transient-data/telegram-ios-shared" telegram@"$VM_IP":telegram-ios-shared
-fi
+#if [ "$BUILD_CONFIGURATION" == "verify" ]; then
+# ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null telegram@"$VM_IP" -o ServerAliveInterval=60 -t "mkdir -p telegram-ios-shared/fastlane; echo '' > telegram-ios-shared/fastlane/Fastfile"
+#else
+# scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -pr "$BUILDBOX_DIR/transient-data/telegram-ios-shared" telegram@"$VM_IP":telegram-ios-shared
+#fi
scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -pr "$BUILDBOX_DIR/guest-build-telegram.sh" "$BUILDBOX_DIR/transient-data/source.tar" telegram@"$VM_IP":
ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null telegram@"$VM_IP" -o ServerAliveInterval=60 -t "export TELEGRAM_BUILD_APPSTORE_PASSWORD=\"$TELEGRAM_BUILD_APPSTORE_PASSWORD\"; export TELEGRAM_BUILD_APPSTORE_TEAM_NAME=\"$TELEGRAM_BUILD_APPSTORE_TEAM_NAME\"; export TELEGRAM_BUILD_APPSTORE_USERNAME=\"$TELEGRAM_BUILD_APPSTORE_USERNAME\"; export BUILD_NUMBER=\"$BUILD_NUMBER\"; export COMMIT_ID=\"$COMMIT_ID\"; export COMMIT_AUTHOR=\"$COMMIT_AUTHOR\"; export BAZEL_HTTP_CACHE_URL=\"$BAZEL_HTTP_CACHE_URL\"; $GUEST_SHELL -l guest-build-telegram.sh $BUILD_CONFIGURATION" || true
diff --git a/buildbox/guest-build-telegram.sh b/buildbox/guest-build-telegram.sh
index 3e4681311c..d540abab4d 100644
--- a/buildbox/guest-build-telegram.sh
+++ b/buildbox/guest-build-telegram.sh
@@ -13,8 +13,8 @@ if [ -z "COMMIT_ID" ]; then
fi
if [ "$1" == "hockeyapp" ] || [ "$1" == "appcenter-experimental" ] || [ "$1" == "appcenter-experimental-2" ] || [ "$1" == "testinghockeyapp" ]; then
- CERTS_PATH="$HOME/codesigning_data/certs"
- PROFILES_PATH="$HOME/codesigning_data/profiles"
+ CERTS_PATH="$HOME/codesigning_data/certs/enterprise"
+ #PROFILES_PATH="$HOME/codesigning_data/profiles"
elif [ "$1" == "testinghockeyapp-local" ]; then
CERTS_PATH="$HOME/codesigning_data/certs"
PROFILES_PATH="$HOME/codesigning_data/profiles"
@@ -79,7 +79,7 @@ echo "Unpacking files..."
mkdir -p "$SOURCE_PATH/buildbox"
mkdir -p "$SOURCE_PATH/buildbox/transient-data"
-cp -r "$HOME/codesigning_teams" "$SOURCE_PATH/buildbox/transient-data/teams"
+#cp -r "$HOME/codesigning_teams" "$SOURCE_PATH/buildbox/transient-data/teams"
BASE_DIR=$(pwd)
cd "$SOURCE_PATH"
@@ -95,17 +95,18 @@ done
security set-key-partition-list -S apple-tool:,apple: -k "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
-mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
+#mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
-for f in $(ls "$PROFILES_PATH"); do
- PROFILE_PATH="$PROFILES_PATH/$f"
- uuid=`grep UUID -A1 -a "$PROFILE_PATH" | grep -io "[-A-F0-9]\{36\}"`
- cp -f "$PROFILE_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/$uuid.mobileprovision"
-done
+#for f in $(ls "$PROFILES_PATH"); do
+# PROFILE_PATH="$PROFILES_PATH/$f"
+# uuid=`grep UUID -A1 -a "$PROFILE_PATH" | grep -io "[-A-F0-9]\{36\}"`
+# cp -f "$PROFILE_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/$uuid.mobileprovision"
+#done
if [ "$1" == "hockeyapp" ] || [ "$1" == "appcenter-experimental" ] || [ "$1" == "appcenter-experimental-2" ]; then
- BUILD_ENV_SCRIPT="../telegram-ios-shared/buildbox/bin/internal.sh"
- APP_TARGET="bazel_app_arm64"
+ #BUILD_ENV_SCRIPT="../telegram-ios-shared/buildbox/bin/internal.sh"
+ #APP_TARGET="bazel_app_arm64"
+ echo "" >> /dev/null
elif [ "$1" == "appstore" ]; then
BUILD_ENV_SCRIPT="../telegram-ios-shared/buildbox/bin/appstore.sh"
APP_TARGET="bazel_app"
@@ -126,7 +127,15 @@ elif [ "$1" == "appcenter-experimental-2" ]; then
export APP_CENTER_ID="$APP_CENTER_EXPERIMENTAL_2_ID"
fi
-PATH="$PATH:$(pwd)/tools" BAZEL_HTTP_CACHE_URL="$BAZEL_HTTP_CACHE_URL" LOCAL_CODESIGNING=1 sh "$BUILD_ENV_SCRIPT" make "$APP_TARGET"
+#PATH="$PATH:$(pwd)/tools" BAZEL_HTTP_CACHE_URL="$BAZEL_HTTP_CACHE_URL" LOCAL_CODESIGNING=1 sh "$BUILD_ENV_SCRIPT" make "$APP_TARGET"
+
+python3 build-system/Make/Make.py \
+ --bazel="$(pwd)/tools/bazel" \
+ --cacheHost="$BAZEL_HTTP_CACHE_URL" \
+ build \
+ --configurationPath="$HOME/telegram-configuration" \
+ --buildNumber="$BUILD_NUMBER" \
+ --configuration=release_arm64
OUTPUT_PATH="build/artifacts"
rm -rf "$OUTPUT_PATH"
diff --git a/submodules/BuildConfig/BUILD b/submodules/BuildConfig/BUILD
index 43c0ca2b29..d3f9c56360 100644
--- a/submodules/BuildConfig/BUILD
+++ b/submodules/BuildConfig/BUILD
@@ -1,5 +1,5 @@
load(
- "//build-input/data:variables.bzl",
+ "@build_configuration//:variables.bzl",
"telegram_api_id",
"telegram_api_hash",
"telegram_app_center_id",
diff --git a/submodules/Postbox/Sources/TopChatMessageView.swift b/submodules/Postbox/Sources/TopChatMessageView.swift
new file mode 100644
index 0000000000..be48793c97
--- /dev/null
+++ b/submodules/Postbox/Sources/TopChatMessageView.swift
@@ -0,0 +1,44 @@
+import Foundation
+
+final class MutableTopChatMessageView: MutablePostboxView {
+ private let peerIds: Set
+ fileprivate var messages: [PeerId: Message] = [:]
+
+ init(postbox: Postbox, peerIds: Set) {
+ self.peerIds = peerIds
+
+ for peerId in self.peerIds {
+ if let index = postbox.chatListIndexTable.get(peerId: peerId).topMessageIndex {
+ self.messages[peerId] = postbox.getMessage(index.id)
+ }
+ }
+ }
+
+ func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool {
+ var updated = false
+ for peerId in self.peerIds {
+ if transaction.currentOperationsByPeerId[peerId] != nil {
+ if let index = postbox.chatListIndexTable.get(peerId: peerId).topMessageIndex {
+ self.messages[peerId] = postbox.getMessage(index.id)
+ } else {
+ self.messages.removeValue(forKey: peerId)
+ }
+ updated = true
+ }
+ }
+
+ return updated
+ }
+
+ func immutableView() -> PostboxView {
+ return TopChatMessageView(self)
+ }
+}
+
+public final class TopChatMessageView: PostboxView {
+ public let messages: [PeerId: Message]
+
+ init(_ view: MutableTopChatMessageView) {
+ self.messages = view.messages
+ }
+}
diff --git a/submodules/Postbox/Sources/Views.swift b/submodules/Postbox/Sources/Views.swift
index 3202e76e23..255489a3fe 100644
--- a/submodules/Postbox/Sources/Views.swift
+++ b/submodules/Postbox/Sources/Views.swift
@@ -30,6 +30,7 @@ public enum PostboxViewKey: Hashable {
case basicPeer(PeerId)
case allChatListHoles(PeerGroupId)
case historyTagInfo(peerId: PeerId, tag: MessageTags)
+ case topChatMessage(peerIds: [PeerId])
public var hashValue: Int {
switch self {
@@ -91,6 +92,8 @@ public enum PostboxViewKey: Hashable {
return groupId.hashValue
case let .historyTagInfo(peerId, tag):
return peerId.hashValue ^ tag.hashValue
+ case let .topChatMessage(peerIds):
+ return peerIds.hashValue
}
}
@@ -270,6 +273,12 @@ public enum PostboxViewKey: Hashable {
} else {
return false
}
+ case let .topChatMessage(peerIds):
+ if case .topChatMessage(peerIds) = rhs {
+ return true
+ } else {
+ return false
+ }
}
}
}
@@ -334,5 +343,7 @@ func postboxViewForKey(postbox: Postbox, key: PostboxViewKey) -> MutablePostboxV
return MutableAllChatListHolesView(postbox: postbox, groupId: groupId)
case let .historyTagInfo(peerId, tag):
return MutableHistoryTagInfoView(postbox: postbox, peerId: peerId, tag: tag)
+ case let .topChatMessage(peerIds):
+ return MutableTopChatMessageView(postbox: postbox, peerIds: Set(peerIds))
}
}
diff --git a/submodules/TelegramCore/Sources/InvitationLinks.swift b/submodules/TelegramCore/Sources/InvitationLinks.swift
index 04a9c3d1d9..8fb5e28bc2 100644
--- a/submodules/TelegramCore/Sources/InvitationLinks.swift
+++ b/submodules/TelegramCore/Sources/InvitationLinks.swift
@@ -12,7 +12,7 @@ public func ensuredExistingPeerExportedInvitation(account: Account, peerId: Peer
let flags: Int32 = (1 << 2)
if let _ = peer as? TelegramChannel {
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil && !revokeExisted {
- return .complete()
+ return .single(cachedData.exportedInvitation)
} else {
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil))
|> retryRequest
@@ -99,10 +99,13 @@ public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: B
return account.postbox.transaction { transaction -> Signal in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var flags: Int32 = 0
+ if let _ = offsetLink {
+ flags |= (1 << 2)
+ }
if revoked {
flags |= (1 << 3)
}
- return account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: nil, offsetLink: nil, limit: 50))
+ return account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: nil, offsetLink: offsetLink, limit: 50))
|> map(Optional.init)
|> `catch` { _ -> Signal in
return .single(nil)
diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD
index 112616c6f1..63e2395943 100644
--- a/submodules/TelegramUI/BUILD
+++ b/submodules/TelegramUI/BUILD
@@ -187,6 +187,7 @@ swift_library(
"//submodules/Markdown:Markdown",
"//submodules/SearchPeerMembers:SearchPeerMembers",
"//submodules/WidgetItems:WidgetItems",
+ "//submodules/WidgetItemsUtils:WidgetItemsUtils",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
"//submodules/PhoneNumberFormat:PhoneNumberFormat",
"//submodules/AppLock:AppLock",
@@ -211,6 +212,7 @@ swift_library(
"//submodules/SlotMachineAnimationNode:SlotMachineAnimationNode",
"//submodules/AnimatedNavigationStripeNode:AnimatedNavigationStripeNode",
"//submodules/AudioBlob:AudioBlob",
+ "//Telegram:GeneratedSources",
],
visibility = [
"//visibility:public",
diff --git a/submodules/TelegramUI/Sources/WidgetDataContext.swift b/submodules/TelegramUI/Sources/WidgetDataContext.swift
index 1822576ce5..f962dbc4f2 100644
--- a/submodules/TelegramUI/Sources/WidgetDataContext.swift
+++ b/submodules/TelegramUI/Sources/WidgetDataContext.swift
@@ -8,6 +8,9 @@ import TelegramPresentationData
import NotificationsPresentationData
import WidgetKit
import TelegramUIPreferences
+import WidgetItemsUtils
+
+import GeneratedSources
final class WidgetDataContext {
private var currentAccount: Account?
@@ -32,9 +35,45 @@ final class WidgetDataContext {
}
case disabled
- case peers(peers: [Peer], unread: [PeerId: Unread])
+ case peers(peers: [Peer], unread: [PeerId: Unread], messages: [PeerId: WidgetDataPeer.Message])
}
+ let updatedAdditionalPeerIds: Signal, NoError> = Signal { subscriber in
+ if #available(iOSApplicationExtension 14.0, iOS 14.0, *) {
+ #if arch(arm64) || arch(i386) || arch(x86_64)
+ WidgetCenter.shared.getCurrentConfigurations({ result in
+ var peerIds = Set()
+ if case let .success(infos) = result {
+ for info in infos {
+ if let configuration = info.configuration as? SelectFriendsIntent {
+ if let items = configuration.friends {
+ for item in items {
+ guard let identifier = item.identifier, let peerIdValue = Int64(identifier) else {
+ continue
+ }
+ peerIds.insert(PeerId(peerIdValue))
+ }
+ }
+ }
+ }
+ }
+
+ subscriber.putNext(peerIds)
+ subscriber.putCompletion()
+ })
+ #else
+ subscriber.putNext(Set())
+ subscriber.putCompletion()
+ #endif
+ } else {
+ subscriber.putNext(Set())
+ subscriber.putCompletion()
+ }
+
+ return EmptyDisposable
+ }
+ |> runOn(.mainQueue())
+
let preferencesKey: PostboxViewKey = .preferences(keys: Set([
ApplicationSpecificPreferencesKeys.widgetSettings
]))
@@ -69,13 +108,24 @@ final class WidgetDataContext {
case .disabled:
return .single(.disabled)
case let .peers(peers):
- return combineLatest(queue: .mainQueue(), peers.filter { !$0.isDeleted }.map { account.postbox.peerView(id: $0.id)}) |> mapToSignal { peerViews -> Signal in
- return account.postbox.unreadMessageCountsView(items: peerViews.map {
- .peer($0.peerId)
- })
- |> map { values -> CombinedRecentPeers in
+ return combineLatest(queue: .mainQueue(), peers.filter { !$0.isDeleted }.map { account.postbox.peerView(id: $0.id)})
+ |> mapToSignal { peerViews -> Signal in
+ let topMessagesKey: PostboxViewKey = .topChatMessage(peerIds: peerViews.map {
+ $0.peerId
+ })
+ return combineLatest(queue: .mainQueue(),
+ account.postbox.unreadMessageCountsView(items: peerViews.map {
+ .peer($0.peerId)
+ }),
+ account.postbox.combinedView(keys: [topMessagesKey])
+ )
+ |> map { values, combinedView -> CombinedRecentPeers in
var peers: [Peer] = []
var unread: [PeerId: CombinedRecentPeers.Unread] = [:]
+ var messages: [PeerId: WidgetDataPeer.Message] = [:]
+
+ let topMessages = combinedView.views[topMessagesKey] as! TopChatMessageView
+
for peerView in peerViews {
if let peer = peerViewMainPeer(peerView) {
var isMuted: Bool = false
@@ -93,21 +143,25 @@ final class WidgetDataContext {
unread[peerView.peerId] = CombinedRecentPeers.Unread(count: Int32(unreadCount), isMuted: isMuted)
}
+ if let message = topMessages.messages[peerView.peerId] {
+ messages[peerView.peerId] = WidgetDataPeer.Message(message: message)
+ }
+
peers.append(peer)
}
}
- return .peers(peers: peers, unread: unread)
+ return .peers(peers: peers, unread: unread, messages: messages)
}
}
}
}
- return recent
+ let processedRecent = recent
|> map { result -> WidgetData in
switch result {
case .disabled:
return WidgetData(accountId: account.id.int64, content: .disabled)
- case let .peers(peers, unread):
+ case let .peers(peers, unread, messages):
return WidgetData(accountId: account.id.int64, content: .peers(WidgetDataPeers(accountPeerId: account.peerId.toInt64(), peers: peers.compactMap { peer -> WidgetDataPeer? in
var name: String = ""
var lastName: String?
@@ -133,13 +187,110 @@ final class WidgetDataContext {
)
}
+ let message = messages[peer.id]
+
return WidgetDataPeer(id: peer.id.toInt64(), name: name, lastName: lastName, letters: peer.displayLetters, avatarPath: smallestImageRepresentation(peer.profileImageRepresentations).flatMap { representation in
return account.postbox.mediaBox.resourcePath(representation.resource)
- }, badge: badge)
+ }, badge: badge, message: message)
})))
}
}
|> distinctUntilChanged
+
+ let additionalPeerIds = Signal, NoError>.single(Set()) |> then(updatedAdditionalPeerIds)
+ let processedCustom: Signal = additionalPeerIds
+ |> distinctUntilChanged
+ |> mapToSignal { additionalPeerIds -> Signal in
+ return combineLatest(queue: .mainQueue(), additionalPeerIds.map { account.postbox.peerView(id: $0) })
+ |> mapToSignal { peerViews -> Signal in
+ let topMessagesKey: PostboxViewKey = .topChatMessage(peerIds: peerViews.map {
+ $0.peerId
+ })
+ return combineLatest(queue: .mainQueue(),
+ account.postbox.unreadMessageCountsView(items: peerViews.map {
+ .peer($0.peerId)
+ }),
+ account.postbox.combinedView(keys: [topMessagesKey])
+ )
+ |> map { values, combinedView -> CombinedRecentPeers in
+ var peers: [Peer] = []
+ var unread: [PeerId: CombinedRecentPeers.Unread] = [:]
+ var messages: [PeerId: WidgetDataPeer.Message] = [:]
+
+ let topMessages = combinedView.views[topMessagesKey] as! TopChatMessageView
+
+ for peerView in peerViews {
+ if let peer = peerViewMainPeer(peerView) {
+ var isMuted: Bool = false
+ if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
+ switch notificationSettings.muteState {
+ case .muted:
+ isMuted = true
+ default:
+ break
+ }
+ }
+
+ let unreadCount = values.count(for: .peer(peerView.peerId))
+ if let unreadCount = unreadCount, unreadCount > 0 {
+ unread[peerView.peerId] = CombinedRecentPeers.Unread(count: Int32(unreadCount), isMuted: isMuted)
+ }
+
+ if let message = topMessages.messages[peerView.peerId] {
+ messages[peerView.peerId] = WidgetDataPeer.Message(message: message)
+ }
+
+ peers.append(peer)
+ }
+ }
+ return .peers(peers: peers, unread: unread, messages: messages)
+ }
+ }
+ }
+ |> map { result -> WidgetData in
+ switch result {
+ case .disabled:
+ return WidgetData(accountId: account.id.int64, content: .disabled)
+ case let .peers(peers, unread, messages):
+ return WidgetData(accountId: account.id.int64, content: .peers(WidgetDataPeers(accountPeerId: account.peerId.toInt64(), peers: peers.compactMap { peer -> WidgetDataPeer? in
+ var name: String = ""
+ var lastName: String?
+
+ if let user = peer as? TelegramUser {
+ if let firstName = user.firstName {
+ name = firstName
+ lastName = user.lastName
+ } else if let lastName = user.lastName {
+ name = lastName
+ } else if let phone = user.phone, !phone.isEmpty {
+ name = phone
+ }
+ } else {
+ name = peer.debugDisplayTitle
+ }
+
+ var badge: WidgetDataPeer.Badge?
+ if let unreadValue = unread[peer.id], unreadValue.count > 0 {
+ badge = WidgetDataPeer.Badge(
+ count: Int(unreadValue.count),
+ isMuted: unreadValue.isMuted
+ )
+ }
+
+ let message = messages[peer.id]
+
+ return WidgetDataPeer(id: peer.id.toInt64(), name: name, lastName: lastName, letters: peer.displayLetters, avatarPath: smallestImageRepresentation(peer.profileImageRepresentations).flatMap { representation in
+ return account.postbox.mediaBox.resourcePath(representation.resource)
+ }, badge: badge, message: message)
+ })))
+ }
+ }
+ |> distinctUntilChanged
+
+ return combineLatest(processedRecent, processedCustom)
+ |> map { processedRecent, _ -> WidgetData in
+ return processedRecent
+ }
}).start(next: { widgetData in
let path = basePath + "/widget-data"
if let data = try? JSONEncoder().encode(widgetData) {
diff --git a/submodules/WidgetItems/BUILD b/submodules/WidgetItems/BUILD
index 0da6915f24..1a1cff6024 100644
--- a/submodules/WidgetItems/BUILD
+++ b/submodules/WidgetItems/BUILD
@@ -10,3 +10,14 @@ swift_library(
"//visibility:public",
],
)
+
+swift_library(
+ name = "WidgetItems_iOS14",
+ module_name = "WidgetItems_iOS14",
+ srcs = glob([
+ "Sources/**/*.swift",
+ ]),
+ visibility = [
+ "//visibility:public",
+ ],
+)
diff --git a/submodules/WidgetItems/Sources/WidgetItems.swift b/submodules/WidgetItems/Sources/WidgetItems.swift
index 703299b475..7b0bb61830 100644
--- a/submodules/WidgetItems/Sources/WidgetItems.swift
+++ b/submodules/WidgetItems/Sources/WidgetItems.swift
@@ -15,20 +15,223 @@ public struct WidgetDataPeer: Codable, Equatable {
}
}
+ public struct Message: Codable, Equatable {
+ public enum Content: Codable, Equatable {
+ public enum DecodingError: Error {
+ case generic
+ }
+
+ public struct Image: Codable, Equatable {
+ public init() {
+ }
+ }
+
+ public struct Video: Codable, Equatable {
+ public init() {
+ }
+ }
+
+ public struct File: Codable, Equatable {
+ public var name: String
+
+ public init(name: String) {
+ self.name = name
+ }
+ }
+
+ public struct Gif: Codable, Equatable {
+ public init() {
+ }
+ }
+
+ public struct Music: Codable, Equatable {
+ public var artist: String
+ public var title: String
+ public var duration: Int32
+
+ public init(artist: String, title: String, duration: Int32) {
+ self.artist = artist
+ self.title = title
+ self.duration = duration
+ }
+ }
+
+ public struct VoiceMessage: Codable, Equatable {
+ public var duration: Int32
+
+ public init(duration: Int32) {
+ self.duration = duration
+ }
+ }
+
+ public struct VideoMessage: Codable, Equatable {
+ public var duration: Int32
+
+ public init(duration: Int32) {
+ self.duration = duration
+ }
+ }
+
+ public struct Sticker: Codable, Equatable {
+ public var altText: String
+
+ public init(altText: String) {
+ self.altText = altText
+ }
+ }
+
+ public struct Call: Codable, Equatable {
+ public var isVideo: Bool
+
+ public init(isVideo: Bool) {
+ self.isVideo = isVideo
+ }
+ }
+
+ public struct MapLocation: Codable, Equatable {
+ public init() {
+ }
+ }
+
+ public struct Game: Codable, Equatable {
+ public var title: String
+
+ public init(title: String) {
+ self.title = title
+ }
+ }
+
+ public struct Poll: Codable, Equatable {
+ public var title: String
+
+ public init(title: String) {
+ self.title = title
+ }
+ }
+
+ enum CodingKeys: String, CodingKey {
+ case text
+ case image
+ case video
+ case file
+ case gif
+ case music
+ case voiceMessage
+ case videoMessage
+ case sticker
+ case call
+ case mapLocation
+ case game
+ case poll
+ }
+
+ case text
+ case image(Image)
+ case video(Video)
+ case file(File)
+ case gif(Gif)
+ case music(Music)
+ case voiceMessage(VoiceMessage)
+ case videoMessage(VideoMessage)
+ case sticker(Sticker)
+ case call(Call)
+ case mapLocation(MapLocation)
+ case game(Game)
+ case poll(Poll)
+
+ public init(from decoder: Decoder) throws {
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+ if let _ = try? container.decode(String.self, forKey: .text) {
+ self = .text
+ } else if let image = try? container.decode(Image.self, forKey: .image) {
+ self = .image(image)
+ } else if let video = try? container.decode(Video.self, forKey: .video) {
+ self = .video(video)
+ } else if let gif = try? container.decode(Gif.self, forKey: .gif) {
+ self = .gif(gif)
+ } else if let file = try? container.decode(File.self, forKey: .file) {
+ self = .file(file)
+ } else if let music = try? container.decode(Music.self, forKey: .voiceMessage) {
+ self = .music(music)
+ } else if let voiceMessage = try? container.decode(VoiceMessage.self, forKey: .voiceMessage) {
+ self = .voiceMessage(voiceMessage)
+ } else if let videoMessage = try? container.decode(VideoMessage.self, forKey: .videoMessage) {
+ self = .videoMessage(videoMessage)
+ } else if let sticker = try? container.decode(Sticker.self, forKey: .sticker) {
+ self = .sticker(sticker)
+ } else if let call = try? container.decode(Call.self, forKey: .call) {
+ self = .call(call)
+ } else if let mapLocation = try? container.decode(MapLocation.self, forKey: .mapLocation) {
+ self = .mapLocation(mapLocation)
+ } else if let game = try? container.decode(Game.self, forKey: .game) {
+ self = .game(game)
+ } else if let poll = try? container.decode(Poll.self, forKey: .poll) {
+ self = .poll(poll)
+ } else {
+ throw DecodingError.generic
+ }
+ }
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ switch self {
+ case .text:
+ try container.encode("", forKey: .text)
+ case let .image(image):
+ try container.encode(image, forKey: .image)
+ case let .video(video):
+ try container.encode(video, forKey: .video)
+ case let .file(file):
+ try container.encode(file, forKey: .file)
+ case let .gif(gif):
+ try container.encode(gif, forKey: .gif)
+ case let .music(music):
+ try container.encode(music, forKey: .music)
+ case let .voiceMessage(voiceMessage):
+ try container.encode(voiceMessage, forKey: .voiceMessage)
+ case let .videoMessage(videoMessage):
+ try container.encode(videoMessage, forKey: .videoMessage)
+ case let .sticker(sticker):
+ try container.encode(sticker, forKey: .sticker)
+ case let .call(call):
+ try container.encode(call, forKey: .call)
+ case let .mapLocation(mapLocation):
+ try container.encode(mapLocation, forKey: .mapLocation)
+ case let .game(game):
+ try container.encode(game, forKey: .game)
+ case let .poll(poll):
+ try container.encode(poll, forKey: .poll)
+ }
+ }
+ }
+
+ public var text: String
+ public var content: Content
+ public var timestamp: Int32
+
+ public init(text: String, content: Content, timestamp: Int32) {
+ self.text = text
+ self.content = content
+ self.timestamp = timestamp
+ }
+ }
+
public var id: Int64
public var name: String
public var lastName: String?
public var letters: [String]
public var avatarPath: String?
public var badge: Badge?
+ public var message: Message?
- public init(id: Int64, name: String, lastName: String?, letters: [String], avatarPath: String?, badge: Badge?) {
+ public init(id: Int64, name: String, lastName: String?, letters: [String], avatarPath: String?, badge: Badge?, message: Message?) {
self.id = id
self.name = name
self.lastName = lastName
self.letters = letters
self.avatarPath = avatarPath
self.badge = badge
+ self.message = message
}
}
diff --git a/submodules/WidgetItemsUtils/BUILD b/submodules/WidgetItemsUtils/BUILD
new file mode 100644
index 0000000000..a17c9cfcbc
--- /dev/null
+++ b/submodules/WidgetItemsUtils/BUILD
@@ -0,0 +1,19 @@
+load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
+
+swift_library(
+ name = "WidgetItemsUtils",
+ module_name = "WidgetItemsUtils",
+ srcs = glob([
+ "Sources/**/*.swift",
+ ]),
+ deps = [
+ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
+ "//submodules/Postbox:Postbox",
+ "//submodules/SyncCore:SyncCore",
+ "//submodules/TelegramCore:TelegramCore",
+ "//submodules/WidgetItems:WidgetItems",
+ ],
+ visibility = [
+ "//visibility:public",
+ ],
+)
diff --git a/submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift b/submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift
new file mode 100644
index 0000000000..75c64372c0
--- /dev/null
+++ b/submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift
@@ -0,0 +1,59 @@
+import Foundation
+
+import Postbox
+import SyncCore
+import TelegramCore
+import WidgetItems
+
+public extension WidgetDataPeer.Message {
+ init(message: Message) {
+ var content: WidgetDataPeer.Message.Content = .text
+ for media in message.media {
+ switch media {
+ case _ as TelegramMediaImage:
+ content = .image(WidgetDataPeer.Message.Content.Image())
+ case let file as TelegramMediaFile:
+ var fileName = "file"
+ for attribute in file.attributes {
+ if case let .FileName(value) = attribute {
+ fileName = value
+ break
+ }
+ }
+ content = .file(WidgetDataPeer.Message.Content.File(name: fileName))
+ for attribute in file.attributes {
+ switch attribute {
+ case let .Sticker(altText, _, _):
+ content = .sticker(WidgetDataPeer.Message.Content.Sticker(altText: altText))
+ case let .Video(duration, _, flags):
+ if flags.contains(.instantRoundVideo) {
+ content = .videoMessage(WidgetDataPeer.Message.Content.VideoMessage(duration: Int32(duration)))
+ } else {
+ content = .video(WidgetDataPeer.Message.Content.Video())
+ }
+ case let .Audio(isVoice, duration, title, performer, _):
+ if isVoice {
+ content = .voiceMessage(WidgetDataPeer.Message.Content.VoiceMessage(duration: Int32(duration)))
+ } else {
+ content = .music(WidgetDataPeer.Message.Content.Music(artist: performer ?? "", title: title ?? "", duration: Int32(duration)))
+ }
+ default:
+ break
+ }
+ }
+ case let action as TelegramMediaAction:
+ switch action.action {
+ case let .phoneCall(_, _, _, isVideo):
+ content = .call(WidgetDataPeer.Message.Content.Call(isVideo: isVideo))
+ default:
+ break
+ }
+ case _ as TelegramMediaMap:
+ content = .mapLocation(WidgetDataPeer.Message.Content.MapLocation())
+ default:
+ break
+ }
+ }
+ self.init(text: message.text, content: content, timestamp: message.timestamp)
+ }
+}
diff --git a/third-party/libvpx/BUILD b/third-party/libvpx/BUILD
index b1c435b166..8ee1bef895 100644
--- a/third-party/libvpx/BUILD
+++ b/third-party/libvpx/BUILD
@@ -55,6 +55,12 @@ genrule(
rm -rf "$$BUILD_DIR"
mkdir -p "$$BUILD_DIR"
+ YASM_DIR="$$BUILD_DIR/yasm"
+ rm -rf "$$YASM_DIR"
+ mkdir -p "$$YASM_DIR"
+ tar -xf "$(location //third-party/yasm:yasm.tar)" -C "$$YASM_DIR"
+ ABS_YASM_DIR="$$(pwd)/$$(dirname $$YASM_DIR)/$$(basename $$YASM_DIR)"
+
cp $(location :build-libvpx-bazel.sh) "$$BUILD_DIR/"
cp $(location :0001-Add-support-for-arm64-iphonesimulator-gcc.patch) "$$BUILD_DIR/"
@@ -81,6 +87,9 @@ genrule(
outs = ["Public/vpx/" + x for x in headers] +
["Public/vpx/vpx_config.h"] +
["Public/vpx/lib{}.a".format(x) for x in libs],
+ tools = [
+ "//third-party/yasm:yasm.tar",
+ ],
visibility = [
"//visibility:public",
]
diff --git a/third-party/mozjpeg/mozjpeg/src/jconfig.h b/third-party/mozjpeg/mozjpeg/src/jconfig.h
new file mode 100644
index 0000000000..beccc163e6
--- /dev/null
+++ b/third-party/mozjpeg/mozjpeg/src/jconfig.h
@@ -0,0 +1,73 @@
+/* Version ID for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
+ */
+#define JPEG_LIB_VERSION 80
+
+/* libjpeg-turbo version */
+#define LIBJPEG_TURBO_VERSION 4.0.0
+
+/* libjpeg-turbo version in integer form */
+#define LIBJPEG_TURBO_VERSION_NUMBER 4000000
+
+/* Support arithmetic encoding */
+#define C_ARITH_CODING_SUPPORTED 1
+
+/* Support arithmetic decoding */
+#define D_ARITH_CODING_SUPPORTED 1
+
+/* Support in-memory source/destination managers */
+/* #undef MEM_SRCDST_SUPPORTED */
+
+/* Use accelerated SIMD routines. */
+#define WITH_SIMD 1
+
+/*
+ * Define BITS_IN_JSAMPLE as either
+ * 8 for 8-bit sample values (the usual setting)
+ * 12 for 12-bit sample values
+ * Only 8 and 12 are legal data precisions for lossy JPEG according to the
+ * JPEG standard, and the IJG code does not support anything else!
+ * We do not support run-time selection of data precision, sorry.
+ */
+
+#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you need to include to get size_t. */
+#define NEED_SYS_TYPES_H 1
+
+/* Define if you have BSD-like bzero and bcopy in rather than
+ memset/memcpy in . */
+/* #undef NEED_BSD_STRINGS */
+
+/* Define to 1 if the system has the type `unsigned char'. */
+#define HAVE_UNSIGNED_CHAR 1
+
+/* Define to 1 if the system has the type `unsigned short'. */
+#define HAVE_UNSIGNED_SHORT 1
+
+/* Compiler does not support pointers to undefined structures. */
+/* #undef INCOMPLETE_TYPES_BROKEN */
+
+/* Define if your (broken) compiler shifts signed values as if they were
+ unsigned. */
+/* #undef RIGHT_SHIFT_IS_UNSIGNED */
+
+/* Define to 1 if type `char' is unsigned and you are not using gcc. */
+#ifndef __CHAR_UNSIGNED__
+/* #undef __CHAR_UNSIGNED__ */
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `unsigned int' if does not define. */
+/* #undef size_t */
diff --git a/third-party/mozjpeg/mozjpeg/src/jconfigint.h b/third-party/mozjpeg/mozjpeg/src/jconfigint.h
new file mode 100644
index 0000000000..4d0059156a
--- /dev/null
+++ b/third-party/mozjpeg/mozjpeg/src/jconfigint.h
@@ -0,0 +1,31 @@
+/* libjpeg-turbo build number */
+#define BUILD "20201129"
+
+/* Compiler's inline keyword */
+#undef inline
+
+/* How to obtain function inlining. */
+#define INLINE __inline__ __attribute__((always_inline))
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "mozjpeg"
+
+/* Version number of package */
+#define VERSION "4.0.0"
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* Define if your compiler has __builtin_ctzl() and sizeof(unsigned long) == sizeof(size_t). */
+#define HAVE_BUILTIN_CTZL
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_INTRIN_H */
+
+#if defined(_MSC_VER) && defined(HAVE_INTRIN_H)
+#if (SIZEOF_SIZE_T == 8)
+#define HAVE_BITSCANFORWARD64
+#elif (SIZEOF_SIZE_T == 4)
+#define HAVE_BITSCANFORWARD
+#endif
+#endif
diff --git a/versions.json b/versions.json
new file mode 100644
index 0000000000..a99715704d
--- /dev/null
+++ b/versions.json
@@ -0,0 +1,5 @@
+{
+ "app": "7.3.1",
+ "bazel": "3.7.0",
+ "xcode": "12.3"
+}