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
d370927b9e
@ -86,7 +86,7 @@ deploy_beta_testflight:
|
|||||||
- ios_beta
|
- ios_beta
|
||||||
stage: deploy
|
stage: deploy
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta1
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
script:
|
script:
|
||||||
|
@ -522,6 +522,7 @@
|
|||||||
"Notification.Kicked" = "%@ removed %@";
|
"Notification.Kicked" = "%@ removed %@";
|
||||||
"Notification.CreatedChat" = "%@ created a group";
|
"Notification.CreatedChat" = "%@ created a group";
|
||||||
"Notification.CreatedChannel" = "Channel created";
|
"Notification.CreatedChannel" = "Channel created";
|
||||||
|
"Notification.CreatedGroup" = "Group created";
|
||||||
"Notification.CreatedChatWithTitle" = "%@ created the group \"%@\" ";
|
"Notification.CreatedChatWithTitle" = "%@ created the group \"%@\" ";
|
||||||
"Notification.Joined" = "%@ joined Telegram";
|
"Notification.Joined" = "%@ joined Telegram";
|
||||||
"Notification.ChangedGroupName" = "%@ changed group name to \"%@\" ";
|
"Notification.ChangedGroupName" = "%@ changed group name to \"%@\" ";
|
||||||
@ -5915,7 +5916,7 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"ReportPeer.ReasonFake" = "Fake Account";
|
"ReportPeer.ReasonFake" = "Fake Account";
|
||||||
|
|
||||||
"ChatList.HeaderImportIntoAnExistingGroup" = "OR IMPORT INTO AN EXISTING GROUP";
|
"ChatList.HeaderImportIntoAnExistingGroup" = "SELECT A CHAT TO IMPORT MESSAGES TO";
|
||||||
|
|
||||||
"Group.ErrorAdminsTooMuch" = "Sorry, too many administrators in this group.";
|
"Group.ErrorAdminsTooMuch" = "Sorry, too many administrators in this group.";
|
||||||
"Channel.ErrorAdminsTooMuch" = "Sorry, too many administrators in this channel.";
|
"Channel.ErrorAdminsTooMuch" = "Sorry, too many administrators in this channel.";
|
||||||
@ -5947,7 +5948,7 @@ Sorry for the inconvenience.";
|
|||||||
"ChatImport.SelectionConfirmationUserWithTitle" = "Import messages from **%1$@** into the chat with **%2$@**?";
|
"ChatImport.SelectionConfirmationUserWithTitle" = "Import messages from **%1$@** into the chat with **%2$@**?";
|
||||||
"ChatImport.SelectionConfirmationUserWithoutTitle" = "Import messages into the chat with **%@?**";
|
"ChatImport.SelectionConfirmationUserWithoutTitle" = "Import messages into the chat with **%@?**";
|
||||||
|
|
||||||
"PeerSelection.CreateNewGroup" = "Create a New Group";
|
"PeerSelection.ImportIntoNewGroup" = "Import to a New Group";
|
||||||
"Message.ImportedDateFormat" = "%1$@, %2$@ Imported %3$@";
|
"Message.ImportedDateFormat" = "%1$@, %2$@ Imported %3$@";
|
||||||
|
|
||||||
"ChatImportActivity.Title" = "Importing Chat";
|
"ChatImportActivity.Title" = "Importing Chat";
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
telegram_bundle_id = "ph.telegra.Telegraph"
|
telegram_bundle_id = "ph.telegra.Telegraph"
|
||||||
telegram_api_id = "8"
|
telegram_api_id = "8"
|
||||||
telegram_api_hash = "7245de8e747a0d6fbe11f7cc14fcc0bb"
|
telegram_api_hash = "7245de8e747a0d6fbe11f7cc14fcc0bb"
|
||||||
@ -5,6 +6,6 @@ telegram_team_id = "C67CF9S4VU"
|
|||||||
telegram_app_center_id = "0"
|
telegram_app_center_id = "0"
|
||||||
telegram_is_internal_build = "false"
|
telegram_is_internal_build = "false"
|
||||||
telegram_is_appstore_build = "true"
|
telegram_is_appstore_build = "true"
|
||||||
telegram_appstore_id = "0"
|
telegram_appstore_id = "686449807"
|
||||||
telegram_app_specific_url_scheme = "tg"
|
telegram_app_specific_url_scheme = "tg"
|
||||||
telegram_aps_environment = "production"
|
telegram_aps_environment = "production"
|
||||||
|
@ -58,13 +58,11 @@ cp "$BAZEL" "tools/bazel"
|
|||||||
BUILD_CONFIGURATION="$1"
|
BUILD_CONFIGURATION="$1"
|
||||||
|
|
||||||
if [ "$BUILD_CONFIGURATION" == "hockeyapp" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental-2" ]; then
|
if [ "$BUILD_CONFIGURATION" == "hockeyapp" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental" ] || [ "$BUILD_CONFIGURATION" == "appcenter-experimental-2" ]; then
|
||||||
CODESIGNING_SUBPATH="transient-data/telegram-codesigning/codesigning"
|
CODESIGNING_SUBPATH="$BUILDBOX_DIR/transient-data/telegram-codesigning/codesigning"
|
||||||
CODESIGNING_TEAMS_SUBPATH="transient-data/teams"
|
|
||||||
elif [ "$BUILD_CONFIGURATION" == "appstore" ]; then
|
elif [ "$BUILD_CONFIGURATION" == "appstore" ]; then
|
||||||
CODESIGNING_SUBPATH="transient-data/codesigning"
|
CODESIGNING_SUBPATH="$BUILDBOX_DIR/transient-data/telegram-codesigning/codesigning"
|
||||||
CODESIGNING_TEAMS_SUBPATH="transient-data/teams"
|
|
||||||
elif [ "$BUILD_CONFIGURATION" == "verify" ]; then
|
elif [ "$BUILD_CONFIGURATION" == "verify" ]; then
|
||||||
CODESIGNING_SUBPATH="fake-codesigning"
|
CODESIGNING_SUBPATH="build-system/fake-codesigning"
|
||||||
else
|
else
|
||||||
echo "Unknown configuration $1"
|
echo "Unknown configuration $1"
|
||||||
exit 1
|
exit 1
|
||||||
@ -99,34 +97,29 @@ if [ "$BUILD_CONFIGURATION" == "hockeyapp" ] || [ "$BUILD_CONFIGURATION" == "app
|
|||||||
mkdir -p "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
|
mkdir -p "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
|
||||||
|
|
||||||
case "$BUILD_CONFIGURATION" in
|
case "$BUILD_CONFIGURATION" in
|
||||||
"hockeyapp")
|
"hockeyapp"|"appcenter-experimental"|"appcenter-experimental-2")
|
||||||
generate-configuration.sh internal release "$BASE_DIR/$BUILDBOX_DIR/transient-data/telegram-codesigning" "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
|
generate-configuration.sh internal release "$BASE_DIR/$BUILDBOX_DIR/transient-data/telegram-codesigning" "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
"appstore")
|
||||||
|
generate-configuration.sh appstore release "$BASE_DIR/$BUILDBOX_DIR/transient-data/telegram-codesigning" "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
|
||||||
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Unknown build configuration $BUILD_CONFIGURATION"
|
echo "Unknown build configuration $BUILD_CONFIGURATION"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
elif [ "$BUILD_CONFIGURATION" == "verify" ]; then
|
||||||
|
mkdir -p "$BASE_DIR/$BUILDBOX_DIR/transient-data/telegram-codesigning"
|
||||||
|
mkdir -p "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration"
|
||||||
|
|
||||||
if [ "$BUILD_CONFIGURATION" == "appstore" ]; then
|
cp -R build-system/fake-codesigning/* "$BASE_DIR/$BUILDBOX_DIR/transient-data/telegram-codesigning/"
|
||||||
if [ -z "$TELEGRAM_BUILD_APPSTORE_PASSWORD" ]; then
|
cp -R build-system/example-configuration/* "$BASE_DIR/$BUILDBOX_DIR/transient-data/build-configuration/"
|
||||||
echo "TELEGRAM_BUILD_APPSTORE_PASSWORD is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$TELEGRAM_BUILD_APPSTORE_TEAM_NAME" ]; then
|
|
||||||
echo "TELEGRAM_BUILD_APPSTORE_TEAM_NAME is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$TELEGRAM_BUILD_APPSTORE_USERNAME" ]; then
|
|
||||||
echo "TELEGRAM_BUILD_APPSTORE_USERNAME is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "$BUILDBOX_DIR/$CODESIGNING_SUBPATH" ]; then
|
if [ ! -d "$CODESIGNING_SUBPATH" ]; then
|
||||||
echo "$BUILDBOX_DIR/$CODESIGNING_SUBPATH does not exist"
|
echo "$CODESIGNING_SUBPATH does not exist"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -182,18 +175,12 @@ elif [ "$BUILD_MACHINE" == "macOS" ]; then
|
|||||||
echo "VM_IP=$VM_IP"
|
echo "VM_IP=$VM_IP"
|
||||||
fi
|
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 "$CODESIGNING_SUBPATH" telegram@"$VM_IP":codesigning_data
|
||||||
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 "$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
|
|
||||||
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":
|
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
|
ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null telegram@"$VM_IP" -o ServerAliveInterval=60 -t "export BUILD_NUMBER=\"$BUILD_NUMBER\"; export BAZEL_HTTP_CACHE_URL=\"$BAZEL_HTTP_CACHE_URL\"; $GUEST_SHELL -l guest-build-telegram.sh $BUILD_CONFIGURATION" || true
|
||||||
|
|
||||||
OUTPUT_PATH="build/artifacts"
|
OUTPUT_PATH="build/artifacts"
|
||||||
rm -rf "$OUTPUT_PATH"
|
rm -rf "$OUTPUT_PATH"
|
||||||
|
@ -7,31 +7,14 @@ if [ -z "BUILD_NUMBER" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "COMMIT_ID" ]; then
|
|
||||||
echo "COMMIT_ID is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" == "hockeyapp" ] || [ "$1" == "appcenter-experimental" ] || [ "$1" == "appcenter-experimental-2" ] || [ "$1" == "testinghockeyapp" ]; then
|
if [ "$1" == "hockeyapp" ] || [ "$1" == "appcenter-experimental" ] || [ "$1" == "appcenter-experimental-2" ] || [ "$1" == "testinghockeyapp" ]; then
|
||||||
CERTS_PATH="$HOME/codesigning_data/certs/enterprise"
|
CERTS_PATH="$HOME/codesigning_data/certs/enterprise"
|
||||||
#PROFILES_PATH="$HOME/codesigning_data/profiles"
|
|
||||||
elif [ "$1" == "testinghockeyapp-local" ]; then
|
elif [ "$1" == "testinghockeyapp-local" ]; then
|
||||||
CERTS_PATH="$HOME/codesigning_data/certs"
|
CERTS_PATH="$HOME/codesigning_data/certs/enterprise"
|
||||||
PROFILES_PATH="$HOME/codesigning_data/profiles"
|
|
||||||
elif [ "$1" == "appstore" ]; then
|
elif [ "$1" == "appstore" ]; then
|
||||||
if [ -z "$TELEGRAM_BUILD_APPSTORE_PASSWORD" ]; then
|
CERTS_PATH="$HOME/codesigning_data/certs/distribution"
|
||||||
echo "TELEGRAM_BUILD_APPSTORE_PASSWORD is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$TELEGRAM_BUILD_APPSTORE_TEAM_NAME" ]; then
|
|
||||||
echo "TELEGRAM_BUILD_APPSTORE_TEAM_NAME is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
CERTS_PATH="$HOME/codesigning_data/certs"
|
|
||||||
PROFILES_PATH="$HOME/codesigning_data/profiles"
|
|
||||||
elif [ "$1" == "verify" ]; then
|
elif [ "$1" == "verify" ]; then
|
||||||
CERTS_PATH="build-system/fake-codesigning/certs/distribution"
|
CERTS_PATH="$HOME/codesigning_data/certs/distribution"
|
||||||
PROFILES_PATH="build-system/fake-codesigning/profiles"
|
|
||||||
else
|
else
|
||||||
echo "Unknown configuration $1"
|
echo "Unknown configuration $1"
|
||||||
exit 1
|
exit 1
|
||||||
@ -95,47 +78,24 @@ done
|
|||||||
|
|
||||||
security set-key-partition-list -S apple-tool:,apple: -k "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
|
security set-key-partition-list -S apple-tool:,apple: -k "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
if [ "$1" == "hockeyapp" ] || [ "$1" == "appcenter-experimental" ] || [ "$1" == "appcenter-experimental-2" ]; then
|
if [ "$1" == "hockeyapp" ] || [ "$1" == "appcenter-experimental" ] || [ "$1" == "appcenter-experimental-2" ]; then
|
||||||
#BUILD_ENV_SCRIPT="../telegram-ios-shared/buildbox/bin/internal.sh"
|
APP_CONFIGURATION="release_arm64"
|
||||||
#APP_TARGET="bazel_app_arm64"
|
|
||||||
echo "" >> /dev/null
|
|
||||||
elif [ "$1" == "appstore" ]; then
|
elif [ "$1" == "appstore" ]; then
|
||||||
BUILD_ENV_SCRIPT="../telegram-ios-shared/buildbox/bin/appstore.sh"
|
APP_CONFIGURATION="release_universal"
|
||||||
APP_TARGET="bazel_app"
|
|
||||||
elif [ "$1" == "verify" ]; then
|
elif [ "$1" == "verify" ]; then
|
||||||
BUILD_ENV_SCRIPT="build-system/verify.sh"
|
APP_CONFIGURATION="release_universal"
|
||||||
APP_TARGET="bazel_app"
|
|
||||||
export CODESIGNING_DATA_PATH="build-system/fake-codesigning"
|
|
||||||
export CODESIGNING_CERTS_VARIANT="distribution"
|
|
||||||
export CODESIGNING_PROFILES_VARIANT="appstore"
|
|
||||||
else
|
else
|
||||||
echo "Unsupported configuration $1"
|
echo "Unsupported configuration $1"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "appcenter-experimental" ]; then
|
|
||||||
export APP_CENTER_ID="$APP_CENTER_EXPERIMENTAL_ID"
|
|
||||||
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"
|
|
||||||
|
|
||||||
python3 build-system/Make/Make.py \
|
python3 build-system/Make/Make.py \
|
||||||
--bazel="$(pwd)/tools/bazel" \
|
--bazel="$(pwd)/tools/bazel" \
|
||||||
--cacheHost="$BAZEL_HTTP_CACHE_URL" \
|
--cacheHost="$BAZEL_HTTP_CACHE_URL" \
|
||||||
build \
|
build \
|
||||||
--configurationPath="$HOME/telegram-configuration" \
|
--configurationPath="$HOME/telegram-configuration" \
|
||||||
--buildNumber="$BUILD_NUMBER" \
|
--buildNumber="$BUILD_NUMBER" \
|
||||||
--configuration=release_arm64
|
--configuration="$APP_CONFIGURATION"
|
||||||
|
|
||||||
OUTPUT_PATH="build/artifacts"
|
OUTPUT_PATH="build/artifacts"
|
||||||
rm -rf "$OUTPUT_PATH"
|
rm -rf "$OUTPUT_PATH"
|
||||||
|
@ -24,8 +24,6 @@ fi
|
|||||||
|
|
||||||
OUTPUT_PATH="build/artifacts"
|
OUTPUT_PATH="build/artifacts"
|
||||||
|
|
||||||
BAZEL_HTTP_CACHE_URL="$BAZEL_HTTP_CACHE_URL" sh buildbox/build-telegram.sh verify
|
|
||||||
|
|
||||||
if [ "$CONFIGURATION" == "appstore" ]; then
|
if [ "$CONFIGURATION" == "appstore" ]; then
|
||||||
if [ -z "$IPA_PATH" ]; then
|
if [ -z "$IPA_PATH" ]; then
|
||||||
IPA_PATH="$OUTPUT_PATH/Telegram.ipa"
|
IPA_PATH="$OUTPUT_PATH/Telegram.ipa"
|
||||||
@ -45,6 +43,8 @@ VERIFY_PATH="TelegramVerifyBuild.ipa"
|
|||||||
rm -f "$VERIFY_PATH"
|
rm -f "$VERIFY_PATH"
|
||||||
cp "$IPA_PATH" "$VERIFY_PATH"
|
cp "$IPA_PATH" "$VERIFY_PATH"
|
||||||
|
|
||||||
|
BAZEL_HTTP_CACHE_URL="$BAZEL_HTTP_CACHE_URL" sh buildbox/build-telegram.sh verify
|
||||||
|
|
||||||
python3 tools/ipadiff.py "$IPA_PATH" "$VERIFY_PATH"
|
python3 tools/ipadiff.py "$IPA_PATH" "$VERIFY_PATH"
|
||||||
retVal=$?
|
retVal=$?
|
||||||
if [ $retVal -ne 0 ]; then
|
if [ $retVal -ne 0 ]; then
|
||||||
|
@ -72,8 +72,9 @@ public final class AnimatedStickerFrame {
|
|||||||
public let bytesPerRow: Int
|
public let bytesPerRow: Int
|
||||||
let index: Int
|
let index: Int
|
||||||
let isLastFrame: Bool
|
let isLastFrame: Bool
|
||||||
|
let totalFrames: Int
|
||||||
|
|
||||||
init(data: Data, type: AnimationRendererFrameType, width: Int, height: Int, bytesPerRow: Int, index: Int, isLastFrame: Bool) {
|
init(data: Data, type: AnimationRendererFrameType, width: Int, height: Int, bytesPerRow: Int, index: Int, isLastFrame: Bool, totalFrames: Int) {
|
||||||
self.data = data
|
self.data = data
|
||||||
self.type = type
|
self.type = type
|
||||||
self.width = width
|
self.width = width
|
||||||
@ -81,6 +82,7 @@ public final class AnimatedStickerFrame {
|
|||||||
self.bytesPerRow = bytesPerRow
|
self.bytesPerRow = bytesPerRow
|
||||||
self.index = index
|
self.index = index
|
||||||
self.isLastFrame = isLastFrame
|
self.isLastFrame = isLastFrame
|
||||||
|
self.totalFrames = totalFrames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +257,7 @@ public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let frameData = frameData, draw {
|
if let frameData = frameData, draw {
|
||||||
return AnimatedStickerFrame(data: frameData, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: isLastFrame)
|
return AnimatedStickerFrame(data: frameData, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: isLastFrame, totalFrames: self.frameCount)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -633,7 +635,7 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
|
|||||||
self.currentFrame += 1
|
self.currentFrame += 1
|
||||||
if draw {
|
if draw {
|
||||||
if let cache = self.cache, let yuvData = cache.readUncompressedYuvFrame(index: frameIndex) {
|
if let cache = self.cache, let yuvData = cache.readUncompressedYuvFrame(index: frameIndex) {
|
||||||
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: 0, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1)
|
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: 0, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
|
||||||
} else {
|
} else {
|
||||||
var frameData = Data(count: self.bytesPerRow * self.height)
|
var frameData = Data(count: self.bytesPerRow * self.height)
|
||||||
frameData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
frameData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||||
@ -643,7 +645,7 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
|
|||||||
if let cache = self.cache {
|
if let cache = self.cache {
|
||||||
cache.storeUncompressedRgbFrame(index: frameIndex, rgbData: frameData)
|
cache.storeUncompressedRgbFrame(index: frameIndex, rgbData: frameData)
|
||||||
}
|
}
|
||||||
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1)
|
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
@ -744,6 +746,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
|||||||
private var reportedStarted = false
|
private var reportedStarted = false
|
||||||
|
|
||||||
public var completed: (Bool) -> Void = { _ in }
|
public var completed: (Bool) -> Void = { _ in }
|
||||||
|
public var frameUpdated: (Int, Int) -> Void = { _, _ in }
|
||||||
|
|
||||||
private let timer = Atomic<SwiftSignalKit.Timer?>(value: nil)
|
private let timer = Atomic<SwiftSignalKit.Timer?>(value: nil)
|
||||||
private let frameSource = Atomic<QueueLocalObject<AnimatedStickerFrameSourceWrapper>?>(value: nil)
|
private let frameSource = Atomic<QueueLocalObject<AnimatedStickerFrameSourceWrapper>?>(value: nil)
|
||||||
@ -966,6 +969,8 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
strongSelf.frameUpdated(frame.index, frame.totalFrames)
|
||||||
|
|
||||||
if frame.isLastFrame {
|
if frame.isLastFrame {
|
||||||
var stopped = false
|
var stopped = false
|
||||||
var stopNow = false
|
var stopNow = false
|
||||||
@ -1049,6 +1054,8 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
strongSelf.frameUpdated(frame.index, frame.totalFrames)
|
||||||
|
|
||||||
if frame.isLastFrame {
|
if frame.isLastFrame {
|
||||||
var stopped = false
|
var stopped = false
|
||||||
var stopNow = false
|
var stopNow = false
|
||||||
|
@ -17,6 +17,39 @@ import ConfettiEffect
|
|||||||
import TelegramUniversalVideoContent
|
import TelegramUniversalVideoContent
|
||||||
import SolidRoundedButtonNode
|
import SolidRoundedButtonNode
|
||||||
|
|
||||||
|
private final class ProgressEstimator {
|
||||||
|
private var averageProgressPerSecond: Double = 0.0
|
||||||
|
private var lastMeasurement: (Double, Float)?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(progress: Float) -> Double? {
|
||||||
|
let timestamp = CACurrentMediaTime()
|
||||||
|
if let (lastTimestamp, lastProgress) = self.lastMeasurement {
|
||||||
|
if abs(lastProgress - progress) >= 0.01 || abs(lastTimestamp - timestamp) > 1.0 {
|
||||||
|
let immediateProgressPerSecond = Double(progress - lastProgress) / (timestamp - lastTimestamp)
|
||||||
|
let alpha: Double = 0.05
|
||||||
|
self.averageProgressPerSecond = alpha * immediateProgressPerSecond + (1.0 - alpha) * self.averageProgressPerSecond
|
||||||
|
self.lastMeasurement = (timestamp, progress)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.lastMeasurement = (timestamp, progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
//print("progress = \(progress)")
|
||||||
|
//print("averageProgressPerSecond = \(self.averageProgressPerSecond)")
|
||||||
|
|
||||||
|
if self.averageProgressPerSecond < 0.0001 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
let remainingProgress = Double(1.0 - progress)
|
||||||
|
let remainingTime = remainingProgress / self.averageProgressPerSecond
|
||||||
|
return remainingTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final class ChatImportActivityScreen: ViewController {
|
public final class ChatImportActivityScreen: ViewController {
|
||||||
enum ImportError {
|
enum ImportError {
|
||||||
case generic
|
case generic
|
||||||
@ -57,6 +90,8 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
private var videoNode: UniversalVideoNode?
|
private var videoNode: UniversalVideoNode?
|
||||||
private var feedback: HapticFeedback?
|
private var feedback: HapticFeedback?
|
||||||
|
|
||||||
|
fileprivate var remainingAnimationSeconds: Double?
|
||||||
|
|
||||||
init(controller: ChatImportActivityScreen, context: AccountContext, totalBytes: Int) {
|
init(controller: ChatImportActivityScreen, context: AccountContext, totalBytes: Int) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -109,11 +144,11 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
|
|
||||||
if let path = getAppBundle().path(forResource: "HistoryImport", ofType: "tgs") {
|
if let path = getAppBundle().path(forResource: "HistoryImport", ofType: "tgs") {
|
||||||
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 170 * 2, height: 170 * 2, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 190 * 2, height: 190 * 2, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||||
self.animationNode.visibility = true
|
self.animationNode.visibility = true
|
||||||
}
|
}
|
||||||
if let path = getAppBundle().path(forResource: "HistoryImportDone", ofType: "tgs") {
|
if let path = getAppBundle().path(forResource: "HistoryImportDone", ofType: "tgs") {
|
||||||
self.doneAnimationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 170 * 2, height: 170 * 2, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
self.doneAnimationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 190 * 2, height: 190 * 2, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||||
self.doneAnimationNode.started = { [weak self] in
|
self.doneAnimationNode.started = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -157,6 +192,16 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
strongSelf.doneAnimationNode.isHidden = false
|
strongSelf.doneAnimationNode.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.animationNode.frameUpdated = { [weak self] index, totalCount in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let remainingSeconds = Double(totalCount - index) / 60.0
|
||||||
|
strongSelf.remainingAnimationSeconds = remainingSeconds
|
||||||
|
strongSelf.controller?.updateProgressEstimation()
|
||||||
|
}
|
||||||
|
|
||||||
if let path = getAppBundle().path(forResource: "BlankVideo", ofType: "m4v"), let size = fileSize(path) {
|
if let path = getAppBundle().path(forResource: "BlankVideo", ofType: "m4v"), let size = fileSize(path) {
|
||||||
let decoration = ChatBubbleVideoDecoration(corners: ImageCorners(), nativeSize: CGSize(width: 100.0, height: 100.0), contentMode: .aspectFit, backgroundColor: .black)
|
let decoration = ChatBubbleVideoDecoration(corners: ImageCorners(), nativeSize: CGSize(width: 100.0, height: 100.0), contentMode: .aspectFit, backgroundColor: .black)
|
||||||
|
|
||||||
@ -200,9 +245,9 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
let isFirstLayout = self.validLayout == nil
|
let isFirstLayout = self.validLayout == nil
|
||||||
self.validLayout = (layout, navigationHeight)
|
self.validLayout = (layout, navigationHeight)
|
||||||
|
|
||||||
let iconSize = CGSize(width: 170.0, height: 170.0)
|
let iconSize = CGSize(width: 190.0, height: 190.0)
|
||||||
let radialStatusSize = CGSize(width: 186.0, height: 186.0)
|
let radialStatusSize = CGSize(width: 186.0, height: 186.0)
|
||||||
let maxIconStatusSpacing: CGFloat = 62.0
|
let maxIconStatusSpacing: CGFloat = 46.0
|
||||||
let maxProgressTextSpacing: CGFloat = 33.0
|
let maxProgressTextSpacing: CGFloat = 33.0
|
||||||
let progressStatusSpacing: CGFloat = 14.0
|
let progressStatusSpacing: CGFloat = 14.0
|
||||||
let statusButtonSpacing: CGFloat = 19.0
|
let statusButtonSpacing: CGFloat = 19.0
|
||||||
@ -217,7 +262,7 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
effectiveProgress = 1.0
|
effectiveProgress = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(effectiveProgress * 100.0))%", font: Font.with(size: 42.0, design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(effectiveProgress * 100.0))%", font: Font.with(size: 36.0, design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||||
let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
||||||
|
|
||||||
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(effectiveProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(effectiveProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||||
@ -240,9 +285,9 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
case .chatAdminRequired:
|
case .chatAdminRequired:
|
||||||
errorText = self.presentationData.strings.ChatImportActivity_ErrorNotAdmin
|
errorText = self.presentationData.strings.ChatImportActivity_ErrorNotAdmin
|
||||||
case .invalidChatType:
|
case .invalidChatType:
|
||||||
errorText = self.presentationData.strings.ChatImportActivity_ErrorGeneric
|
|
||||||
case .generic:
|
|
||||||
errorText = self.presentationData.strings.ChatImportActivity_ErrorInvalidChatType
|
errorText = self.presentationData.strings.ChatImportActivity_ErrorInvalidChatType
|
||||||
|
case .generic:
|
||||||
|
errorText = self.presentationData.strings.ChatImportActivity_ErrorGeneric
|
||||||
}
|
}
|
||||||
self.statusText.attributedText = NSAttributedString(string: errorText, font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemDestructiveColor)
|
self.statusText.attributedText = NSAttributedString(string: errorText, font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemDestructiveColor)
|
||||||
case .done:
|
case .done:
|
||||||
@ -331,6 +376,10 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transitionToDoneAnimation() {
|
||||||
|
self.animationNode.stopAtNearestLoop = true
|
||||||
|
}
|
||||||
|
|
||||||
func updateState(state: State, animated: Bool) {
|
func updateState(state: State, animated: Bool) {
|
||||||
var wasDone = false
|
var wasDone = false
|
||||||
if case .done = self.state {
|
if case .done = self.state {
|
||||||
@ -388,8 +437,6 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
self.feedback = HapticFeedback()
|
self.feedback = HapticFeedback()
|
||||||
}
|
}
|
||||||
self.feedback?.success()
|
self.feedback?.success()
|
||||||
|
|
||||||
self.animationNode.stopAtNearestLoop = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,8 +454,13 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
private let archivePath: String
|
private let archivePath: String
|
||||||
private let mainEntry: TempBoxFile
|
private let mainEntry: TempBoxFile
|
||||||
private let mainEntrySize: Int
|
private let mainEntrySize: Int
|
||||||
private let otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType, Promise<TempBoxFile?>)]
|
private let otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType, Signal<TempBoxFile?, NoError>)]
|
||||||
private let totalBytes: Int
|
private let totalBytes: Int
|
||||||
|
private let totalMediaBytes: Int
|
||||||
|
|
||||||
|
private var progressEstimator: ProgressEstimator?
|
||||||
|
private var totalMediaProgress: Float = 0.0
|
||||||
|
private var beganCompletion: Bool = false
|
||||||
|
|
||||||
private var pendingEntries: [String: (Int, Float)] = [:]
|
private var pendingEntries: [String: (Int, Float)] = [:]
|
||||||
|
|
||||||
@ -428,10 +480,14 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
self.archivePath = archivePath
|
self.archivePath = archivePath
|
||||||
self.mainEntry = mainEntry
|
self.mainEntry = mainEntry
|
||||||
|
|
||||||
self.otherEntries = otherEntries.map { entry -> (SSZipEntry, String, ChatHistoryImport.MediaType, Promise<TempBoxFile?>) in
|
var isFirstFile = true
|
||||||
|
self.otherEntries = otherEntries.map { entry -> (SSZipEntry, String, ChatHistoryImport.MediaType, Signal<TempBoxFile?, NoError>) in
|
||||||
let signal = Signal<TempBoxFile?, NoError> { subscriber in
|
let signal = Signal<TempBoxFile?, NoError> { subscriber in
|
||||||
let tempFile = TempBox.shared.tempFile(fileName: entry.1)
|
let tempFile = TempBox.shared.tempFile(fileName: entry.1)
|
||||||
|
print("Extracting \(entry.0.path) to \(tempFile.path)...")
|
||||||
|
let startTime = CACurrentMediaTime()
|
||||||
if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.0.path, toPath: tempFile.path) {
|
if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.0.path, toPath: tempFile.path) {
|
||||||
|
print("[Done in \(CACurrentMediaTime() - startTime) s] Extract \(entry.0.path) to \(tempFile.path)")
|
||||||
subscriber.putNext(tempFile)
|
subscriber.putNext(tempFile)
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
} else {
|
} else {
|
||||||
@ -441,10 +497,9 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
|
|
||||||
return EmptyDisposable
|
return EmptyDisposable
|
||||||
}
|
}
|
||||||
|> runOn(Queue.concurrentDefaultQueue())
|
//let promise = Promise<TempBoxFile?>()
|
||||||
let promise = Promise<TempBoxFile?>()
|
//promise.set(signal)
|
||||||
promise.set(signal)
|
return (entry.0, entry.1, entry.2, signal)
|
||||||
return (entry.0, entry.1, entry.2, promise)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let size = fileSize(self.mainEntry.path) {
|
if let size = fileSize(self.mainEntry.path) {
|
||||||
@ -457,11 +512,12 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
self.pendingEntries[fileName] = (Int(entry.uncompressedSize), 0.0)
|
self.pendingEntries[fileName] = (Int(entry.uncompressedSize), 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalBytes: Int = self.mainEntrySize
|
var totalMediaBytes = 0
|
||||||
for entry in self.otherEntries {
|
for entry in self.otherEntries {
|
||||||
totalBytes += Int(entry.0.uncompressedSize)
|
totalMediaBytes += Int(entry.0.uncompressedSize)
|
||||||
}
|
}
|
||||||
self.totalBytes = totalBytes
|
self.totalBytes = self.mainEntrySize + totalMediaBytes
|
||||||
|
self.totalMediaBytes = totalMediaBytes
|
||||||
|
|
||||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
@ -515,6 +571,9 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
self.pendingEntries[key] = (value.0, 0.0)
|
self.pendingEntries[key] = (value.0, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.progressEstimator = ProgressEstimator()
|
||||||
|
self.beganCompletion = false
|
||||||
|
|
||||||
self.controllerNode.updateState(state: .progress(0.0), animated: true)
|
self.controllerNode.updateState(state: .progress(0.0), animated: true)
|
||||||
|
|
||||||
let context = self.context
|
let context = self.context
|
||||||
@ -553,7 +612,7 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
var mediaSignals: [Signal<(String, Float), ImportError>] = []
|
var mediaSignals: [Signal<(String, Float), ImportError>] = []
|
||||||
|
|
||||||
for (_, fileName, mediaType, fileData) in otherEntries {
|
for (_, fileName, mediaType, fileData) in otherEntries {
|
||||||
let unpackedFile: Signal<TempBoxFile, ImportError> = fileData.get()
|
let unpackedFile: Signal<TempBoxFile, ImportError> = fileData
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> castError(ImportError.self)
|
|> castError(ImportError.self)
|
||||||
@ -611,16 +670,24 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalDoneBytes = strongSelf.mainEntrySize
|
var totalDoneMediaBytes = 0
|
||||||
for (_, sizeAndProgress) in strongSelf.pendingEntries {
|
for (_, sizeAndProgress) in strongSelf.pendingEntries {
|
||||||
totalDoneBytes += Int(Float(sizeAndProgress.0) * sizeAndProgress.1)
|
totalDoneMediaBytes += Int(Float(sizeAndProgress.0) * sizeAndProgress.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let totalDoneBytes = strongSelf.mainEntrySize + totalDoneMediaBytes
|
||||||
|
|
||||||
var totalProgress: CGFloat = 1.0
|
var totalProgress: CGFloat = 1.0
|
||||||
if !strongSelf.otherEntries.isEmpty {
|
if !strongSelf.otherEntries.isEmpty {
|
||||||
totalProgress = CGFloat(totalDoneBytes) / CGFloat(strongSelf.totalBytes)
|
totalProgress = CGFloat(totalDoneBytes) / CGFloat(strongSelf.totalBytes)
|
||||||
}
|
}
|
||||||
|
var totalMediaProgress: CGFloat = 1.0
|
||||||
|
if !strongSelf.otherEntries.isEmpty {
|
||||||
|
totalProgress = CGFloat(totalDoneBytes) / CGFloat(strongSelf.totalBytes)
|
||||||
|
totalMediaProgress = CGFloat(totalDoneMediaBytes) / CGFloat(strongSelf.totalMediaBytes)
|
||||||
|
}
|
||||||
strongSelf.controllerNode.updateState(state: .progress(totalProgress), animated: true)
|
strongSelf.controllerNode.updateState(state: .progress(totalProgress), animated: true)
|
||||||
|
strongSelf.totalMediaProgress = Float(totalMediaProgress)
|
||||||
}, error: { [weak self] error in
|
}, error: { [weak self] error in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -637,4 +704,17 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate func updateProgressEstimation() {
|
||||||
|
if !self.beganCompletion, let progressEstimator = self.progressEstimator, let remainingAnimationSeconds = self.controllerNode.remainingAnimationSeconds {
|
||||||
|
if let remainingSeconds = progressEstimator.update(progress: self.totalMediaProgress) {
|
||||||
|
//print("remainingSeconds: \(remainingSeconds)")
|
||||||
|
//print("remainingAnimationSeconds + 1.0: \(remainingAnimationSeconds + 1.0)")
|
||||||
|
if remainingSeconds <= remainingAnimationSeconds + 1.0 {
|
||||||
|
self.beganCompletion = true
|
||||||
|
self.controllerNode.transitionToDoneAnimation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ public class ChatListAdditionalCategoryItem: ItemListItem, ListViewItemWithHeade
|
|||||||
image: UIImage?,
|
image: UIImage?,
|
||||||
appearance: ChatListNodeAdditionalCategory.Appearance,
|
appearance: ChatListNodeAdditionalCategory.Appearance,
|
||||||
isSelected: Bool,
|
isSelected: Bool,
|
||||||
|
header: ListViewItemHeader?,
|
||||||
action: @escaping () -> Void
|
action: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
@ -47,7 +48,7 @@ public class ChatListAdditionalCategoryItem: ItemListItem, ListViewItemWithHeade
|
|||||||
case .option:
|
case .option:
|
||||||
self.header = ChatListSearchItemHeader(type: .chatTypes, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
self.header = ChatListSearchItemHeader(type: .chatTypes, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||||
case .action:
|
case .action:
|
||||||
self.header = nil
|
self.header = header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,12 +262,12 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
hideAuthor = true
|
hideAuthor = true
|
||||||
if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId) {
|
if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId, forChatList: true) {
|
||||||
messageText = text
|
messageText = text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case _ as TelegramMediaExpiredContent:
|
case _ as TelegramMediaExpiredContent:
|
||||||
if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId) {
|
if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId, forChatList: true) {
|
||||||
messageText = text
|
messageText = text
|
||||||
}
|
}
|
||||||
case let poll as TelegramMediaPoll:
|
case let poll as TelegramMediaPoll:
|
||||||
|
@ -166,6 +166,11 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||||
case let .AdditionalCategory(_, id, title, image, appearance, selected, presentationData):
|
case let .AdditionalCategory(_, id, title, image, appearance, selected, presentationData):
|
||||||
|
var header: ChatListSearchItemHeader?
|
||||||
|
if case .action = appearance {
|
||||||
|
// TODO: hack, generalize
|
||||||
|
header = ChatListSearchItemHeader(type: .orImportIntoAnExistingGroup, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||||
|
}
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
||||||
context: context,
|
context: context,
|
||||||
@ -173,6 +178,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
image: image,
|
image: image,
|
||||||
appearance: appearance,
|
appearance: appearance,
|
||||||
isSelected: selected,
|
isSelected: selected,
|
||||||
|
header: header,
|
||||||
action: {
|
action: {
|
||||||
nodeInteraction.additionalCategorySelected(id)
|
nodeInteraction.additionalCategorySelected(id)
|
||||||
}
|
}
|
||||||
@ -371,6 +377,11 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||||
case let .AdditionalCategory(index: _, id, title, image, appearance, selected, presentationData):
|
case let .AdditionalCategory(index: _, id, title, image, appearance, selected, presentationData):
|
||||||
|
var header: ChatListSearchItemHeader?
|
||||||
|
if case .action = appearance {
|
||||||
|
// TODO: hack, generalize
|
||||||
|
header = ChatListSearchItemHeader(type: .orImportIntoAnExistingGroup, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||||
|
}
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
||||||
context: context,
|
context: context,
|
||||||
@ -378,6 +389,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
image: image,
|
image: image,
|
||||||
appearance: appearance,
|
appearance: appearance,
|
||||||
isSelected: selected,
|
isSelected: selected,
|
||||||
|
header: header,
|
||||||
action: {
|
action: {
|
||||||
nodeInteraction.additionalCategorySelected(id)
|
nodeInteraction.additionalCategorySelected(id)
|
||||||
}
|
}
|
||||||
|
@ -559,6 +559,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) }
|
dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) }
|
||||||
dict[-58224696] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) }
|
dict[-58224696] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) }
|
||||||
dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) }
|
dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) }
|
||||||
|
dict[-275956116] = { return Api.messages.AffectedFoundMessages.parse_affectedFoundMessages($0) }
|
||||||
dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) }
|
dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) }
|
||||||
dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) }
|
dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) }
|
||||||
dict[-1963717851] = { return Api.WallPaper.parse_wallPaperNoFile($0) }
|
dict[-1963717851] = { return Api.WallPaper.parse_wallPaperNoFile($0) }
|
||||||
@ -1301,6 +1302,8 @@ public struct Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.StatsDateRangeDays:
|
case let _1 as Api.StatsDateRangeDays:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.messages.AffectedFoundMessages:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.MessageFwdAuthor:
|
case let _1 as Api.MessageFwdAuthor:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.WallPaper:
|
case let _1 as Api.WallPaper:
|
||||||
|
@ -1127,6 +1127,58 @@ public struct messages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public enum AffectedFoundMessages: TypeConstructorDescription {
|
||||||
|
case affectedFoundMessages(pts: Int32, ptsCount: Int32, offset: Int32, messages: [Int32])
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .affectedFoundMessages(let pts, let ptsCount, let offset, let messages):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-275956116)
|
||||||
|
}
|
||||||
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(offset, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(messages.count))
|
||||||
|
for item in messages {
|
||||||
|
serializeInt32(item, buffer: buffer, boxed: false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .affectedFoundMessages(let pts, let ptsCount, let offset, let messages):
|
||||||
|
return ("affectedFoundMessages", [("pts", pts), ("ptsCount", ptsCount), ("offset", offset), ("messages", messages)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_affectedFoundMessages(_ reader: BufferReader) -> AffectedFoundMessages? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: Int32?
|
||||||
|
_3 = reader.readInt32()
|
||||||
|
var _4: [Int32]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_4 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 {
|
||||||
|
return Api.messages.AffectedFoundMessages.affectedFoundMessages(pts: _1!, ptsCount: _2!, offset: _3!, messages: _4!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public enum Messages: TypeConstructorDescription {
|
public enum Messages: TypeConstructorDescription {
|
||||||
case messages(messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
|
case messages(messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
|
||||||
|
@ -3917,15 +3917,15 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func deletePhoneCallHistory(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedHistory>) {
|
public static func deletePhoneCallHistory(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AffectedFoundMessages>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(1828657989)
|
buffer.appendInt32(-104078327)
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
return (FunctionDescription(name: "messages.deletePhoneCallHistory", parameters: [("flags", flags)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in
|
return (FunctionDescription(name: "messages.deletePhoneCallHistory", parameters: [("flags", flags)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedFoundMessages? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.messages.AffectedHistory?
|
var result: Api.messages.AffectedFoundMessages?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
result = Api.parse(reader, signature: signature) as? Api.messages.AffectedHistory
|
result = Api.parse(reader, signature: signature) as? Api.messages.AffectedFoundMessages
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
|
@ -49,7 +49,7 @@ public enum ChatHistoryImport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static func initSession(account: Account, peerId: PeerId, file: TempBoxFile, mediaCount: Int32) -> Signal<Session, InitImportError> {
|
public static func initSession(account: Account, peerId: PeerId, file: TempBoxFile, mediaCount: Int32) -> Signal<Session, InitImportError> {
|
||||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> InitImportError in
|
|> mapError { _ -> InitImportError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
@ -104,7 +104,12 @@ public enum ChatHistoryImport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static func uploadMedia(account: Account, session: Session, file: TempBoxFile, fileName: String, mimeType: String, type: MediaType) -> Signal<Float, UploadMediaError> {
|
public static func uploadMedia(account: Account, session: Session, file: TempBoxFile, fileName: String, mimeType: String, type: MediaType) -> Signal<Float, UploadMediaError> {
|
||||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, useLargerParts: true, useMultiplexedRequests: true)
|
var forceNoBigParts = true
|
||||||
|
if let size = fileSize(file.path), size >= 30 * 1024 * 1024 {
|
||||||
|
forceNoBigParts = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: forceNoBigParts, useLargerParts: true, useMultiplexedRequests: true)
|
||||||
|> mapError { _ -> UploadMediaError in
|
|> mapError { _ -> UploadMediaError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|
@ -104,16 +104,16 @@ public func clearCallHistory(account: Account, forEveryone: Bool) -> Signal<Neve
|
|||||||
}
|
}
|
||||||
|
|
||||||
let signal = account.network.request(Api.functions.messages.deletePhoneCallHistory(flags: flags))
|
let signal = account.network.request(Api.functions.messages.deletePhoneCallHistory(flags: flags))
|
||||||
|> map { result -> Api.messages.AffectedHistory? in
|
|> map { result -> Api.messages.AffectedFoundMessages? in
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|> `catch` { _ -> Signal<Api.messages.AffectedHistory?, Bool> in
|
|> `catch` { _ -> Signal<Api.messages.AffectedFoundMessages?, Bool> in
|
||||||
return .fail(false)
|
return .fail(false)
|
||||||
}
|
}
|
||||||
|> mapToSignal { result -> Signal<Void, Bool> in
|
|> mapToSignal { result -> Signal<Void, Bool> in
|
||||||
if let result = result {
|
if let result = result {
|
||||||
switch result {
|
switch result {
|
||||||
case let .affectedHistory(pts, ptsCount, offset):
|
case let .affectedFoundMessages(pts, ptsCount, offset, _):
|
||||||
account.stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
|
account.stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
|
||||||
if offset == 0 {
|
if offset == 0 {
|
||||||
return .fail(true)
|
return .fail(true)
|
||||||
|
@ -37,7 +37,7 @@ private final class MessageMediaPreuploadManagerContext {
|
|||||||
let context = MessageMediaPreuploadManagerUploadContext()
|
let context = MessageMediaPreuploadManagerUploadContext()
|
||||||
self.uploadContexts[id] = context
|
self.uploadContexts[id] = context
|
||||||
let queue = self.queue
|
let queue = self.queue
|
||||||
context.disposable.set(multipartUpload(network: network, postbox: postbox, source: .custom(source), encrypt: encrypt, tag: tag, hintFileSize: nil, hintFileIsLarge: false).start(next: { [weak self] next in
|
context.disposable.set(multipartUpload(network: network, postbox: postbox, source: .custom(source), encrypt: encrypt, tag: tag, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false).start(next: { [weak self] next in
|
||||||
queue.async {
|
queue.async {
|
||||||
if let strongSelf = self, let context = strongSelf.uploadContexts[id] {
|
if let strongSelf = self, let context = strongSelf.uploadContexts[id] {
|
||||||
switch next {
|
switch next {
|
||||||
@ -86,7 +86,7 @@ private final class MessageMediaPreuploadManagerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: source, encrypt: encrypt, tag: tag, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge).start(next: { next in
|
return multipartUpload(network: network, postbox: postbox, source: source, encrypt: encrypt, tag: tag, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, forceNoBigParts: false).start(next: { next in
|
||||||
subscriber.putNext(next)
|
subscriber.putNext(next)
|
||||||
}, error: { error in
|
}, error: { error in
|
||||||
subscriber.putError(error)
|
subscriber.putError(error)
|
||||||
|
@ -117,6 +117,7 @@ private final class MultipartUploadManager {
|
|||||||
var defaultPartSize: Int
|
var defaultPartSize: Int
|
||||||
var bigTotalParts: Int?
|
var bigTotalParts: Int?
|
||||||
var bigParts: Bool
|
var bigParts: Bool
|
||||||
|
private let forceNoBigParts: Bool
|
||||||
private let useLargerParts: Bool
|
private let useLargerParts: Bool
|
||||||
|
|
||||||
let queue = Queue()
|
let queue = Queue()
|
||||||
@ -139,13 +140,14 @@ private final class MultipartUploadManager {
|
|||||||
|
|
||||||
let state: MultipartUploadState
|
let state: MultipartUploadState
|
||||||
|
|
||||||
init(headerSize: Int32, data: Signal<MultipartUploadData, NoError>, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, hintFileIsLarge: Bool, useLargerParts: Bool, uploadPart: @escaping (UploadPart) -> Signal<Void, UploadPartError>, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult?) -> Void) {
|
init(headerSize: Int32, data: Signal<MultipartUploadData, NoError>, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, hintFileIsLarge: Bool, forceNoBigParts: Bool, useLargerParts: Bool, uploadPart: @escaping (UploadPart) -> Signal<Void, UploadPartError>, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult?) -> Void) {
|
||||||
self.dataSignal = data
|
self.dataSignal = data
|
||||||
|
|
||||||
var fileId: Int64 = 0
|
var fileId: Int64 = 0
|
||||||
arc4random_buf(&fileId, 8)
|
arc4random_buf(&fileId, 8)
|
||||||
self.fileId = fileId
|
self.fileId = fileId
|
||||||
|
|
||||||
|
self.forceNoBigParts = forceNoBigParts
|
||||||
self.useLargerParts = useLargerParts
|
self.useLargerParts = useLargerParts
|
||||||
|
|
||||||
self.state = MultipartUploadState(encryptionKey: encryptionKey)
|
self.state = MultipartUploadState(encryptionKey: encryptionKey)
|
||||||
@ -161,11 +163,11 @@ private final class MultipartUploadManager {
|
|||||||
self.headerPartState = .notStarted
|
self.headerPartState = .notStarted
|
||||||
}
|
}
|
||||||
|
|
||||||
if let hintFileSize = hintFileSize, hintFileSize > 10 * 1024 * 1024 {
|
if let hintFileSize = hintFileSize, hintFileSize > 10 * 1024 * 1024, !forceNoBigParts {
|
||||||
self.defaultPartSize = 512 * 1024
|
self.defaultPartSize = 512 * 1024
|
||||||
self.bigTotalParts = (hintFileSize / self.defaultPartSize) + (hintFileSize % self.defaultPartSize == 0 ? 0 : 1)
|
self.bigTotalParts = (hintFileSize / self.defaultPartSize) + (hintFileSize % self.defaultPartSize == 0 ? 0 : 1)
|
||||||
self.bigParts = true
|
self.bigParts = true
|
||||||
} else if hintFileIsLarge {
|
} else if hintFileIsLarge, !forceNoBigParts {
|
||||||
self.defaultPartSize = 512 * 1024
|
self.defaultPartSize = 512 * 1024
|
||||||
self.bigTotalParts = nil
|
self.bigTotalParts = nil
|
||||||
self.bigParts = true
|
self.bigParts = true
|
||||||
@ -203,7 +205,7 @@ private final class MultipartUploadManager {
|
|||||||
func checkState() {
|
func checkState() {
|
||||||
if let resourceData = self.resourceData, resourceData.complete && resourceData.size != 0 {
|
if let resourceData = self.resourceData, resourceData.complete && resourceData.size != 0 {
|
||||||
if self.committedOffset == 0 && self.uploadedParts.isEmpty && self.uploadingParts.isEmpty {
|
if self.committedOffset == 0 && self.uploadedParts.isEmpty && self.uploadingParts.isEmpty {
|
||||||
if resourceData.size > 10 * 1024 * 1024 {
|
if resourceData.size > 10 * 1024 * 1024, !self.forceNoBigParts {
|
||||||
self.defaultPartSize = 512 * 1024
|
self.defaultPartSize = 512 * 1024
|
||||||
self.bigTotalParts = (resourceData.size / self.defaultPartSize) + (resourceData.size % self.defaultPartSize == 0 ? 0 : 1)
|
self.bigTotalParts = (resourceData.size / self.defaultPartSize) + (resourceData.size % self.defaultPartSize == 0 ? 0 : 1)
|
||||||
self.bigParts = true
|
self.bigParts = true
|
||||||
@ -379,7 +381,7 @@ enum MultipartUploadError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool, useLargerParts: Bool = false, useMultiplexedRequests: Bool = false) -> Signal<MultipartUploadResult, MultipartUploadError> {
|
func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool, forceNoBigParts: Bool, useLargerParts: Bool = false, useMultiplexedRequests: Bool = false) -> Signal<MultipartUploadResult, MultipartUploadError> {
|
||||||
enum UploadInterface {
|
enum UploadInterface {
|
||||||
case download(Download)
|
case download(Download)
|
||||||
case multiplexed(manager: MultiplexedRequestManager, datacenterId: Int, consumerId: Int64)
|
case multiplexed(manager: MultiplexedRequestManager, datacenterId: Int, consumerId: Int64)
|
||||||
@ -445,7 +447,7 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload
|
|||||||
fetchedResource = .complete()
|
fetchedResource = .complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, useLargerParts: useLargerParts, uploadPart: { part in
|
let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, forceNoBigParts: forceNoBigParts, useLargerParts: useLargerParts, uploadPart: { part in
|
||||||
switch uploadInterface {
|
switch uploadInterface {
|
||||||
case let .download(download):
|
case let .download(download):
|
||||||
return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts)
|
return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts)
|
||||||
|
@ -144,7 +144,7 @@ private final class MultiplexedRequestManagerContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateState() {
|
private func updateState() {
|
||||||
let maxRequestsPerWorker = 2
|
let maxRequestsPerWorker = 3
|
||||||
let maxWorkersPerTarget = 4
|
let maxWorkersPerTarget = 4
|
||||||
|
|
||||||
var requestIndex = 0
|
var requestIndex = 0
|
||||||
|
@ -38,7 +38,7 @@ enum UploadedPeerPhotoDataContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func uploadedPeerPhoto(postbox: Postbox, network: Network, resource: MediaResource) -> Signal<UploadedPeerPhotoData, NoError> {
|
public func uploadedPeerPhoto(postbox: Postbox, network: Network, resource: MediaResource) -> Signal<UploadedPeerPhotoData, NoError> {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> map { result -> UploadedPeerPhotoData in
|
|> map { result -> UploadedPeerPhotoData in
|
||||||
return UploadedPeerPhotoData(resource: resource, content: .result(result))
|
return UploadedPeerPhotoData(resource: resource, content: .result(result))
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ public func uploadedPeerVideo(postbox: Postbox, network: Network, messageMediaPr
|
|||||||
return .single(UploadedPeerPhotoData(resource: resource, content: .error))
|
return .single(UploadedPeerPhotoData(resource: resource, content: .error))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .video), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .video), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> map { result -> UploadedPeerPhotoData in
|
|> map { result -> UploadedPeerPhotoData in
|
||||||
return UploadedPeerPhotoData(resource: resource, content: .result(result))
|
return UploadedPeerPhotoData(resource: resource, content: .result(result))
|
||||||
}
|
}
|
||||||
|
@ -406,7 +406,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans
|
|||||||
} else {
|
} else {
|
||||||
imageReference = .standalone(media: transformedImage)
|
imageReference = .standalone(media: transformedImage)
|
||||||
}
|
}
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .resource(imageReference.resourceReference(largestRepresentation.resource)), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .resource(imageReference.resourceReference(largestRepresentation.resource)), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||||
|> mapToSignal { next -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
|> mapToSignal { next -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||||
switch next {
|
switch next {
|
||||||
@ -560,7 +560,7 @@ private enum UploadedMediaFileAndThumbnail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedThumbnail(network: Network, postbox: Postbox, resourceReference: MediaResourceReference) -> Signal<Api.InputFile?, PendingMessageUploadError> {
|
private func uploadedThumbnail(network: Network, postbox: Postbox, resourceReference: MediaResourceReference) -> Signal<Api.InputFile?, PendingMessageUploadError> {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .resource(resourceReference), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .resource(resourceReference), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||||
|> mapToSignal { result -> Signal<Api.InputFile?, PendingMessageUploadError> in
|
|> mapToSignal { result -> Signal<Api.InputFile?, PendingMessageUploadError> in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -144,7 +144,7 @@ private enum UploadMediaEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedImage(account: Account, data: Data) -> Signal<UploadMediaEvent, StandaloneSendMessageError> {
|
private func uploadedImage(account: Account, data: Data) -> Signal<UploadMediaEvent, StandaloneSendMessageError> {
|
||||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> StandaloneSendMessageError in return .generic }
|
|> mapError { _ -> StandaloneSendMessageError in return .generic }
|
||||||
|> map { next -> UploadMediaEvent in
|
|> map { next -> UploadMediaEvent in
|
||||||
switch next {
|
switch next {
|
||||||
@ -159,7 +159,7 @@ private func uploadedImage(account: Account, data: Data) -> Signal<UploadMediaEv
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedFile(account: Account, data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute]) -> Signal<UploadMediaEvent, PendingMessageUploadError> {
|
private func uploadedFile(account: Account, data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute]) -> Signal<UploadMediaEvent, PendingMessageUploadError> {
|
||||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes)), hintFileSize: data.count, hintFileIsLarge: false)
|
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes)), hintFileSize: data.count, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||||
|> map { next -> UploadMediaEvent in
|
|> map { next -> UploadMediaEvent in
|
||||||
switch next {
|
switch next {
|
||||||
|
@ -39,7 +39,7 @@ public enum StandaloneUploadMediaEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedThumbnail(network: Network, postbox: Postbox, data: Data) -> Signal<Api.InputFile?, StandaloneUploadMediaError> {
|
private func uploadedThumbnail(network: Network, postbox: Postbox, data: Data) -> Signal<Api.InputFile?, StandaloneUploadMediaError> {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
||||||
|> mapToSignal { result -> Signal<Api.InputFile?, StandaloneUploadMediaError> in
|
|> mapToSignal { result -> Signal<Api.InputFile?, StandaloneUploadMediaError> in
|
||||||
switch result {
|
switch result {
|
||||||
@ -54,7 +54,7 @@ private func uploadedThumbnail(network: Network, postbox: Postbox, data: Data) -
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func standaloneUploadedImage(account: Account, peerId: PeerId, text: String, data: Data, thumbnailData: Data? = nil, dimensions: PixelDimensions) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
|
public func standaloneUploadedImage(account: Account, peerId: PeerId, text: String, data: Data, thumbnailData: Data? = nil, dimensions: PixelDimensions) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
|
||||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
||||||
|> mapToSignal { next -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
|
|> mapToSignal { next -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
|
||||||
switch next {
|
switch next {
|
||||||
@ -115,7 +115,7 @@ public func standaloneUploadedImage(account: Account, peerId: PeerId, text: Stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func standaloneUploadedFile(account: Account, peerId: PeerId, text: String, source: MultipartUploadSource, thumbnailData: Data? = nil, mimeType: String, attributes: [TelegramMediaFileAttribute], hintFileIsLarge: Bool) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
|
public func standaloneUploadedFile(account: Account, peerId: PeerId, text: String, source: MultipartUploadSource, thumbnailData: Data? = nil, mimeType: String, attributes: [TelegramMediaFileAttribute], hintFileIsLarge: Bool) -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> {
|
||||||
let upload = multipartUpload(network: account.network, postbox: account.postbox, source: source, encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes)), hintFileSize: nil, hintFileIsLarge: hintFileIsLarge)
|
let upload = multipartUpload(network: account.network, postbox: account.postbox, source: source, encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes)), hintFileSize: nil, hintFileIsLarge: hintFileIsLarge, forceNoBigParts: false)
|
||||||
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
||||||
|
|
||||||
let uploadThumbnail: Signal<StandaloneUploadMediaThumbnailResult, StandaloneUploadMediaError>
|
let uploadThumbnail: Signal<StandaloneUploadMediaThumbnailResult, StandaloneUploadMediaError>
|
||||||
|
@ -203,7 +203,7 @@ private enum UploadedThemeDataContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedTheme(postbox: Postbox, network: Network, resource: MediaResource) -> Signal<UploadedThemeData, NoError> {
|
private func uploadedTheme(postbox: Postbox, network: Network, resource: MediaResource) -> Signal<UploadedThemeData, NoError> {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .file), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .file), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> map { result -> UploadedThemeData in
|
|> map { result -> UploadedThemeData in
|
||||||
return UploadedThemeData(content: .result(result))
|
return UploadedThemeData(content: .result(result))
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ private func uploadedTheme(postbox: Postbox, network: Network, resource: MediaRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedThemeThumbnail(postbox: Postbox, network: Network, data: Data) -> Signal<UploadedThemeData, NoError> {
|
private func uploadedThemeThumbnail(postbox: Postbox, network: Network, data: Data) -> Signal<UploadedThemeData, NoError> {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> map { result -> UploadedThemeData in
|
|> map { result -> UploadedThemeData in
|
||||||
return UploadedThemeData(content: .result(result))
|
return UploadedThemeData(content: .result(result))
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ public func uploadSecureIdFile(context: SecureIdAccessContext, postbox: Postbox,
|
|||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .data(encryptedData.data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .data(encryptedData.data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> mapError { _ -> UploadSecureIdFileError in
|
|> mapError { _ -> UploadSecureIdFileError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ private enum UploadedWallpaperDataContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func uploadedWallpaper(postbox: Postbox, network: Network, resource: MediaResource) -> Signal<UploadedWallpaperData, NoError> {
|
private func uploadedWallpaper(postbox: Postbox, network: Network, resource: MediaResource) -> Signal<UploadedWallpaperData, NoError> {
|
||||||
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|
||||||
|> map { result -> UploadedWallpaperData in
|
|> map { result -> UploadedWallpaperData in
|
||||||
return UploadedWallpaperData(resource: resource, content: .result(result))
|
return UploadedWallpaperData(resource: resource, content: .result(result))
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -163,7 +163,7 @@ public func mediaContentKind(_ media: Media, message: Message? = nil, strings: P
|
|||||||
}
|
}
|
||||||
case _ as TelegramMediaAction:
|
case _ as TelegramMediaAction:
|
||||||
if let message = message, let strings = strings, let nameDisplayOrder = nameDisplayOrder, let accountPeerId = accountPeerId {
|
if let message = message, let strings = strings, let nameDisplayOrder = nameDisplayOrder, let accountPeerId = accountPeerId {
|
||||||
return .text(plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId) ?? "")
|
return .text(plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId, forChatList: false) ?? "")
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,11 @@ private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, P
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, message: Message, accountPeerId: PeerId) -> String? {
|
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, message: Message, accountPeerId: PeerId, forChatList: Bool) -> String? {
|
||||||
return universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId)?.string
|
return universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId, forChatList: forChatList)?.string
|
||||||
}
|
}
|
||||||
|
|
||||||
public func universalServiceMessageString(presentationData: (PresentationTheme, TelegramWallpaper)?, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, message: Message, accountPeerId: PeerId) -> NSAttributedString? {
|
public func universalServiceMessageString(presentationData: (PresentationTheme, TelegramWallpaper)?, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, message: Message, accountPeerId: PeerId, forChatList: Bool) -> NSAttributedString? {
|
||||||
var attributedString: NSAttributedString?
|
var attributedString: NSAttributedString?
|
||||||
|
|
||||||
let primaryTextColor: UIColor
|
let primaryTextColor: UIColor
|
||||||
@ -57,7 +57,11 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
if isChannel {
|
if isChannel {
|
||||||
attributedString = NSAttributedString(string: strings.Notification_CreatedChannel, font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: strings.Notification_CreatedChannel, font: titleFont, textColor: primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
attributedString = addAttributesToStringWithRanges(strings.Notification_CreatedChatWithTitle(authorName, title), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
if forChatList {
|
||||||
|
attributedString = NSAttributedString(string: strings.Notification_CreatedGroup, font: titleFont, textColor: primaryTextColor)
|
||||||
|
} else {
|
||||||
|
attributedString = addAttributesToStringWithRanges(strings.Notification_CreatedChatWithTitle(authorName, title), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case let .addedMembers(peerIds):
|
case let .addedMembers(peerIds):
|
||||||
if let peerId = peerIds.first, peerId == message.author?.id {
|
if let peerId = peerIds.first, peerId == message.author?.id {
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -19,7 +19,7 @@ import TelegramUniversalVideoContent
|
|||||||
import GalleryUI
|
import GalleryUI
|
||||||
|
|
||||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, message: Message, accountPeerId: PeerId) -> NSAttributedString? {
|
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, message: Message, accountPeerId: PeerId) -> NSAttributedString? {
|
||||||
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId)
|
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId, forChatList: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||||
|
@ -90,7 +90,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
var chatListcategories: [ChatListNodeAdditionalCategory] = []
|
var chatListcategories: [ChatListNodeAdditionalCategory] = []
|
||||||
|
|
||||||
if let _ = createNewGroup {
|
if let _ = createNewGroup {
|
||||||
chatListcategories.append(ChatListNodeAdditionalCategory(id: 0, icon: PresentationResourcesItemList.createGroupIcon(self.presentationData.theme), title: self.presentationData.strings.PeerSelection_CreateNewGroup, appearance: .action))
|
chatListcategories.append(ChatListNodeAdditionalCategory(id: 0, icon: PresentationResourcesItemList.createGroupIcon(self.presentationData.theme), title: self.presentationData.strings.PeerSelection_ImportIntoNewGroup, appearance: .action))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: filter, isSelecting: false, additionalCategories: chatListcategories, chatListFilters: nil), theme: self.presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
|
self.chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: filter, isSelecting: false, additionalCategories: chatListcategories, chatListFilters: nil), theme: self.presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
|
||||||
|
@ -223,7 +223,7 @@ public class ShareRootControllerImpl {
|
|||||||
}
|
}
|
||||||
|> castError(ShareAuthorizationError.self)
|
|> castError(ShareAuthorizationError.self)
|
||||||
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||||
Logger.shared.logToFile = loggingSettings.logToFile
|
Logger.shared.logToFile = true//loggingSettings.logToFile
|
||||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
Logger.shared.logToConsole = loggingSettings.logToConsole
|
||||||
|
|
||||||
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
||||||
|
Loading…
x
Reference in New Issue
Block a user