#62 QR code widgets
|
@ -83,6 +83,9 @@ public class ApplicationState: ObservableObject {
|
|||
/// Status which should be shown from URL.
|
||||
@Published public var showStatusId: String?
|
||||
|
||||
/// Account which should be shown from URL.
|
||||
@Published public var showAccountId: String?
|
||||
|
||||
/// Updated user profile.
|
||||
@Published public var updatedProfile: Account?
|
||||
|
||||
|
|
|
@ -17,6 +17,10 @@ public struct AppConstants {
|
|||
public static let statusCallbackPart = "statuses"
|
||||
public static let statusUri = "\(AppConstants.statusScheme)://\(statusCallbackPart)"
|
||||
|
||||
public static let accountScheme = "account-vernissage"
|
||||
public static let accountCallbackPart = "accounts"
|
||||
public static let accountUri = "\(AppConstants.accountScheme)://\(accountCallbackPart)"
|
||||
|
||||
public static let imagePipelineCacheName = "dev.mczachurski.Vernissage.DataCache"
|
||||
public static let coreDataPersistantContainerName = "Vernissage"
|
||||
}
|
||||
|
|
|
@ -299,7 +299,8 @@
|
|||
"thirdParty.navigationBar.title" = "Third party";
|
||||
|
||||
// Mark: Widget view.
|
||||
"widget.title.description" = "Widget with photos from Pixelfed.";
|
||||
"widget.title.photoDescription" = "Widget with photos from Pixelfed.";
|
||||
"widget.title.qrCodeDescription" = "Widget with QR Code to your Pixelfed profile.";
|
||||
|
||||
// Mark: In-app purchases.
|
||||
"purchase.donut.title" = "Donut";
|
||||
|
|
|
@ -299,7 +299,8 @@
|
|||
"thirdParty.navigationBar.title" = "Hirugarrenak";
|
||||
|
||||
// Mark: Widget view.
|
||||
"widget.title.description" = "Widgeta Pixelfed-eko argazkiekin.";
|
||||
"widget.title.photoDescription" = "Widgeta Pixelfed-eko argazkiekin.";
|
||||
"widget.title.qrCodeDescription" = "Widget with QR Code to your Pixelfed profile.";
|
||||
|
||||
// Mark: In-app purchases.
|
||||
"purchase.donut.title" = "Opila";
|
||||
|
|
|
@ -299,7 +299,8 @@
|
|||
"thirdParty.navigationBar.title" = "Tiers";
|
||||
|
||||
// Mark: Widget view.
|
||||
"widget.title.description" = "Widget avec des photos de Pixelfed.";
|
||||
"widget.title.photoDescription" = "Widget avec des photos de Pixelfed.";
|
||||
"widget.title.qrCodeDescription" = "Widget with QR Code to your Pixelfed profile.";
|
||||
|
||||
// Mark: In-app purchases.
|
||||
"purchase.donut.title" = "Beignet";
|
||||
|
|
|
@ -299,7 +299,8 @@
|
|||
"thirdParty.navigationBar.title" = "Zewnętrzne biblioteki";
|
||||
|
||||
// Mark: Widget view.
|
||||
"widget.title.description" = "Widget ze zdjęciami z Pixelfed.";
|
||||
"widget.title.photoDescription" = "Widget ze zdjęciami z Pixelfed.";
|
||||
"widget.title.qrCodeDescription" = "Widget z QR kodem do profilu na Pixelfed.";
|
||||
|
||||
// Mark: In-app purchases.
|
||||
"purchase.donut.title" = "Pączek";
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
F835082329BEF9C400DE3247 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F835082629BEF9C400DE3247 /* Localizable.strings */; };
|
||||
F835082429BEF9C400DE3247 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F835082629BEF9C400DE3247 /* Localizable.strings */; };
|
||||
F83CBEFB298298A1002972C8 /* ImageCarouselPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83CBEFA298298A1002972C8 /* ImageCarouselPicture.swift */; };
|
||||
F84625E929FE2788002D3AF4 /* QRCodeWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84625E829FE2788002D3AF4 /* QRCodeWidget.swift */; };
|
||||
F84625EB29FE28D4002D3AF4 /* QRCodeWidgetEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84625EA29FE28D4002D3AF4 /* QRCodeWidgetEntryView.swift */; };
|
||||
F84625ED29FE295B002D3AF4 /* QRCodeLargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84625EC29FE295B002D3AF4 /* QRCodeLargeWidgetView.swift */; };
|
||||
F84625F229FE2B6B002D3AF4 /* QRCodeWidgetEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84625F129FE2B6B002D3AF4 /* QRCodeWidgetEntry.swift */; };
|
||||
F84625F429FE2BF9002D3AF4 /* QRCodeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84625F329FE2BF9002D3AF4 /* QRCodeProvider.swift */; };
|
||||
F84625F829FE2C2F002D3AF4 /* AccountFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84625F729FE2C2F002D3AF4 /* AccountFetcher.swift */; };
|
||||
F84625FB29FE393B002D3AF4 /* QRCode in Frameworks */ = {isa = PBXBuildFile; productRef = F84625FA29FE393B002D3AF4 /* QRCode */; };
|
||||
F858906B29E1CC7A00D4BDED /* UIApplication+Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = F858906A29E1CC7A00D4BDED /* UIApplication+Window.swift */; };
|
||||
F85D4971296402DC00751DF7 /* AuthorizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D4970296402DC00751DF7 /* AuthorizationService.swift */; };
|
||||
F85D4975296407F100751DF7 /* HomeTimelineService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D4974296407F100751DF7 /* HomeTimelineService.swift */; };
|
||||
|
@ -46,14 +53,14 @@
|
|||
F864F75F29BB91B400B13921 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F864F75E29BB91B400B13921 /* WidgetKit.framework */; };
|
||||
F864F76129BB91B400B13921 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F864F76029BB91B400B13921 /* SwiftUI.framework */; };
|
||||
F864F76429BB91B400B13921 /* VernissageWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F76329BB91B400B13921 /* VernissageWidgetBundle.swift */; };
|
||||
F864F76629BB91B400B13921 /* VernissageWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F76529BB91B400B13921 /* VernissageWidget.swift */; };
|
||||
F864F76629BB91B400B13921 /* PhotoWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F76529BB91B400B13921 /* PhotoWidget.swift */; };
|
||||
F864F76829BB91B600B13921 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F864F76729BB91B600B13921 /* Assets.xcassets */; };
|
||||
F864F76C29BB91B600B13921 /* VernissageWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = F864F75D29BB91B400B13921 /* VernissageWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
F864F77529BB92CE00B13921 /* Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77329BB929A00B13921 /* Provider.swift */; };
|
||||
F864F77629BB92CE00B13921 /* VernissageWidgetEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77129BB924D00B13921 /* VernissageWidgetEntryView.swift */; };
|
||||
F864F77829BB930000B13921 /* WidgetEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77729BB930000B13921 /* WidgetEntry.swift */; };
|
||||
F864F77529BB92CE00B13921 /* PhotoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77329BB929A00B13921 /* PhotoProvider.swift */; };
|
||||
F864F77629BB92CE00B13921 /* PhotoWidgetEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77129BB924D00B13921 /* PhotoWidgetEntryView.swift */; };
|
||||
F864F77829BB930000B13921 /* PhotoWidgetEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77729BB930000B13921 /* PhotoWidgetEntry.swift */; };
|
||||
F864F77A29BB94A800B13921 /* PixelfedKit in Frameworks */ = {isa = PBXBuildFile; productRef = F864F77929BB94A800B13921 /* PixelfedKit */; };
|
||||
F864F77C29BB982100B13921 /* ImageFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77B29BB982100B13921 /* ImageFetcher.swift */; };
|
||||
F864F77C29BB982100B13921 /* StatusFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F77B29BB982100B13921 /* StatusFetcher.swift */; };
|
||||
F864F77D29BB9A4600B13921 /* AttachmentData+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80047FF2961850500E6868A /* AttachmentData+CoreDataClass.swift */; };
|
||||
F864F77E29BB9A4900B13921 /* AttachmentData+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048002961850500E6868A /* AttachmentData+CoreDataProperties.swift */; };
|
||||
F864F78229BB9A6500B13921 /* StatusData+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048012961850500E6868A /* StatusData+CoreDataClass.swift */; };
|
||||
|
@ -87,6 +94,10 @@
|
|||
F86B7221296C49A300EE59EC /* EmptyButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7220296C49A300EE59EC /* EmptyButtonStyle.swift */; };
|
||||
F86BC9E929EBBB67009415EC /* ImageSaver.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86BC9E829EBBB66009415EC /* ImageSaver.swift */; };
|
||||
F86BC9EB29EBDA2E009415EC /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86BC9EA29EBDA2E009415EC /* ActivityView.swift */; };
|
||||
F8705A7729FF7ABD00DA818A /* QRCodeSmallWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8705A7629FF7ABD00DA818A /* QRCodeSmallWidgetView.swift */; };
|
||||
F8705A7929FF7CCB00DA818A /* QRCodeMediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8705A7829FF7CCB00DA818A /* QRCodeMediumWidgetView.swift */; };
|
||||
F8705A7B29FF872F00DA818A /* QRCodeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8705A7A29FF872F00DA818A /* QRCodeGenerator.swift */; };
|
||||
F8705A7E29FF880600DA818A /* FileFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8705A7D29FF880600DA818A /* FileFetcher.swift */; };
|
||||
F870EE5229F1645C00A2D43B /* MainNavigationOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F870EE5129F1645C00A2D43B /* MainNavigationOptions.swift */; };
|
||||
F871F21D29EF0D7000A351EF /* NavigationMenuItemDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F871F21C29EF0D7000A351EF /* NavigationMenuItemDetails.swift */; };
|
||||
F8742FC429990AFB00E9642B /* ClientError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8742FC329990AFB00E9642B /* ClientError.swift */; };
|
||||
|
@ -178,9 +189,9 @@
|
|||
F8DF38E629DDB98A0047F1AA /* SocialsSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF38E529DDB98A0047F1AA /* SocialsSectionView.swift */; };
|
||||
F8E6D03329CDD52500416CCA /* EditProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E6D03229CDD52500416CCA /* EditProfileView.swift */; };
|
||||
F8F6E44229BC58F20004795E /* Vernissage.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */; };
|
||||
F8F6E44C29BCC1F70004795E /* SmallWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44629BCC0DC0004795E /* SmallWidgetView.swift */; };
|
||||
F8F6E44D29BCC1F90004795E /* MediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */; };
|
||||
F8F6E44E29BCC1FB0004795E /* LargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */; };
|
||||
F8F6E44C29BCC1F70004795E /* PhotoSmallWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44629BCC0DC0004795E /* PhotoSmallWidgetView.swift */; };
|
||||
F8F6E44D29BCC1F90004795E /* PhotoMediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44829BCC0F00004795E /* PhotoMediumWidgetView.swift */; };
|
||||
F8F6E44E29BCC1FB0004795E /* PhotoLargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44A29BCC0FF0004795E /* PhotoLargeWidgetView.swift */; };
|
||||
F8F6E45129BCE9190004795E /* UIImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E45029BCE9190004795E /* UIImage+Resize.swift */; };
|
||||
F8FB8ABA29EB2ED400342C04 /* NavigationMenuButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FB8AB929EB2ED400342C04 /* NavigationMenuButtons.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
@ -240,6 +251,12 @@
|
|||
F837269429A221420098D3C4 /* PixelfedKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PixelfedKit; sourceTree = "<group>"; };
|
||||
F83CBEFA298298A1002972C8 /* ImageCarouselPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarouselPicture.swift; sourceTree = "<group>"; };
|
||||
F844F42429D2DC39000DD896 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
F84625E829FE2788002D3AF4 /* QRCodeWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeWidget.swift; sourceTree = "<group>"; };
|
||||
F84625EA29FE28D4002D3AF4 /* QRCodeWidgetEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeWidgetEntryView.swift; sourceTree = "<group>"; };
|
||||
F84625EC29FE295B002D3AF4 /* QRCodeLargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLargeWidgetView.swift; sourceTree = "<group>"; };
|
||||
F84625F129FE2B6B002D3AF4 /* QRCodeWidgetEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeWidgetEntry.swift; sourceTree = "<group>"; };
|
||||
F84625F329FE2BF9002D3AF4 /* QRCodeProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeProvider.swift; sourceTree = "<group>"; };
|
||||
F84625F729FE2C2F002D3AF4 /* AccountFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFetcher.swift; sourceTree = "<group>"; };
|
||||
F858906A29E1CC7A00D4BDED /* UIApplication+Window.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Window.swift"; sourceTree = "<group>"; };
|
||||
F85B586C29ED169B00A16D12 /* Vernissage-010.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-010.xcdatamodel"; sourceTree = "<group>"; };
|
||||
F85D4970296402DC00751DF7 /* AuthorizationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationService.swift; sourceTree = "<group>"; };
|
||||
|
@ -258,13 +275,13 @@
|
|||
F864F75E29BB91B400B13921 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||
F864F76029BB91B400B13921 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||
F864F76329BB91B400B13921 /* VernissageWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VernissageWidgetBundle.swift; sourceTree = "<group>"; };
|
||||
F864F76529BB91B400B13921 /* VernissageWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VernissageWidget.swift; sourceTree = "<group>"; };
|
||||
F864F76529BB91B400B13921 /* PhotoWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoWidget.swift; sourceTree = "<group>"; };
|
||||
F864F76729BB91B600B13921 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
F864F76929BB91B600B13921 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
F864F77129BB924D00B13921 /* VernissageWidgetEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VernissageWidgetEntryView.swift; sourceTree = "<group>"; };
|
||||
F864F77329BB929A00B13921 /* Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Provider.swift; sourceTree = "<group>"; };
|
||||
F864F77729BB930000B13921 /* WidgetEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetEntry.swift; sourceTree = "<group>"; };
|
||||
F864F77B29BB982100B13921 /* ImageFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageFetcher.swift; sourceTree = "<group>"; };
|
||||
F864F77129BB924D00B13921 /* PhotoWidgetEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoWidgetEntryView.swift; sourceTree = "<group>"; };
|
||||
F864F77329BB929A00B13921 /* PhotoProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoProvider.swift; sourceTree = "<group>"; };
|
||||
F864F77729BB930000B13921 /* PhotoWidgetEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoWidgetEntry.swift; sourceTree = "<group>"; };
|
||||
F864F77B29BB982100B13921 /* StatusFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFetcher.swift; sourceTree = "<group>"; };
|
||||
F864F7A429BBA01D00B13921 /* CoreDataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataError.swift; sourceTree = "<group>"; };
|
||||
F866F69E296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ApplicationSettings+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
F866F69F296040A8002E8F88 /* ApplicationSettings+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ApplicationSettings+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||
|
@ -285,6 +302,10 @@
|
|||
F86B7220296C49A300EE59EC /* EmptyButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyButtonStyle.swift; sourceTree = "<group>"; };
|
||||
F86BC9E829EBBB66009415EC /* ImageSaver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSaver.swift; sourceTree = "<group>"; };
|
||||
F86BC9EA29EBDA2E009415EC /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = "<group>"; };
|
||||
F8705A7629FF7ABD00DA818A /* QRCodeSmallWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeSmallWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8705A7829FF7CCB00DA818A /* QRCodeMediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeMediumWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8705A7A29FF872F00DA818A /* QRCodeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeGenerator.swift; sourceTree = "<group>"; };
|
||||
F8705A7D29FF880600DA818A /* FileFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileFetcher.swift; sourceTree = "<group>"; };
|
||||
F870EE5129F1645C00A2D43B /* MainNavigationOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainNavigationOptions.swift; sourceTree = "<group>"; };
|
||||
F871F21C29EF0D7000A351EF /* NavigationMenuItemDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationMenuItemDetails.swift; sourceTree = "<group>"; };
|
||||
F871F21F29EF0FEC00A351EF /* Vernissage-011.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-011.xcdatamodel"; sourceTree = "<group>"; };
|
||||
|
@ -370,9 +391,9 @@
|
|||
F8EF3C8B29FC3A5F00CBFF7C /* Vernissage-012.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-012.xcdatamodel"; sourceTree = "<group>"; };
|
||||
F8F6E44329BC5CAA0004795E /* VernissageWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = VernissageWidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||
F8F6E44429BC5CC50004795E /* Vernissage.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Vernissage.entitlements; sourceTree = "<group>"; };
|
||||
F8F6E44629BCC0DC0004795E /* SmallWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediumWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8F6E44629BCC0DC0004795E /* PhotoSmallWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoSmallWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8F6E44829BCC0F00004795E /* PhotoMediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoMediumWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8F6E44A29BCC0FF0004795E /* PhotoLargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLargeWidgetView.swift; sourceTree = "<group>"; };
|
||||
F8F6E45029BCE9190004795E /* UIImage+Resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Resize.swift"; sourceTree = "<group>"; };
|
||||
F8FB8AB929EB2ED400342C04 /* NavigationMenuButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationMenuButtons.swift; sourceTree = "<group>"; };
|
||||
F8FFBD4929E99BEE0047EE80 /* Vernissage-009.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-009.xcdatamodel"; sourceTree = "<group>"; };
|
||||
|
@ -383,6 +404,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F84625FB29FE393B002D3AF4 /* QRCode in Frameworks */,
|
||||
F864F76129BB91B400B13921 /* SwiftUI.framework in Frameworks */,
|
||||
F864F77A29BB94A800B13921 /* PixelfedKit in Frameworks */,
|
||||
F864F75F29BB91B400B13921 /* WidgetKit.framework in Frameworks */,
|
||||
|
@ -557,6 +579,59 @@
|
|||
path = Widgets;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F84625EE29FE2ABA002D3AF4 /* PhotoWidget */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F84625F629FE2C18002D3AF4 /* Service */,
|
||||
F84625EF29FE2AC5002D3AF4 /* Views */,
|
||||
F864F77729BB930000B13921 /* PhotoWidgetEntry.swift */,
|
||||
F864F77329BB929A00B13921 /* PhotoProvider.swift */,
|
||||
F864F77129BB924D00B13921 /* PhotoWidgetEntryView.swift */,
|
||||
F864F76529BB91B400B13921 /* PhotoWidget.swift */,
|
||||
);
|
||||
path = PhotoWidget;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F84625EF29FE2AC5002D3AF4 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8F6E44629BCC0DC0004795E /* PhotoSmallWidgetView.swift */,
|
||||
F8F6E44829BCC0F00004795E /* PhotoMediumWidgetView.swift */,
|
||||
F8F6E44A29BCC0FF0004795E /* PhotoLargeWidgetView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F84625F029FE2B40002D3AF4 /* QRCodeWidget */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F84625F529FE2C0D002D3AF4 /* Service */,
|
||||
F8F6E44529BCC0C90004795E /* Views */,
|
||||
F84625E829FE2788002D3AF4 /* QRCodeWidget.swift */,
|
||||
F84625EA29FE28D4002D3AF4 /* QRCodeWidgetEntryView.swift */,
|
||||
F84625F129FE2B6B002D3AF4 /* QRCodeWidgetEntry.swift */,
|
||||
F84625F329FE2BF9002D3AF4 /* QRCodeProvider.swift */,
|
||||
);
|
||||
path = QRCodeWidget;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F84625F529FE2C0D002D3AF4 /* Service */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F84625F729FE2C2F002D3AF4 /* AccountFetcher.swift */,
|
||||
F8705A7A29FF872F00DA818A /* QRCodeGenerator.swift */,
|
||||
);
|
||||
path = Service;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F84625F629FE2C18002D3AF4 /* Service */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F864F77B29BB982100B13921 /* StatusFetcher.swift */,
|
||||
);
|
||||
path = Service;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F858906729E1CC2900D4BDED /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -570,14 +645,11 @@
|
|||
children = (
|
||||
F8F6E44329BC5CAA0004795E /* VernissageWidgetExtension.entitlements */,
|
||||
F864F76929BB91B600B13921 /* Info.plist */,
|
||||
F8705A7C29FF87EE00DA818A /* SharedServices */,
|
||||
F84625F029FE2B40002D3AF4 /* QRCodeWidget */,
|
||||
F84625EE29FE2ABA002D3AF4 /* PhotoWidget */,
|
||||
F8F6E44F29BCE9030004795E /* Extensions */,
|
||||
F8F6E44529BCC0C90004795E /* Views */,
|
||||
F864F77B29BB982100B13921 /* ImageFetcher.swift */,
|
||||
F864F77729BB930000B13921 /* WidgetEntry.swift */,
|
||||
F864F77329BB929A00B13921 /* Provider.swift */,
|
||||
F864F76329BB91B400B13921 /* VernissageWidgetBundle.swift */,
|
||||
F864F77129BB924D00B13921 /* VernissageWidgetEntryView.swift */,
|
||||
F864F76529BB91B400B13921 /* VernissageWidget.swift */,
|
||||
F864F76729BB91B600B13921 /* Assets.xcassets */,
|
||||
);
|
||||
path = VernissageWidget;
|
||||
|
@ -591,6 +663,14 @@
|
|||
path = Styles;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F8705A7C29FF87EE00DA818A /* SharedServices */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8705A7D29FF880600DA818A /* FileFetcher.swift */,
|
||||
);
|
||||
path = SharedServices;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F878841B29A49493003CFAD2 /* Subviews */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -802,9 +882,9 @@
|
|||
F8F6E44529BCC0C90004795E /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8F6E44629BCC0DC0004795E /* SmallWidgetView.swift */,
|
||||
F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */,
|
||||
F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */,
|
||||
F84625EC29FE295B002D3AF4 /* QRCodeLargeWidgetView.swift */,
|
||||
F8705A7629FF7ABD00DA818A /* QRCodeSmallWidgetView.swift */,
|
||||
F8705A7829FF7CCB00DA818A /* QRCodeMediumWidgetView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
|
@ -837,6 +917,7 @@
|
|||
packageProductDependencies = (
|
||||
F864F77929BB94A800B13921 /* PixelfedKit */,
|
||||
F88BC52E29E04C5F00CE6141 /* EnvironmentKit */,
|
||||
F84625FA29FE393B002D3AF4 /* QRCode */,
|
||||
);
|
||||
productName = VernissageWidgetExtension;
|
||||
productReference = F864F75D29BB91B400B13921 /* VernissageWidgetExtension.appex */;
|
||||
|
@ -934,6 +1015,7 @@
|
|||
F8210DD32966BB7E001D9973 /* XCRemoteSwiftPackageReference "Nuke" */,
|
||||
F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */,
|
||||
F89B5CBE29D019B600549F2F /* XCRemoteSwiftPackageReference "HTMLString" */,
|
||||
F84625F929FE393B002D3AF4 /* XCRemoteSwiftPackageReference "QRCode" */,
|
||||
);
|
||||
productRefGroup = F88C2469295C37B80006098B /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -1005,16 +1087,18 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F864F77829BB930000B13921 /* WidgetEntry.swift in Sources */,
|
||||
F864F77529BB92CE00B13921 /* Provider.swift in Sources */,
|
||||
F864F77629BB92CE00B13921 /* VernissageWidgetEntryView.swift in Sources */,
|
||||
F864F77C29BB982100B13921 /* ImageFetcher.swift in Sources */,
|
||||
F864F77829BB930000B13921 /* PhotoWidgetEntry.swift in Sources */,
|
||||
F864F77529BB92CE00B13921 /* PhotoProvider.swift in Sources */,
|
||||
F864F77629BB92CE00B13921 /* PhotoWidgetEntryView.swift in Sources */,
|
||||
F8705A7729FF7ABD00DA818A /* QRCodeSmallWidgetView.swift in Sources */,
|
||||
F864F77C29BB982100B13921 /* StatusFetcher.swift in Sources */,
|
||||
F84625ED29FE295B002D3AF4 /* QRCodeLargeWidgetView.swift in Sources */,
|
||||
F8F6E44229BC58F20004795E /* Vernissage.xcdatamodeld in Sources */,
|
||||
F8F6E44C29BCC1F70004795E /* SmallWidgetView.swift in Sources */,
|
||||
F864F76629BB91B400B13921 /* VernissageWidget.swift in Sources */,
|
||||
F8F6E44D29BCC1F90004795E /* MediumWidgetView.swift in Sources */,
|
||||
F8F6E44C29BCC1F70004795E /* PhotoSmallWidgetView.swift in Sources */,
|
||||
F864F76629BB91B400B13921 /* PhotoWidget.swift in Sources */,
|
||||
F8F6E44D29BCC1F90004795E /* PhotoMediumWidgetView.swift in Sources */,
|
||||
F815F60C29E49CF20044566B /* Avatar.swift in Sources */,
|
||||
F8F6E44E29BCC1FB0004795E /* LargeWidgetView.swift in Sources */,
|
||||
F8F6E44E29BCC1FB0004795E /* PhotoLargeWidgetView.swift in Sources */,
|
||||
F864F76429BB91B400B13921 /* VernissageWidgetBundle.swift in Sources */,
|
||||
F864F77D29BB9A4600B13921 /* AttachmentData+CoreDataClass.swift in Sources */,
|
||||
F864F7A629BBA01D00B13921 /* CoreDataError.swift in Sources */,
|
||||
|
@ -1023,14 +1107,22 @@
|
|||
F864F78329BB9A6800B13921 /* StatusData+CoreDataProperties.swift in Sources */,
|
||||
F864F78429BB9A6E00B13921 /* ApplicationSettings+CoreDataClass.swift in Sources */,
|
||||
F864F78629BB9A7400B13921 /* AccountData+CoreDataClass.swift in Sources */,
|
||||
F8705A7B29FF872F00DA818A /* QRCodeGenerator.swift in Sources */,
|
||||
F8705A7E29FF880600DA818A /* FileFetcher.swift in Sources */,
|
||||
F864F78529BB9A7100B13921 /* ApplicationSettings+CoreDataProperties.swift in Sources */,
|
||||
F84625E929FE2788002D3AF4 /* QRCodeWidget.swift in Sources */,
|
||||
F864F78729BB9A7700B13921 /* AccountData+CoreDataProperties.swift in Sources */,
|
||||
F864F78829BB9A7B00B13921 /* CoreDataHandler.swift in Sources */,
|
||||
F8F6E45129BCE9190004795E /* UIImage+Resize.swift in Sources */,
|
||||
F864F78929BB9A7D00B13921 /* AccountDataHandler.swift in Sources */,
|
||||
F864F78A29BB9A8000B13921 /* ApplicationSettingsHandler.swift in Sources */,
|
||||
F84625F229FE2B6B002D3AF4 /* QRCodeWidgetEntry.swift in Sources */,
|
||||
F84625EB29FE28D4002D3AF4 /* QRCodeWidgetEntryView.swift in Sources */,
|
||||
F864F78C29BB9A8500B13921 /* AttachmentDataHandler.swift in Sources */,
|
||||
F84625F829FE2C2F002D3AF4 /* AccountFetcher.swift in Sources */,
|
||||
F84625F429FE2BF9002D3AF4 /* QRCodeProvider.swift in Sources */,
|
||||
F864F78B29BB9A8300B13921 /* StatusDataHandler.swift in Sources */,
|
||||
F8705A7929FF7CCB00DA818A /* QRCodeMediumWidgetView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1561,6 +1653,14 @@
|
|||
minimumVersion = 12.0.0;
|
||||
};
|
||||
};
|
||||
F84625F929FE393B002D3AF4 /* XCRemoteSwiftPackageReference "QRCode" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/dmrschmidt/QRCode";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/divadretlaw/EmojiText";
|
||||
|
@ -1595,6 +1695,11 @@
|
|||
package = F8210DD32966BB7E001D9973 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = NukeUI;
|
||||
};
|
||||
F84625FA29FE393B002D3AF4 /* QRCode */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = F84625F929FE393B002D3AF4 /* XCRemoteSwiftPackageReference "QRCode" */;
|
||||
productName = QRCode;
|
||||
};
|
||||
F864F77929BB94A800B13921 /* PixelfedKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = PixelfedKit;
|
||||
|
|
|
@ -22,6 +22,11 @@ class SceneDelegate: NSObject, UISceneDelegate {
|
|||
if statusId.isEmpty == false {
|
||||
ApplicationState.shared.showStatusId = statusId
|
||||
}
|
||||
} else if url.host == AppConstants.accountCallbackPart {
|
||||
let accountId = url.string.replacingOccurrences(of: "\(AppConstants.accountUri)/", with: "")
|
||||
if accountId.isEmpty == false {
|
||||
ApplicationState.shared.showAccountId = accountId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,12 @@ struct VernissageApp: App {
|
|||
self.applicationState.showStatusId = nil
|
||||
}
|
||||
}
|
||||
.onChange(of: applicationState.showAccountId) { newValue in
|
||||
if let accountId = newValue {
|
||||
self.routerPath.navigate(to: .userProfile(accountId: accountId, accountDisplayName: nil, accountUserName: ""))
|
||||
self.applicationState.showAccountId = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,16 @@ struct ThirdPartyView: View {
|
|||
}
|
||||
.font(.footnote)
|
||||
}
|
||||
|
||||
Section("QR codes") {
|
||||
VStack(alignment: .leading) {
|
||||
Link("https://github.com/dmrschmidt/QRCode",
|
||||
destination: URL(string: "https://github.com/dmrschmidt/QRCode")!)
|
||||
.padding(.bottom, 4)
|
||||
Text("A simple QR code image generator to use in your apps, written in Swift 5.")
|
||||
}
|
||||
.font(.footnote)
|
||||
}
|
||||
}
|
||||
.navigationTitle("thirdParty.navigationBar.title")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "PixelfedBlack.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "PixelfedWhite.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "PixelfedBlack@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "PixelfedWhite@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "PixelfedBlack@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "PixelfedWhite@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "QRCode.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "QRCode@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "QRCode@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 28 KiB |
|
@ -1,106 +0,0 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import PixelfedKit
|
||||
|
||||
public class ImageFetcher {
|
||||
public static let shared = ImageFetcher()
|
||||
private init() { }
|
||||
|
||||
private let maxImageSize = 1000.0
|
||||
|
||||
func fetchWidgetEntries(length: Int = 8) async throws -> [WidgetEntry] {
|
||||
let defaultSettings = ApplicationSettingsHandler.shared.get()
|
||||
guard let accountId = defaultSettings.currentAccount else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
guard let account = AccountDataHandler.shared.getAccountData(accountId: accountId) else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
guard let accessToken = account.accessToken else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken)
|
||||
let statuses = try await client.getHomeTimeline(limit: 20)
|
||||
var widgetEntries: [WidgetEntry] = []
|
||||
|
||||
for status in statuses {
|
||||
// When we have images for next hour we can skip.
|
||||
if widgetEntries.count == length {
|
||||
break
|
||||
}
|
||||
|
||||
// We have to skip sensitive (we cannot show them on iPhone home screen).
|
||||
if status.sensitive {
|
||||
continue
|
||||
}
|
||||
|
||||
guard let imageAttachment = status.mediaAttachments.first(where: { $0.type == .image }) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let uiImage = await self.getImage(url: imageAttachment.url)
|
||||
let uiAvatar = await self.getImage(url: status.account.avatar)
|
||||
|
||||
guard let uiImage, let uiAvatar else {
|
||||
continue
|
||||
}
|
||||
|
||||
let displayDate = Calendar.current.date(byAdding: .minute, value: widgetEntries.count * 20, to: Date())
|
||||
|
||||
widgetEntries.append(WidgetEntry(date: displayDate ?? Date(),
|
||||
image: uiImage,
|
||||
avatar: uiAvatar,
|
||||
displayName: status.account.displayNameWithoutEmojis,
|
||||
statusId: status.id))
|
||||
}
|
||||
|
||||
if widgetEntries.isEmpty {
|
||||
widgetEntries.append(self.placeholder())
|
||||
}
|
||||
|
||||
return widgetEntries.shuffled()
|
||||
}
|
||||
|
||||
func placeholder() -> WidgetEntry {
|
||||
WidgetEntry(date: Date(), image: nil, avatar: nil, displayName: "Caroline Rick", statusId: "")
|
||||
}
|
||||
|
||||
private func getImage(url: URL?) async -> UIImage? {
|
||||
guard let url else {
|
||||
return nil
|
||||
}
|
||||
|
||||
do {
|
||||
let (data, response) = try await URLSession.shared.data(from: url)
|
||||
|
||||
guard (response as? HTTPURLResponse)?.status?.responseType == .success else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let uiImage = UIImage(data: data) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if uiImage.size.width < self.maxImageSize && uiImage.size.height < self.maxImageSize {
|
||||
return uiImage
|
||||
}
|
||||
|
||||
if uiImage.size.width > uiImage.size.height {
|
||||
return uiImage.resized(toWidth: self.maxImageSize)
|
||||
} else {
|
||||
return uiImage.resized(toHeight: self.maxImageSize)
|
||||
}
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,19 +8,19 @@ import WidgetKit
|
|||
import SwiftUI
|
||||
import Intents
|
||||
|
||||
struct Provider: TimelineProvider {
|
||||
typealias Entry = WidgetEntry
|
||||
struct PhotoProvider: TimelineProvider {
|
||||
typealias Entry = PhotoWidgetEntry
|
||||
|
||||
func placeholder(in context: Context) -> WidgetEntry {
|
||||
ImageFetcher.shared.placeholder()
|
||||
func placeholder(in context: Context) -> PhotoWidgetEntry {
|
||||
StatusFetcher.shared.placeholder()
|
||||
}
|
||||
|
||||
func getSnapshot(in context: Context, completion: @escaping (WidgetEntry) -> Void) {
|
||||
func getSnapshot(in context: Context, completion: @escaping (PhotoWidgetEntry) -> Void) {
|
||||
Task {
|
||||
if let widgetEntry = await self.getWidgetEntries(length: 1).first {
|
||||
completion(widgetEntry)
|
||||
} else {
|
||||
let entry = ImageFetcher.shared.placeholder()
|
||||
let entry = StatusFetcher.shared.placeholder()
|
||||
completion(entry)
|
||||
}
|
||||
}
|
||||
|
@ -37,11 +37,11 @@ struct Provider: TimelineProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func getWidgetEntries(length: Int = 3) async -> [WidgetEntry] {
|
||||
func getWidgetEntries(length: Int = 3) async -> [PhotoWidgetEntry] {
|
||||
do {
|
||||
return try await ImageFetcher.shared.fetchWidgetEntries(length: length)
|
||||
return try await StatusFetcher.shared.fetchWidgetEntries(length: length)
|
||||
} catch {
|
||||
return [ImageFetcher.shared.placeholder()]
|
||||
return [StatusFetcher.shared.placeholder()]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,15 +7,15 @@
|
|||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct VernissageWidget: Widget {
|
||||
struct PhotoWidget: Widget {
|
||||
let kind: String = "VernissageWidget"
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(kind: kind, provider: Provider()) { entry in
|
||||
VernissageWidgetEntryView(entry: entry)
|
||||
StaticConfiguration(kind: kind, provider: PhotoProvider()) { entry in
|
||||
PhotoWidgetEntryView(entry: entry)
|
||||
}
|
||||
.configurationDisplayName("Vernissage")
|
||||
.description("widget.title.description")
|
||||
.description("widget.title.photoDescription")
|
||||
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct WidgetEntry: TimelineEntry {
|
||||
struct PhotoWidgetEntry: TimelineEntry {
|
||||
let date: Date
|
||||
let image: UIImage?
|
||||
let avatar: UIImage?
|
|
@ -7,16 +7,16 @@
|
|||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct VernissageWidgetEntryView: View {
|
||||
struct PhotoWidgetEntryView: View {
|
||||
@Environment(\.widgetFamily) var family: WidgetFamily
|
||||
|
||||
var entry: Provider.Entry
|
||||
var entry: PhotoProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
switch family {
|
||||
case .systemSmall: SmallWidgetView(entry: entry)
|
||||
case .systemMedium: MediumWidgetView(entry: entry)
|
||||
case .systemLarge: LargeWidgetView(entry: entry)
|
||||
case .systemSmall: PhotoSmallWidgetView(entry: entry)
|
||||
case .systemMedium: PhotoMediumWidgetView(entry: entry)
|
||||
case .systemLarge: PhotoLargeWidgetView(entry: entry)
|
||||
default: Text("Not supported")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import PixelfedKit
|
||||
|
||||
public class StatusFetcher {
|
||||
public static let shared = StatusFetcher()
|
||||
private init() { }
|
||||
|
||||
func fetchWidgetEntries(length: Int = 8) async throws -> [PhotoWidgetEntry] {
|
||||
let defaultSettings = ApplicationSettingsHandler.shared.get()
|
||||
guard let accountId = defaultSettings.currentAccount else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
guard let account = AccountDataHandler.shared.getAccountData(accountId: accountId) else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
guard let accessToken = account.accessToken else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken)
|
||||
let statuses = try await client.getHomeTimeline(limit: 20)
|
||||
var widgetEntries: [PhotoWidgetEntry] = []
|
||||
|
||||
for status in statuses {
|
||||
// When we have images for next hour we can skip.
|
||||
if widgetEntries.count == length {
|
||||
break
|
||||
}
|
||||
|
||||
// We have to skip sensitive (we cannot show them on iPhone home screen).
|
||||
if status.sensitive {
|
||||
continue
|
||||
}
|
||||
|
||||
guard let imageAttachment = status.mediaAttachments.first(where: { $0.type == .image }) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let uiImage = await FileFetcher.shared.getImage(url: imageAttachment.url)
|
||||
let uiAvatar = await FileFetcher.shared.getImage(url: status.account.avatar)
|
||||
|
||||
guard let uiImage, let uiAvatar else {
|
||||
continue
|
||||
}
|
||||
|
||||
let displayDate = Calendar.current.date(byAdding: .minute, value: widgetEntries.count * 20, to: Date())
|
||||
|
||||
widgetEntries.append(PhotoWidgetEntry(date: displayDate ?? Date(),
|
||||
image: uiImage,
|
||||
avatar: uiAvatar,
|
||||
displayName: status.account.displayNameWithoutEmojis,
|
||||
statusId: status.id))
|
||||
}
|
||||
|
||||
if widgetEntries.isEmpty {
|
||||
widgetEntries.append(self.placeholder())
|
||||
}
|
||||
|
||||
return widgetEntries.shuffled()
|
||||
}
|
||||
|
||||
func placeholder() -> PhotoWidgetEntry {
|
||||
PhotoWidgetEntry(date: Date(), image: nil, avatar: nil, displayName: "Caroline Rick", statusId: "")
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@ import SwiftUI
|
|||
import WidgetKit
|
||||
import EnvironmentKit
|
||||
|
||||
struct LargeWidgetView: View {
|
||||
var entry: Provider.Entry
|
||||
struct PhotoLargeWidgetView: View {
|
||||
var entry: PhotoProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
if let uiImage = entry.image, let uiAvatar = entry.avatar {
|
|
@ -8,8 +8,8 @@ import SwiftUI
|
|||
import WidgetKit
|
||||
import EnvironmentKit
|
||||
|
||||
struct MediumWidgetView: View {
|
||||
var entry: Provider.Entry
|
||||
struct PhotoMediumWidgetView: View {
|
||||
var entry: PhotoProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
if let uiImage = entry.image, let uiAvatar = entry.avatar {
|
|
@ -8,8 +8,8 @@ import SwiftUI
|
|||
import WidgetKit
|
||||
import EnvironmentKit
|
||||
|
||||
struct SmallWidgetView: View {
|
||||
var entry: Provider.Entry
|
||||
struct PhotoSmallWidgetView: View {
|
||||
var entry: PhotoProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
if let uiImage = entry.image, let uiAvatar = entry.avatar {
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
import Intents
|
||||
|
||||
struct QRCodeProvider: TimelineProvider {
|
||||
typealias Entry = QRCodeWidgetEntry
|
||||
|
||||
func placeholder(in context: Context) -> QRCodeWidgetEntry {
|
||||
AccountFetcher.shared.placeholder()
|
||||
}
|
||||
|
||||
func getSnapshot(in context: Context, completion: @escaping (QRCodeWidgetEntry) -> Void) {
|
||||
Task {
|
||||
if let widgetEntry = await self.getWidgetEntry().first {
|
||||
completion(widgetEntry)
|
||||
} else {
|
||||
let entry = AccountFetcher.shared.placeholder()
|
||||
completion(entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
|
||||
Task {
|
||||
let currentDate = Date()
|
||||
let widgetEntries = await self.getWidgetEntry()
|
||||
|
||||
let nextUpdateDate = Calendar.current.date(byAdding: .day, value: 1, to: currentDate)!
|
||||
let timeline = Timeline(entries: widgetEntries, policy: .after(nextUpdateDate))
|
||||
completion(timeline)
|
||||
}
|
||||
}
|
||||
|
||||
func getWidgetEntry() async -> [QRCodeWidgetEntry] {
|
||||
do {
|
||||
return try await AccountFetcher.shared.fetchWidgetEntry()
|
||||
} catch {
|
||||
return [AccountFetcher.shared.placeholder()]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct QRCodeWidget: Widget {
|
||||
let kind: String = "QRCodeWidget"
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(kind: kind, provider: QRCodeProvider()) { entry in
|
||||
QRCodeWidgetEntryView(entry: entry)
|
||||
}
|
||||
.configurationDisplayName("Vernissage")
|
||||
.description("widget.title.qrCodeDescription")
|
||||
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct QRCodeWidgetEntry: TimelineEntry {
|
||||
let date: Date
|
||||
let accountId: String
|
||||
let avatar: UIImage?
|
||||
let displayName: String?
|
||||
let profileUrl: URL?
|
||||
let avatarUrl: URL?
|
||||
let portfolioUrl: URL?
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct QRCodeWidgetEntryView: View {
|
||||
@Environment(\.widgetFamily) var family: WidgetFamily
|
||||
|
||||
var entry: QRCodeProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
switch family {
|
||||
case .systemSmall: QRCodeSmallWidgetView(entry: entry)
|
||||
case .systemMedium: QRCodeMediumWidgetView(entry: entry)
|
||||
case .systemLarge: QRCodeLargeWidgetView(entry: entry)
|
||||
default: Text("Not supported")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import PixelfedKit
|
||||
|
||||
public class AccountFetcher {
|
||||
public static let shared = AccountFetcher()
|
||||
private init() { }
|
||||
|
||||
func fetchWidgetEntry() async throws -> [QRCodeWidgetEntry] {
|
||||
let defaultSettings = ApplicationSettingsHandler.shared.get()
|
||||
guard let accountId = defaultSettings.currentAccount else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
guard let account = AccountDataHandler.shared.getAccountData(accountId: accountId) else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
let uiAvatar = await FileFetcher.shared.getImage(url: account.avatar)
|
||||
|
||||
return [
|
||||
QRCodeWidgetEntry(date: Date(),
|
||||
accountId: accountId,
|
||||
avatar: uiAvatar,
|
||||
displayName: account.displayName,
|
||||
profileUrl: account.url,
|
||||
avatarUrl: account.avatar,
|
||||
portfolioUrl: nil)
|
||||
]
|
||||
}
|
||||
|
||||
func placeholder() -> QRCodeWidgetEntry {
|
||||
QRCodeWidgetEntry(date: Date(),
|
||||
accountId: "",
|
||||
avatar: nil,
|
||||
displayName: "Caroline Rick",
|
||||
profileUrl: URL(string: "https://pixelfed.org"),
|
||||
avatarUrl: nil,
|
||||
portfolioUrl: nil)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import QRCode
|
||||
|
||||
public class QRCodeGenerator {
|
||||
public static let shared = QRCodeGenerator()
|
||||
private init() { }
|
||||
|
||||
func generateQRCode(from string: String, scheme: ColorScheme) -> UIImage? {
|
||||
let qrCode = QRCode(string: string,
|
||||
color: scheme == .light ? Color.black.toUIColor() : Color.white.toUIColor(),
|
||||
backgroundColor: scheme == .light ? Color.white.toUIColor() : Color.black.toUIColor(),
|
||||
size: CGSize(width: 150, height: 150),
|
||||
scale: 4.0,
|
||||
inputCorrection: .medium)
|
||||
return try? qrCode?.image()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
import EnvironmentKit
|
||||
|
||||
struct QRCodeLargeWidgetView: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var entry: QRCodeProvider.Entry
|
||||
|
||||
private let qrCodeLightImage: UIImage?
|
||||
private let qrCodeDarkImage: UIImage?
|
||||
|
||||
init(entry: QRCodeProvider.Entry) {
|
||||
self.entry = entry
|
||||
|
||||
if let profileUrl = entry.profileUrl {
|
||||
self.qrCodeLightImage = QRCodeGenerator.shared.generateQRCode(from: profileUrl.absoluteString, scheme: .light)
|
||||
self.qrCodeDarkImage = QRCodeGenerator.shared.generateQRCode(from: profileUrl.absoluteString, scheme: .dark)
|
||||
} else {
|
||||
self.qrCodeLightImage = QRCodeGenerator.shared.generateQRCode(from: "https://pixelfed.org", scheme: .light)
|
||||
self.qrCodeDarkImage = QRCodeGenerator.shared.generateQRCode(from: "https://pixelfed.org", scheme: .dark)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if let uiAvatar = entry.avatar, let qrCodeImage {
|
||||
self.getWidgetBody(uiAvatar: Image(uiImage: uiAvatar), uiQRCode: Image(uiImage: qrCodeImage))
|
||||
} else {
|
||||
self.getWidgetBody(uiAvatar: Image("Avatar"), uiQRCode: Image("QRCode"))
|
||||
.unredacted()
|
||||
}
|
||||
}
|
||||
|
||||
var qrCodeImage: UIImage? {
|
||||
colorScheme == .dark ? qrCodeDarkImage : qrCodeLightImage
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func getWidgetBody(uiAvatar: Image, uiQRCode: Image) -> some View {
|
||||
VStack(spacing: 0) {
|
||||
HStack(alignment: .center) {
|
||||
uiAvatar
|
||||
.avatar(size: 32)
|
||||
|
||||
Text(entry.displayName ?? "")
|
||||
.font(.system(size: 18))
|
||||
.foregroundColor(Color.primary)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.leading, 6)
|
||||
.padding(.bottom, 4)
|
||||
|
||||
uiQRCode
|
||||
.resizable()
|
||||
.widgetURL(URL(string: "\(AppConstants.accountUri)/\(entry.accountId)"))
|
||||
|
||||
if let profileUrl = entry.profileUrl {
|
||||
HStack {
|
||||
Text(profileUrl.absoluteString)
|
||||
.font(.system(size: 10))
|
||||
.foregroundColor(Color.primary.opacity(0.6))
|
||||
Spacer()
|
||||
}
|
||||
.offset(y: -2)
|
||||
.padding(.leading, 8)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
Image("Pixelfed")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(height: 32)
|
||||
.offset(y: -8)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing, .top], 24)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
import EnvironmentKit
|
||||
|
||||
struct QRCodeMediumWidgetView: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var entry: QRCodeProvider.Entry
|
||||
|
||||
private let qrCodeLightImage: UIImage?
|
||||
private let qrCodeDarkImage: UIImage?
|
||||
|
||||
init(entry: QRCodeProvider.Entry) {
|
||||
self.entry = entry
|
||||
|
||||
if let profileUrl = entry.profileUrl {
|
||||
self.qrCodeLightImage = QRCodeGenerator.shared.generateQRCode(from: profileUrl.absoluteString, scheme: .light)
|
||||
self.qrCodeDarkImage = QRCodeGenerator.shared.generateQRCode(from: profileUrl.absoluteString, scheme: .dark)
|
||||
} else {
|
||||
self.qrCodeLightImage = QRCodeGenerator.shared.generateQRCode(from: "https://pixelfed.org", scheme: .light)
|
||||
self.qrCodeDarkImage = QRCodeGenerator.shared.generateQRCode(from: "https://pixelfed.org", scheme: .dark)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if let uiAvatar = entry.avatar, let qrCodeImage {
|
||||
self.getWidgetBody(uiAvatar: Image(uiImage: uiAvatar), uiQRCode: Image(uiImage: qrCodeImage))
|
||||
} else {
|
||||
self.getWidgetBody(uiAvatar: Image("Avatar"), uiQRCode: Image("QRCode"))
|
||||
.unredacted()
|
||||
}
|
||||
}
|
||||
|
||||
var qrCodeImage: UIImage? {
|
||||
colorScheme == .dark ? qrCodeDarkImage : qrCodeLightImage
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func getWidgetBody(uiAvatar: Image, uiQRCode: Image) -> some View {
|
||||
VStack(spacing: 0) {
|
||||
uiQRCode
|
||||
.resizable()
|
||||
.widgetURL(URL(string: "\(AppConstants.accountUri)/\(entry.accountId)"))
|
||||
|
||||
HStack {
|
||||
uiAvatar
|
||||
.avatar(size: 24)
|
||||
.padding(.leading, 8)
|
||||
|
||||
Text(entry.displayName ?? "")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(Color.primary)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image("Pixelfed")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(height: 32)
|
||||
}
|
||||
.padding(.top, 4)
|
||||
}
|
||||
.padding(8)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
import EnvironmentKit
|
||||
|
||||
struct QRCodeSmallWidgetView: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var entry: QRCodeProvider.Entry
|
||||
|
||||
private let qrCodeLightImage: UIImage?
|
||||
private let qrCodeDarkImage: UIImage?
|
||||
|
||||
init(entry: QRCodeProvider.Entry) {
|
||||
self.entry = entry
|
||||
|
||||
if let profileUrl = entry.profileUrl {
|
||||
self.qrCodeLightImage = QRCodeGenerator.shared.generateQRCode(from: profileUrl.absoluteString, scheme: .light)
|
||||
self.qrCodeDarkImage = QRCodeGenerator.shared.generateQRCode(from: profileUrl.absoluteString, scheme: .dark)
|
||||
} else {
|
||||
self.qrCodeLightImage = QRCodeGenerator.shared.generateQRCode(from: "https://pixelfed.org", scheme: .light)
|
||||
self.qrCodeDarkImage = QRCodeGenerator.shared.generateQRCode(from: "https://pixelfed.org", scheme: .dark)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if let uiAvatar = entry.avatar, let qrCodeImage {
|
||||
self.getWidgetBody(uiAvatar: Image(uiImage: uiAvatar), uiQRCode: Image(uiImage: qrCodeImage))
|
||||
} else {
|
||||
self.getWidgetBody(uiAvatar: Image("Avatar"), uiQRCode: Image("QRCode"))
|
||||
.unredacted()
|
||||
}
|
||||
}
|
||||
|
||||
var qrCodeImage: UIImage? {
|
||||
colorScheme == .dark ? qrCodeDarkImage : qrCodeLightImage
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func getWidgetBody(uiAvatar: Image, uiQRCode: Image) -> some View {
|
||||
VStack(spacing: 0) {
|
||||
uiQRCode
|
||||
.resizable()
|
||||
.widgetURL(URL(string: "\(AppConstants.accountUri)/\(entry.accountId)"))
|
||||
|
||||
HStack {
|
||||
uiAvatar
|
||||
.avatar(size: 16)
|
||||
.padding(.leading, 6)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image("Pixelfed")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(height: 24)
|
||||
}
|
||||
}
|
||||
.padding(8)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the Apache License 2.0.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class FileFetcher {
|
||||
public static let shared = FileFetcher()
|
||||
private init() { }
|
||||
|
||||
private let maxImageSize = 1000.0
|
||||
|
||||
public func getImage(url: URL?) async -> UIImage? {
|
||||
guard let url else {
|
||||
return nil
|
||||
}
|
||||
|
||||
do {
|
||||
let (data, response) = try await URLSession.shared.data(from: url)
|
||||
|
||||
guard (response as? HTTPURLResponse)?.status?.responseType == .success else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let uiImage = UIImage(data: data) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if uiImage.size.width < self.maxImageSize && uiImage.size.height < self.maxImageSize {
|
||||
return uiImage
|
||||
}
|
||||
|
||||
if uiImage.size.width > uiImage.size.height {
|
||||
return uiImage.resized(toWidth: self.maxImageSize)
|
||||
} else {
|
||||
return uiImage.resized(toHeight: self.maxImageSize)
|
||||
}
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,10 @@ import SwiftUI
|
|||
|
||||
@main
|
||||
struct VernissageWidgetBundle: WidgetBundle {
|
||||
|
||||
@WidgetBundleBuilder
|
||||
var body: some Widget {
|
||||
VernissageWidget()
|
||||
PhotoWidget()
|
||||
QRCodeWidget()
|
||||
}
|
||||
}
|
||||
|
|