mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 14:45:21 +00:00
[WIP] Fix widget data
This commit is contained in:
@@ -26,7 +26,7 @@ struct Provider: TimelineProvider {
|
|||||||
var entries: [SimpleEntry] = []
|
var entries: [SimpleEntry] = []
|
||||||
|
|
||||||
let currentDate = Date()
|
let currentDate = Date()
|
||||||
for hourOffset in 0 ..< 5 {
|
for hourOffset in 0 ..< 1 {
|
||||||
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
|
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
|
||||||
let entry = SimpleEntry(date: entryDate)
|
let entry = SimpleEntry(date: entryDate)
|
||||||
entries.append(entry)
|
entries.append(entry)
|
||||||
@@ -38,19 +38,13 @@ struct Provider: TimelineProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct SimpleEntry: TimelineEntry {
|
struct SimpleEntry: TimelineEntry {
|
||||||
public let date: Date
|
let date: Date
|
||||||
}
|
|
||||||
|
|
||||||
struct Static_WidgetEntryView: View {
|
|
||||||
var entry: Provider.Entry
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Text(entry.date, style: .time)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PeersWidgetData {
|
enum PeersWidgetData {
|
||||||
case placeholder
|
case placeholder
|
||||||
|
case empty
|
||||||
|
case locked
|
||||||
case data(WidgetData)
|
case data(WidgetData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +55,7 @@ extension PeersWidgetData {
|
|||||||
struct WidgetView: View {
|
struct WidgetView: View {
|
||||||
let data: PeersWidgetData
|
let data: PeersWidgetData
|
||||||
|
|
||||||
func peerViews(geometry: GeometryProxy) -> AnyView {
|
func placeholder(geometry: GeometryProxy) -> some View {
|
||||||
let defaultItemSize: CGFloat = 60.0
|
let defaultItemSize: CGFloat = 60.0
|
||||||
let defaultPaddingFraction: CGFloat = 0.36
|
let defaultPaddingFraction: CGFloat = 0.36
|
||||||
|
|
||||||
@@ -71,24 +65,53 @@ struct WidgetView: View {
|
|||||||
let firstRowY = itemSize / 2.0
|
let firstRowY = itemSize / 2.0
|
||||||
let secondRowY = itemSize / 2.0 + geometry.size.height - itemSize
|
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 {
|
switch data {
|
||||||
case .placeholder:
|
case .placeholder:
|
||||||
return AnyView(ZStack {
|
return AnyView(GeometryReader { geometry in
|
||||||
ForEach(0 ..< rowCount * 2, content: { i in
|
placeholder(geometry: geometry)
|
||||||
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)
|
})
|
||||||
})
|
case .empty:
|
||||||
|
return AnyView(VStack {
|
||||||
|
Text(presentationData.applicationStartRequiredString)
|
||||||
|
})
|
||||||
|
case .locked:
|
||||||
|
return AnyView(VStack {
|
||||||
|
Text(presentationData.applicationLockedString)
|
||||||
})
|
})
|
||||||
case let .data(data):
|
case let .data(data):
|
||||||
switch data {
|
switch data {
|
||||||
case let .peers(peers):
|
case let .peers(peers):
|
||||||
return AnyView(ZStack {
|
return AnyView(GeometryReader { geometry in
|
||||||
ForEach(0 ..< min(peers.peers.count, rowCount * 2), content: { i in
|
peersView(geometry: geometry, peers: peers)
|
||||||
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)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
return AnyView(ZStack {
|
return AnyView(ZStack {
|
||||||
@@ -101,9 +124,7 @@ struct WidgetView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(.systemBackground)
|
Color(.systemBackground)
|
||||||
GeometryReader { geometry in
|
peerViews()
|
||||||
peerViews(geometry: geometry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.padding(.all)
|
.padding(.all)
|
||||||
}
|
}
|
||||||
@@ -152,10 +173,10 @@ private let presentationData: WidgetPresentationData = {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let widgetData: WidgetData? = {
|
func getWidgetData() -> PeersWidgetData {
|
||||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||||
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||||
return nil
|
return .placeholder
|
||||||
}
|
}
|
||||||
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
|
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
|
||||||
|
|
||||||
@@ -163,37 +184,34 @@ let widgetData: WidgetData? = {
|
|||||||
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
||||||
|
|
||||||
guard let appGroupUrl = maybeAppGroupUrl else {
|
guard let appGroupUrl = maybeAppGroupUrl else {
|
||||||
return nil
|
return .placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
||||||
|
|
||||||
|
if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) {
|
||||||
|
return .locked
|
||||||
|
}
|
||||||
|
|
||||||
let dataPath = rootPath + "/widget-data"
|
let dataPath = rootPath + "/widget-data"
|
||||||
|
|
||||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: dataPath)), let widgetData = try? JSONDecoder().decode(WidgetData.self, from: data) {
|
if let data = try? Data(contentsOf: URL(fileURLWithPath: dataPath)), let widgetData = try? JSONDecoder().decode(WidgetData.self, from: data) {
|
||||||
return widgetData
|
return .data(widgetData)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return .placeholder
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct Static_Widget: Widget {
|
struct Static_Widget: Widget {
|
||||||
private let kind: String = "Static_Widget"
|
private let kind: String = "Static_Widget"
|
||||||
|
|
||||||
public var body: some WidgetConfiguration {
|
public var body: some WidgetConfiguration {
|
||||||
let data: PeersWidgetData
|
|
||||||
if let widgetData = widgetData {
|
|
||||||
data = .data(widgetData)
|
|
||||||
} else {
|
|
||||||
data = .placeholder
|
|
||||||
}
|
|
||||||
|
|
||||||
return StaticConfiguration(
|
return StaticConfiguration(
|
||||||
kind: kind,
|
kind: kind,
|
||||||
provider: Provider(),
|
provider: Provider(),
|
||||||
content: { entry in
|
content: { entry in
|
||||||
WidgetView(data: data)
|
WidgetView(data: getWidgetData())
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.supportedFamilies([.systemMedium])
|
.supportedFamilies([.systemMedium])
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ final class WidgetDataContext {
|
|||||||
} else {
|
} else {
|
||||||
let _ = try? FileManager.default.removeItem(atPath: path)
|
let _ = try? FileManager.default.removeItem(atPath: path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if #available(iOSApplicationExtension 14.0, iOS 14.0, *) {
|
||||||
|
WidgetCenter.shared.reloadAllTimelines()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.widgetPresentationDataDisposable = (presentationData
|
self.widgetPresentationDataDisposable = (presentationData
|
||||||
|
|||||||
Reference in New Issue
Block a user