Cleanup home_widget views, add comments, fix rounding issue

This commit is contained in:
Shawn 2024-01-25 15:01:16 -07:00
parent 45a9a8348f
commit 8d5daf3edd
9 changed files with 62 additions and 38 deletions

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
296251252AE7410D00D574FF /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296251242AE7410D00D574FF /* Colors.swift */; }; 296251252AE7410D00D574FF /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296251242AE7410D00D574FF /* Colors.swift */; };
2978ECDD2B62D00C00E36CE8 /* FlutterAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2978ECDC2B62D00C00E36CE8 /* FlutterAssets.swift */; };
297F6FC72AD06E0D00FF159E /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 297F6FC62AD06E0D00FF159E /* WidgetKit.framework */; }; 297F6FC72AD06E0D00FF159E /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 297F6FC62AD06E0D00FF159E /* WidgetKit.framework */; };
297F6FC92AD06E0D00FF159E /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 297F6FC82AD06E0D00FF159E /* SwiftUI.framework */; }; 297F6FC92AD06E0D00FF159E /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 297F6FC82AD06E0D00FF159E /* SwiftUI.framework */; };
297F6FCC2AD06E0D00FF159E /* WonderousWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 297F6FCB2AD06E0D00FF159E /* WonderousWidgetBundle.swift */; }; 297F6FCC2AD06E0D00FF159E /* WonderousWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 297F6FCB2AD06E0D00FF159E /* WonderousWidgetBundle.swift */; };
@ -73,6 +74,7 @@
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>"; };
296251242AE7410D00D574FF /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; }; 296251242AE7410D00D574FF /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
2978ECDC2B62D00C00E36CE8 /* FlutterAssets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterAssets.swift; sourceTree = "<group>"; };
297F6FC52AD06E0D00FF159E /* Wonderous WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; name = "Wonderous WidgetExtension.appex"; path = WonderousWidgetExtension.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; };
@ -141,6 +143,7 @@
297FD5732AE18011008D8BFE /* WonderousWidgetView.swift */, 297FD5732AE18011008D8BFE /* WonderousWidgetView.swift */,
297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */, 297FD5752AE19BD9008D8BFE /* WonderWidgetViewComponents.swift */,
296251242AE7410D00D574FF /* Colors.swift */, 296251242AE7410D00D574FF /* Colors.swift */,
2978ECDC2B62D00C00E36CE8 /* FlutterAssets.swift */,
); );
path = WonderousWidget; path = WonderousWidget;
sourceTree = "<group>"; sourceTree = "<group>";
@ -451,6 +454,7 @@
297FD5762AE19BD9008D8BFE /* WonderWidgetViewComponents.swift in Sources */, 297FD5762AE19BD9008D8BFE /* WonderWidgetViewComponents.swift in Sources */,
296251252AE7410D00D574FF /* Colors.swift in Sources */, 296251252AE7410D00D574FF /* Colors.swift in Sources */,
297F6FD32AD06E0F00FF159E /* WonderousWidget.intentdefinition in Sources */, 297F6FD32AD06E0F00FF159E /* WonderousWidget.intentdefinition in Sources */,
2978ECDD2B62D00C00E36CE8 /* FlutterAssets.swift in Sources */,
297FD5742AE18011008D8BFE /* WonderousWidgetView.swift in Sources */, 297FD5742AE18011008D8BFE /* WonderousWidgetView.swift in Sources */,
297F6FCE2AD06E0D00FF159E /* WonderousWidget.swift in Sources */, 297F6FCE2AD06E0D00FF159E /* WonderousWidget.swift in Sources */,
297F6FCC2AD06E0D00FF159E /* WonderousWidgetBundle.swift in Sources */, 297F6FCC2AD06E0D00FF159E /* WonderousWidgetBundle.swift in Sources */,
@ -640,14 +644,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 = "WonderousWidgetExtension.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 = "WonderousWidget/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;

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
/// Define some custom extensions on the Color class, so we can use the shorthand syntax `..myColor`
extension Color { extension Color {
public static let accent = Color(red: 0.89, green: 0.58, blue: 0.36) public static let accent = Color(red: 0.89, green: 0.58, blue: 0.36)
public static let offWhite = Color(red: 0.97, green: 0.92, blue: 0.9) public static let offWhite = Color(red: 0.97, green: 0.92, blue: 0.9)

View File

@ -0,0 +1,22 @@
import Foundation
struct FlutterImages {
static let bgEmpty = getAssetPath("/assets/images/widget/background-empty.jpg")
static let icon = getAssetPath("/assets/images/widget/wonderous-icon.png")
}
func getAssetPath(_ path : String) -> String {
return assetBundleUrl.appending(path: path).path()
}
// Returns a file path to the location of the flutter assetBundle
var assetBundleUrl: URL {
let bundle = Bundle.main
if bundle.bundleURL.pathExtension == "appex" {
// Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
var url = bundle.bundleURL.deletingLastPathComponent().deletingLastPathComponent()
url.append(component: "Frameworks/App.framework/flutter_assets")
return url
}
return bundle.bundleURL
}

View File

@ -10,15 +10,14 @@ struct BgImage : View {
var uiImage:UIImage?; var uiImage:UIImage?;
// If there is no saved imageData, use the default bg image // If there is no saved imageData, use the default bg image
if(entry.imageData.isEmpty){ if(entry.imageData.isEmpty){
let defaultImage = flutterAssetBundle.appending(path: "/assets/images/widget/background-empty.jpg").path(); uiImage = UIImage(contentsOfFile: FlutterImages.bgEmpty);
uiImage = UIImage(contentsOfFile: defaultImage);
} }
// Load a base64 encoded image that has been written by the flutter app // Load a base64 encoded image that has been written by the flutter app
else { else {
uiImage = UIImage(data: Data(base64Encoded: entry.imageData)!) uiImage = UIImage(data: Data(base64Encoded: entry.imageData)!)
} }
if(uiImage != nil){ if(uiImage != nil){
// Use geometry reader to prevent the image from pushing the other content out of the widgets bounds (https://stackoverflow.com/questions/57593552/swiftui-prevent-image-from-expanding-view-rect-outside-of-screen-bounds) // Use geometry reader to prevent an oversized bg image from pushing the other content out of the widgets bounds (https://stackoverflow.com/questions/57593552/swiftui-prevent-image-from-expanding-view-rect-outside-of-screen-bounds)
let image = GeometryReader { geometry in let image = GeometryReader { geometry in
Image(uiImage: uiImage!) Image(uiImage: uiImage!)
.resizable() .resizable()
@ -34,6 +33,7 @@ struct BgImage : View {
} }
// Declares a restyled version of the native ProgressView
struct GaugeProgressStyle: ProgressViewStyle { struct GaugeProgressStyle: ProgressViewStyle {
func makeBody(configuration: Configuration) -> some View { func makeBody(configuration: Configuration) -> some View {
let fractionCompleted = configuration.fractionCompleted ?? 0 let fractionCompleted = configuration.fractionCompleted ?? 0

View File

@ -2,19 +2,20 @@ import WidgetKit
import SwiftUI import SwiftUI
import Intents import Intents
/// Entry, is passed into the view and defines the data it needs /// Every home-widget requires a TimelineEntry. This is passed into the view and propvides any data it needs
struct WonderousTimelineEntry : TimelineEntry { struct WonderousTimelineEntry : TimelineEntry {
// Date is a mandatory field for all TimelineEntries
let date: Date let date: Date
// Custom field for the wonderous view
let discoveredCount:Int; let discoveredCount:Int;
var title:String = ""; var title:String = "";
var subTitle:String = ""; var subTitle:String = "";
var imageData:String = ""; var imageData:String = "";
} }
// Widget, defines the display name and description and also declared the main View /// Widget, defines some high level configuration options as well as the primary view that will display the widget.
struct WonderousWidget: Widget { struct WonderousWidget: Widget {
let kind: String = "WonderousWidget" let kind: String = "WonderousWidget"
var body: some WidgetConfiguration { var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: WonderousTimelineProvider()) { entry in StaticConfiguration(kind: kind, provider: WonderousTimelineProvider()) { entry in
WonderousWidgetView(entry: entry) WonderousWidgetView(entry: entry)
@ -26,7 +27,12 @@ struct WonderousWidget: Widget {
} }
} }
// Provider,returns various WonderousEntry configs based on current context struct WonderousConfig {
let iosKey = "group.com.gskinner.flutter.wonders.widget"
let discoveredCountKey = "dicoveredCount"
}
/// TimelineProvider, returns various WonderousTimelineEntry configurations for different contexts
struct WonderousTimelineProvider: TimelineProvider { struct WonderousTimelineProvider: 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) -> WonderousTimelineEntry { func placeholder(in context: Context) -> WonderousTimelineEntry {

View File

@ -1,13 +1,9 @@
//
// WonderousWidgetBundle.swift
// Wonderous Widget
//
// Created by Shawn on 2023-10-06.
//
import WidgetKit import WidgetKit
import SwiftUI import SwiftUI
// WonderousWidgetBundle
// -> WonderousWidgetView
// -> WonderousWidgetViewComponents
@main @main
struct WonderousWidgetBundle: WidgetBundle { struct WonderousWidgetBundle: WidgetBundle {
var body: some Widget { var body: some Widget {

View File

@ -2,7 +2,7 @@ import WidgetKit
import SwiftUI import SwiftUI
import Intents import Intents
// Defines the view / layout of the widget /// Defines the view / layout of the widget
struct WonderousWidgetView : View { struct WonderousWidgetView : View {
@Environment(\.widgetFamily) var family: WidgetFamily @Environment(\.widgetFamily) var family: WidgetFamily
var entry: WonderousTimelineProvider.Entry var entry: WonderousTimelineProvider.Entry
@ -10,14 +10,13 @@ struct WonderousWidgetView : View {
let showTitle = family == .systemLarge let showTitle = family == .systemLarge
let showIcon = family != .systemSmall let showIcon = family != .systemSmall
let showTitleAndDesc = family != .systemSmall let showTitleAndDesc = family != .systemSmall
let progressPct = Double(entry.discoveredCount) / 24.0
let progress = Double(entry.discoveredCount) / 24.0 let iconImage = FlutterImages.icon;
let iconImage = flutterAssetBundle.appending(
path: "/assets/images/widget/wonderous-icon.png"
).path()
let title = entry.title.isEmpty ? "Wonderous" : entry.title; let title = entry.title.isEmpty ? "Wonderous" : entry.title;
let subTitle = entry.subTitle.isEmpty ? "Search for hidden artifacts" : entry.subTitle; let subTitle = entry.subTitle.isEmpty ? "Search for hidden artifacts" : entry.subTitle;
let content = VStack{ let content = VStack{
// Top row with optional Title and Icon
HStack { HStack {
if(showTitle) { if(showTitle) {
Text("Collection") Text("Collection")
@ -32,7 +31,10 @@ struct WonderousWidgetView : View {
.frame(height: 24) .frame(height: 24)
} }
} }
Spacer(); Spacer();
// Bottom hz row with title, desc and progress gauge
HStack { HStack {
if(showTitleAndDesc) { if(showTitleAndDesc) {
VStack(alignment: .leading){ VStack(alignment: .leading){
@ -46,14 +48,16 @@ struct WonderousWidgetView : View {
} }
Spacer(); Spacer();
ZStack{ ZStack{
ProgressView(value: progress) ProgressView(value: progressPct)
.progressViewStyle(GaugeProgressStyle()) .progressViewStyle(GaugeProgressStyle())
.frame(width: 48, height: 48) .frame(width: 48, height: 48)
Text("\(Int(progress * 100))%").font(.system(size: 13)).foregroundColor(.white)
Text("\(Int((progressPct * 100).rounded()))%").font(.system(size: 13)).foregroundColor(.white)
} }
} }
} }
// Stack content on top of the background image and a gradient
return ZStack{ return ZStack{
BgImage(entry: entry).opacity(0.8) BgImage(entry: entry).opacity(0.8)
LinearGradient( LinearGradient(
@ -62,21 +66,11 @@ struct WonderousWidgetView : View {
endPoint: .bottom) endPoint: .bottom)
content.padding(16) content.padding(16)
} }
// Ios requires that widgets have a background color
.widgetBackground(Color.darkGrey) .widgetBackground(Color.darkGrey)
// Deeplink into collections view when tapped
.widgetURL(URL(string: "wonderous:///home/collection")) .widgetURL(URL(string: "wonderous:///home/collection"))
} }
} }
// Todo: Refactor to getFlutterAsset(String path), include /assets, or maybe just getFlutterImage(String path), include assets/images
// Returns a file path to the location of the flutter assetBundle
var flutterAssetBundle: URL {
let bundle = Bundle.main
if bundle.bundleURL.pathExtension == "appex" {
// Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
var url = bundle.bundleURL.deletingLastPathComponent().deletingLastPathComponent()
url.append(component: "Frameworks/App.framework/flutter_assets")
return url
}
return bundle.bundleURL
}

View File

@ -42,9 +42,10 @@ class _CollectionFooter extends StatelessWidget {
} }
Widget _buildProgressRow(BuildContext context) { Widget _buildProgressRow(BuildContext context) {
int percent = (count / total * 100).round();
return Row(children: [ return Row(children: [
Text( Text(
$strings.collectionLabelDiscovered((count / total * 100).round()), $strings.collectionLabelDiscovered(percent),
style: $styles.text.body.copyWith(color: $styles.colors.accent1), style: $styles.text.body.copyWith(color: $styles.colors.accent1),
), ),
Spacer(), Spacer(),

View File

@ -1,7 +1,7 @@
name: wonders name: wonders
description: Explore the famous wonders of the world. description: Explore the famous wonders of the world.
publish_to: "none" publish_to: "none"
version: 2.2.0 version: 2.2.1
environment: environment:
sdk: ">=2.17.0 <3.0.0" sdk: ">=2.17.0 <3.0.0"