Add ability to see last collected image, title and subtitle
This commit is contained in:
parent
758a58b93d
commit
a2a5eef138
@ -33,7 +33,7 @@
|
|||||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
proxyType = 1;
|
proxyType = 1;
|
||||||
remoteGlobalIDString = 297F6FC42AD06E0D00FF159E;
|
remoteGlobalIDString = 297F6FC42AD06E0D00FF159E;
|
||||||
remoteInfo = "Wonderous WidgetExtension";
|
remoteInfo = WonderousWidgetExtension;
|
||||||
};
|
};
|
||||||
E214FC8827C5A18E005F78FB /* PBXContainerItemProxy */ = {
|
E214FC8827C5A18E005F78FB /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
@ -72,7 +72,7 @@
|
|||||||
1475293CB8660AC785DF56AB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
1475293CB8660AC785DF56AB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Wonderous WidgetExtension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; name = "Wonderous WidgetExtension.appex"; path = WonderousWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
297F6FC62AD06E0D00FF159E /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
297F6FC62AD06E0D00FF159E /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||||
297F6FC82AD06E0D00FF159E /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
297F6FC82AD06E0D00FF159E /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||||
297F6FCB2AD06E0D00FF159E /* WonderousWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WonderousWidgetBundle.swift; sourceTree = "<group>"; };
|
297F6FCB2AD06E0D00FF159E /* WonderousWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WonderousWidgetBundle.swift; sourceTree = "<group>"; };
|
||||||
@ -80,7 +80,7 @@
|
|||||||
297F6FCF2AD06E0D00FF159E /* WonderousWidget.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = WonderousWidget.intentdefinition; sourceTree = "<group>"; };
|
297F6FCF2AD06E0D00FF159E /* WonderousWidget.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = WonderousWidget.intentdefinition; sourceTree = "<group>"; };
|
||||||
297F6FD02AD06E0F00FF159E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
297F6FD02AD06E0F00FF159E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
297F6FD22AD06E0F00FF159E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
297F6FD22AD06E0F00FF159E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
297FD56C2ADF0DAB008D8BFE /* Wonderous WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Wonderous WidgetExtension.entitlements"; sourceTree = "<group>"; };
|
297FD56C2ADF0DAB008D8BFE /* WonderousWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WonderousWidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||||
297FD5732AE18011008D8BFE /* WonderousWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WonderousWidgetView.swift; sourceTree = "<group>"; };
|
297FD5732AE18011008D8BFE /* WonderousWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WonderousWidgetView.swift; sourceTree = "<group>"; };
|
||||||
297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WonderWidgetViewComponents.swift; sourceTree = "<group>"; };
|
297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WonderWidgetViewComponents.swift; sourceTree = "<group>"; };
|
||||||
297FD5772AE19C25008D8BFE /* FlutterUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterUtils.swift; sourceTree = "<group>"; };
|
297FD5772AE19C25008D8BFE /* FlutterUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterUtils.swift; sourceTree = "<group>"; };
|
||||||
@ -142,7 +142,7 @@
|
|||||||
297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */,
|
297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */,
|
||||||
297FD5772AE19C25008D8BFE /* FlutterUtils.swift */,
|
297FD5772AE19C25008D8BFE /* FlutterUtils.swift */,
|
||||||
);
|
);
|
||||||
path = "Wonderous Widget";
|
path = WonderousWidget;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
5073AC1D92C10773F20D12A2 /* Frameworks */ = {
|
5073AC1D92C10773F20D12A2 /* Frameworks */ = {
|
||||||
@ -230,8 +230,8 @@
|
|||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = "Wonderous WidgetExtension";
|
name = WonderousWidgetExtension;
|
||||||
productName = "Wonderous WidgetExtension";
|
productName = WonderousWidgetExtension;
|
||||||
productReference = 297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */;
|
productReference = 297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */;
|
||||||
productType = "com.apple.product-type.app-extension";
|
productType = "com.apple.product-type.app-extension";
|
||||||
};
|
};
|
||||||
@ -600,14 +600,14 @@
|
|||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_ENTITLEMENTS = "Wonderous WidgetExtension.entitlements";
|
CODE_SIGN_ENTITLEMENTS = WonderousWidgetExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = S3TL5AY6Y3;
|
DEVELOPMENT_TEAM = S3TL5AY6Y3;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Wonderous Widget/Info.plist";
|
INFOPLIST_FILE = WonderousWidget/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Wonderous Widget";
|
INFOPLIST_KEY_CFBundleDisplayName = "Wonderous Widget";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"colors" : [
|
|
||||||
{
|
|
||||||
"color" : {
|
|
||||||
"color-space" : "srgb",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "0.360",
|
|
||||||
"green" : "0.580",
|
|
||||||
"red" : "0.890"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"colors" : [
|
|
||||||
{
|
|
||||||
"color" : {
|
|
||||||
"color-space" : "srgb",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "0.580",
|
|
||||||
"green" : "0.600",
|
|
||||||
"red" : "0.620"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
//
|
|
||||||
// File.swift
|
|
||||||
// Wonderous WidgetExtension
|
|
||||||
//
|
|
||||||
// Created by Shawn on 2023-10-19.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Add support for showing the last-found artifact from the app
|
|
||||||
// Load an image from the flutter assets bundle
|
|
||||||
struct BgImage : View {
|
|
||||||
var entry: WonderousEntry
|
|
||||||
var body: some View {
|
|
||||||
let image = bundle.appending(path: "/assets/images/widget/background-empty.jpg").path();
|
|
||||||
//print(image)
|
|
||||||
if let uiImage = UIImage(contentsOfFile: image) {
|
|
||||||
let image = Image(uiImage: uiImage)
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fill) // Fill the entire view
|
|
||||||
.edgesIgnoringSafeArea(.all) // Ignore the safe area
|
|
||||||
return AnyView(image)
|
|
||||||
}
|
|
||||||
print("The image file could not be loaded")
|
|
||||||
return AnyView(EmptyView())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display a previously loaded remote image
|
|
||||||
struct NetImage : View {
|
|
||||||
var imageData: Data?
|
|
||||||
var body: some View {
|
|
||||||
if imageData != nil, let uiImage = UIImage(data: imageData!) {
|
|
||||||
return Image(uiImage: uiImage)
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(width: 80, height: 26.0)
|
|
||||||
} else {
|
|
||||||
return Image("EmptyChart")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(width: 80, height: 26.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GaugeProgressStyle: ProgressViewStyle {
|
|
||||||
let color:Color
|
|
||||||
func makeBody(configuration: Configuration) -> some View {
|
|
||||||
let fractionCompleted = configuration.fractionCompleted ?? 0
|
|
||||||
|
|
||||||
return ZStack {
|
|
||||||
Circle()
|
|
||||||
.stroke(.gray, style: StrokeStyle(lineWidth: 2))
|
|
||||||
Circle()
|
|
||||||
.trim(from: 0, to: fractionCompleted)
|
|
||||||
.stroke(color, style: StrokeStyle(lineWidth: 4, lineCap: .round))
|
|
||||||
.rotationEffect(.degrees(90))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import WidgetKit
|
|
||||||
import SwiftUI
|
|
||||||
import Intents
|
|
||||||
|
|
||||||
// Defines the view / layout of the widget
|
|
||||||
struct WonderousWidgetView : View {
|
|
||||||
@Environment(\.widgetFamily) var family: WidgetFamily
|
|
||||||
var entry: Provider.Entry
|
|
||||||
var body: some View {
|
|
||||||
let showTitle = family == .systemLarge
|
|
||||||
let showIcon = family != .systemSmall
|
|
||||||
let showTitleAndDesc = family != .systemSmall
|
|
||||||
let accentColor:Color = Color("AccentColor")
|
|
||||||
let progress = 7.0 / 32.0;
|
|
||||||
let image = bundle.appending(path: "/assets/images/widget/wonderous-icon.png").path();
|
|
||||||
let content = VStack{
|
|
||||||
HStack {
|
|
||||||
if(showTitle) {
|
|
||||||
Text("Collection").foregroundColor(accentColor)
|
|
||||||
}
|
|
||||||
Spacer();
|
|
||||||
if(showIcon || true) {
|
|
||||||
Image(uiImage: UIImage(contentsOfFile: image)!)
|
|
||||||
.resizable().scaledToFit().frame(height: 24)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer();
|
|
||||||
HStack {
|
|
||||||
if(showTitleAndDesc) {
|
|
||||||
VStack(alignment: .leading){
|
|
||||||
Text("Wonderous")
|
|
||||||
.font(.system(size: 22))
|
|
||||||
.foregroundColor(accentColor);
|
|
||||||
Text("Search for hidden artifacts")
|
|
||||||
.font(.system(size: 15))
|
|
||||||
.foregroundColor(Color("GreyMediumColor"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer();
|
|
||||||
ZStack{
|
|
||||||
ProgressView(value: progress)
|
|
||||||
.progressViewStyle(
|
|
||||||
GaugeProgressStyle(color: accentColor)
|
|
||||||
)
|
|
||||||
.frame(width: 48, height: 48)
|
|
||||||
Text("\(Int(progress * 100))%").font(.system(size: 12)).foregroundColor(accentColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//NetImage(imageData: netImgData)
|
|
||||||
}.widgetURL(URL(string: "wonderous://collections"))
|
|
||||||
|
|
||||||
ZStack{
|
|
||||||
BgImage(entry: entry)
|
|
||||||
LinearGradient(
|
|
||||||
gradient: Gradient(colors: [.black.opacity(0), .black]),
|
|
||||||
startPoint: .center,
|
|
||||||
endPoint: .bottom)
|
|
||||||
switch(family) {
|
|
||||||
case .systemSmall:
|
|
||||||
content.padding(16)
|
|
||||||
case .systemMedium:
|
|
||||||
content.padding(24)
|
|
||||||
default:
|
|
||||||
content.padding(32)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
47
ios/WonderousWidget/WonderWidgetViewComponents.swift
Normal file
47
ios/WonderousWidget/WonderWidgetViewComponents.swift
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
|
// Loads a default image from the flutter assets bundle,
|
||||||
|
// or displays a base64 encoded image
|
||||||
|
struct BgImage : View {
|
||||||
|
var entry: WonderousEntry
|
||||||
|
var body: some View {
|
||||||
|
var uiImage:UIImage?;
|
||||||
|
if(entry.imageData.isEmpty){
|
||||||
|
let defaultImage = bundle.appending(path: "/assets/images/widget/background-empty.jpg").path();
|
||||||
|
uiImage = UIImage(contentsOfFile: defaultImage);
|
||||||
|
} else {
|
||||||
|
uiImage = UIImage(data: Data(base64Encoded: entry.imageData)!)
|
||||||
|
}
|
||||||
|
if(uiImage != nil){
|
||||||
|
let image = GeometryReader { geometry in
|
||||||
|
Image(uiImage: uiImage!)
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.edgesIgnoringSafeArea(.all) // Ignore the safe area
|
||||||
|
.frame(maxWidth: geometry.size.width, maxHeight: geometry.size.height)
|
||||||
|
}
|
||||||
|
return AnyView(image)
|
||||||
|
}
|
||||||
|
print("The image file could not be loaded")
|
||||||
|
return AnyView(EmptyView())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GaugeProgressStyle: ProgressViewStyle {
|
||||||
|
|
||||||
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
|
let fractionCompleted = configuration.fractionCompleted ?? 0
|
||||||
|
|
||||||
|
return ZStack {
|
||||||
|
Circle()
|
||||||
|
.stroke(Colors.darkGrey, style: StrokeStyle(lineWidth: 2))
|
||||||
|
Circle()
|
||||||
|
.trim(from: 0, to: fractionCompleted)
|
||||||
|
.stroke(Colors.accentColor, style: StrokeStyle(lineWidth: 4, lineCap: .round))
|
||||||
|
.rotationEffect(.degrees(90))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,19 @@ import Intents
|
|||||||
var netImgData: Data? = nil
|
var netImgData: Data? = nil
|
||||||
|
|
||||||
|
|
||||||
|
/// Entry, is passed into the view and defines the data it needs
|
||||||
|
struct WonderousEntry : TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
//let displaySize: CGSize
|
||||||
|
//let imageData: Data?
|
||||||
|
let discoveredCount:Int;
|
||||||
|
var title:String = "";
|
||||||
|
var subTitle:String = "";
|
||||||
|
var imageData:String = "";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Widget, defines the display name and description, and also wraps the View
|
// Widget, defines the display name and description, and also wraps the View
|
||||||
struct WonderousWidget: Widget {
|
struct WonderousWidget: Widget {
|
||||||
let kind: String = "WonderousWidget"
|
let kind: String = "WonderousWidget"
|
||||||
@ -30,30 +43,40 @@ struct WonderousWidget: Widget {
|
|||||||
struct Provider: TimelineProvider {
|
struct Provider: TimelineProvider {
|
||||||
// Provide an entry for a placeholder version of the widget
|
// Provide an entry for a placeholder version of the widget
|
||||||
func placeholder(in context: Context) -> WonderousEntry {
|
func placeholder(in context: Context) -> WonderousEntry {
|
||||||
WonderousEntry(date: Date(), count: 0, displaySize: context.displaySize, imageData: netImgData)
|
WonderousEntry(date: Date(), discoveredCount: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide an entry for the current time and state of the widget
|
// Provide an entry for the current time and state of the widget
|
||||||
func getSnapshot(in context: Context, completion: @escaping (WonderousEntry) -> ()) {
|
func getSnapshot(in context: Context, completion: @escaping (WonderousEntry) -> ()) {
|
||||||
let entry:WonderousEntry
|
let entry:WonderousEntry
|
||||||
if(context.isPreview){
|
let userDefaults = UserDefaults(suiteName: "group.com.gskinner.flutter.wonders.widget")
|
||||||
// entry = placeholder(in: context)
|
let discoveredCount = userDefaults?.integer(forKey: "discoveredCount") ?? 0
|
||||||
entry = WonderousEntry(date: Date(), count: 0, displaySize: context.displaySize, imageData: netImgData)
|
let title = userDefaults?.string(forKey: "lastDiscoveredTitle") ?? ""
|
||||||
} else {
|
let subTitle = userDefaults?.string(forKey: "lastDiscoveredSubTitle") ?? ""
|
||||||
let userDefaults = UserDefaults(suiteName: "group.com.gskinner.homewidget")
|
let imageData = userDefaults?.string(forKey: "lastDiscoveredImageData") ?? ""
|
||||||
let count = userDefaults?.integer(forKey: "counter") ?? 0;
|
// if(context.isPreview){
|
||||||
entry = WonderousEntry(date: Date(), count: count, displaySize: context.displaySize, imageData: netImgData)
|
// entry = WonderousEntry(date: Date(), discoveredCount: discoveredCount)
|
||||||
}
|
// }
|
||||||
|
entry = WonderousEntry(
|
||||||
|
date: Date(),
|
||||||
|
discoveredCount:discoveredCount,
|
||||||
|
title: title,
|
||||||
|
subTitle: subTitle.prefix(1).capitalized + subTitle.dropFirst(),
|
||||||
|
imageData: imageData
|
||||||
|
)
|
||||||
completion(entry);
|
completion(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide an array of entries for the current time and, optionally, any future times
|
// Provide an array of entries for the current time and, optionally, any future times
|
||||||
func getTimeline(in context: Context, completion: @escaping (Timeline<WonderousEntry>) -> ()) {
|
func getTimeline(in context: Context, completion: @escaping (Timeline<WonderousEntry>) -> ()) {
|
||||||
// Load a remote image so it can be shown later
|
// Load a remote image so it can be shown later
|
||||||
netImgData = try? Data(
|
// let userDefaults = UserDefaults(suiteName: "group.com.gskinner.flutter.wonders.widget")
|
||||||
contentsOf: URL(string: "https://www.wonderous.info/unsplash/-e0u9SAFeP4-32.jpg")!
|
// let url = userDefaults?.string(forKey: "lastDiscoveredImageUrl");
|
||||||
)
|
// if(url != nil){
|
||||||
|
// netImgData = try? Data(contentsOf: URL(string: url!)!)
|
||||||
|
// } else {
|
||||||
|
// netImgData = nil;
|
||||||
|
// }
|
||||||
getSnapshot(in: context) { (entry) in
|
getSnapshot(in: context) { (entry) in
|
||||||
let timeline = Timeline(entries: [entry], policy: .atEnd)
|
let timeline = Timeline(entries: [entry], policy: .atEnd)
|
||||||
completion(timeline)
|
completion(timeline)
|
||||||
@ -62,15 +85,6 @@ struct Provider: TimelineProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Entry, is passed into the view and defines the data it needs
|
|
||||||
struct WonderousEntry : TimelineEntry {
|
|
||||||
let date: Date
|
|
||||||
let count:Int;
|
|
||||||
let displaySize: CGSize
|
|
||||||
let imageData: Data?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
72
ios/WonderousWidget/WonderousWidgetView.swift
Normal file
72
ios/WonderousWidget/WonderousWidgetView.swift
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
import Intents
|
||||||
|
|
||||||
|
struct Colors {
|
||||||
|
static let accentColor:Color = Color(red: 0.89, green: 0.58, blue: 0.36)
|
||||||
|
static let offWhiteColor:Color = Color(red: 0.97, green: 0.92, blue: 0.9)
|
||||||
|
static let mediumGrey:Color = Color(red: 0.62, green: 0.6, blue: 0.58)
|
||||||
|
static let darkGrey:Color = Color(red: 0.32, green: 0.31, blue: 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defines the view / layout of the widget
|
||||||
|
struct WonderousWidgetView : View {
|
||||||
|
@Environment(\.widgetFamily) var family: WidgetFamily
|
||||||
|
var entry: Provider.Entry
|
||||||
|
var body: some View {
|
||||||
|
let showTitle = family == .systemLarge
|
||||||
|
let showIcon = family != .systemSmall
|
||||||
|
let showTitleAndDesc = family != .systemSmall
|
||||||
|
|
||||||
|
let progress = Double(entry.discoveredCount) / 24.0
|
||||||
|
let iconImage = bundle.appending(path: "/assets/images/widget/wonderous-icon.png").path()
|
||||||
|
let title:String = entry.title.isEmpty ? "Wonderous" : entry.title;
|
||||||
|
let subTitle:String = entry.subTitle.isEmpty ? "Search for hidden artifacts" : entry.subTitle;
|
||||||
|
let content = VStack{
|
||||||
|
HStack {
|
||||||
|
if(showTitle) {
|
||||||
|
Text("Collection")
|
||||||
|
.font(.system(size: 15))
|
||||||
|
.foregroundColor(Colors.offWhiteColor)
|
||||||
|
}
|
||||||
|
Spacer();
|
||||||
|
if(showIcon) {
|
||||||
|
Image(uiImage: UIImage(contentsOfFile: iconImage)!)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(height: 24)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer();
|
||||||
|
HStack {
|
||||||
|
if(showTitleAndDesc) {
|
||||||
|
VStack(alignment: .leading){
|
||||||
|
Text(title)
|
||||||
|
.font(.system(size: 22))
|
||||||
|
.foregroundColor(.white);
|
||||||
|
Text(subTitle)
|
||||||
|
.font(.system(size: 15))
|
||||||
|
.foregroundColor(Colors.mediumGrey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer();
|
||||||
|
ZStack{
|
||||||
|
ProgressView(value: progress)
|
||||||
|
.progressViewStyle(GaugeProgressStyle())
|
||||||
|
.frame(width: 48, height: 48)
|
||||||
|
Text("\(Int(progress * 100))%").font(.system(size: 13)).foregroundColor(.white)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZStack{
|
||||||
|
BgImage(entry: entry)
|
||||||
|
LinearGradient(
|
||||||
|
gradient: Gradient(colors: [.black.opacity(0), .black]),
|
||||||
|
startPoint: .center,
|
||||||
|
endPoint: .bottom)
|
||||||
|
content.padding(16)
|
||||||
|
}.widgetURL(URL(string: "wonderous://collection"))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -59,6 +59,7 @@ class AppLogic {
|
|||||||
timelineLogic.init();
|
timelineLogic.init();
|
||||||
|
|
||||||
// Collectibles
|
// Collectibles
|
||||||
|
collectiblesLogic.init();
|
||||||
await collectiblesLogic.load();
|
await collectiblesLogic.load();
|
||||||
|
|
||||||
// Flag bootStrap as complete
|
// Flag bootStrap as complete
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:home_widget/home_widget.dart';
|
||||||
import 'package:wonders/common_libs.dart';
|
import 'package:wonders/common_libs.dart';
|
||||||
import 'package:wonders/logic/common/save_load_mixin.dart';
|
import 'package:wonders/logic/common/save_load_mixin.dart';
|
||||||
import 'package:wonders/logic/data/collectible_data.dart';
|
import 'package:wonders/logic/data/collectible_data.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
class CollectiblesLogic with ThrottledSaveLoadMixin {
|
class CollectiblesLogic with ThrottledSaveLoadMixin {
|
||||||
@override
|
@override
|
||||||
String get fileName => 'collectibles.dat';
|
String get fileName => 'collectibles.dat';
|
||||||
|
static const _appGroupId = 'group.com.gskinner.flutter.wonders.widget';
|
||||||
|
static const _appName = 'WonderousWidget';
|
||||||
|
|
||||||
/// Holds all collectibles that the views should care about
|
/// Holds all collectibles that the views should care about
|
||||||
final List<CollectibleData> all = collectiblesData;
|
final List<CollectibleData> all = collectiblesData;
|
||||||
@ -13,11 +19,17 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
|||||||
late final statesById = ValueNotifier<Map<String, int>>({})..addListener(_updateCounts);
|
late final statesById = ValueNotifier<Map<String, int>>({})..addListener(_updateCounts);
|
||||||
|
|
||||||
int _discoveredCount = 0;
|
int _discoveredCount = 0;
|
||||||
|
|
||||||
int get discoveredCount => _discoveredCount;
|
int get discoveredCount => _discoveredCount;
|
||||||
|
|
||||||
int _exploredCount = 0;
|
int _exploredCount = 0;
|
||||||
|
|
||||||
int get exploredCount => _exploredCount;
|
int get exploredCount => _exploredCount;
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
HomeWidget.setAppGroupId(_appGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
CollectibleData? fromId(String? id) => id == null ? null : all.firstWhereOrNull((o) => o.id == id);
|
CollectibleData? fromId(String? id) => id == null ? null : all.firstWhereOrNull((o) => o.id == id);
|
||||||
|
|
||||||
List<CollectibleData> forWonder(WonderType wonder) {
|
List<CollectibleData> forWonder(WonderType wonder) {
|
||||||
@ -26,6 +38,14 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
|||||||
|
|
||||||
void setState(String id, int state) {
|
void setState(String id, int state) {
|
||||||
Map<String, int> states = Map.of(statesById.value);
|
Map<String, int> states = Map.of(statesById.value);
|
||||||
|
if (state == CollectibleState.discovered) {
|
||||||
|
final data = fromId(id)!;
|
||||||
|
_updateHomeWidgetTextData(
|
||||||
|
title: data.title,
|
||||||
|
id: data.id,
|
||||||
|
imageUrl: data.imageUrlSmall,
|
||||||
|
);
|
||||||
|
}
|
||||||
states[id] = state;
|
states[id] = state;
|
||||||
statesById.value = states;
|
statesById.value = states;
|
||||||
scheduleSave();
|
scheduleSave();
|
||||||
@ -37,6 +57,9 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
|||||||
if (state == CollectibleState.discovered) _discoveredCount++;
|
if (state == CollectibleState.discovered) _discoveredCount++;
|
||||||
if (state == CollectibleState.explored) _exploredCount++;
|
if (state == CollectibleState.explored) _exploredCount++;
|
||||||
});
|
});
|
||||||
|
HomeWidget.saveWidgetData<int>('discoveredCount', _discoveredCount);
|
||||||
|
HomeWidget.updateWidget(iOSName: _appName);
|
||||||
|
debugPrint('setting discovered count for home widget $_discoveredCount');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a discovered item, sorted by the order of wondersLogic.all
|
/// Get a discovered item, sorted by the order of wondersLogic.all
|
||||||
@ -67,11 +90,35 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
|||||||
for (int i = 0; i < all.length; i++) {
|
for (int i = 0; i < all.length; i++) {
|
||||||
states[all[i].id] = CollectibleState.lost;
|
states[all[i].id] = CollectibleState.lost;
|
||||||
}
|
}
|
||||||
|
_updateHomeWidgetTextData(); // clear home widget data
|
||||||
statesById.value = states;
|
statesById.value = states;
|
||||||
debugPrint('collection reset');
|
debugPrint('collection reset');
|
||||||
scheduleSave();
|
scheduleSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Optimize to send both network requests simultaneously
|
||||||
|
Future<void> _updateHomeWidgetTextData({String title = '', String id = '', String imageUrl = ''}) async {
|
||||||
|
// Save title
|
||||||
|
HomeWidget.saveWidgetData<String>('lastDiscoveredTitle', title);
|
||||||
|
// Subtitle
|
||||||
|
String subTitle = '';
|
||||||
|
if(id.isNotEmpty){
|
||||||
|
final artifactData = await artifactLogic.getArtifactByID(id);
|
||||||
|
subTitle = artifactData?.date ?? '';
|
||||||
|
}
|
||||||
|
HomeWidget.saveWidgetData<String>('lastDiscoveredSubTitle', subTitle);
|
||||||
|
// Image,
|
||||||
|
// Download, convert to base64 string and write to shared widget data
|
||||||
|
String imageBase64 = '';
|
||||||
|
if(imageUrl.isNotEmpty){
|
||||||
|
var bytes = await http.readBytes(Uri.parse(imageUrl));
|
||||||
|
imageBase64 = base64Encode(bytes);
|
||||||
|
debugPrint('Saving base64 bytes: $imageBase64');
|
||||||
|
}
|
||||||
|
HomeWidget.saveWidgetData<String>('lastDiscoveredImageData', imageBase64);
|
||||||
|
HomeWidget.updateWidget(iOSName: _appName);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void copyFromJson(Map<String, dynamic> value) {
|
void copyFromJson(Map<String, dynamic> value) {
|
||||||
Map<String, int> states = {};
|
Map<String, int> states = {};
|
||||||
|
@ -77,7 +77,7 @@ WondersLogic get wondersLogic => GetIt.I.get<WondersLogic>();
|
|||||||
TimelineLogic get timelineLogic => GetIt.I.get<TimelineLogic>();
|
TimelineLogic get timelineLogic => GetIt.I.get<TimelineLogic>();
|
||||||
SettingsLogic get settingsLogic => GetIt.I.get<SettingsLogic>();
|
SettingsLogic get settingsLogic => GetIt.I.get<SettingsLogic>();
|
||||||
UnsplashLogic get unsplashLogic => GetIt.I.get<UnsplashLogic>();
|
UnsplashLogic get unsplashLogic => GetIt.I.get<UnsplashLogic>();
|
||||||
ArtifactAPILogic get metAPILogic => GetIt.I.get<ArtifactAPILogic>();
|
ArtifactAPILogic get artifactLogic => GetIt.I.get<ArtifactAPILogic>();
|
||||||
CollectiblesLogic get collectiblesLogic => GetIt.I.get<CollectiblesLogic>();
|
CollectiblesLogic get collectiblesLogic => GetIt.I.get<CollectiblesLogic>();
|
||||||
WallPaperLogic get wallpaperLogic => GetIt.I.get<WallPaperLogic>();
|
WallPaperLogic get wallpaperLogic => GetIt.I.get<WallPaperLogic>();
|
||||||
LocaleLogic get localeLogic => GetIt.I.get<LocaleLogic>();
|
LocaleLogic get localeLogic => GetIt.I.get<LocaleLogic>();
|
||||||
|
@ -18,7 +18,7 @@ class ArtifactDetailsScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ArtifactDetailsScreenState extends State<ArtifactDetailsScreen> {
|
class _ArtifactDetailsScreenState extends State<ArtifactDetailsScreen> {
|
||||||
late final _future = metAPILogic.getArtifactByID(widget.artifactId, selfHosted: true);
|
late final _future = artifactLogic.getArtifactByID(widget.artifactId, selfHosted: true);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// This is a generated file; do not edit or check into version control.
|
// This is a generated file; do not edit or check into version control.
|
||||||
FLUTTER_ROOT=C:\_dev\sdks\flutter
|
FLUTTER_ROOT=/Users/shawn/Dev/flutter
|
||||||
FLUTTER_APPLICATION_PATH=C:\_dev\gskinner\flutter_wonders_app
|
FLUTTER_APPLICATION_PATH=/Users/shawn/Dev/gskinner/flutter-wonders-app
|
||||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||||
FLUTTER_BUILD_DIR=build
|
FLUTTER_BUILD_DIR=build
|
||||||
FLUTTER_BUILD_NAME=2.0.19
|
FLUTTER_BUILD_NAME=2.0.19
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# This is a generated file; do not edit or check into version control.
|
# This is a generated file; do not edit or check into version control.
|
||||||
export "FLUTTER_ROOT=C:\_dev\sdks\flutter"
|
export "FLUTTER_ROOT=/Users/shawn/Dev/flutter"
|
||||||
export "FLUTTER_APPLICATION_PATH=C:\_dev\gskinner\flutter_wonders_app"
|
export "FLUTTER_APPLICATION_PATH=/Users/shawn/Dev/gskinner/flutter-wonders-app"
|
||||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||||
export "FLUTTER_BUILD_DIR=build"
|
export "FLUTTER_BUILD_DIR=build"
|
||||||
export "FLUTTER_BUILD_NAME=2.0.19"
|
export "FLUTTER_BUILD_NAME=2.0.19"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user