diff --git a/Telegram/LegacyWidget/Info.plist b/Telegram/LegacyWidget/Info.plist
new file mode 100644
index 0000000000..6917b6ac76
--- /dev/null
+++ b/Telegram/LegacyWidget/Info.plist
@@ -0,0 +1,31 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ ${APP_NAME}
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
+ CFBundleVersion
+ ${BUILD_NUMBER}
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.widget-extension
+ NSExtensionPrincipalClass
+ TodayViewController
+
+
+
diff --git a/Telegram/LegacyWidget/PeerNode.swift b/Telegram/LegacyWidget/PeerNode.swift
new file mode 100644
index 0000000000..b89deba9e6
--- /dev/null
+++ b/Telegram/LegacyWidget/PeerNode.swift
@@ -0,0 +1,172 @@
+import Foundation
+import UIKit
+import WidgetItems
+
+private extension UIColor {
+ convenience init(rgb: UInt32) {
+ self.init(red: CGFloat((rgb >> 16) & 0xff) / 255.0, green: CGFloat((rgb >> 8) & 0xff) / 255.0, blue: CGFloat(rgb & 0xff) / 255.0, alpha: 1.0)
+ }
+}
+
+private let UIScreenScale = UIScreen.main.scale
+private func floorToScreenPixels(_ value: CGFloat) -> CGFloat {
+ return floor(value * UIScreenScale) / UIScreenScale
+}
+
+private let gradientColors: [NSArray] = [
+ [UIColor(rgb: 0xff516a).cgColor, UIColor(rgb: 0xff885e).cgColor],
+ [UIColor(rgb: 0xffa85c).cgColor, UIColor(rgb: 0xffcd6a).cgColor],
+ [UIColor(rgb: 0x665fff).cgColor, UIColor(rgb: 0x82b1ff).cgColor],
+ [UIColor(rgb: 0x54cb68).cgColor, UIColor(rgb: 0xa0de7e).cgColor],
+ [UIColor(rgb: 0x4acccd).cgColor, UIColor(rgb: 0x00fcfd).cgColor],
+ [UIColor(rgb: 0x2a9ef1).cgColor, UIColor(rgb: 0x72d5fd).cgColor],
+ [UIColor(rgb: 0xd669ed).cgColor, UIColor(rgb: 0xe0a2f3).cgColor],
+]
+
+private func avatarRoundImage(size: CGSize, source: UIImage) -> UIImage? {
+ UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
+ let context = UIGraphicsGetCurrentContext()
+
+ context?.beginPath()
+ context?.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
+ context?.clip()
+
+ source.draw(in: CGRect(origin: CGPoint(), size: size))
+
+ let image = UIGraphicsGetImageFromCurrentImageContext()
+ UIGraphicsEndImageContext()
+ return image
+}
+
+private let deviceColorSpace: CGColorSpace = {
+ if #available(iOSApplicationExtension 9.3, *) {
+ if let colorSpace = CGColorSpace(name: CGColorSpace.displayP3) {
+ return colorSpace
+ } else {
+ return CGColorSpaceCreateDeviceRGB()
+ }
+ } else {
+ return CGColorSpaceCreateDeviceRGB()
+ }
+}()
+
+private func avatarViewLettersImage(size: CGSize, peerId: Int64, accountPeerId: Int64, letters: [String]) -> UIImage? {
+ UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
+ let context = UIGraphicsGetCurrentContext()
+
+ context?.beginPath()
+ context?.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
+ context?.clip()
+
+ let colorIndex = abs(Int(accountPeerId + peerId))
+
+ let colorsArray = gradientColors[colorIndex % gradientColors.count]
+ var locations: [CGFloat] = [1.0, 0.0]
+ let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray, locations: &locations)!
+
+ context?.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
+
+ context?.setBlendMode(.normal)
+
+ let string = letters.count == 0 ? "" : (letters[0] + (letters.count == 1 ? "" : letters[1]))
+ let attributedString = NSAttributedString(string: string, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 20.0), NSAttributedString.Key.foregroundColor: UIColor.white])
+
+ let line = CTLineCreateWithAttributedString(attributedString)
+ let lineBounds = CTLineGetBoundsWithOptions(line, .useGlyphPathBounds)
+
+ let lineOffset = CGPoint(x: string == "B" ? 1.0 : 0.0, y: 0.0)
+ let lineOrigin = CGPoint(x: floorToScreenPixels(-lineBounds.origin.x + (size.width - lineBounds.size.width) / 2.0) + lineOffset.x, y: floorToScreenPixels(-lineBounds.origin.y + (size.height - lineBounds.size.height) / 2.0))
+
+ context?.translateBy(x: size.width / 2.0, y: size.height / 2.0)
+ context?.scaleBy(x: 1.0, y: -1.0)
+ context?.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
+
+ context?.translateBy(x: lineOrigin.x, y: lineOrigin.y)
+ if let context = context {
+ CTLineDraw(line, context)
+ }
+ context?.translateBy(x: -lineOrigin.x, y: -lineOrigin.y)
+
+ let image = UIGraphicsGetImageFromCurrentImageContext()
+ UIGraphicsEndImageContext()
+ return image
+}
+
+private let avatarSize = CGSize(width: 50.0, height: 50.0)
+
+private final class AvatarView: UIImageView {
+ init(accountPeerId: Int64, peer: WidgetDataPeer, size: CGSize) {
+ super.init(frame: CGRect())
+
+ if let path = peer.avatarPath, let image = UIImage(contentsOfFile: path), let roundImage = avatarRoundImage(size: size, source: image) {
+ self.image = roundImage
+ } else {
+ self.image = avatarViewLettersImage(size: size, peerId: peer.id, accountPeerId: accountPeerId, letters: peer.letters)
+ }
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+}
+
+final class PeerView: UIView {
+ let peer: WidgetDataPeer
+ private let avatarView: AvatarView
+ private let titleLabel: UILabel
+
+ private let tapped: () -> Void
+
+ init(primaryColor: UIColor, accountPeerId: Int64, peer: WidgetDataPeer, tapped: @escaping () -> Void) {
+ self.peer = peer
+ self.tapped = tapped
+ self.avatarView = AvatarView(accountPeerId: accountPeerId, peer: peer, size: avatarSize)
+
+ self.titleLabel = UILabel()
+ var title = peer.name
+ if let lastName = peer.lastName, !lastName.isEmpty {
+ title.append("\n")
+ title.append(lastName)
+ }
+
+ let systemFontSize = UIFont.preferredFont(forTextStyle: .body).pointSize
+ let fontSize = floor(systemFontSize * 11.0 / 17.0)
+
+ self.titleLabel.text = title
+ if #available(iOSApplicationExtension 13.0, *) {
+ self.titleLabel.textColor = UIColor.label
+ } else {
+ self.titleLabel.textColor = primaryColor
+ }
+ self.titleLabel.font = UIFont.systemFont(ofSize: fontSize)
+ self.titleLabel.lineBreakMode = .byTruncatingTail
+ self.titleLabel.numberOfLines = 2
+ self.titleLabel.textAlignment = .center
+
+ super.init(frame: CGRect())
+
+ self.addSubview(self.avatarView)
+ self.addSubview(self.titleLabel)
+
+ self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ func updateLayout(size: CGSize) {
+ self.avatarView.frame = CGRect(origin: CGPoint(x: floor((size.width - avatarSize.width) / 2.0), y: 0.0), size: avatarSize)
+
+ var titleSize = self.titleLabel.sizeThatFits(size)
+ titleSize.width = min(size.width - 6.0, ceil(titleSize.width))
+ titleSize.height = ceil(titleSize.height)
+ self.titleLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: avatarSize.height + 5.0), size: titleSize)
+ }
+
+ @objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
+ if case .ended = recognizer.state {
+ self.tapped()
+ }
+ }
+}
diff --git a/Telegram/LegacyWidget/TodayViewController.swift b/Telegram/LegacyWidget/TodayViewController.swift
new file mode 100644
index 0000000000..f99f7903ce
--- /dev/null
+++ b/Telegram/LegacyWidget/TodayViewController.swift
@@ -0,0 +1,171 @@
+import UIKit
+import NotificationCenter
+import BuildConfig
+import WidgetItems
+import AppLockState
+
+private func rootPathForBasePath(_ appGroupPath: String) -> String {
+ return appGroupPath + "/telegram-data"
+}
+
+@objc(TodayViewController)
+class TodayViewController: UIViewController, NCWidgetProviding {
+ private var initializedInterface = false
+
+ private var buildConfig: BuildConfig?
+
+ private var primaryColor: UIColor = .black
+ private var placeholderLabel: UILabel?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ let appBundleIdentifier = Bundle.main.bundleIdentifier!
+ guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
+ return
+ }
+ let baseAppBundleId = String(appBundleIdentifier[.. Void)) {
+ completionHandler(.newData)
+ }
+
+ @available(iOSApplicationExtension 10.0, *)
+ func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) {
+
+ }
+
+ private var widgetData: WidgetData?
+
+ private func setWidgetData(widgetData: WidgetData, presentationData: WidgetPresentationData) {
+ self.widgetData = widgetData
+ self.peerViews.forEach {
+ $0.removeFromSuperview()
+ }
+ self.peerViews = []
+ switch widgetData {
+ case .notAuthorized, .disabled:
+ break
+ case let .peers(peers):
+ for peer in peers.peers {
+ let peerView = PeerView(primaryColor: self.primaryColor, accountPeerId: peers.accountPeerId, peer: peer, tapped: { [weak self] in
+ if let strongSelf = self, let buildConfig = strongSelf.buildConfig {
+ if let url = URL(string: "\(buildConfig.appSpecificUrlScheme)://localpeer?id=\(peer.id)") {
+ strongSelf.extensionContext?.open(url, completionHandler: nil)
+ }
+ }
+ })
+ self.view.addSubview(peerView)
+ self.peerViews.append(peerView)
+ }
+ }
+
+ if self.peerViews.isEmpty {
+ self.setPlaceholderText(presentationData.applicationStartRequiredString)
+ } else {
+ self.placeholderLabel?.removeFromSuperview()
+ self.placeholderLabel = nil
+ }
+
+ if let size = self.validLayout {
+ self.updateLayout(size: size)
+ }
+ }
+
+ private var validLayout: CGSize?
+
+ private var peerViews: [PeerView] = []
+
+ override func viewDidLayoutSubviews() {
+ super.viewDidLayoutSubviews()
+
+ self.updateLayout(size: self.view.bounds.size)
+ }
+
+ private func updateLayout(size: CGSize) {
+ self.validLayout = size
+
+ if let placeholderLabel = self.placeholderLabel {
+ placeholderLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - placeholderLabel.bounds.width) / 2.0), y: floor((size.height - placeholderLabel.bounds.height) / 2.0)), size: placeholderLabel.bounds.size)
+ }
+
+ let peerSize = CGSize(width: 70.0, height: 100.0)
+
+ var peerFrames: [CGRect] = []
+
+ var offset: CGFloat = 0.0
+ for _ in self.peerViews {
+ let peerFrame = CGRect(origin: CGPoint(x: offset, y: 10.0), size: peerSize)
+ offset += peerFrame.size.width
+ if peerFrame.maxX > size.width {
+ break
+ }
+ peerFrames.append(peerFrame)
+ }
+
+ var totalSize: CGFloat = 0.0
+ for i in 0 ..< peerFrames.count {
+ totalSize += peerFrames[i].width
+ }
+
+ let spacing: CGFloat = floor((size.width - totalSize) / CGFloat(peerFrames.count))
+ offset = floor(spacing / 2.0)
+ for i in 0 ..< peerFrames.count {
+ let peerView = self.peerViews[i]
+ peerView.frame = CGRect(origin: CGPoint(x: offset, y: 16.0), size: peerFrames[i].size)
+ peerView.updateLayout(size: peerFrames[i].size)
+ offset += peerFrames[i].width + spacing
+ }
+ }
+}
diff --git a/Telegram/LegacyWidget/Widget-AppStore.entitlements b/Telegram/LegacyWidget/Widget-AppStore.entitlements
new file mode 100644
index 0000000000..5e963c4f0f
--- /dev/null
+++ b/Telegram/LegacyWidget/Widget-AppStore.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.org.telegram.TelegramHD
+
+
+
diff --git a/Telegram/LegacyWidget/Widget-AppStoreLLC.entitlements b/Telegram/LegacyWidget/Widget-AppStoreLLC.entitlements
new file mode 100644
index 0000000000..c9a9054223
--- /dev/null
+++ b/Telegram/LegacyWidget/Widget-AppStoreLLC.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.ph.telegra.Telegraph
+
+
+
diff --git a/Telegram/LegacyWidget/Widget-Bridging-Header.h b/Telegram/LegacyWidget/Widget-Bridging-Header.h
new file mode 100644
index 0000000000..16747def3f
--- /dev/null
+++ b/Telegram/LegacyWidget/Widget-Bridging-Header.h
@@ -0,0 +1,4 @@
+#ifndef Widget_Bridging_Header_h
+#define Widget_Bridging_Header_h
+
+#endif
diff --git a/Telegram/LegacyWidget/Widget-Fork.entitlements b/Telegram/LegacyWidget/Widget-Fork.entitlements
new file mode 100644
index 0000000000..eb39a047f1
--- /dev/null
+++ b/Telegram/LegacyWidget/Widget-Fork.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.fork.telegram.Telegram-iOS
+
+
+
diff --git a/Telegram/LegacyWidget/Widget-HockeyApp.entitlements b/Telegram/LegacyWidget/Widget-HockeyApp.entitlements
new file mode 100644
index 0000000000..65f2a19d32
--- /dev/null
+++ b/Telegram/LegacyWidget/Widget-HockeyApp.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.org.telegram.Telegram-iOS
+
+
+
diff --git a/Telegram/LegacyWidget/ar.lproj/InfoPlist.strings b/Telegram/LegacyWidget/ar.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..07394dd6c9
--- /dev/null
+++ b/Telegram/LegacyWidget/ar.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "الأشخاص";
diff --git a/Telegram/LegacyWidget/de.lproj/InfoPlist.strings b/Telegram/LegacyWidget/de.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..1ad24433c2
--- /dev/null
+++ b/Telegram/LegacyWidget/de.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "Leute";
diff --git a/Telegram/LegacyWidget/en.lproj/InfoPlist.strings b/Telegram/LegacyWidget/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..b1ddd1ac39
--- /dev/null
+++ b/Telegram/LegacyWidget/en.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "People";
diff --git a/Telegram/LegacyWidget/en.lproj/Localizable.strings b/Telegram/LegacyWidget/en.lproj/Localizable.strings
new file mode 100644
index 0000000000..c90696d0fb
--- /dev/null
+++ b/Telegram/LegacyWidget/en.lproj/Localizable.strings
@@ -0,0 +1,2 @@
+"Widget.NoUsers" = "No users here yet...";
+"Widget.AuthRequired" = "Open Telegram and log in.";
diff --git a/Telegram/LegacyWidget/es.lproj/InfoPlist.strings b/Telegram/LegacyWidget/es.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..3d5094963a
--- /dev/null
+++ b/Telegram/LegacyWidget/es.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "Personas";
diff --git a/Telegram/LegacyWidget/it.lproj/InfoPlist.strings b/Telegram/LegacyWidget/it.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..f118d25a4d
--- /dev/null
+++ b/Telegram/LegacyWidget/it.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "Persone";
diff --git a/Telegram/LegacyWidget/ko.lproj/InfoPlist.strings b/Telegram/LegacyWidget/ko.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..e1bc831c53
--- /dev/null
+++ b/Telegram/LegacyWidget/ko.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "사람";
diff --git a/Telegram/LegacyWidget/nl.lproj/InfoPlist.strings b/Telegram/LegacyWidget/nl.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..a23cbfc4a2
--- /dev/null
+++ b/Telegram/LegacyWidget/nl.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "Mensen";
diff --git a/Telegram/LegacyWidget/pt.lproj/InfoPlist.strings b/Telegram/LegacyWidget/pt.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..a6c032d0ed
--- /dev/null
+++ b/Telegram/LegacyWidget/pt.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "Pessoas";
diff --git a/Telegram/LegacyWidget/ru.lproj/InfoPlist.strings b/Telegram/LegacyWidget/ru.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..689e714f47
--- /dev/null
+++ b/Telegram/LegacyWidget/ru.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+"CFBundleDisplayName" = "Люди";
diff --git a/Telegram/NotificationServiceNext/NotificationServiceNext.swift b/Telegram/NotificationServiceNext/NotificationServiceNext.swift
deleted file mode 100644
index cbf5c7df64..0000000000
--- a/Telegram/NotificationServiceNext/NotificationServiceNext.swift
+++ /dev/null
@@ -1,8 +0,0 @@
-import Foundation
-import UserNotifications
-
-@available(iOSApplicationExtension 10.0, *)
-@objc(NotificationService)
-public final class NotificationService: UNNotificationServiceExtension {
-
-}