From e547ee0075337294d7514392057fb5a36ea12f4b Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 20 Oct 2020 23:00:11 +0400 Subject: [PATCH] Project organization updates --- Telegram/BUCK | 7 +- Telegram/BUILD | 2 +- .../LegacyWidget/TodayViewController.swift | 171 ---------- .../LegacyWidget/Widget-AppStore.entitlements | 10 - .../Widget-AppStoreLLC.entitlements | 10 - .../LegacyWidget/Widget-Bridging-Header.h | 4 - .../LegacyWidget/Widget-Fork.entitlements | 10 - .../Widget-HockeyApp.entitlements | 10 - Telegram/NotificationService/BUCK | 2 - .../NotificationServiceObjC/BUCK | 5 + .../Telegram-iOS/en.lproj/Localizable.strings | 2 + Telegram/Widget/PeerNode.swift | 12 +- Telegram/Widget/TodayViewController.swift | 318 ++++++++---------- .../Info.plist | 0 .../PeerNode.swift | 12 +- .../WidgetKitWidget/TodayViewController.swift | 221 ++++++++++++ .../ar.lproj/InfoPlist.strings | 0 .../de.lproj/InfoPlist.strings | 0 .../en.lproj/InfoPlist.strings | 0 .../en.lproj/Localizable.strings | 0 .../es.lproj/InfoPlist.strings | 0 .../it.lproj/InfoPlist.strings | 0 .../ko.lproj/InfoPlist.strings | 0 .../nl.lproj/InfoPlist.strings | 0 .../pt.lproj/InfoPlist.strings | 0 .../ru.lproj/InfoPlist.strings | 0 submodules/BuildConfig/BUCK | 2 +- submodules/Database/MurmurHash/BUCK | 2 +- third-party/webrtc/BUILD | 2 +- 29 files changed, 381 insertions(+), 421 deletions(-) delete mode 100644 Telegram/LegacyWidget/TodayViewController.swift delete mode 100644 Telegram/LegacyWidget/Widget-AppStore.entitlements delete mode 100644 Telegram/LegacyWidget/Widget-AppStoreLLC.entitlements delete mode 100644 Telegram/LegacyWidget/Widget-Bridging-Header.h delete mode 100644 Telegram/LegacyWidget/Widget-Fork.entitlements delete mode 100644 Telegram/LegacyWidget/Widget-HockeyApp.entitlements delete mode 100644 Telegram/NotificationService/BUCK rename Telegram/{LegacyWidget => WidgetKitWidget}/Info.plist (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/PeerNode.swift (92%) create mode 100644 Telegram/WidgetKitWidget/TodayViewController.swift rename Telegram/{LegacyWidget => WidgetKitWidget}/ar.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/de.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/en.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/en.lproj/Localizable.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/es.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/it.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/ko.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/nl.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/pt.lproj/InfoPlist.strings (100%) rename Telegram/{LegacyWidget => WidgetKitWidget}/ru.lproj/InfoPlist.strings (100%) diff --git a/Telegram/BUCK b/Telegram/BUCK index 0f38d7b3ae..c4684b313b 100644 --- a/Telegram/BUCK +++ b/Telegram/BUCK @@ -315,13 +315,11 @@ apple_bundle( apple_binary( name = "NotificationServiceBinary", srcs = glob([ - "NotificationService/**/*.m", - "NotificationService/**/*.swift", + "NotificationService/*.swift", ]), headers = glob([ - "NotificationService/**/*.h", + "NotificationService/*.h", ]), - bridging_header = "NotificationService/NotificationService-Bridging-Header.h", configs = notification_service_extension_configs(), swift_compiler_flags = [ "-application-extension", @@ -339,6 +337,7 @@ apple_binary( "@executable_path/../../Frameworks", ], deps = [ + "//Telegram/NotificationService/NotificationServiceObjC:NotificationServiceObjC", "//submodules/BuildConfig:BuildConfig", "//submodules/MtProtoKit:MtProtoKit#shared", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared", diff --git a/Telegram/BUILD b/Telegram/BUILD index 1f7950dab1..6ea28c6303 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -1099,7 +1099,7 @@ swift_library( name = "WidgetExtensionLib", module_name = "WidgetExtensionLib", srcs = glob([ - "Widget/**/*.swift", + "WidgetKitWidget/**/*.swift", ]), deps = [ "//submodules/BuildConfig:BuildConfig", diff --git a/Telegram/LegacyWidget/TodayViewController.swift b/Telegram/LegacyWidget/TodayViewController.swift deleted file mode 100644 index f99f7903ce..0000000000 --- a/Telegram/LegacyWidget/TodayViewController.swift +++ /dev/null @@ -1,171 +0,0 @@ -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 deleted file mode 100644 index 5e963c4f0f..0000000000 --- a/Telegram/LegacyWidget/Widget-AppStore.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.application-groups - - group.org.telegram.TelegramHD - - - diff --git a/Telegram/LegacyWidget/Widget-AppStoreLLC.entitlements b/Telegram/LegacyWidget/Widget-AppStoreLLC.entitlements deleted file mode 100644 index c9a9054223..0000000000 --- a/Telegram/LegacyWidget/Widget-AppStoreLLC.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - 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 deleted file mode 100644 index 16747def3f..0000000000 --- a/Telegram/LegacyWidget/Widget-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -#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 deleted file mode 100644 index eb39a047f1..0000000000 --- a/Telegram/LegacyWidget/Widget-Fork.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.application-groups - - group.fork.telegram.Telegram-iOS - - - diff --git a/Telegram/LegacyWidget/Widget-HockeyApp.entitlements b/Telegram/LegacyWidget/Widget-HockeyApp.entitlements deleted file mode 100644 index 65f2a19d32..0000000000 --- a/Telegram/LegacyWidget/Widget-HockeyApp.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.application-groups - - group.org.telegram.Telegram-iOS - - - diff --git a/Telegram/NotificationService/BUCK b/Telegram/NotificationService/BUCK deleted file mode 100644 index e918952b8c..0000000000 --- a/Telegram/NotificationService/BUCK +++ /dev/null @@ -1,2 +0,0 @@ -load("//Config:buck_rule_macros.bzl", "static_library") - diff --git a/Telegram/NotificationService/NotificationServiceObjC/BUCK b/Telegram/NotificationService/NotificationServiceObjC/BUCK index 56d88969a4..4c0ef51377 100644 --- a/Telegram/NotificationService/NotificationServiceObjC/BUCK +++ b/Telegram/NotificationService/NotificationServiceObjC/BUCK @@ -11,6 +11,11 @@ static_library( exported_headers = glob([ "PublicHeaders/**/*.h", ]), + deps = [ + "//submodules/BuildConfig:BuildConfig", + "//submodules/MtProtoKit:MtProtoKit#shared", + "//submodules/NotificationsPresentationData:NotificationsPresentationData", + ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/UIKit.framework", diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index bff6e949ab..5df313806f 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -5861,6 +5861,8 @@ Any member of this group will be able to see messages in the channel."; "Chat.PanelHidePinnedMessages" = "Don't Show Pinned Messages"; "Chat.PanelUnpinAllMessages_1" = "Unpin Message"; "Chat.PanelUnpinAllMessages_any" = "Unpin All %@ Messages"; +"Chat.UnpinAllMessagesConfirmation_1" = "Do you want to unpin 1 message in this chat?"; +"Chat.UnpinAllMessagesConfirmation_any" = "Do you want to unpin all %@ messages in this chat?"; "Chat.MessagesUnpinned_1" = "Message Unpinned"; "Chat.MessagesUnpinned_any" = "%@ Messages Unpinned"; diff --git a/Telegram/Widget/PeerNode.swift b/Telegram/Widget/PeerNode.swift index e1ffc91b47..b89deba9e6 100644 --- a/Telegram/Widget/PeerNode.swift +++ b/Telegram/Widget/PeerNode.swift @@ -39,7 +39,7 @@ private func avatarRoundImage(size: CGSize, source: UIImage) -> UIImage? { } private let deviceColorSpace: CGColorSpace = { - if #available(iOSApplicationExtension 9.3, iOS 9.3, *) { + if #available(iOSApplicationExtension 9.3, *) { if let colorSpace = CGColorSpace(name: CGColorSpace.displayP3) { return colorSpace } else { @@ -94,14 +94,6 @@ private func avatarViewLettersImage(size: CGSize, peerId: Int64, accountPeerId: private let avatarSize = CGSize(width: 50.0, height: 50.0) -func avatarImage(accountPeerId: Int64, peer: WidgetDataPeer, size: CGSize) -> UIImage { - if let path = peer.avatarPath, let image = UIImage(contentsOfFile: path), let roundImage = avatarRoundImage(size: size, source: image) { - return roundImage - } else { - return avatarViewLettersImage(size: size, peerId: peer.id, accountPeerId: accountPeerId, letters: peer.letters)! - } -} - private final class AvatarView: UIImageView { init(accountPeerId: Int64, peer: WidgetDataPeer, size: CGSize) { super.init(frame: CGRect()) @@ -141,7 +133,7 @@ final class PeerView: UIView { let fontSize = floor(systemFontSize * 11.0 / 17.0) self.titleLabel.text = title - if #available(iOSApplicationExtension 13.0, iOS 13.0, *) { + if #available(iOSApplicationExtension 13.0, *) { self.titleLabel.textColor = UIColor.label } else { self.titleLabel.textColor = primaryColor diff --git a/Telegram/Widget/TodayViewController.swift b/Telegram/Widget/TodayViewController.swift index e9285f1436..454691e89d 100644 --- a/Telegram/Widget/TodayViewController.swift +++ b/Telegram/Widget/TodayViewController.swift @@ -3,219 +3,169 @@ import NotificationCenter import BuildConfig import WidgetItems import AppLockState -import SwiftUI -import WidgetKit private func rootPathForBasePath(_ appGroupPath: String) -> String { return appGroupPath + "/telegram-data" } -struct Provider: TimelineProvider { - public typealias Entry = SimpleEntry +@objc(TodayViewController) +class TodayViewController: UIViewController, NCWidgetProviding { + private var initializedInterface = false - func placeholder(in context: Context) -> SimpleEntry { - return SimpleEntry(date: Date()) - } + private var buildConfig: BuildConfig? - func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) { - let entry = SimpleEntry(date: Date()) - completion(entry) - } + private var primaryColor: UIColor = .black + private var placeholderLabel: UILabel? - func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { - var entries: [SimpleEntry] = [] + override func viewDidLoad() { + super.viewDidLoad() - let currentDate = Date() - for hourOffset in 0 ..< 1 { - let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! - let entry = SimpleEntry(date: entryDate) - entries.append(entry) + let appBundleIdentifier = Bundle.main.bundleIdentifier! + guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else { + return } - - let timeline = Timeline(entries: entries, policy: .atEnd) - completion(timeline) - } -} - -struct SimpleEntry: TimelineEntry { - let date: Date -} - -enum PeersWidgetData { - case placeholder - case empty - case locked - case data(WidgetData) -} - -extension PeersWidgetData { - static let previewData = PeersWidgetData.placeholder -} - -struct WidgetView: View { - let data: PeersWidgetData - - func placeholder(geometry: GeometryProxy) -> some View { - let defaultItemSize: CGFloat = 60.0 - let defaultPaddingFraction: CGFloat = 0.36 + let baseAppBundleId = String(appBundleIdentifier[.. some View { - let defaultItemSize: CGFloat = 60.0 - let defaultPaddingFraction: CGFloat = 0.36 - - let rowCount = Int(round(geometry.size.width / (defaultItemSize * (1.0 + defaultPaddingFraction)))) - let itemSize = floor(geometry.size.width / (CGFloat(rowCount) + defaultPaddingFraction * CGFloat(rowCount - 1))) - - let firstRowY = itemSize / 2.0 - let secondRowY = itemSize / 2.0 + geometry.size.height - itemSize - - return ZStack { - ForEach(0 ..< min(peers.peers.count, rowCount * 2), content: { i in - Link(destination: URL(string: "\(buildConfig.appSpecificUrlScheme)://localpeer?id=\(peers.peers[i].id)")!, label: { - Image(uiImage: avatarImage(accountPeerId: peers.accountPeerId, peer: peers.peers[i], size: CGSize(width: itemSize, height: itemSize))) - .frame(width: itemSize, height: itemSize) - }).frame(width: itemSize, height: itemSize) - .position(x: itemSize / 2.0 + floor(CGFloat(i % rowCount) * itemSize * (1.0 + defaultPaddingFraction)), y: i / rowCount == 0 ? firstRowY : secondRowY) - }) + private func setPlaceholderText(_ text: String) { + let fontSize = UIFont.preferredFont(forTextStyle: .body).pointSize + let placeholderLabel = UILabel() + if #available(iOSApplicationExtension 13.0, *) { + placeholderLabel.textColor = UIColor.label + } else { + placeholderLabel.textColor = self.primaryColor } + placeholderLabel.font = UIFont.systemFont(ofSize: fontSize) + placeholderLabel.text = text + placeholderLabel.sizeToFit() + self.placeholderLabel = placeholderLabel + self.view.addSubview(placeholderLabel) } - func peerViews() -> AnyView { - switch data { - case .placeholder: - return AnyView(GeometryReader { geometry in - placeholder(geometry: geometry) - }) - case .empty: - return AnyView(VStack { - Text(presentationData.applicationStartRequiredString) - }) - case .locked: - return AnyView(VStack { - Text(presentationData.applicationLockedString) - }) - case let .data(data): - switch data { - case let .peers(peers): - return AnyView(GeometryReader { geometry in - peersView(geometry: geometry, peers: peers) - }) - default: - return AnyView(ZStack { - Circle() + func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> 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) } } - } - - var body: some View { - ZStack { - Color(.systemBackground) - peerViews() + + if self.peerViews.isEmpty { + self.setPlaceholderText(presentationData.applicationStartRequiredString) + } else { + self.placeholderLabel?.removeFromSuperview() + self.placeholderLabel = nil + } + + if let size = self.validLayout { + self.updateLayout(size: size) } - .padding(.all) - } -} - -private let buildConfig: BuildConfig = { - let appBundleIdentifier = Bundle.main.bundleIdentifier! - guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else { - preconditionFailure() - } - let baseAppBundleId = String(appBundleIdentifier[.. PeersWidgetData { - let appBundleIdentifier = Bundle.main.bundleIdentifier! - guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else { - return .placeholder - } - let baseAppBundleId = String(appBundleIdentifier[.. size.width { + break } - ) - .supportedFamilies([.systemMedium]) - .configurationDisplayName(presentationData.widgetGalleryTitle) - .description(presentationData.widgetGalleryDescription) + 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/Info.plist b/Telegram/WidgetKitWidget/Info.plist similarity index 100% rename from Telegram/LegacyWidget/Info.plist rename to Telegram/WidgetKitWidget/Info.plist diff --git a/Telegram/LegacyWidget/PeerNode.swift b/Telegram/WidgetKitWidget/PeerNode.swift similarity index 92% rename from Telegram/LegacyWidget/PeerNode.swift rename to Telegram/WidgetKitWidget/PeerNode.swift index b89deba9e6..e1ffc91b47 100644 --- a/Telegram/LegacyWidget/PeerNode.swift +++ b/Telegram/WidgetKitWidget/PeerNode.swift @@ -39,7 +39,7 @@ private func avatarRoundImage(size: CGSize, source: UIImage) -> UIImage? { } private let deviceColorSpace: CGColorSpace = { - if #available(iOSApplicationExtension 9.3, *) { + if #available(iOSApplicationExtension 9.3, iOS 9.3, *) { if let colorSpace = CGColorSpace(name: CGColorSpace.displayP3) { return colorSpace } else { @@ -94,6 +94,14 @@ private func avatarViewLettersImage(size: CGSize, peerId: Int64, accountPeerId: private let avatarSize = CGSize(width: 50.0, height: 50.0) +func avatarImage(accountPeerId: Int64, peer: WidgetDataPeer, size: CGSize) -> UIImage { + if let path = peer.avatarPath, let image = UIImage(contentsOfFile: path), let roundImage = avatarRoundImage(size: size, source: image) { + return roundImage + } else { + return avatarViewLettersImage(size: size, peerId: peer.id, accountPeerId: accountPeerId, letters: peer.letters)! + } +} + private final class AvatarView: UIImageView { init(accountPeerId: Int64, peer: WidgetDataPeer, size: CGSize) { super.init(frame: CGRect()) @@ -133,7 +141,7 @@ final class PeerView: UIView { let fontSize = floor(systemFontSize * 11.0 / 17.0) self.titleLabel.text = title - if #available(iOSApplicationExtension 13.0, *) { + if #available(iOSApplicationExtension 13.0, iOS 13.0, *) { self.titleLabel.textColor = UIColor.label } else { self.titleLabel.textColor = primaryColor diff --git a/Telegram/WidgetKitWidget/TodayViewController.swift b/Telegram/WidgetKitWidget/TodayViewController.swift new file mode 100644 index 0000000000..e9285f1436 --- /dev/null +++ b/Telegram/WidgetKitWidget/TodayViewController.swift @@ -0,0 +1,221 @@ +import UIKit +import NotificationCenter +import BuildConfig +import WidgetItems +import AppLockState +import SwiftUI +import WidgetKit + +private func rootPathForBasePath(_ appGroupPath: String) -> String { + return appGroupPath + "/telegram-data" +} + +struct Provider: TimelineProvider { + public typealias Entry = SimpleEntry + + func placeholder(in context: Context) -> SimpleEntry { + return SimpleEntry(date: Date()) + } + + func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + var entries: [SimpleEntry] = [] + + let currentDate = Date() + for hourOffset in 0 ..< 1 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate) + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date +} + +enum PeersWidgetData { + case placeholder + case empty + case locked + case data(WidgetData) +} + +extension PeersWidgetData { + static let previewData = PeersWidgetData.placeholder +} + +struct WidgetView: View { + let data: PeersWidgetData + + func placeholder(geometry: GeometryProxy) -> some View { + let defaultItemSize: CGFloat = 60.0 + let defaultPaddingFraction: CGFloat = 0.36 + + let rowCount = Int(round(geometry.size.width / (defaultItemSize * (1.0 + defaultPaddingFraction)))) + let itemSize = floor(geometry.size.width / (CGFloat(rowCount) + defaultPaddingFraction * CGFloat(rowCount - 1))) + + let firstRowY = itemSize / 2.0 + let secondRowY = itemSize / 2.0 + geometry.size.height - itemSize + + return ZStack { + ForEach(0 ..< rowCount * 2, content: { i in + return Circle().frame(width: itemSize, height: itemSize).position(x: itemSize / 2.0 + floor(CGFloat(i % rowCount) * itemSize * (1.0 + defaultPaddingFraction)), y: i / rowCount == 0 ? firstRowY : secondRowY).foregroundColor(.gray) + }) + } + } + + func peersView(geometry: GeometryProxy, peers: WidgetDataPeers) -> some View { + let defaultItemSize: CGFloat = 60.0 + let defaultPaddingFraction: CGFloat = 0.36 + + let rowCount = Int(round(geometry.size.width / (defaultItemSize * (1.0 + defaultPaddingFraction)))) + let itemSize = floor(geometry.size.width / (CGFloat(rowCount) + defaultPaddingFraction * CGFloat(rowCount - 1))) + + let firstRowY = itemSize / 2.0 + let secondRowY = itemSize / 2.0 + geometry.size.height - itemSize + + return ZStack { + ForEach(0 ..< min(peers.peers.count, rowCount * 2), content: { i in + Link(destination: URL(string: "\(buildConfig.appSpecificUrlScheme)://localpeer?id=\(peers.peers[i].id)")!, label: { + Image(uiImage: avatarImage(accountPeerId: peers.accountPeerId, peer: peers.peers[i], size: CGSize(width: itemSize, height: itemSize))) + .frame(width: itemSize, height: itemSize) + }).frame(width: itemSize, height: itemSize) + .position(x: itemSize / 2.0 + floor(CGFloat(i % rowCount) * itemSize * (1.0 + defaultPaddingFraction)), y: i / rowCount == 0 ? firstRowY : secondRowY) + }) + } + } + + func peerViews() -> AnyView { + switch data { + case .placeholder: + return AnyView(GeometryReader { geometry in + placeholder(geometry: geometry) + }) + case .empty: + return AnyView(VStack { + Text(presentationData.applicationStartRequiredString) + }) + case .locked: + return AnyView(VStack { + Text(presentationData.applicationLockedString) + }) + case let .data(data): + switch data { + case let .peers(peers): + return AnyView(GeometryReader { geometry in + peersView(geometry: geometry, peers: peers) + }) + default: + return AnyView(ZStack { + Circle() + }) + } + } + } + + var body: some View { + ZStack { + Color(.systemBackground) + peerViews() + } + .padding(.all) + } +} + +private let buildConfig: BuildConfig = { + let appBundleIdentifier = Bundle.main.bundleIdentifier! + guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else { + preconditionFailure() + } + let baseAppBundleId = String(appBundleIdentifier[.. PeersWidgetData { + let appBundleIdentifier = Bundle.main.bundleIdentifier! + guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else { + return .placeholder + } + let baseAppBundleId = String(appBundleIdentifier[..