2025-01-10 08:11:35 +05:30
|
|
|
//
|
|
|
|
|
// ActiveAppsTimelineProvider.swift
|
|
|
|
|
// AltStore
|
|
|
|
|
//
|
|
|
|
|
// Created by Magesh K on 10/01/25.
|
|
|
|
|
// Copyright © 2025 SideStore. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import WidgetKit
|
|
|
|
|
|
2025-01-11 03:25:25 +05:30
|
|
|
protocol WidgetInfo{
|
|
|
|
|
var ID: Int? { get }
|
2025-01-10 08:11:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@available(iOS 17, *)
|
2025-01-11 03:25:25 +05:30
|
|
|
class ActiveAppsTimelineProvider<T: WidgetInfo>: AppsTimelineProviderBase<WidgetInfo> {
|
|
|
|
|
public struct WidgetData: WidgetInfo {
|
|
|
|
|
let ID: Int?
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-11 21:31:10 +05:30
|
|
|
private let defaultDataHolder = PaginationDataHolder(
|
2025-01-11 04:10:02 +05:30
|
|
|
itemsPerPage: ActiveAppsWidget.Constants.MAX_ROWS_PER_PAGE
|
|
|
|
|
)
|
2025-01-10 08:11:35 +05:30
|
|
|
|
2025-01-11 21:31:10 +05:30
|
|
|
let widgetKind: String
|
|
|
|
|
|
|
|
|
|
init(widgetKind: String){
|
|
|
|
|
self.widgetKind = widgetKind
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-11 03:25:25 +05:30
|
|
|
deinit{
|
|
|
|
|
// if this provider goes out of scope, clear all entries
|
|
|
|
|
PageInfoManager.shared.clearAll()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func getUpdatedData(_ apps: [AppSnapshot], _ context: WidgetInfo?) -> [AppSnapshot] {
|
2025-01-10 08:11:35 +05:30
|
|
|
var apps = apps
|
|
|
|
|
|
2025-01-11 21:31:10 +05:30
|
|
|
// if simulator, get the 10 simulated entries based on first entry
|
2025-01-11 03:25:25 +05:30
|
|
|
#if targetEnvironment(simulator)
|
|
|
|
|
apps = getSimulatedData(apps: apps)
|
|
|
|
|
#endif
|
2025-01-10 08:11:35 +05:30
|
|
|
|
2025-01-12 00:03:25 +05:30
|
|
|
// always start with first page since defaultDataHolder is never updated
|
2025-01-11 21:31:10 +05:30
|
|
|
var currentPageApps = defaultDataHolder.currentPage(inItems: apps)
|
|
|
|
|
|
2025-01-12 00:03:25 +05:30
|
|
|
if let widgetInfo = context,
|
|
|
|
|
let widgetID = widgetInfo.ID {
|
|
|
|
|
|
|
|
|
|
var navEvent = getPageInfo(widgetID: widgetID)
|
|
|
|
|
if let event = navEvent,
|
|
|
|
|
let direction = event.direction
|
|
|
|
|
{
|
|
|
|
|
let dataHolder = event.dataHolder!
|
|
|
|
|
currentPageApps = dataHolder.currentPage(inItems: apps)
|
|
|
|
|
|
|
|
|
|
// process navigation request only if event wasn't consumed yet
|
|
|
|
|
if !event.consumed {
|
|
|
|
|
switch (direction){
|
|
|
|
|
case Direction.up:
|
|
|
|
|
currentPageApps = dataHolder.prevPage(inItems: apps, whenUnavailable: .current)!
|
|
|
|
|
case Direction.down:
|
|
|
|
|
currentPageApps = dataHolder.nextPage(inItems: apps, whenUnavailable: .current)!
|
|
|
|
|
}
|
|
|
|
|
// mark the event as consumed
|
|
|
|
|
// this prevents duplicate getUpdatedData() requests for same navigation event
|
|
|
|
|
navEvent!.consumed = true
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
// construct fresh/replace existing
|
|
|
|
|
navEvent = NavigationEvent(direction: nil, consumed: true, dataHolder: PaginationDataHolder(other: defaultDataHolder))
|
2025-01-10 08:11:35 +05:30
|
|
|
}
|
2025-01-12 00:03:25 +05:30
|
|
|
// put back the data
|
|
|
|
|
updatePageInfo(widgetID: widgetID, navEvent: navEvent)
|
2025-01-10 08:11:35 +05:30
|
|
|
}
|
2025-01-12 00:03:25 +05:30
|
|
|
|
2025-01-11 03:25:25 +05:30
|
|
|
return currentPageApps
|
2025-01-10 08:11:35 +05:30
|
|
|
}
|
2025-01-11 21:31:10 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
private func getPageInfo(widgetID: Int) -> NavigationEvent?{
|
|
|
|
|
return PageInfoManager.shared.getPageInfo(forWidgetKind: widgetKind, forWidgetID: widgetID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func updatePageInfo(widgetID: Int, navEvent: NavigationEvent?) {
|
|
|
|
|
PageInfoManager.shared.setPageInfo(forWidgetKind: widgetKind, forWidgetID: widgetID, value: navEvent)
|
|
|
|
|
}
|
2025-01-10 08:11:35 +05:30
|
|
|
}
|
|
|
|
|
|
2025-01-11 03:25:25 +05:30
|
|
|
/// TimelineProvider for WidgetAppIntentConfiguration widget type
|
2025-01-10 08:11:35 +05:30
|
|
|
@available(iOS 17, *)
|
|
|
|
|
extension ActiveAppsTimelineProvider: AppIntentTimelineProvider {
|
|
|
|
|
|
|
|
|
|
typealias Intent = WidgetUpdateIntent
|
|
|
|
|
|
2025-01-11 03:25:25 +05:30
|
|
|
func snapshot(for intent: Intent, in context: Context) async -> AppsEntry<WidgetInfo> {
|
|
|
|
|
// system retains the previously configured ID value and posts the same here
|
|
|
|
|
let widgetData = WidgetData(ID: intent.ID)
|
2025-01-10 08:11:35 +05:30
|
|
|
|
|
|
|
|
let bundleIDs = await super.fetchActiveAppBundleIDs()
|
2025-01-11 03:25:25 +05:30
|
|
|
let snapshot = await self.snapshot(for: bundleIDs, in: widgetData)
|
2025-01-10 08:11:35 +05:30
|
|
|
|
|
|
|
|
return snapshot
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-11 03:25:25 +05:30
|
|
|
func timeline(for intent: Intent, in context: Context) async -> Timeline<AppsEntry<WidgetInfo>> {
|
|
|
|
|
// system retains the previously configured ID value and posts the same here
|
|
|
|
|
let widgetData = WidgetData(ID: intent.ID)
|
|
|
|
|
|
2025-01-10 08:11:35 +05:30
|
|
|
let bundleIDs = await self.fetchActiveAppBundleIDs()
|
2025-01-11 03:25:25 +05:30
|
|
|
let timeline = await self.timeline(for: bundleIDs, in: widgetData)
|
2025-01-10 08:11:35 +05:30
|
|
|
|
|
|
|
|
return timeline
|
|
|
|
|
}
|
|
|
|
|
}
|