Skip to content

Commit 7dc7037

Browse files
committed
Maui: add AppWidget extension
1 parent 43fdaa1 commit 7dc7037

File tree

55 files changed

+3161
-68
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3161
-68
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,10 @@ ModelManifest.xml
244244
# FAKE - F# Make
245245
.fake/
246246

247-
# MacOS
247+
# MaciOS
248248
.DS_Store
249+
*.xcuserstate
250+
/Maui/SimpleWeather.Maui.AppWidget/DerivedData
249251

250252
# SimpleWeather
251253
API_KEY.txt

.vscode/tasks.json

+48-8
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
"dependsOn": [
88
"keyCheckShared",
99
"keyCheckWApi",
10-
"editManifestiOSDebug",
11-
"editManifestMacDebug",
10+
"editManifestInfoiOSDebug",
11+
"editManifestEntitlementsiOSDebug",
12+
"editManifestInfoMacDebug",
13+
"editManifestEntitlementsMacDebug",
1214
"dotnet: restore",
1315
"cleanDebug",
1416
"maui: Build"
@@ -20,8 +22,10 @@
2022
"dependsOn": [
2123
"keyCheckShared",
2224
"keyCheckWApi",
23-
"editManifestiOSRelease",
24-
"editManifestMacRelease",
25+
"editManifestInfoiOSRelease",
26+
"editManifestEntitlementsiOSRelease",
27+
"editManifestInfoMacRelease",
28+
"editManifestEntitlementsMacRelease",
2529
"restore",
2630
"cleanRelease",
2731
"maui: Build"
@@ -46,7 +50,7 @@
4650
}
4751
},
4852
{
49-
"label": "editManifestiOSDebug",
53+
"label": "editManifestInfoiOSDebug",
5054
"type": "shell",
5155
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/iOS/Info.plist \"Debug\"",
5256
"group": "build",
@@ -55,7 +59,7 @@
5559
}
5660
},
5761
{
58-
"label": "editManifestMacDebug",
62+
"label": "editManifestInfoMacDebug",
5963
"type": "shell",
6064
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/MacCatalyst/Info.plist \"Debug\"",
6165
"group": "build",
@@ -64,7 +68,25 @@
6468
}
6569
},
6670
{
67-
"label": "editManifestiOSRelease",
71+
"label": "editManifestEntitlementsiOSDebug",
72+
"type": "shell",
73+
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/iOS/Entitlements.plist \"Debug\"",
74+
"group": "build",
75+
"options": {
76+
"cwd": "${workspaceFolder}/Maui/SimpleWeather.Maui/"
77+
}
78+
},
79+
{
80+
"label": "editManifestEntitlementsMacDebug",
81+
"type": "shell",
82+
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/MacCatalyst/Entitlements.plist \"Debug\"",
83+
"group": "build",
84+
"options": {
85+
"cwd": "${workspaceFolder}/Maui/SimpleWeather.Maui/"
86+
}
87+
},
88+
{
89+
"label": "editManifestInfoiOSRelease",
6890
"type": "shell",
6991
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/iOS/Info.plist \"Release\"",
7092
"group": "build",
@@ -73,14 +95,32 @@
7395
}
7496
},
7597
{
76-
"label": "editManifestMacRelease",
98+
"label": "editManifestInfoMacRelease",
7799
"type": "shell",
78100
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/MacCatalyst/Info.plist \"Release\"",
79101
"group": "build",
80102
"options": {
81103
"cwd": "${workspaceFolder}/Maui/SimpleWeather.Maui/"
82104
}
83105
},
106+
{
107+
"label": "editManifestEntitlementsiOSRelease",
108+
"type": "shell",
109+
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/iOS/Entitlements.plist \"Release\"",
110+
"group": "build",
111+
"options": {
112+
"cwd": "${workspaceFolder}/Maui/SimpleWeather.Maui/"
113+
}
114+
},
115+
{
116+
"label": "editManifestEntitlementsMacRelease",
117+
"type": "shell",
118+
"command": "../../EditManifest/bin/Release/net7.0/publish/EditManifest Platforms/MacCatalyst/Entitlements.plist \"Release\"",
119+
"group": "build",
120+
"options": {
121+
"cwd": "${workspaceFolder}/Maui/SimpleWeather.Maui/"
122+
}
123+
},
84124
{
85125
"label": "cleanDebug",
86126
"type": "shell",

EditManifest/Program.cs

+20-5
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ private static void Main(string[] args)
4040
{
4141
OSVersion = OSVersion.UWP;
4242
}
43-
else if (FilePath.EndsWith("Info.plist", StringComparison.InvariantCultureIgnoreCase))
43+
else if (FilePath.EndsWith("Info.plist", StringComparison.InvariantCultureIgnoreCase) ||
44+
FilePath.EndsWith("Entitlements.plist", StringComparison.InvariantCultureIgnoreCase))
4445
{
4546
OSVersion = OSVersion.MaciOS;
4647
}
@@ -80,13 +81,27 @@ private static void Main(string[] args)
8081
}
8182
else if (OSVersion == OSVersion.MaciOS)
8283
{
83-
if (ConfigMode?.StartsWith("Debug") == true)
84+
if (FilePath.EndsWith("Info.plist", StringComparison.InvariantCultureIgnoreCase))
8485
{
85-
line = line.Replace("<string>com.thewizrd.simpleweather</string>", "<string>com.thewizrd.simpleweather.debug</string>");
86+
if (ConfigMode?.StartsWith("Debug") == true)
87+
{
88+
line = line.Replace("<string>com.thewizrd.simpleweather</string>", "<string>com.thewizrd.simpleweather.debug</string>");
89+
}
90+
else
91+
{
92+
line = line.Replace("<string>com.thewizrd.simpleweather.debug</string>", "<string>com.thewizrd.simpleweather</string>");
93+
}
8694
}
87-
else
95+
else if (FilePath.EndsWith("Entitlements.plist", StringComparison.InvariantCultureIgnoreCase))
8896
{
89-
line = line.Replace("<string>com.thewizrd.simpleweather.debug</string>", "<string>com.thewizrd.simpleweather</string>");
97+
if (ConfigMode?.StartsWith("Debug") == true)
98+
{
99+
line = line.Replace("<string>group.com.thewizrd.simpleweather</string>", "<string>group.com.thewizrd.simpleweather.debug</string>");
100+
}
101+
else
102+
{
103+
line = line.Replace("<string>group.com.thewizrd.simpleweather.debug</string>", "<string>group.com.thewizrd.simpleweather</string>");
104+
}
90105
}
91106
}
92107

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// FileLogger.swift
3+
// SimpleWeather
4+
//
5+
// Created by Dave Antoine on 10/14/23.
6+
//
7+
8+
import Foundation
9+
10+
struct FileGroupLogger: TextOutputStream {
11+
12+
func getDateTimestamp() -> String {
13+
let formatter = DateFormatter()
14+
formatter.dateFormat = "yyyy-MM-dd"
15+
return formatter.string(from: Date())
16+
}
17+
18+
func getLogTimestamp() -> String {
19+
let formatter = DateFormatter()
20+
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
21+
return formatter.string(from: Date())
22+
}
23+
24+
func write(_ string: String) {
25+
let fm = FileManager.default
26+
if let containerUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: getGroupIdentifier()) {
27+
let logFolderPath = containerUrl.appendingPathComponent("logs")
28+
29+
if !fm.fileExists(atPath: logFolderPath.path()) {
30+
try? fm.createDirectory(at: logFolderPath, withIntermediateDirectories: true)
31+
}
32+
33+
let logPath = logFolderPath.appendingPathComponent("Logger.\(getDateTimestamp()).log")
34+
let message = "\(getLogTimestamp())|\(string)\n"
35+
36+
if let handle = try? FileHandle(forWritingTo: logPath) {
37+
handle.seekToEndOfFile()
38+
handle.write(message.data(using: .utf8)!)
39+
handle.closeFile()
40+
} else {
41+
try? message.data(using: .utf8)?.write(to: logPath)
42+
}
43+
}
44+
}
45+
}
46+
47+
var fileGroupLogger = FileGroupLogger()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// GroupIdentifier.swift
3+
// SimpleWeather
4+
//
5+
// Created by Dave Antoine on 10/14/23.
6+
//
7+
8+
import Foundation
9+
10+
func getGroupIdentifier() -> String {
11+
#if DEBUG
12+
return "group.com.thewizrd.simpleweather.debug"
13+
#else
14+
return "group.com.thewizrd.simpleweather"
15+
#endif
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// UIColorExtensions.swift
3+
// SimpleWeather
4+
//
5+
// Created by Dave Antoine on 10/6/23.
6+
//
7+
8+
import Foundation
9+
import SwiftUI
10+
11+
// Source: https://stackoverflow.com/a/33397427
12+
extension Color {
13+
init(hexString: String) {
14+
let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
15+
var int = UInt64()
16+
Scanner(string: hex).scanHexInt64(&int)
17+
let a, r, g, b: UInt64
18+
switch hex.count {
19+
case 3: // RGB (12-bit)
20+
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
21+
case 6: // RGB (24-bit)
22+
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
23+
case 8: // ARGB (32-bit)
24+
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
25+
default:
26+
(a, r, g, b) = (255, 0, 0, 0)
27+
}
28+
self.init(CGColor(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255))
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// WeatherBackground.swift
3+
// SimpleWeather
4+
//
5+
// Created by Dave Antoine on 10/13/23.
6+
//
7+
8+
import Foundation
9+
10+
public struct WeatherBackground
11+
{
12+
private init() {}
13+
14+
static let DAY = "day"
15+
static let DUST = "dust"
16+
static let FOG = "fog"
17+
static let MOSTLYCLOUDY_DAY = "mostlycloudy_day"
18+
static let MOSTLYCLOUDY_NIGHT = "mostlycloudy_night"
19+
static let NIGHT = "night"
20+
static let PARTLYCLOUDY_DAY = "partlycloudy_day"
21+
static let PARTLYCLOUDY_NIGHT = "partlycloudy_night"
22+
static let RAIN = "rain_day"
23+
static let RAIN_NIGHT = "rain_night"
24+
static let SNOW = "snow"
25+
static let SNOW_WINDY = "snow_windy"
26+
static let STORMS = "storms"
27+
static let TSTORMS_DAY = "tstorms_day"
28+
static let TSTORMS_NIGHT = "tstorms_night"
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//
2+
// WeatherData.swift
3+
// widgetExtension
4+
//
5+
// Created by Dave Antoine on 10/2/23.
6+
//
7+
8+
import Foundation
9+
10+
struct WeatherData : Codable {
11+
var current: _Current
12+
var forecasts: [_Forecast]?
13+
var hr_forecasts: [_HourlyForecast]?
14+
}
15+
16+
internal struct _Current : Codable {
17+
var locationName: String
18+
var tz_long: String
19+
var isGPS: Bool
20+
21+
var temp: String
22+
var condition: String
23+
var icon: String
24+
var hi: String?
25+
var lo: String?
26+
var showHiLo: Bool
27+
28+
var chance: String?
29+
30+
var backgroundColor: String?
31+
var backgroundCode: String?
32+
}
33+
34+
internal struct _Forecast : Codable {
35+
var epochTime: Double
36+
var hi: String
37+
var lo: String
38+
var icon: String
39+
var chance: String?
40+
}
41+
42+
internal struct _HourlyForecast : Codable {
43+
var epochTime: Double
44+
var temp: String
45+
var icon: String
46+
}
47+
48+
extension Locale {
49+
var is24Hour: Bool {
50+
let dateFormat = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: self)!
51+
return dateFormat.firstIndex(of: "a") == nil
52+
}
53+
}
54+
55+
extension WeatherData {
56+
func toModel() -> WeatherModel {
57+
let tzStr = current.tz_long
58+
let tz = TimeZone(identifier: tzStr)
59+
60+
let fcastDateFmt = DateFormatter()
61+
fcastDateFmt.timeZone = tz
62+
fcastDateFmt.dateFormat = "EEE"
63+
64+
let hrfcastDateFmt = DateFormatter()
65+
hrfcastDateFmt.timeZone = tz
66+
hrfcastDateFmt.dateFormat = Locale.current.is24Hour ? "HH:00" : "ha"
67+
68+
let fcasts = forecasts?.map { f in
69+
Forecast(
70+
date: fcastDateFmt.string(from: Date(timeIntervalSince1970: f.epochTime)),
71+
weatherIcon: f.icon,
72+
hi: f.hi,
73+
lo: f.lo,
74+
chance: f.chance
75+
)
76+
}
77+
78+
let hrfcasts = hr_forecasts?.map { f in
79+
HourlyForecast(
80+
date: hrfcastDateFmt.string(from: Date(timeIntervalSince1970: f.epochTime)),
81+
weatherIcon: f.icon,
82+
hi: f.temp
83+
)
84+
}
85+
86+
let cur = Current(
87+
weatherIcon: current.icon,
88+
temp: current.temp,
89+
condition: current.condition,
90+
chance: current.chance,
91+
location: current.locationName,
92+
isGPS: current.isGPS,
93+
backgroundColor: current.backgroundColor,
94+
backgroundCode: current.backgroundCode,
95+
hi: current.hi,
96+
lo: current.lo,
97+
showHiLo: current.showHiLo
98+
)
99+
100+
return WeatherModel(
101+
current: cur,
102+
forecasts: fcasts ?? [],
103+
showForecast: !(fcasts?.isEmpty ?? true),
104+
hourlyForecasts: hrfcasts ?? [],
105+
showHourlyForecast: !(hrfcasts?.isEmpty ?? true)
106+
)
107+
}
108+
}

0 commit comments

Comments
 (0)