mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
d5a25602ce
159
Makefile
159
Makefile
@ -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
|
100
README.md
100
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
|
||||
```
|
||||
|
195
Telegram/BUILD
195
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 =
|
||||
"""
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<string>{buildNumber}</string>
|
||||
"""
|
||||
)
|
||||
|
||||
plist_fragment(
|
||||
name = "UrlTypesInfoPlist",
|
||||
extension = "plist",
|
||||
template =
|
||||
"""
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
@ -210,16 +230,6 @@ plist_fragment(
|
||||
<string>telegram</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>{telegram_bundle_id}.ton</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>ton</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
@ -232,8 +242,6 @@ plist_fragment(
|
||||
</dict>
|
||||
</array>
|
||||
""".format(
|
||||
telegram_version = telegram_version,
|
||||
telegram_build_number = telegram_build_number,
|
||||
telegram_bundle_id = telegram_bundle_id,
|
||||
)
|
||||
)
|
||||
@ -371,13 +379,8 @@ plist_fragment(
|
||||
template =
|
||||
"""
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
""".format(
|
||||
telegram_version = telegram_version,
|
||||
telegram_build_number = telegram_build_number,
|
||||
)
|
||||
<string>{telegramVersion}</string>
|
||||
"""
|
||||
)
|
||||
|
||||
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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.MtProtoKit</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>MtProtoKit</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.SwiftSignalKit</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>SwiftSignalKit</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.Postbox</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Postbox</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.TelegramApi</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>TelegramApi</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.SyncCore</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>SyncCore</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.TelegramCore</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>TelegramCore</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.AsyncDisplayKit</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>AsyncDisplayKit</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.Display</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Display</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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(
|
||||
"""
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>{telegram_bundle_id}.TelegramUI</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>{telegram_build_number}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>TelegramUI</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>{telegram_version}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
""".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",
|
||||
|
@ -9,6 +9,7 @@ import Contacts
|
||||
import OpenSSLEncryptionProvider
|
||||
import AppLockState
|
||||
import UIKit
|
||||
import GeneratedSources
|
||||
|
||||
private var accountCache: Account?
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
148
build-system/Make/BuildEnvironment.py
Normal file
148
build-system/Make/BuildEnvironment.py
Normal file
@ -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)
|
484
build-system/Make/Make.py
Normal file
484
build-system/Make/Make.py
Normal file
@ -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
|
155
build-system/Make/ProjectGeneration.py
Normal file
155
build-system/Make/ProjectGeneration.py
Normal file
@ -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('''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>defaultBazelURL</key>
|
||||
<string>{}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
'''.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])
|
@ -1 +0,0 @@
|
||||
3.7.0
|
0
build-system/example-configuration/WORKSPACE
Normal file
0
build-system/example-configuration/WORKSPACE
Normal file
11
build-system/example-configuration/provisioning/BUILD
Normal file
11
build-system/example-configuration/provisioning/BUILD
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
exports_files([
|
||||
"Intents.mobileprovision",
|
||||
"NotificationContent.mobileprovision",
|
||||
"NotificationService.mobileprovision",
|
||||
"Share.mobileprovision",
|
||||
"Telegram.mobileprovision",
|
||||
"WatchApp.mobileprovision",
|
||||
"WatchExtension.mobileprovision",
|
||||
"Widget.mobileprovision",
|
||||
])
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10
build-system/example-configuration/variables.bzl
Normal file
10
build-system/example-configuration/variables.bzl
Normal file
@ -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"
|
7
build-system/example-generate-configuration
Executable file
7
build-system/example-generate-configuration
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -d "$1" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp -R build-system/example-configuration/* "$1/"
|
@ -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"
|
@ -1 +1 @@
|
||||
Subproject commit b965114f31a464185318c71ef3d0c1538d0c52de
|
||||
Subproject commit 734518e85d769de070b5a78b234080d9580ae625
|
@ -1 +0,0 @@
|
||||
12.2
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -1,5 +1,5 @@
|
||||
load(
|
||||
"//build-input/data:variables.bzl",
|
||||
"@build_configuration//:variables.bzl",
|
||||
"telegram_api_id",
|
||||
"telegram_api_hash",
|
||||
"telegram_app_center_id",
|
||||
|
44
submodules/Postbox/Sources/TopChatMessageView.swift
Normal file
44
submodules/Postbox/Sources/TopChatMessageView.swift
Normal file
@ -0,0 +1,44 @@
|
||||
import Foundation
|
||||
|
||||
final class MutableTopChatMessageView: MutablePostboxView {
|
||||
private let peerIds: Set<PeerId>
|
||||
fileprivate var messages: [PeerId: Message] = [:]
|
||||
|
||||
init(postbox: Postbox, peerIds: Set<PeerId>) {
|
||||
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
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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<ExportedInvitations?, NoError> 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<Api.messages.ExportedChatInvites?, NoError> in
|
||||
return .single(nil)
|
||||
|
@ -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",
|
||||
|
@ -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<Set<PeerId>, 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<PeerId>()
|
||||
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<CombinedRecentPeers, NoError> 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<CombinedRecentPeers, NoError> 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<Set<PeerId>, NoError>.single(Set()) |> then(updatedAdditionalPeerIds)
|
||||
let processedCustom: Signal<WidgetData, NoError> = additionalPeerIds
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { additionalPeerIds -> Signal<CombinedRecentPeers, NoError> in
|
||||
return combineLatest(queue: .mainQueue(), additionalPeerIds.map { account.postbox.peerView(id: $0) })
|
||||
|> mapToSignal { peerViews -> Signal<CombinedRecentPeers, NoError> 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) {
|
||||
|
@ -10,3 +10,14 @@ swift_library(
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
swift_library(
|
||||
name = "WidgetItems_iOS14",
|
||||
module_name = "WidgetItems_iOS14",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
19
submodules/WidgetItemsUtils/BUILD
Normal file
19
submodules/WidgetItemsUtils/BUILD
Normal file
@ -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",
|
||||
],
|
||||
)
|
59
submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift
Normal file
59
submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift
Normal file
@ -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)
|
||||
}
|
||||
}
|
9
third-party/libvpx/BUILD
vendored
9
third-party/libvpx/BUILD
vendored
@ -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",
|
||||
]
|
||||
|
73
third-party/mozjpeg/mozjpeg/src/jconfig.h
vendored
Normal file
73
third-party/mozjpeg/mozjpeg/src/jconfig.h
vendored
Normal file
@ -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 <locale.h> header file. */
|
||||
#define HAVE_LOCALE_H 1
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define if you need to include <sys/types.h> to get size_t. */
|
||||
#define NEED_SYS_TYPES_H 1
|
||||
|
||||
/* Define if you have BSD-like bzero and bcopy in <strings.h> rather than
|
||||
memset/memcpy in <string.h>. */
|
||||
/* #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 <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
31
third-party/mozjpeg/mozjpeg/src/jconfigint.h
vendored
Normal file
31
third-party/mozjpeg/mozjpeg/src/jconfigint.h
vendored
Normal file
@ -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 <intrin.h> 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
|
5
versions.json
Normal file
5
versions.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"app": "7.3.1",
|
||||
"bazel": "3.7.0",
|
||||
"xcode": "12.3"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user