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 */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 297F6FC42AD06E0D00FF159E;
|
||||
remoteInfo = "Wonderous WidgetExtension";
|
||||
remoteInfo = WonderousWidgetExtension;
|
||||
};
|
||||
E214FC8827C5A18E005F78FB /* 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>"; };
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
@ -80,7 +80,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -130,7 +130,7 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
297F6FCA2AD06E0D00FF159E /* Wonderous Widget */ = {
|
||||
297F6FCA2AD06E0D00FF159E /* WonderousWidget */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
297F6FCB2AD06E0D00FF159E /* WonderousWidgetBundle.swift */,
|
||||
@ -142,7 +142,7 @@
|
||||
297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */,
|
||||
297FD5772AE19C25008D8BFE /* FlutterUtils.swift */,
|
||||
);
|
||||
path = "Wonderous Widget";
|
||||
path = WonderousWidget;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5073AC1D92C10773F20D12A2 /* Frameworks */ = {
|
||||
@ -169,10 +169,10 @@
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
297FD56C2ADF0DAB008D8BFE /* Wonderous WidgetExtension.entitlements */,
|
||||
297FD56C2ADF0DAB008D8BFE /* WonderousWidgetExtension.entitlements */,
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
297F6FCA2AD06E0D00FF159E /* Wonderous Widget */,
|
||||
297F6FCA2AD06E0D00FF159E /* WonderousWidget */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
5073AC1D92C10773F20D12A2 /* Frameworks */,
|
||||
E090BB04291350D10AF9DE4E /* Pods */,
|
||||
@ -218,9 +218,9 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
297F6FC42AD06E0D00FF159E /* Wonderous WidgetExtension */ = {
|
||||
297F6FC42AD06E0D00FF159E /* WonderousWidgetExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 297F6FDC2AD06E0F00FF159E /* Build configuration list for PBXNativeTarget "Wonderous WidgetExtension" */;
|
||||
buildConfigurationList = 297F6FDC2AD06E0F00FF159E /* Build configuration list for PBXNativeTarget "WonderousWidgetExtension" */;
|
||||
buildPhases = (
|
||||
297F6FC12AD06E0D00FF159E /* Sources */,
|
||||
297F6FC22AD06E0D00FF159E /* Frameworks */,
|
||||
@ -230,8 +230,8 @@
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "Wonderous WidgetExtension";
|
||||
productName = "Wonderous WidgetExtension";
|
||||
name = WonderousWidgetExtension;
|
||||
productName = WonderousWidgetExtension;
|
||||
productReference = 297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
@ -319,7 +319,7 @@
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
E214FC8127C5A18D005F78FB /* wondersUITests */,
|
||||
297F6FC42AD06E0D00FF159E /* Wonderous WidgetExtension */,
|
||||
297F6FC42AD06E0D00FF159E /* WonderousWidgetExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@ -479,7 +479,7 @@
|
||||
/* Begin PBXTargetDependency section */
|
||||
297F6FD62AD06E0F00FF159E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 297F6FC42AD06E0D00FF159E /* Wonderous WidgetExtension */;
|
||||
target = 297F6FC42AD06E0D00FF159E /* WonderousWidgetExtension */;
|
||||
targetProxy = 297F6FD52AD06E0F00FF159E /* PBXContainerItemProxy */;
|
||||
};
|
||||
E214FC8927C5A18E005F78FB /* PBXTargetDependency */ = {
|
||||
@ -600,14 +600,14 @@
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = "Wonderous WidgetExtension.entitlements";
|
||||
CODE_SIGN_ENTITLEMENTS = WonderousWidgetExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = S3TL5AY6Y3;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "Wonderous Widget/Info.plist";
|
||||
INFOPLIST_FILE = WonderousWidget/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Wonderous Widget";
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
@ -958,7 +958,7 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
297F6FDC2AD06E0F00FF159E /* Build configuration list for PBXNativeTarget "Wonderous WidgetExtension" */ = {
|
||||
297F6FDC2AD06E0F00FF159E /* Build configuration list for PBXNativeTarget "WonderousWidgetExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
297F6FD92AD06E0F00FF159E /* Debug */,
|
||||
|
@ -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
|
||||
|
||||
|
||||
/// 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
|
||||
struct WonderousWidget: Widget {
|
||||
let kind: String = "WonderousWidget"
|
||||
@ -30,30 +43,40 @@ struct WonderousWidget: Widget {
|
||||
struct Provider: TimelineProvider {
|
||||
// Provide an entry for a placeholder version of the widget
|
||||
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
|
||||
func getSnapshot(in context: Context, completion: @escaping (WonderousEntry) -> ()) {
|
||||
let entry:WonderousEntry
|
||||
if(context.isPreview){
|
||||
// entry = placeholder(in: context)
|
||||
entry = WonderousEntry(date: Date(), count: 0, displaySize: context.displaySize, imageData: netImgData)
|
||||
} else {
|
||||
let userDefaults = UserDefaults(suiteName: "group.com.gskinner.homewidget")
|
||||
let count = userDefaults?.integer(forKey: "counter") ?? 0;
|
||||
entry = WonderousEntry(date: Date(), count: count, displaySize: context.displaySize, imageData: netImgData)
|
||||
}
|
||||
let userDefaults = UserDefaults(suiteName: "group.com.gskinner.flutter.wonders.widget")
|
||||
let discoveredCount = userDefaults?.integer(forKey: "discoveredCount") ?? 0
|
||||
let title = userDefaults?.string(forKey: "lastDiscoveredTitle") ?? ""
|
||||
let subTitle = userDefaults?.string(forKey: "lastDiscoveredSubTitle") ?? ""
|
||||
let imageData = userDefaults?.string(forKey: "lastDiscoveredImageData") ?? ""
|
||||
// if(context.isPreview){
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Provide an array of entries for the current time and, optionally, any future times
|
||||
func getTimeline(in context: Context, completion: @escaping (Timeline<WonderousEntry>) -> ()) {
|
||||
// Load a remote image so it can be shown later
|
||||
netImgData = try? Data(
|
||||
contentsOf: URL(string: "https://www.wonderous.info/unsplash/-e0u9SAFeP4-32.jpg")!
|
||||
)
|
||||
|
||||
// let userDefaults = UserDefaults(suiteName: "group.com.gskinner.flutter.wonders.widget")
|
||||
// let url = userDefaults?.string(forKey: "lastDiscoveredImageUrl");
|
||||
// if(url != nil){
|
||||
// netImgData = try? Data(contentsOf: URL(string: url!)!)
|
||||
// } else {
|
||||
// netImgData = nil;
|
||||
// }
|
||||
getSnapshot(in: context) { (entry) in
|
||||
let timeline = Timeline(entries: [entry], policy: .atEnd)
|
||||
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();
|
||||
|
||||
// Collectibles
|
||||
collectiblesLogic.init();
|
||||
await collectiblesLogic.load();
|
||||
|
||||
// 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/logic/common/save_load_mixin.dart';
|
||||
import 'package:wonders/logic/data/collectible_data.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class CollectiblesLogic with ThrottledSaveLoadMixin {
|
||||
@override
|
||||
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
|
||||
final List<CollectibleData> all = collectiblesData;
|
||||
@ -13,11 +19,17 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
||||
late final statesById = ValueNotifier<Map<String, int>>({})..addListener(_updateCounts);
|
||||
|
||||
int _discoveredCount = 0;
|
||||
|
||||
int get discoveredCount => _discoveredCount;
|
||||
|
||||
int _exploredCount = 0;
|
||||
|
||||
int get exploredCount => _exploredCount;
|
||||
|
||||
void init() {
|
||||
HomeWidget.setAppGroupId(_appGroupId);
|
||||
}
|
||||
|
||||
CollectibleData? fromId(String? id) => id == null ? null : all.firstWhereOrNull((o) => o.id == id);
|
||||
|
||||
List<CollectibleData> forWonder(WonderType wonder) {
|
||||
@ -26,6 +38,14 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
||||
|
||||
void setState(String id, int state) {
|
||||
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;
|
||||
statesById.value = states;
|
||||
scheduleSave();
|
||||
@ -37,6 +57,9 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
||||
if (state == CollectibleState.discovered) _discoveredCount++;
|
||||
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
|
||||
@ -67,11 +90,35 @@ class CollectiblesLogic with ThrottledSaveLoadMixin {
|
||||
for (int i = 0; i < all.length; i++) {
|
||||
states[all[i].id] = CollectibleState.lost;
|
||||
}
|
||||
_updateHomeWidgetTextData(); // clear home widget data
|
||||
statesById.value = states;
|
||||
debugPrint('collection reset');
|
||||
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
|
||||
void copyFromJson(Map<String, dynamic> value) {
|
||||
Map<String, int> states = {};
|
||||
|
@ -77,7 +77,7 @@ WondersLogic get wondersLogic => GetIt.I.get<WondersLogic>();
|
||||
TimelineLogic get timelineLogic => GetIt.I.get<TimelineLogic>();
|
||||
SettingsLogic get settingsLogic => GetIt.I.get<SettingsLogic>();
|
||||
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>();
|
||||
WallPaperLogic get wallpaperLogic => GetIt.I.get<WallPaperLogic>();
|
||||
LocaleLogic get localeLogic => GetIt.I.get<LocaleLogic>();
|
||||
|
@ -18,7 +18,7 @@ class ArtifactDetailsScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ArtifactDetailsScreenState extends State<ArtifactDetailsScreen> {
|
||||
late final _future = metAPILogic.getArtifactByID(widget.artifactId, selfHosted: true);
|
||||
late final _future = artifactLogic.getArtifactByID(widget.artifactId, selfHosted: true);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=C:\_dev\sdks\flutter
|
||||
FLUTTER_APPLICATION_PATH=C:\_dev\gskinner\flutter_wonders_app
|
||||
FLUTTER_ROOT=/Users/shawn/Dev/flutter
|
||||
FLUTTER_APPLICATION_PATH=/Users/shawn/Dev/gskinner/flutter-wonders-app
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=2.0.19
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=C:\_dev\sdks\flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=C:\_dev\gskinner\flutter_wonders_app"
|
||||
export "FLUTTER_ROOT=/Users/shawn/Dev/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/shawn/Dev/gskinner/flutter-wonders-app"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=2.0.19"
|
||||
|
Loading…
x
Reference in New Issue
Block a user