mirror of
https://github.com/XITRIX/iTorrent.git
synced 2026-05-30 11:46:50 +00:00
LiveActivity pause button added
This commit is contained in:
@@ -7,14 +7,13 @@
|
||||
|
||||
#if canImport(ActivityKit)
|
||||
import ActivityKit
|
||||
import AppIntents
|
||||
import MarqueeText
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
import MarqueeText
|
||||
|
||||
|
||||
|
||||
struct ProgressWidgetLiveActivity: Widget {
|
||||
static var userDefaults: UserDefaults { UserDefaults(suiteName: "group.itorrent.life-activity") ?? .standard }
|
||||
static var userDefaults: UserDefaults { .itorrentGroup }
|
||||
|
||||
static var tintColor: UIColor {
|
||||
guard let data = Self.userDefaults.data(forKey: "preferencesTintColor")
|
||||
@@ -26,7 +25,7 @@ struct ProgressWidgetLiveActivity: Widget {
|
||||
let config = ActivityConfiguration(for: ProgressWidgetAttributes.self) { context in
|
||||
// Lock screen/banner UI goes here
|
||||
|
||||
if #available(iOSApplicationExtension 18, *) {
|
||||
if #available(iOS 18, *) {
|
||||
#if XCODE16
|
||||
ProgressWidgetLiveActivityWatchSupportContent(context: context)
|
||||
.tint(Color(uiColor: ProgressWidgetLiveActivity.tintColor))
|
||||
@@ -37,7 +36,7 @@ struct ProgressWidgetLiveActivity: Widget {
|
||||
.padding()
|
||||
#endif
|
||||
|
||||
} else {
|
||||
} else {
|
||||
ProgressWidgetLiveActivityContent(context: context)
|
||||
.tint(Color(uiColor: Self.tintColor))
|
||||
.padding()
|
||||
@@ -64,6 +63,17 @@ struct ProgressWidgetLiveActivity: Widget {
|
||||
if context.state.state == .downloading {
|
||||
Text(context.state.timeRemainig)
|
||||
}
|
||||
|
||||
if #available(iOS 17.0, *),
|
||||
context.state.state == .seeding
|
||||
{
|
||||
let intent = {
|
||||
let intent = PauseTorrentIntent()
|
||||
intent.torrentHash = context.attributes.hash
|
||||
return intent
|
||||
}()
|
||||
PauseButton(intent: intent)
|
||||
}
|
||||
}
|
||||
ProgressView(value: context.state.progress)
|
||||
.progressViewStyle(.linear)
|
||||
@@ -92,7 +102,6 @@ struct ProgressWidgetLiveActivity: Widget {
|
||||
return config
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if XCODE16
|
||||
@@ -124,9 +133,9 @@ struct ProgressWidgetLiveActivityWatchSupportContent: View {
|
||||
Text(context.state.state.name)
|
||||
Spacer()
|
||||
case .downloading:
|
||||
Text(String("\(context.state.downSpeed.bitrateToHumanReadable)/s ↓"))
|
||||
Spacer()
|
||||
Text(String("\(context.state.upSpeed.bitrateToHumanReadable)/s ↑"))
|
||||
Text(String("\(context.state.downSpeed.bitrateToHumanReadable)/s ↓"))
|
||||
Spacer()
|
||||
Text(String("\(context.state.upSpeed.bitrateToHumanReadable)/s ↑"))
|
||||
case .finished:
|
||||
Text(context.state.state.name)
|
||||
Spacer()
|
||||
@@ -167,6 +176,17 @@ struct ProgressWidgetLiveActivityContent: View {
|
||||
HStack {
|
||||
Text(context.attributes.name)
|
||||
Spacer()
|
||||
|
||||
if #available(iOS 17.0, *),
|
||||
context.state.state == .seeding
|
||||
{
|
||||
let intent = {
|
||||
let intent = PauseTorrentIntent()
|
||||
intent.torrentHash = context.attributes.hash
|
||||
return intent
|
||||
}()
|
||||
PauseButton(intent: intent)
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
switch context.state.state {
|
||||
@@ -203,6 +223,17 @@ struct ProgressWidgetLiveActivityContent: View {
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
struct PauseButton: View {
|
||||
let intent: any LiveActivityIntent
|
||||
|
||||
var body: some View {
|
||||
Button(intent: intent) {
|
||||
Image(systemName: "pause.fill")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LeadingView: View {
|
||||
@State var context: ActivityViewContext<ProgressWidgetAttributes>
|
||||
|
||||
@@ -240,19 +271,19 @@ struct TrailingView: View {
|
||||
}
|
||||
}
|
||||
|
||||
//#Preview("Progress",
|
||||
// #Preview("Progress",
|
||||
// as: .dynamicIsland(.compact),
|
||||
// using: ProgressWidgetAttributes(name: "Test torrent", hash: "")
|
||||
//) {
|
||||
// ) {
|
||||
// ProgressWidgetLiveActivity()
|
||||
//} contentStates: {
|
||||
// } contentStates: {
|
||||
// ProgressWidgetAttributes.ContentState(progress: 0.2, downSpeed: 2000, upSpeed: 1000, timeRemainig: "Осталось САСАТБ", timeStamp: .now)
|
||||
//}
|
||||
// }
|
||||
|
||||
//#Preview("Notification", as: .content, using: ProgressWidgetAttributes(name: "Test torrent", hash: "")) {
|
||||
// #Preview("Notification", as: .content, using: ProgressWidgetAttributes(name: "Test torrent", hash: "")) {
|
||||
// ProgressWidgetLiveActivity()
|
||||
//} contentStates: {
|
||||
// } contentStates: {
|
||||
// ProgressWidgetAttributes.ContentState(progress: 0.2, downSpeed: 2000, upSpeed: 1000, timeRemainig: "Осталось САСАТБ", timeStamp: .now)
|
||||
// ProgressWidgetAttributes.ContentState(progress: 0.7, downSpeed: 12000000, upSpeed: 1000000, timeRemainig: "Осталось САСАТБ", timeStamp: .now)
|
||||
//}
|
||||
// }
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
7C013DE32C28AA3C0026A11B /* sound.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 7C013DE22C28A97F0026A11B /* sound.m4a */; };
|
||||
7C013DE42C2F38AA0026A11B /* LocalizationAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1352D1D2BBC2F7F00104E7B /* LocalizationAttribute.swift */; };
|
||||
7C013DE52C2F41760026A11B /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D1AA00CF2AFAC7D200B74629 /* Localizable.xcstrings */; };
|
||||
7C1C08AA2C31F2F800569B45 /* PauseTorrentIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C1C08A92C31F2F000569B45 /* PauseTorrentIntent.swift */; };
|
||||
7C1C08AB2C31F31900569B45 /* PauseTorrentIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C1C08A92C31F2F000569B45 /* PauseTorrentIntent.swift */; };
|
||||
7C1C08AD2C31FEA400569B45 /* IntentsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C1C08AC2C31FEA000569B45 /* IntentsService.swift */; };
|
||||
7C3142D02C317E6400397E82 /* MarqueeText in Frameworks */ = {isa = PBXBuildFile; productRef = 7C3142CF2C317E6400397E82 /* MarqueeText */; };
|
||||
7C4CF2FA2BDE712D0078FEA1 /* UnityAdsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4CF2F92BDE712D0078FEA1 /* UnityAdsManager.swift */; };
|
||||
7C4CF2FC2BDE78F50078FEA1 /* AdView+Unity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4CF2FB2BDE78F50078FEA1 /* AdView+Unity.swift */; };
|
||||
@@ -55,6 +58,8 @@
|
||||
7CB2639C2C0671320083C052 /* Publisher+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB2639B2C0671320083C052 /* Publisher+UI.swift */; };
|
||||
7CB2639E2C0A5B420083C052 /* BaseSafariViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB2639D2C0A5B420083C052 /* BaseSafariViewController.swift */; };
|
||||
7CB6F6CE2BD82BAB00D0813B /* FileSharingPreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB6F6CD2BD82BAB00D0813B /* FileSharingPreferencesViewModel.swift */; };
|
||||
7CBDBAAD2C31EF0C008C986B /* UserDefaults+AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CBDBAAC2C31EF0C008C986B /* UserDefaults+AppGroup.swift */; };
|
||||
7CBDBAAE2C31EF52008C986B /* UserDefaults+AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CBDBAAC2C31EF0C008C986B /* UserDefaults+AppGroup.swift */; };
|
||||
7CC411582BD2DCF800CA8B13 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7CC411572BD2DCF800CA8B13 /* GoogleService-Info.plist */; };
|
||||
7CC4115B2BD2DE3800CA8B13 /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */ = {isa = PBXBuildFile; platformFilters = (ios, xros, ); productRef = 7CC4115A2BD2DE3800CA8B13 /* FirebaseAnalyticsWithoutAdIdSupport */; };
|
||||
7CC4115D2BD2DE3800CA8B13 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; platformFilters = (ios, xros, ); productRef = 7CC4115C2BD2DE3800CA8B13 /* FirebaseCrashlytics */; };
|
||||
@@ -239,6 +244,8 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
7C013DE22C28A97F0026A11B /* sound.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = sound.m4a; sourceTree = "<group>"; };
|
||||
7C1C08A92C31F2F000569B45 /* PauseTorrentIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PauseTorrentIntent.swift; sourceTree = "<group>"; };
|
||||
7C1C08AC2C31FEA000569B45 /* IntentsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentsService.swift; sourceTree = "<group>"; };
|
||||
7C4CF2F22BDD586C0078FEA1 /* UnityAds.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = UnityAds.xcframework; path = Submodules/UnityAds.xcframework; sourceTree = "<group>"; };
|
||||
7C4CF2F92BDE712D0078FEA1 /* UnityAdsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnityAdsManager.swift; sourceTree = "<group>"; };
|
||||
7C4CF2FB2BDE78F50078FEA1 /* AdView+Unity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdView+Unity.swift"; sourceTree = "<group>"; };
|
||||
@@ -286,6 +293,7 @@
|
||||
7CB2639B2C0671320083C052 /* Publisher+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publisher+UI.swift"; sourceTree = "<group>"; };
|
||||
7CB2639D2C0A5B420083C052 /* BaseSafariViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseSafariViewController.swift; sourceTree = "<group>"; };
|
||||
7CB6F6CD2BD82BAB00D0813B /* FileSharingPreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSharingPreferencesViewModel.swift; sourceTree = "<group>"; };
|
||||
7CBDBAAC2C31EF0C008C986B /* UserDefaults+AppGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+AppGroup.swift"; sourceTree = "<group>"; };
|
||||
7CC411572BD2DCF800CA8B13 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
7CC411612BD319AE00CA8B13 /* AppDelegate+RemoteConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+RemoteConfig.swift"; sourceTree = "<group>"; };
|
||||
7CC411632BD326C300CA8B13 /* AppDelegate+Firebase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Firebase.swift"; sourceTree = "<group>"; };
|
||||
@@ -465,6 +473,31 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
7C1C08AE2C31FEF700569B45 /* IntentsService */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7C1C08AF2C31FEFD00569B45 /* Intents */,
|
||||
7C1C08AC2C31FEA000569B45 /* IntentsService.swift */,
|
||||
);
|
||||
path = IntentsService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7C1C08AF2C31FEFD00569B45 /* Intents */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7C1C08A92C31F2F000569B45 /* PauseTorrentIntent.swift */,
|
||||
);
|
||||
path = Intents;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7C3142D42C31ED4600397E82 /* LiveActivityService */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7CF6DA3D2C0F9DC40033D03F /* LiveActivityService.swift */,
|
||||
);
|
||||
path = LiveActivityService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7C4CF2F82BDE711A0078FEA1 /* Ads */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -958,6 +991,7 @@
|
||||
D1AA00CA2AFA8A9200B74629 /* UserDefaultItem.swift */,
|
||||
7C5FBE222BBDD1B60069E5A0 /* NSUserDefaultItem.swift */,
|
||||
7CE25BA62C24A848007B2FD7 /* CircularAnimation.swift */,
|
||||
7CBDBAAC2C31EF0C008C986B /* UserDefaults+AppGroup.swift */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
@@ -1059,6 +1093,8 @@
|
||||
D1A226F02AEF018500669D6D /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7C1C08AE2C31FEF700569B45 /* IntentsService */,
|
||||
7C3142D42C31ED4600397E82 /* LiveActivityService */,
|
||||
D1B99D842BEE5E4100F51514 /* Patreon */,
|
||||
7C4CF2F82BDE711A0078FEA1 /* Ads */,
|
||||
D1DB71892BD915F4007F9267 /* ImageCache */,
|
||||
@@ -1070,7 +1106,6 @@
|
||||
7C5FBE182BBC91E70069E5A0 /* NetworkMonitoringService.swift */,
|
||||
D1352D2B2BBD6E0E00104E7B /* MemorySpaceManager.swift */,
|
||||
D1352D3B2BBD7F8800104E7B /* TorrentMonitoringService.swift */,
|
||||
7CF6DA3D2C0F9DC40033D03F /* LiveActivityService.swift */,
|
||||
);
|
||||
path = Services;
|
||||
sourceTree = "<group>";
|
||||
@@ -1447,7 +1482,9 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7C1C08AA2C31F2F800569B45 /* PauseTorrentIntent.swift in Sources */,
|
||||
7C5FBE442BC0ADC90069E5A0 /* ProgressWidgetLiveActivity.swift in Sources */,
|
||||
7CBDBAAE2C31EF52008C986B /* UserDefaults+AppGroup.swift in Sources */,
|
||||
7C5FBE422BC0ADC90069E5A0 /* ProgressWidgetBundle.swift in Sources */,
|
||||
7C5FBE532BC0B2780069E5A0 /* SpeedFormat.swift in Sources */,
|
||||
7C5FBE562BC0B35C0069E5A0 /* ProgressWidgetAttributes.swift in Sources */,
|
||||
@@ -1493,6 +1530,7 @@
|
||||
7C5FBE702BC2EF8B0069E5A0 /* EditTextViewController.swift in Sources */,
|
||||
7CFEBEA02BC6F3CD0013233F /* Date+Extensions.swift in Sources */,
|
||||
D1DB718B2BD91606007F9267 /* ImageCache.swift in Sources */,
|
||||
7CBDBAAD2C31EF0C008C986B /* UserDefaults+AppGroup.swift in Sources */,
|
||||
D1B1BEC92AFE25AE0030C2A4 /* TorrentTrackersViewController.swift in Sources */,
|
||||
D1DB718D2BD9165C007F9267 /* ImageLoader.swift in Sources */,
|
||||
7C5FBE292BBDD4030069E5A0 /* PRColorPickerViewModel.swift in Sources */,
|
||||
@@ -1548,6 +1586,7 @@
|
||||
D135C5992AEFB96100440680 /* TorrentDetailsViewController.swift in Sources */,
|
||||
D1048D8B2BBEB6DE0027EF2F /* CombineLatest.swift in Sources */,
|
||||
D11138572AF976CE008907F7 /* TorrentAddDirectoryItemViewModel.swift in Sources */,
|
||||
7C1C08AB2C31F31900569B45 /* PauseTorrentIntent.swift in Sources */,
|
||||
D1CAB8872AF3B52E00EB6AFF /* ToggleCellViewModel.swift in Sources */,
|
||||
D11BE5492AFBA03D00780C1B /* PRButtonView.swift in Sources */,
|
||||
7CFEBE8B2BC439CF0013233F /* RssChannelItemCellViewModel.swift in Sources */,
|
||||
@@ -1556,6 +1595,7 @@
|
||||
D1352D322BBD720C00104E7B /* PRStorageCell.swift in Sources */,
|
||||
7C5FBE232BBDD1B60069E5A0 /* NSUserDefaultItem.swift in Sources */,
|
||||
D1EFCD092AF56A4C00D33A7A /* TorrentFilesViewController.swift in Sources */,
|
||||
7C1C08AD2C31FEA400569B45 /* IntentsService.swift in Sources */,
|
||||
7CFEBE832BC434A10013233F /* BaseCollectionViewController.swift in Sources */,
|
||||
D1A5D0CE2BE52728003E05D5 /* AdView+Google.swift in Sources */,
|
||||
D1352D3A2BBD747100104E7B /* PortionBarLabels.swift in Sources */,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"" : {
|
||||
|
||||
},
|
||||
"%@ of %@ (%@)" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -1156,6 +1159,54 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.pauseTorrent.hash.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Hash of the Torrent that needs to be stopped"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Хэш торрента который требуется остановить"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.pauseTorrent.hash.title" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Torrent hash"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Хэш торрента"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.pauseTorrent.title" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pause Torrent"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Остановить торрент"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"iTorrent" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
|
||||
@@ -29,6 +29,7 @@ class SceneDelegate: MvvmSceneDelegate {
|
||||
container.registerDaemon(factory: RssFeedProvider.init)
|
||||
container.registerDaemon(factory: WebServerService.init)
|
||||
container.registerDaemon(factory: LiveActivityService.init)
|
||||
container.registerDaemon(factory: IntentsService.init)
|
||||
container.registerDaemon(factory: AdsManager.init)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// PauseTorrentIntent.swift
|
||||
// iTorrent
|
||||
//
|
||||
// Created by Даниил Виноградов on 30.06.2024.
|
||||
//
|
||||
|
||||
import AppIntents
|
||||
|
||||
extension NSNotification.Name {
|
||||
static var pauseTorrent: Self {
|
||||
.init("pauseTorrent")
|
||||
}
|
||||
}
|
||||
|
||||
struct PauseTorrentIntent: LiveActivityIntent {
|
||||
static var title: LocalizedStringResource = "intent.pauseTorrent.title"
|
||||
|
||||
@Parameter(title: "intent.pauseTorrent.hash.title", description: "intent.pauseTorrent.hash.description")
|
||||
var torrentHash: String
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
NotificationCenter.default.post(name: .pauseTorrent, object: torrentHash)
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// IntentsService.swift
|
||||
// iTorrent
|
||||
//
|
||||
// Created by Даниил Виноградов on 30.06.2024.
|
||||
//
|
||||
|
||||
import MvvmFoundation
|
||||
import Foundation
|
||||
|
||||
actor IntentsService {
|
||||
init() {
|
||||
disposeBag.bind {
|
||||
NotificationCenter.default.publisher(for: .pauseTorrent).sink { notification in
|
||||
guard let hash = notification.object as? String,
|
||||
let torrentHandle = TorrentService.shared.torrents.first(where: { $0.snapshot.infoHashes.best.hex == hash })
|
||||
else { return }
|
||||
|
||||
torrentHandle.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let disposeBag = DisposeBag()
|
||||
}
|
||||
@@ -13,16 +13,27 @@ import MvvmFoundation
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
extension UserDefaults {
|
||||
@objc dynamic var greetingsCount: Int {
|
||||
return integer(forKey: "greetingsCount")
|
||||
}
|
||||
}
|
||||
|
||||
actor LiveActivityService {
|
||||
init() {
|
||||
#if canImport(ActivityKit)
|
||||
disposeBag.bind {
|
||||
#if canImport(ActivityKit)
|
||||
TorrentService.shared.updateNotifier
|
||||
.sink { [unowned self] updateModel in
|
||||
Task { await updateLiveActivity(with: updateModel.handle.snapshot) }
|
||||
}
|
||||
}
|
||||
|
||||
UserDefaults.standard.publisher(for: <#T##KeyPath<UserDefaults, Value>#>)
|
||||
NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink { notification in
|
||||
notification.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private let disposeBag = DisposeBag()
|
||||
@@ -105,7 +116,7 @@ private extension TorrentHandle.State {
|
||||
}
|
||||
|
||||
var shouldShowLiveActivity: Bool {
|
||||
let notShow: [Self] = [ .finished, .paused ]
|
||||
let notShow: [Self] = [.finished, .paused]
|
||||
return !notShow.contains(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// LiveActivityService.swift
|
||||
// iTorrent
|
||||
//
|
||||
// Created by Даниил Виноградов on 06.04.2024.
|
||||
//
|
||||
|
||||
#if canImport(ActivityKit)
|
||||
import ActivityKit
|
||||
import Combine
|
||||
import LibTorrent
|
||||
import MvvmFoundation
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
actor LiveActivityService {
|
||||
init() {
|
||||
disposeBag.bind {
|
||||
#if canImport(ActivityKit)
|
||||
TorrentService.shared.updateNotifier
|
||||
.sink { [unowned self] updateModel in
|
||||
Task { await updateLiveActivity(with: updateModel.handle.snapshot) }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private let disposeBag = DisposeBag()
|
||||
@Injected private var torrentService: TorrentService
|
||||
}
|
||||
|
||||
#if canImport(ActivityKit)
|
||||
private extension LiveActivityService {
|
||||
func updateLiveActivity(with snapshot: TorrentHandle.Snapshot) async {
|
||||
if #available(iOS 16.1, *) {
|
||||
guard ActivityAuthorizationInfo().areActivitiesEnabled
|
||||
else { return }
|
||||
|
||||
for activity in Activity<ProgressWidgetAttributes>.activities {
|
||||
if activity.attributes.name == snapshot.name {
|
||||
if snapshot.friendlyState.shouldShowLiveActivity {
|
||||
if #available(iOS 16.2, *) {
|
||||
await activity.update(.init(state: snapshot.toLiveActivityState, staleDate: .now + 10))
|
||||
} else {
|
||||
await activity.update(using: snapshot.toLiveActivityState)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
await activity.end(dismissalPolicy: .immediate)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if snapshot.friendlyState.shouldShowLiveActivity {
|
||||
showLiveActivity(with: snapshot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showLiveActivity(with snapshot: TorrentHandle.Snapshot) {
|
||||
if #available(iOS 16.1, *) {
|
||||
let attributes = ProgressWidgetAttributes(name: snapshot.name, hash: snapshot.infoHashes.best.hex)
|
||||
|
||||
do {
|
||||
_ = try Activity<ProgressWidgetAttributes>.request(attributes: attributes, contentState: snapshot.toLiveActivityState, pushType: .none)
|
||||
} catch {
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension TorrentHandle.Snapshot {
|
||||
var toLiveActivityState: ProgressWidgetAttributes.ContentState {
|
||||
.init(state: friendlyState.toState,
|
||||
progress: progress,
|
||||
downSpeed: downloadRate,
|
||||
upSpeed: uploadRate,
|
||||
timeRemainig: timeRemains,
|
||||
timeStamp: Date())
|
||||
}
|
||||
}
|
||||
|
||||
private extension TorrentHandle.State {
|
||||
var toState: ProgressWidgetAttributes.State {
|
||||
switch self {
|
||||
case .checkingFiles:
|
||||
return .checkingFiles
|
||||
case .downloadingMetadata:
|
||||
return .downloadingMetadata
|
||||
case .downloading:
|
||||
return .downloading
|
||||
case .finished:
|
||||
return .finished
|
||||
case .seeding:
|
||||
return .seeding
|
||||
case .checkingResumeData:
|
||||
return .checkingResumeData
|
||||
case .paused:
|
||||
return .paused
|
||||
@unknown default:
|
||||
fatalError("\(ProgressWidgetAttributes.State.self) has no such case \(self)")
|
||||
}
|
||||
}
|
||||
|
||||
var shouldShowLiveActivity: Bool {
|
||||
let notShow: [Self] = [.finished, .paused]
|
||||
return !notShow.contains(self)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -33,7 +33,7 @@ struct NSUserDefaultItem<Value: NSObject & NSCoding> {
|
||||
}
|
||||
|
||||
private extension NSUserDefaultItem {
|
||||
static var userDefaults: UserDefaults { UserDefaults(suiteName: "group.itorrent.life-activity") ?? .standard }
|
||||
static var userDefaults: UserDefaults { .itorrentGroup }
|
||||
|
||||
static func value(for key: String) -> Value? {
|
||||
guard let data = userDefaults.data(forKey: key)
|
||||
|
||||
@@ -39,7 +39,7 @@ struct UserDefaultItem<T: Codable> {
|
||||
}
|
||||
|
||||
private extension UserDefaultItem {
|
||||
static var userDefaults: UserDefaults { UserDefaults(suiteName: "group.itorrent.life-activity") ?? .standard }
|
||||
static var userDefaults: UserDefaults { .itorrentGroup }
|
||||
|
||||
static func get(by key: String) -> T? {
|
||||
guard let decoded = userDefaults.data(forKey: key),
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// UserDefaults+AppGroup.swift
|
||||
// iTorrent
|
||||
//
|
||||
// Created by Даниил Виноградов on 30.06.2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension UserDefaults {
|
||||
static var itorrentGroup: UserDefaults {
|
||||
UserDefaults(suiteName: "group.itorrent.life-activity") ?? .standard
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user