mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Update widget
This commit is contained in:
parent
bddf1b565e
commit
1efcf53ca6
@ -19,6 +19,8 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>INIntentCategory</key>
|
<key>INIntentCategory</key>
|
||||||
<string>information</string>
|
<string>information</string>
|
||||||
|
<key>INIntentDescription</key>
|
||||||
|
<string>Display the latest message from the most important chats.</string>
|
||||||
<key>INIntentDescriptionID</key>
|
<key>INIntentDescriptionID</key>
|
||||||
<string>jmsEbj</string>
|
<string>jmsEbj</string>
|
||||||
<key>INIntentEligibleForWidgets</key>
|
<key>INIntentEligibleForWidgets</key>
|
||||||
@ -56,7 +58,7 @@
|
|||||||
<key>INIntentParameterConfigurable</key>
|
<key>INIntentParameterConfigurable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>INIntentParameterDisplayName</key>
|
<key>INIntentParameterDisplayName</key>
|
||||||
<string> </string>
|
<string>SELECT CHATS</string>
|
||||||
<key>INIntentParameterDisplayNameID</key>
|
<key>INIntentParameterDisplayNameID</key>
|
||||||
<string>WIf4LD</string>
|
<string>WIf4LD</string>
|
||||||
<key>INIntentParameterDisplayPriority</key>
|
<key>INIntentParameterDisplayPriority</key>
|
||||||
@ -124,7 +126,7 @@
|
|||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
<key>INIntentTitle</key>
|
<key>INIntentTitle</key>
|
||||||
<string>Select Chats</string>
|
<string>Chats</string>
|
||||||
<key>INIntentTitleID</key>
|
<key>INIntentTitleID</key>
|
||||||
<string>lMot0c</string>
|
<string>lMot0c</string>
|
||||||
<key>INIntentType</key>
|
<key>INIntentType</key>
|
||||||
@ -135,6 +137,8 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>INIntentCategory</key>
|
<key>INIntentCategory</key>
|
||||||
<string>information</string>
|
<string>information</string>
|
||||||
|
<key>INIntentDescription</key>
|
||||||
|
<string>"Display shortcuts of your most important chats to always have quick access to them.</string>
|
||||||
<key>INIntentDescriptionID</key>
|
<key>INIntentDescriptionID</key>
|
||||||
<string>DwL4WQ</string>
|
<string>DwL4WQ</string>
|
||||||
<key>INIntentEligibleForWidgets</key>
|
<key>INIntentEligibleForWidgets</key>
|
||||||
@ -172,7 +176,7 @@
|
|||||||
<key>INIntentParameterConfigurable</key>
|
<key>INIntentParameterConfigurable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>INIntentParameterDisplayName</key>
|
<key>INIntentParameterDisplayName</key>
|
||||||
<string> </string>
|
<string>SELECT CHATS</string>
|
||||||
<key>INIntentParameterDisplayNameID</key>
|
<key>INIntentParameterDisplayNameID</key>
|
||||||
<string>Jg5dYF</string>
|
<string>Jg5dYF</string>
|
||||||
<key>INIntentParameterDisplayPriority</key>
|
<key>INIntentParameterDisplayPriority</key>
|
||||||
@ -240,7 +244,7 @@
|
|||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
<key>INIntentTitle</key>
|
<key>INIntentTitle</key>
|
||||||
<string>Select Chats</string>
|
<string>Shortcuts</string>
|
||||||
<key>INIntentTitleID</key>
|
<key>INIntentTitleID</key>
|
||||||
<string>3Sbb7H</string>
|
<string>3Sbb7H</string>
|
||||||
<key>INIntentType</key>
|
<key>INIntentType</key>
|
||||||
|
@ -1161,6 +1161,12 @@ plist_fragment(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "WidgetAssets",
|
||||||
|
srcs = glob(["WidgetKitWidget/WidgetImages.xcassets/**"]),
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
swift_library(
|
swift_library(
|
||||||
name = "WidgetExtensionLib",
|
name = "WidgetExtensionLib",
|
||||||
module_name = "WidgetExtensionLib",
|
module_name = "WidgetExtensionLib",
|
||||||
@ -1168,7 +1174,7 @@ swift_library(
|
|||||||
"WidgetKitWidget/**/*.swift",
|
"WidgetKitWidget/**/*.swift",
|
||||||
]),
|
]),
|
||||||
data = [
|
data = [
|
||||||
#"SiriIntents/Intents.intentdefinition",
|
":WidgetAssets",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//submodules/BuildConfig:BuildConfig",
|
"//submodules/BuildConfig:BuildConfig",
|
||||||
@ -1205,7 +1211,9 @@ ios_extension(
|
|||||||
":disableProvisioningProfilesSetting": None,
|
":disableProvisioningProfilesSetting": None,
|
||||||
"//conditions:default": "@build_configuration//provisioning:Widget.mobileprovision",
|
"//conditions:default": "@build_configuration//provisioning:Widget.mobileprovision",
|
||||||
}),
|
}),
|
||||||
deps = [":WidgetExtensionLib"],
|
deps = [
|
||||||
|
":WidgetExtensionLib",
|
||||||
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
":SwiftSignalKitFramework",
|
":SwiftSignalKitFramework",
|
||||||
":PostboxFramework",
|
":PostboxFramework",
|
||||||
|
@ -87,11 +87,16 @@ struct Provider: IntentTimelineProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getSnapshot(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
func getSnapshot(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
||||||
let entry = SimpleEntry(date: Date(), contents: .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0))))
|
let entry = SimpleEntry(date: Date(), contents: context.isPreview ? .preview : .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0))))
|
||||||
completion(entry)
|
completion(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTimeline(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
func getTimeline(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
if context.isPreview {
|
||||||
|
completion(Timeline(entries: [SimpleEntry(date: Date(), contents: .preview)], policy: .atEnd))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let currentDate = Date()
|
let currentDate = Date()
|
||||||
let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)!
|
let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)!
|
||||||
|
|
||||||
@ -240,11 +245,16 @@ struct AvatarsProvider: IntentTimelineProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getSnapshot(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
func getSnapshot(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
||||||
let entry = SimpleEntry(date: Date(), contents: .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0))))
|
let entry = SimpleEntry(date: Date(), contents: context.isPreview ? .preview : .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0))))
|
||||||
completion(entry)
|
completion(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTimeline(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
func getTimeline(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
if context.isPreview {
|
||||||
|
completion(Timeline(entries: [SimpleEntry(date: Date(), contents: .preview)], policy: .atEnd))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let currentDate = Date()
|
let currentDate = Date()
|
||||||
let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)!
|
let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)!
|
||||||
|
|
||||||
@ -388,6 +398,7 @@ struct AvatarsProvider: IntentTimelineProvider {
|
|||||||
struct SimpleEntry: TimelineEntry {
|
struct SimpleEntry: TimelineEntry {
|
||||||
enum Contents {
|
enum Contents {
|
||||||
case recent
|
case recent
|
||||||
|
case preview
|
||||||
case peers(ParsedPeers)
|
case peers(ParsedPeers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,13 +408,10 @@ struct SimpleEntry: TimelineEntry {
|
|||||||
|
|
||||||
enum PeersWidgetData {
|
enum PeersWidgetData {
|
||||||
case empty
|
case empty
|
||||||
|
case preview
|
||||||
case peers(ParsedPeers)
|
case peers(ParsedPeers)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PeersWidgetData {
|
|
||||||
static let previewData = PeersWidgetData.empty
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AvatarItemView: View {
|
struct AvatarItemView: View {
|
||||||
var peer: ParsedPeer?
|
var peer: ParsedPeer?
|
||||||
var itemSize: CGFloat
|
var itemSize: CGFloat
|
||||||
@ -428,23 +436,6 @@ struct WidgetView: View {
|
|||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
let data: PeersWidgetData
|
let data: PeersWidgetData
|
||||||
|
|
||||||
func placeholder(geometry: GeometryProxy) -> some View {
|
|
||||||
let defaultItemSize: CGFloat = 60.0
|
|
||||||
let defaultPaddingFraction: CGFloat = 0.36
|
|
||||||
|
|
||||||
let columnCount = Int(round(geometry.size.width / (defaultItemSize * (1.0 + defaultPaddingFraction))))
|
|
||||||
let itemSize = floor(geometry.size.width / (CGFloat(columnCount) + defaultPaddingFraction * CGFloat(columnCount - 1)))
|
|
||||||
|
|
||||||
let firstRowY = itemSize / 2.0
|
|
||||||
let secondRowY = itemSize / 2.0 + geometry.size.height - itemSize
|
|
||||||
|
|
||||||
return ZStack {
|
|
||||||
ForEach(0 ..< columnCount * 2, content: { i in
|
|
||||||
return Circle().frame(width: itemSize, height: itemSize).position(x: itemSize / 2.0 + floor(CGFloat(i % columnCount) * itemSize * (1.0 + defaultPaddingFraction)), y: i / columnCount == 0 ? firstRowY : secondRowY).foregroundColor(.gray)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func linkForPeer(accountId: Int64, id: Int64) -> String {
|
private func linkForPeer(accountId: Int64, id: Int64) -> String {
|
||||||
switch self.widgetFamily {
|
switch self.widgetFamily {
|
||||||
case .systemSmall:
|
case .systemSmall:
|
||||||
@ -454,94 +445,15 @@ struct WidgetView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func peersView(geometry: GeometryProxy, peers: ParsedPeers) -> some View {
|
func chatTopLine(_ content: ChatContent) -> some View {
|
||||||
let columnCount: Int
|
|
||||||
let rowCount: Int
|
|
||||||
|
|
||||||
let itemSizeFraction: CGFloat
|
|
||||||
let horizontalInsetFraction: CGFloat
|
|
||||||
let verticalInsetFraction: CGFloat
|
|
||||||
let horizontalSpacingFraction: CGFloat
|
|
||||||
let verticalSpacingFraction: CGFloat
|
|
||||||
|
|
||||||
switch self.widgetFamily {
|
|
||||||
case .systemLarge:
|
|
||||||
itemSizeFraction = 0.1762917933
|
|
||||||
horizontalInsetFraction = 0.04863221884
|
|
||||||
verticalInsetFraction = 0.04863221884
|
|
||||||
horizontalSpacingFraction = 0.06079027356
|
|
||||||
verticalSpacingFraction = 0.06079027356
|
|
||||||
columnCount = 4
|
|
||||||
rowCount = 4
|
|
||||||
case .systemMedium:
|
|
||||||
itemSizeFraction = 0.1762917933
|
|
||||||
horizontalInsetFraction = 0.04863221884
|
|
||||||
verticalInsetFraction = 0.1032258065
|
|
||||||
horizontalSpacingFraction = 0.06079027356
|
|
||||||
verticalSpacingFraction = 0.07741935484
|
|
||||||
columnCount = 4
|
|
||||||
rowCount = 2
|
|
||||||
case .systemSmall:
|
|
||||||
itemSizeFraction = 0.335483871
|
|
||||||
horizontalInsetFraction = 0.1032258065
|
|
||||||
verticalInsetFraction = 0.1032258065
|
|
||||||
horizontalSpacingFraction = 0.1161290323
|
|
||||||
verticalSpacingFraction = 0.1161290323
|
|
||||||
columnCount = 2
|
|
||||||
rowCount = 2
|
|
||||||
@unknown default:
|
|
||||||
itemSizeFraction = 0.335483871
|
|
||||||
horizontalInsetFraction = 0.1032258065
|
|
||||||
verticalInsetFraction = 0.1032258065
|
|
||||||
horizontalSpacingFraction = 0.1161290323
|
|
||||||
verticalSpacingFraction = 0.1161290323
|
|
||||||
columnCount = 2
|
|
||||||
rowCount = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
let itemSize = floor(geometry.size.width * itemSizeFraction)
|
|
||||||
|
|
||||||
return ZStack {
|
|
||||||
ForEach(0 ..< min(peers.peers.count, columnCount * rowCount), content: { i in
|
|
||||||
Link(destination: URL(string: linkForPeer(accountId: peers.peers[i].accountId, id: peers.peers[i].peer.id))!, label: {
|
|
||||||
AvatarItemView(
|
|
||||||
peer: peers.peers[i],
|
|
||||||
itemSize: itemSize,
|
|
||||||
placeholderColor: getPlaceholderColor()
|
|
||||||
).frame(width: itemSize, height: itemSize)
|
|
||||||
}).frame(width: itemSize, height: itemSize)
|
|
||||||
.position(x: floor(horizontalInsetFraction * geometry.size.width + itemSize / 2.0 + CGFloat(i % columnCount) * (itemSize + horizontalSpacingFraction * geometry.size.width)), y: floor(verticalInsetFraction * geometry.size.height + itemSize / 2.0 + CGFloat(i / columnCount) * (itemSize + verticalSpacingFraction * geometry.size.height)))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func peerViews() -> AnyView {
|
|
||||||
switch data {
|
|
||||||
case .empty:
|
|
||||||
return AnyView(GeometryReader { geometry in
|
|
||||||
placeholder(geometry: geometry)
|
|
||||||
})
|
|
||||||
case let .peers(peers):
|
|
||||||
return AnyView(GeometryReader { geometry in
|
|
||||||
peersView(geometry: geometry, peers: peers)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var body1: some View {
|
|
||||||
ZStack {
|
|
||||||
peerViews()
|
|
||||||
}
|
|
||||||
.padding(0.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func chatTopLine(_ peer: ParsedPeer?) -> some View {
|
|
||||||
let dateText: String
|
let dateText: String
|
||||||
|
|
||||||
let chatTitle: AnyView
|
let chatTitle: AnyView
|
||||||
let date: Text
|
let date: Text
|
||||||
|
var isPlaceholder = false
|
||||||
|
|
||||||
if let peer = peer {
|
switch content {
|
||||||
|
case let .peer(peer):
|
||||||
if let message = peer.peer.message {
|
if let message = peer.peer.message {
|
||||||
dateText = DateFormatter.localizedString(from: Date(timeIntervalSince1970: Double(message.timestamp)), dateStyle: .none, timeStyle: .short)
|
dateText = DateFormatter.localizedString(from: Date(timeIntervalSince1970: Double(message.timestamp)), dateStyle: .none, timeStyle: .short)
|
||||||
} else {
|
} else {
|
||||||
@ -553,14 +465,23 @@ struct WidgetView: View {
|
|||||||
.foregroundColor(.primary))
|
.foregroundColor(.primary))
|
||||||
date = Text(dateText)
|
date = Text(dateText)
|
||||||
.font(Font.system(size: 14.0, weight: .regular, design: .default)).foregroundColor(.secondary)
|
.font(Font.system(size: 14.0, weight: .regular, design: .default)).foregroundColor(.secondary)
|
||||||
} else {
|
case let .preview(index):
|
||||||
|
dateText = index == 0 ? "9:00" : "8:42"
|
||||||
|
chatTitle = AnyView(Text("News Channel")
|
||||||
|
.lineLimit(1)
|
||||||
|
.font(Font.system(size: 16.0, weight: .medium, design: .default))
|
||||||
|
.foregroundColor(.primary))
|
||||||
|
date = Text(dateText)
|
||||||
|
.font(Font.system(size: 14.0, weight: .regular, design: .default)).foregroundColor(.secondary)
|
||||||
|
case .placeholder:
|
||||||
|
isPlaceholder = true
|
||||||
dateText = " "
|
dateText = " "
|
||||||
chatTitle = AnyView(Text(" ").font(Font.system(size: 16.0, weight: .medium, design: .default)).foregroundColor(.primary))
|
chatTitle = AnyView(Text(" ").font(Font.system(size: 16.0, weight: .medium, design: .default)).foregroundColor(.primary))
|
||||||
date = Text(dateText)
|
date = Text(dateText)
|
||||||
.font(Font.system(size: 16.0, weight: .regular, design: .default)).foregroundColor(.secondary)
|
.font(Font.system(size: 16.0, weight: .regular, design: .default)).foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
return HStack(alignment: .center, spacing: 0.0, content: {
|
return HStack(alignment: .center, spacing: 0.0, content: {
|
||||||
if peer != nil {
|
if !isPlaceholder {
|
||||||
chatTitle
|
chatTitle
|
||||||
} else {
|
} else {
|
||||||
chatTitle
|
chatTitle
|
||||||
@ -574,7 +495,7 @@ struct WidgetView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
if peer != nil {
|
if !isPlaceholder {
|
||||||
date
|
date
|
||||||
} else {
|
} else {
|
||||||
date
|
date
|
||||||
@ -590,78 +511,88 @@ struct WidgetView: View {
|
|||||||
.padding(0.0)
|
.padding(0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatBottomLine(_ peer: ParsedPeer?) -> AnyView {
|
func chatBottomLine(_ content: ChatContent) -> AnyView {
|
||||||
var text = peer?.peer.message?.text ?? ""
|
var text = ""
|
||||||
text += "\n"
|
var isPlaceholder = false
|
||||||
if peer == nil {
|
switch content {
|
||||||
text = "First Line Of Text Here\nSecond line fwqefeqwfqwef qwef wq"
|
case let .peer(peer):
|
||||||
}
|
if let message = peer.peer.message {
|
||||||
if let message = peer?.peer.message {
|
//TODO:localize
|
||||||
//TODO:localize
|
switch message.content {
|
||||||
switch message.content {
|
case .text:
|
||||||
case .text:
|
break
|
||||||
break
|
case .image:
|
||||||
case .image:
|
if !message.text.isEmpty {
|
||||||
if !message.text.isEmpty {
|
text = "🖼 \(message.text)"
|
||||||
text = "🖼 \(message.text)"
|
} else {
|
||||||
} else {
|
text = "🖼 Photo"
|
||||||
text = "🖼 Photo"
|
}
|
||||||
|
case .video:
|
||||||
|
if !message.text.isEmpty {
|
||||||
|
text = "📹 \(message.text)"
|
||||||
|
} else {
|
||||||
|
text = "📹 Video"
|
||||||
|
}
|
||||||
|
case .gif:
|
||||||
|
if !message.text.isEmpty {
|
||||||
|
text = "\(message.text)"
|
||||||
|
} else {
|
||||||
|
text = "Gif"
|
||||||
|
}
|
||||||
|
case let .file(file):
|
||||||
|
if !message.text.isEmpty {
|
||||||
|
text = "📹 \(message.text)"
|
||||||
|
} else {
|
||||||
|
text = "📎 \(file.name)"
|
||||||
|
}
|
||||||
|
case let .music(music):
|
||||||
|
if !music.title.isEmpty && !music.artist.isEmpty {
|
||||||
|
text = "\(music.artist) — \(music.title)"
|
||||||
|
} else if !music.title.isEmpty {
|
||||||
|
text = music.title
|
||||||
|
} else if !music.artist.isEmpty {
|
||||||
|
text = music.artist
|
||||||
|
} else {
|
||||||
|
text = "Music"
|
||||||
|
}
|
||||||
|
case .voiceMessage:
|
||||||
|
text = "🎤 Voice Message"
|
||||||
|
case .videoMessage:
|
||||||
|
text = "Video Message"
|
||||||
|
case let .sticker(sticker):
|
||||||
|
text = "\(sticker.altText) Sticker"
|
||||||
|
case let .call(call):
|
||||||
|
if call.isVideo {
|
||||||
|
text = "Video Call"
|
||||||
|
} else {
|
||||||
|
text = "Voice Call"
|
||||||
|
}
|
||||||
|
case .mapLocation:
|
||||||
|
text = "Location"
|
||||||
|
case let .game(game):
|
||||||
|
text = "🎮 \(game.title)"
|
||||||
|
case let .poll(poll):
|
||||||
|
text = "📊 \(poll.title)"
|
||||||
}
|
}
|
||||||
case .video:
|
|
||||||
if !message.text.isEmpty {
|
if let author = message.author {
|
||||||
text = "📹 \(message.text)"
|
if author.isMe {
|
||||||
} else {
|
text = "You: \(text)"
|
||||||
text = "📹 Video"
|
} else {
|
||||||
}
|
text = "\(author.title): \(text)"
|
||||||
case .gif:
|
}
|
||||||
if !message.text.isEmpty {
|
|
||||||
text = "\(message.text)"
|
|
||||||
} else {
|
|
||||||
text = "Gif"
|
|
||||||
}
|
|
||||||
case let .file(file):
|
|
||||||
if !message.text.isEmpty {
|
|
||||||
text = "📹 \(message.text)"
|
|
||||||
} else {
|
|
||||||
text = "📎 \(file.name)"
|
|
||||||
}
|
|
||||||
case let .music(music):
|
|
||||||
if !music.title.isEmpty && !music.artist.isEmpty {
|
|
||||||
text = "\(music.artist) — \(music.title)"
|
|
||||||
} else if !music.title.isEmpty {
|
|
||||||
text = music.title
|
|
||||||
} else if !music.artist.isEmpty {
|
|
||||||
text = music.artist
|
|
||||||
} else {
|
|
||||||
text = "Music"
|
|
||||||
}
|
|
||||||
case .voiceMessage:
|
|
||||||
text = "🎤 Voice Message"
|
|
||||||
case .videoMessage:
|
|
||||||
text = "Video Message"
|
|
||||||
case let .sticker(sticker):
|
|
||||||
text = "\(sticker.altText) Sticker"
|
|
||||||
case let .call(call):
|
|
||||||
if call.isVideo {
|
|
||||||
text = "Video Call"
|
|
||||||
} else {
|
|
||||||
text = "Voice Call"
|
|
||||||
}
|
|
||||||
case .mapLocation:
|
|
||||||
text = "Location"
|
|
||||||
case let .game(game):
|
|
||||||
text = "🎮 \(game.title)"
|
|
||||||
case let .poll(poll):
|
|
||||||
text = "📊 \(poll.title)"
|
|
||||||
}
|
|
||||||
|
|
||||||
if let author = message.author {
|
|
||||||
if author.isMe {
|
|
||||||
text = "You: \(text)"
|
|
||||||
} else {
|
|
||||||
text = "\(author.title): \(text)"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
text += "\n"
|
||||||
|
case let .preview(index):
|
||||||
|
if index == 0 {
|
||||||
|
text = "☀️ 23 °C\n☁️ Passing Clouds"
|
||||||
|
} else {
|
||||||
|
text = "😂 Sticker"
|
||||||
|
text += "\n"
|
||||||
|
}
|
||||||
|
case .placeholder:
|
||||||
|
isPlaceholder = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let textView = Text(text)
|
let textView = Text(text)
|
||||||
@ -671,7 +602,7 @@ struct WidgetView: View {
|
|||||||
.multilineTextAlignment(.leading)
|
.multilineTextAlignment(.leading)
|
||||||
.padding(0.0)
|
.padding(0.0)
|
||||||
|
|
||||||
if peer != nil {
|
if !isPlaceholder {
|
||||||
return AnyView(textView)
|
return AnyView(textView)
|
||||||
} else {
|
} else {
|
||||||
return AnyView(
|
return AnyView(
|
||||||
@ -709,16 +640,23 @@ struct WidgetView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatContent(_ peer: ParsedPeer?) -> some View {
|
enum ChatContent {
|
||||||
|
case peer(ParsedPeer)
|
||||||
|
case preview(Int)
|
||||||
|
case placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
func chatContent(_ content: ChatContent) -> some View {
|
||||||
return VStack(alignment: .leading, spacing: 0.0, content: {
|
return VStack(alignment: .leading, spacing: 0.0, content: {
|
||||||
chatTopLine(peer)
|
chatTopLine(content)
|
||||||
chatBottomLine(peer)
|
chatBottomLine(content)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatContentView(_ index: Int, size: CGSize) -> AnyView {
|
func chatContentView(_ index: Int, size: CGSize) -> AnyView {
|
||||||
let peers: ParsedPeers?
|
let peers: ParsedPeers?
|
||||||
var isPlaceholder = false
|
var isPlaceholder = false
|
||||||
|
var isPreview = false
|
||||||
switch data {
|
switch data {
|
||||||
case let .peers(peersValue):
|
case let .peers(peersValue):
|
||||||
if peersValue.peers.count <= index {
|
if peersValue.peers.count <= index {
|
||||||
@ -727,6 +665,9 @@ struct WidgetView: View {
|
|||||||
} else {
|
} else {
|
||||||
peers = peersValue
|
peers = peersValue
|
||||||
}
|
}
|
||||||
|
case .preview:
|
||||||
|
peers = nil
|
||||||
|
isPreview = true
|
||||||
default:
|
default:
|
||||||
peers = nil
|
peers = nil
|
||||||
}
|
}
|
||||||
@ -739,6 +680,20 @@ struct WidgetView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isPreview {
|
||||||
|
return AnyView(
|
||||||
|
HStack(alignment: .center, spacing: 0.0, content: {
|
||||||
|
Image("Widget/Avatar\(index == 0 ? "Channel" : "1")")
|
||||||
|
.aspectRatio(1.0, contentMode: .fit)
|
||||||
|
.clipShape(Circle())
|
||||||
|
.frame(width: 54.0, height: 54.0, alignment: .leading)
|
||||||
|
.padding(EdgeInsets(top: 0.0, leading: 10.0, bottom: 0.0, trailing: 10.0))
|
||||||
|
chatContent(.preview(index)).frame(maxWidth: .infinity).padding(EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 10.0))
|
||||||
|
})
|
||||||
|
.frame(width: size.width, height: itemHeight, alignment: .leading)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let url: URL
|
let url: URL
|
||||||
if let peers = peers {
|
if let peers = peers {
|
||||||
url = URL(string: linkForPeer(accountId: peers.peers[index].accountId, id: peers.peers[index].peer.id))!
|
url = URL(string: linkForPeer(accountId: peers.peers[index].accountId, id: peers.peers[index].peer.id))!
|
||||||
@ -746,11 +701,18 @@ struct WidgetView: View {
|
|||||||
url = URL(string: "\(buildConfig.appSpecificUrlScheme)://")!
|
url = URL(string: "\(buildConfig.appSpecificUrlScheme)://")!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let content: ChatContent
|
||||||
|
if let peer = peers?.peers[index] {
|
||||||
|
content = .peer(peer)
|
||||||
|
} else {
|
||||||
|
content = .placeholder
|
||||||
|
}
|
||||||
|
|
||||||
return AnyView(
|
return AnyView(
|
||||||
Link(destination: url, label: {
|
Link(destination: url, label: {
|
||||||
HStack(alignment: .center, spacing: 0.0, content: {
|
HStack(alignment: .center, spacing: 0.0, content: {
|
||||||
AvatarItemView(peer: peers?.peers[index], itemSize: 54.0, placeholderColor: getPlaceholderColor()).frame(width: 54.0, height: 54.0, alignment: .leading).padding(EdgeInsets(top: 0.0, leading: 10.0, bottom: 0.0, trailing: 10.0))
|
AvatarItemView(peer: peers?.peers[index], itemSize: 54.0, placeholderColor: getPlaceholderColor()).frame(width: 54.0, height: 54.0, alignment: .leading).padding(EdgeInsets(top: 0.0, leading: 10.0, bottom: 0.0, trailing: 10.0))
|
||||||
chatContent(peers?.peers[index]).frame(maxWidth: .infinity).padding(EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 10.0))
|
chatContent(content).frame(maxWidth: .infinity).padding(EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 10.0))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.frame(width: size.width, height: itemHeight, alignment: .leading)
|
.frame(width: size.width, height: itemHeight, alignment: .leading)
|
||||||
@ -795,7 +757,7 @@ struct WidgetView: View {
|
|||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .short
|
formatter.dateStyle = .short
|
||||||
formatter.timeStyle = .none
|
formatter.timeStyle = .none
|
||||||
text = "updated on \(formatter.string(from: date))"
|
text = "updated \(formatter.string(from: date))"
|
||||||
} else {
|
} else {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
formatter.dateStyle = .none
|
formatter.dateStyle = .none
|
||||||
@ -803,6 +765,21 @@ struct WidgetView: View {
|
|||||||
text = "updated at \(formatter.string(from: date))"
|
text = "updated at \(formatter.string(from: date))"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case .preview:
|
||||||
|
let date = Date()
|
||||||
|
let calendar = Calendar.current
|
||||||
|
//TODO:localize
|
||||||
|
if !calendar.isDate(Date(), inSameDayAs: date) {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateStyle = .short
|
||||||
|
formatter.timeStyle = .none
|
||||||
|
text = "updated \(formatter.string(from: date))"
|
||||||
|
} else {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateStyle = .none
|
||||||
|
formatter.timeStyle = .short
|
||||||
|
text = "updated at \(formatter.string(from: date))"
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
text = "Long tap to edit widget"
|
text = "Long tap to edit widget"
|
||||||
}
|
}
|
||||||
@ -902,6 +879,7 @@ struct AvatarsWidgetView: View {
|
|||||||
func itemView(index: Int) -> some View {
|
func itemView(index: Int) -> some View {
|
||||||
let peers: ParsedPeers?
|
let peers: ParsedPeers?
|
||||||
var isPlaceholder = false
|
var isPlaceholder = false
|
||||||
|
var isPreview = false
|
||||||
switch data {
|
switch data {
|
||||||
case let .peers(peersValue):
|
case let .peers(peersValue):
|
||||||
if peersValue.peers.count <= index {
|
if peersValue.peers.count <= index {
|
||||||
@ -910,6 +888,9 @@ struct AvatarsWidgetView: View {
|
|||||||
} else {
|
} else {
|
||||||
peers = peersValue
|
peers = peersValue
|
||||||
}
|
}
|
||||||
|
case .preview:
|
||||||
|
peers = nil
|
||||||
|
isPreview = true
|
||||||
default:
|
default:
|
||||||
peers = nil
|
peers = nil
|
||||||
}
|
}
|
||||||
@ -921,8 +902,9 @@ struct AvatarsWidgetView: View {
|
|||||||
})
|
})
|
||||||
}).aspectRatio(1.0, contentMode: .fit))
|
}).aspectRatio(1.0, contentMode: .fit))
|
||||||
} else if isPlaceholder {
|
} else if isPlaceholder {
|
||||||
//return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(.clear))
|
|
||||||
return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor()))
|
return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor()))
|
||||||
|
} else if isPreview {
|
||||||
|
return AnyView(Image("Widget/Avatar\(index + 1)").aspectRatio(1.0, contentMode: .fit).clipShape(Circle()))
|
||||||
} else {
|
} else {
|
||||||
return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor()))
|
return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor()))
|
||||||
}
|
}
|
||||||
@ -999,6 +981,8 @@ func getWidgetData(contents: SimpleEntry.Contents) -> PeersWidgetData {
|
|||||||
switch contents {
|
switch contents {
|
||||||
case .recent:
|
case .recent:
|
||||||
return .empty
|
return .empty
|
||||||
|
case .preview:
|
||||||
|
return .preview
|
||||||
case let .peers(peers):
|
case let .peers(peers):
|
||||||
return .peers(peers)
|
return .peers(peers)
|
||||||
}
|
}
|
||||||
@ -1012,8 +996,8 @@ struct Static_Widget: Widget {
|
|||||||
WidgetView(data: getWidgetData(contents: entry.contents))
|
WidgetView(data: getWidgetData(contents: entry.contents))
|
||||||
})
|
})
|
||||||
.supportedFamilies([.systemMedium])
|
.supportedFamilies([.systemMedium])
|
||||||
.configurationDisplayName(presentationData.widgetGalleryTitle)
|
.configurationDisplayName("Chats")
|
||||||
.description(presentationData.widgetGalleryDescription)
|
.description("Display the latest message from the most important chats.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1025,8 +1009,8 @@ struct Static_AvatarsWidget: Widget {
|
|||||||
AvatarsWidgetView(data: getWidgetData(contents: entry.contents))
|
AvatarsWidgetView(data: getWidgetData(contents: entry.contents))
|
||||||
})
|
})
|
||||||
.supportedFamilies([.systemMedium])
|
.supportedFamilies([.systemMedium])
|
||||||
.configurationDisplayName(presentationData.widgetGalleryTitle)
|
.configurationDisplayName("Shortcuts")
|
||||||
.description(presentationData.widgetGalleryDescription)
|
.description("Display shortcuts of your most important chats to always have quick access to them.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar1.imageset/Avatar1.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar1.imageset/Avatar1.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar1.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar1.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar1.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar2.imageset/Avatar2.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar2.imageset/Avatar2.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar2.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar2.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar2.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar3.imageset/Avatar3.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar3.imageset/Avatar3.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar3.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar3.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar3.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar4.imageset/Avatar4.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar4.imageset/Avatar4.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar4.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar4.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar4.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar5.imageset/Avatar5.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar5.imageset/Avatar5.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar5.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar5.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar5.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar6.imageset/Avatar6.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar6.imageset/Avatar6.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar6.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar6.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar6.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar7.imageset/Avatar7.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar7.imageset/Avatar7.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar7.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar7.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar7.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar8.imageset/Avatar8.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar8.imageset/Avatar8.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar8.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/Avatar8.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Avatar8.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/AvatarChannel.imageset/AvatarChannel.pdf
vendored
Normal file
BIN
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/AvatarChannel.imageset/AvatarChannel.pdf
vendored
Normal file
Binary file not shown.
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/AvatarChannel.imageset/Contents.json
vendored
Normal file
12
Telegram/WidgetKitWidget/WidgetImages.xcassets/Widget/AvatarChannel.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "AvatarChannel.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"provides-namespace" : true
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user