From 576170dc5de9139a08086cd3b8a7e48bad2a3a53 Mon Sep 17 00:00:00 2001 From: Worth Baker Date: Wed, 28 Sep 2022 07:30:47 -0600 Subject: [PATCH] Adds support for Apple Watch Ultra (#79) * compiled apple watch ultra SKU data for all countries * adds support for Apple Watch Ultra resolves #62; bumps version to v0.1.5; some code cleanup --- InventoryWatch.xcodeproj/project.pbxproj | 8 +- InventoryWatch/AppleWatchUltra-intl.json | 340 +++++++++++++++++++++++ InventoryWatch/Model/Model.swift | 90 +++++- InventoryWatch/Model/ProductType.swift | 3 + 4 files changed, 425 insertions(+), 16 deletions(-) create mode 100644 InventoryWatch/AppleWatchUltra-intl.json diff --git a/InventoryWatch.xcodeproj/project.pbxproj b/InventoryWatch.xcodeproj/project.pbxproj index 6fc6b52..fe44682 100644 --- a/InventoryWatch.xcodeproj/project.pbxproj +++ b/InventoryWatch.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 380CF9FB27448E860080472A /* iPhoneModels13-intl.json in Resources */ = {isa = PBXBuildFile; fileRef = 380CF9FA27448E860080472A /* iPhoneModels13-intl.json */; }; 3817268E273AA898003B8D76 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3817268D273AA898003B8D76 /* SettingsView.swift */; }; + 382981C328E3EA54008C68F7 /* AppleWatchUltra-intl.json in Resources */ = {isa = PBXBuildFile; fileRef = 382981C228E3EA54008C68F7 /* AppleWatchUltra-intl.json */; }; 386FDC572739DA7300C1BAC2 /* InventoryWatchApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386FDC562739DA7300C1BAC2 /* InventoryWatchApp.swift */; }; 386FDC592739DA7300C1BAC2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386FDC582739DA7300C1BAC2 /* ContentView.swift */; }; 386FDC5B2739DA7300C1BAC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 386FDC5A2739DA7300C1BAC2 /* Assets.xcassets */; }; @@ -32,6 +33,7 @@ /* Begin PBXFileReference section */ 380CF9FA27448E860080472A /* iPhoneModels13-intl.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "iPhoneModels13-intl.json"; sourceTree = ""; }; 3817268D273AA898003B8D76 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 382981C228E3EA54008C68F7 /* AppleWatchUltra-intl.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "AppleWatchUltra-intl.json"; sourceTree = ""; }; 386FDC532739DA7300C1BAC2 /* InventoryWatch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InventoryWatch.app; sourceTree = BUILT_PRODUCTS_DIR; }; 386FDC562739DA7300C1BAC2 /* InventoryWatchApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InventoryWatchApp.swift; sourceTree = ""; }; 386FDC582739DA7300C1BAC2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -94,6 +96,7 @@ 38DBAF38273D6692009992D8 /* Stores.json */, 380CF9FA27448E860080472A /* iPhoneModels13-intl.json */, 387F6E7528CCF5B300E68AC0 /* iPhoneModels14-intl.json */, + 382981C228E3EA54008C68F7 /* AppleWatchUltra-intl.json */, 386FDC67273A18F800C1BAC2 /* SKUData.swift */, 38D0C3A1273C60B500A7DE65 /* Countries.swift */, 386FDC5A2739DA7300C1BAC2 /* Assets.xcassets */, @@ -185,6 +188,7 @@ files = ( 387F6E7628CCF5B300E68AC0 /* iPhoneModels14-intl.json in Resources */, 38E4279E273EF542006BF6D7 /* Credits.rtf in Resources */, + 382981C328E3EA54008C68F7 /* AppleWatchUltra-intl.json in Resources */, 38DBAF39273D6692009992D8 /* Stores.json in Resources */, 380CF9FB27448E860080472A /* iPhoneModels13-intl.json in Resources */, 386FDC5E2739DA7300C1BAC2 /* Preview Assets.xcassets in Resources */, @@ -359,7 +363,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.5; - MARKETING_VERSION = 0.1.4; + MARKETING_VERSION = 0.1.5; PRODUCT_BUNDLE_IDENTIFIER = com.worthbak.InventoryWatch; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -390,7 +394,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.5; - MARKETING_VERSION = 0.1.4; + MARKETING_VERSION = 0.1.5; PRODUCT_BUNDLE_IDENTIFIER = com.worthbak.InventoryWatch; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/InventoryWatch/AppleWatchUltra-intl.json b/InventoryWatch/AppleWatchUltra-intl.json new file mode 100644 index 0000000..55ebb1b --- /dev/null +++ b/InventoryWatch/AppleWatchUltra-intl.json @@ -0,0 +1,340 @@ +{ + "us": { + "alpine": { + "MQEY3LL/A": "Titanium Case with Starlight Alpine Loop (small)", + "MQF03LL/A": "Titanium Case with Starlight Alpine Loop (medium)", + "MQF13LL/A": "Titanium Case with Starlight Alpine Loop (large)", + "MNHC3LL/A": "Titanium Case with Green Alpine Loop (small)", + "MQEW3LL/A": "Titanium Case with Green Alpine Loop (medium)", + "MQEX3LL/A": "Titanium Case with Green Alpine Loop (large)", + "MNHA3LL/A": "Titanium Case with Orange Alpine Loop (small)", + "MQEU3LL/A": "Titanium Case with Orange Alpine Loop (medium)", + "MQEV3LL/A": "Titanium Case with Orange Alpine Loop (large)" + }, + "trail": { + "MNHD3LL/A": "Titanium Case with Yellow/Beige Trail Loop (small/medium)", + "MQF23LL/A": "Titanium Case with Yellow/Beige Trail Loop (medium/large)", + "MNHE3LL/A": "Titanium Case with Blue/Gray Trail Loop (small/medium)", + "MQF33LL/A": "Titanium Case with Blue/Gray Trail Loop (medium/large)", + "MQF43LL/A": "Titanium Case with Black/Gray Trail Loop (small/medium)", + "MQF53LL/A": "Titanium Case with Black/Gray Trail Loop (medium/large)" + }, + "ocean": { + "MQET3LL/A": "Titanium Case with Midnight Ocean Band (onesize)", + "MNH83LL/A": "Titanium Case with White Ocean Band (onesize)", + "MNH93LL/A": "Titanium Case with Yellow Ocean Band (onesize)" + } + }, + "ca": { + "alpine": { + "MQEY3VC/A": "Titanium Case with Starlight Alpine Loop (small)", + "MQF03VC/A": "Titanium Case with Starlight Alpine Loop (medium)", + "MQF13VC/A": "Titanium Case with Starlight Alpine Loop (large)", + "MNHC3VC/A": "Titanium Case with Green Alpine Loop (small)", + "MQEW3VC/A": "Titanium Case with Green Alpine Loop (medium)", + "MQEX3VC/A": "Titanium Case with Green Alpine Loop (large)", + "MNHA3VC/A": "Titanium Case with Orange Alpine Loop (small)", + "MQEU3VC/A": "Titanium Case with Orange Alpine Loop (medium)", + "MQEV3VC/A": "Titanium Case with Orange Alpine Loop (large)" + }, + "trail": { + "MNHD3VC/A": "Titanium Case with Yellow/Beige Trail Loop (small/medium)", + "MQF23VC/A": "Titanium Case with Yellow/Beige Trail Loop (medium/large)", + "MNHE3VC/A": "Titanium Case with Blue/Grey Trail Loop (small/medium)", + "MQF33VC/A": "Titanium Case with Blue/Grey Trail Loop (medium/large)", + "MQF43VC/A": "Titanium Case with Black/Grey Trail Loop (small/medium)", + "MQF53VC/A": "Titanium Case with Black/Grey Trail Loop (medium/large)" + }, + "ocean": { + "MQET3VC/A": "Titanium Case with Midnight Ocean Band (onesize)", + "MNH83VC/A": "Titanium Case with White Ocean Band (onesize)", + "MNH93VC/A": "Titanium Case with Yellow Ocean Band (onesize)" + } + }, + "au": { + "alpine": { + "MQFQ3ZP/A": "Titanium Case with Starlight Alpine Loop (small)", + "MQFR3ZP/A": "Titanium Case with Starlight Alpine Loop (medium)", + "MQFT3ZP/A": "Titanium Case with Starlight Alpine Loop (large)", + "MNHJ3ZP/A": "Titanium Case with Green Alpine Loop (small)", + "MQFN3ZP/A": "Titanium Case with Green Alpine Loop (medium)", + "MQFP3ZP/A": "Titanium Case with Green Alpine Loop (large)", + "MNHH3ZP/A": "Titanium Case with Orange Alpine Loop (small)", + "MQFL3ZP/A": "Titanium Case with Orange Alpine Loop (medium)", + "MQFM3ZP/A": "Titanium Case with Orange Alpine Loop (large)" + }, + "trail": { + "MNHK3ZP/A": "Titanium Case with Yellow/Beige Trail Loop (small/medium)", + "MQFU3ZP/A": "Titanium Case with Yellow/Beige Trail Loop (medium/large)", + "MNHL3ZP/A": "Titanium Case with Blue/Grey Trail Loop (small/medium)", + "MQFV3ZP/A": "Titanium Case with Blue/Grey Trail Loop (medium/large)", + "MQFW3ZP/A": "Titanium Case with Black/Grey Trail Loop (small/medium)", + "MQFX3ZP/A": "Titanium Case with Black/Grey Trail Loop (medium/large)" + }, + "ocean": { + "MQFK3ZP/A": "Titanium Case with Midnight Ocean Band (onesize)", + "MNHF3ZP/A": "Titanium Case with White Ocean Band (onesize)", + "MNHG3ZP/A": "Titanium Case with Yellow Ocean Band (onesize)" + } + }, + "de": { + "alpine": { + "MQFQ3FD/A": "Titangehäuse, Alpine Loop Polarstern (small)", + "MQFR3FD/A": "Titangehäuse, Alpine Loop Polarstern (medium)", + "MQFT3FD/A": "Titangehäuse, Alpine Loop Polarstern (large)", + "MNHJ3FD/A": "Titangehäuse, Alpine Loop Grün (small)", + "MQFN3FD/A": "Titangehäuse, Alpine Loop Grün (medium)", + "MQFP3FD/A": "Titangehäuse, Alpine Loop Grün (large)", + "MNHH3FD/A": "Titangehäuse, Alpine Loop Orange (small)", + "MQFL3FD/A": "Titangehäuse, Alpine Loop Orange (medium)", + "MQFM3FD/A": "Titangehäuse, Alpine Loop Orange (large)" + }, + "trail": { + "MNHK3FD/A": "Titangehäuse, Trail Loop Gelb/Beige (small/medium)", + "MQFU3FD/A": "Titangehäuse, Trail Loop Gelb/Beige (medium/large)", + "MNHL3FD/A": "Titangehäuse, Trail Loop Blau/Grau (small/medium)", + "MQFV3FD/A": "Titangehäuse, Trail Loop Blau/Grau (medium/large)", + "MQFW3FD/A": "Titangehäuse, Trail Loop Schwarz/Grau (small/medium)", + "MQFX3FD/A": "Titangehäuse, Trail Loop Schwarz/Grau (medium/large)" + }, + "ocean": { + "MQFK3FD/A": "Titangehäuse, Ocean Armband Mitternacht (onesize)", + "MNHF3FD/A": "Titangehäuse, Ocean Armband Weiß (onesize)", + "MNHG3FD/A": "Titangehäuse, Ocean Armband Gelb (onesize)" + } + }, + "uk": { + "alpine": { + "MQFQ3B/A": "Titanium Case with Starlight Alpine Loop (small)", + "MQFR3B/A": "Titanium Case with Starlight Alpine Loop (medium)", + "MQFT3B/A": "Titanium Case with Starlight Alpine Loop (large)", + "MNHJ3B/A": "Titanium Case with Green Alpine Loop (small)", + "MQFN3B/A": "Titanium Case with Green Alpine Loop (medium)", + "MQFP3B/A": "Titanium Case with Green Alpine Loop (large)", + "MNHH3B/A": "Titanium Case with Orange Alpine Loop (small)", + "MQFL3B/A": "Titanium Case with Orange Alpine Loop (medium)", + "MQFM3B/A": "Titanium Case with Orange Alpine Loop (large)" + }, + "trail": { + "MNHK3B/A": "Titanium Case with Yellow/Beige Trail Loop (small/medium)", + "MQFU3B/A": "Titanium Case with Yellow/Beige Trail Loop (medium/large)", + "MNHL3B/A": "Titanium Case with Blue/Grey Trail Loop (small/medium)", + "MQFV3B/A": "Titanium Case with Blue/Grey Trail Loop (medium/large)", + "MQFW3B/A": "Titanium Case with Black/Grey Trail Loop (small/medium)", + "MQFX3B/A": "Titanium Case with Black/Grey Trail Loop (medium/large)" + }, + "ocean": { + "MQFK3B/A": "Titanium Case with Midnight Ocean Band (onesize)", + "MNHF3B/A": "Titanium Case with White Ocean Band (onesize)", + "MNHG3B/A": "Titanium Case with Yellow Ocean Band (onesize)" + } + }, + "kr": { + "alpine": { + "MQFQ3KH/A": "티타늄 케이스, 그리고 스타라이트 알파인 루프 (small)", + "MQFR3KH/A": "티타늄 케이스, 그리고 스타라이트 알파인 루프 (medium)", + "MQFT3KH/A": "티타늄 케이스, 그리고 스타라이트 알파인 루프 (large)", + "MNHJ3KH/A": "티타늄 케이스, 그리고 그린 알파인 루프 (small)", + "MQFN3KH/A": "티타늄 케이스, 그리고 그린 알파인 루프 (medium)", + "MQFP3KH/A": "티타늄 케이스, 그리고 그린 알파인 루프 (large)", + "MNHH3KH/A": "티타늄 케이스, 그리고 오렌지 알파인 루프 (small)", + "MQFL3KH/A": "티타늄 케이스, 그리고 오렌지 알파인 루프 (medium)", + "MQFM3KH/A": "티타늄 케이스, 그리고 오렌지 알파인 루프 (large)" + }, + "trail": { + "MNHK3KH/A": "티타늄 케이스, 그리고 옐로/베이지 트레일 루프 (small/medium)", + "MQFU3KH/A": "티타늄 케이스, 그리고 옐로/베이지 트레일 루프 (medium/large)", + "MNHL3KH/A": "티타늄 케이스, 그리고 블루/그레이 트레일 루프 (small/medium)", + "MQFV3KH/A": "티타늄 케이스, 그리고 블루/그레이 트레일 루프 (medium/large)", + "MQFW3KH/A": "티타늄 케이스, 그리고 블랙/그레이 트레일 루프 (small/medium)", + "MQFX3KH/A": "티타늄 케이스, 그리고 블랙/그레이 트레일 루프 (medium/large)" + }, + "ocean": { + "MQFK3KH/A": "티타늄 케이스, 그리고 미드나이트 오션 밴드 (onesize)", + "MNHF3KH/A": "티타늄 케이스, 그리고 화이트 오션 밴드 (onesize)", + "MNHG3KH/A": "티타늄 케이스, 그리고 옐로 오션 밴드 (onesize)" + } + }, + "hk": { + "alpine": { + "MQFA3ZA/A": "Titanium Case with Starlight Alpine Loop (small)", + "MQFC3ZA/A": "Titanium Case with Starlight Alpine Loop (medium)", + "MQFD3ZA/A": "Titanium Case with Starlight Alpine Loop (large)", + "MNHQ3ZA/A": "Titanium Case with Green Alpine Loop (small)", + "MQF83ZA/A": "Titanium Case with Green Alpine Loop (medium)", + "MQF93ZA/A": "Titanium Case with Green Alpine Loop (large)", + "MNHP3ZA/A": "Titanium Case with Orange Alpine Loop (small)", + "MQFJ3ZA/A": "Titanium Case with Orange Alpine Loop (medium)", + "MQF73ZA/A": "Titanium Case with Orange Alpine Loop (large)" + }, + "trail": { + "MNHR3ZA/A": "Titanium Case with Yellow/Beige Trail Loop (small/medium)", + "MQFE3ZA/A": "Titanium Case with Yellow/Beige Trail Loop (medium/large)", + "MNHT3ZA/A": "Titanium Case with Blue/Gray Trail Loop (small/medium)", + "MQFF3ZA/A": "Titanium Case with Blue/Gray Trail Loop (medium/large)", + "MQFG3ZA/A": "Titanium Case with Black/Gray Trail Loop (small/medium)", + "MQFH3ZA/A": "Titanium Case with Black/Gray Trail Loop (medium/large)" + }, + "ocean": { + "MQF63ZA/A": "Titanium Case with Midnight Ocean Band (onesize)", + "MNHM3ZA/A": "Titanium Case with White Ocean Band (onesize)", + "MNHN3ZA/A": "Titanium Case with Yellow Ocean Band (onesize)" + } + }, + "fr": { + "alpine": { + "MQFQ3NF/A": "Boîtier en titane, Boucle Alpine lumière stellaire (small)", + "MQFR3NF/A": "Boîtier en titane, Boucle Alpine lumière stellaire (medium)", + "MQFT3NF/A": "Boîtier en titane, Boucle Alpine lumière stellaire (large)", + "MNHJ3NF/A": "Boîtier en titane, Boucle Alpine vert (small)", + "MQFN3NF/A": "Boîtier en titane, Boucle Alpine vert (medium)", + "MQFP3NF/A": "Boîtier en titane, Boucle Alpine vert (large)", + "MNHH3NF/A": "Boîtier en titane, Boucle Alpine orange (small)", + "MQFL3NF/A": "Boîtier en titane, Boucle Alpine orange (medium)", + "MQFM3NF/A": "Boîtier en titane, Boucle Alpine orange (large)" + }, + "trail": { + "MNHK3NF/A": "Boîtier en titane, Boucle Trail jaune/beige (small/medium)", + "MQFU3NF/A": "Boîtier en titane, Boucle Trail jaune/beige (medium/large)", + "MNHL3NF/A": "Boîtier en titane, Boucle Trail bleu/gris (small/medium)", + "MQFV3NF/A": "Boîtier en titane, Boucle Trail bleu/gris (medium/large)", + "MQFW3NF/A": "Boîtier en titane, Boucle Trail noir/gris (small/medium)", + "MQFX3NF/A": "Boîtier en titane, Boucle Trail noir/gris (medium/large)" + }, + "ocean": { + "MQFK3NF/A": "Boîtier en titane, Bracelet Océan minuit (onesize)", + "MNHF3NF/A": "Boîtier en titane, Bracelet Océan blanc (onesize)", + "MNHG3NF/A": "Boîtier en titane, Bracelet Océan jaune (onesize)" + } + }, + "it": { + "alpine": { + "MQFQ3TY/A": "Cassa in titanio con Alpine Loop galassia (small)", + "MQFR3TY/A": "Cassa in titanio con Alpine Loop galassia (medium)", + "MQFT3TY/A": "Cassa in titanio con Alpine Loop galassia (large)", + "MNHJ3TY/A": "Cassa in titanio con Alpine Loop verde (small)", + "MQFN3TY/A": "Cassa in titanio con Alpine Loop verde (medium)", + "MQFP3TY/A": "Cassa in titanio con Alpine Loop verde (large)", + "MNHH3TY/A": "Cassa in titanio con Alpine Loop arancione (small)", + "MQFL3TY/A": "Cassa in titanio con Alpine Loop arancione (medium)", + "MQFM3TY/A": "Cassa in titanio con Alpine Loop arancione (large)" + }, + "trail": { + "MNHK3TY/A": "Cassa in titanio con Trail Loop giallo/beige (small/medium)", + "MQFU3TY/A": "Cassa in titanio con Trail Loop giallo/beige (medium/large)", + "MNHL3TY/A": "Cassa in titanio con Trail Loop blu/grigio (small/medium)", + "MQFV3TY/A": "Cassa in titanio con Trail Loop blu/grigio (medium/large)", + "MQFW3TY/A": "Cassa in titanio con Trail Loop nero/grigio (small/medium)", + "MQFX3TY/A": "Cassa in titanio con Trail Loop nero/grigio (medium/large)" + }, + "ocean": { + "MQFK3TY/A": "Cassa in titanio con Cinturino Ocean mezzanotte (onesize)", + "MNHF3TY/A": "Cassa in titanio con Cinturino Ocean bianco (onesize)", + "MNHG3TY/A": "Cassa in titanio con Cinturino Ocean giallo (onesize)" + } + }, + "jp": { + "alpine": { + "MQFQ3J/A": "チタニウムケースとスターライトアルパインループ (small)", + "MQFR3J/A": "チタニウムケースとスターライトアルパインループ (medium)", + "MQFT3J/A": "チタニウムケースとスターライトアルパインループ (large)", + "MNHJ3J/A": "チタニウムケースとグリーンアルパインループ (small)", + "MQFN3J/A": "チタニウムケースとグリーンアルパインループ (medium)", + "MQFP3J/A": "チタニウムケースとグリーンアルパインループ (large)", + "MNHH3J/A": "チタニウムケースとオレンジアルパインループ (small)", + "MQFL3J/A": "チタニウムケースとオレンジアルパインループ (medium)", + "MQFM3J/A": "チタニウムケースとオレンジアルパインループ (large)" + }, + "trail": { + "MNHK3J/A": "チタニウムケースとイエロー/ベージュトレイルループ (small/medium)", + "MQFU3J/A": "チタニウムケースとイエロー/ベージュトレイルループ (medium/large)", + "MNHL3J/A": "チタニウムケースとブルー/グレイトレイルループ (small/medium)", + "MQFV3J/A": "チタニウムケースとブルー/グレイトレイルループ (medium/large)", + "MQFW3J/A": "チタニウムケースとブラック/グレイトレイルループ (small/medium)", + "MQFX3J/A": "チタニウムケースとブラック/グレイトレイルループ (medium/large)" + }, + "ocean": { + "MQFK3J/A": "チタニウムケースとミッドナイトオーシャンバンド (onesize)", + "MNHF3J/A": "チタニウムケースとホワイトオーシャンバンド (onesize)", + "MNHG3J/A": "チタニウムケースとイエローオーシャンバンド (onesize)" + } + }, + "at": { + "alpine": { + "MQFQ3FD/A": "Titangehäuse, Alpine Loop Polarstern (small)", + "MQFR3FD/A": "Titangehäuse, Alpine Loop Polarstern (medium)", + "MQFT3FD/A": "Titangehäuse, Alpine Loop Polarstern (large)", + "MNHJ3FD/A": "Titangehäuse, Alpine Loop Grün (small)", + "MQFN3FD/A": "Titangehäuse, Alpine Loop Grün (medium)", + "MQFP3FD/A": "Titangehäuse, Alpine Loop Grün (large)", + "MNHH3FD/A": "Titangehäuse, Alpine Loop Orange (small)", + "MQFL3FD/A": "Titangehäuse, Alpine Loop Orange (medium)", + "MQFM3FD/A": "Titangehäuse, Alpine Loop Orange (large)" + }, + "trail": { + "MNHK3FD/A": "Titangehäuse, Trail Loop Gelb/Beige (small/medium)", + "MQFU3FD/A": "Titangehäuse, Trail Loop Gelb/Beige (medium/large)", + "MNHL3FD/A": "Titangehäuse, Trail Loop Blau/Grau (small/medium)", + "MQFV3FD/A": "Titangehäuse, Trail Loop Blau/Grau (medium/large)", + "MQFW3FD/A": "Titangehäuse, Trail Loop Schwarz/Grau (small/medium)", + "MQFX3FD/A": "Titangehäuse, Trail Loop Schwarz/Grau (medium/large)" + }, + "ocean": { + "MQFK3FD/A": "Titangehäuse, Ocean Armband Mitternacht (onesize)", + "MNHF3FD/A": "Titangehäuse, Ocean Armband Weiß (onesize)", + "MNHG3FD/A": "Titangehäuse, Ocean Armband Gelb (onesize)" + } + }, + "nl": { + "alpine": { + "MQFQ3NF/A": "Kast van titanium • Sterrenlicht Alpine-bandje (small)", + "MQFR3NF/A": "Kast van titanium • Sterrenlicht Alpine-bandje (medium)", + "MQFT3NF/A": "Kast van titanium • Sterrenlicht Alpine-bandje (large)", + "MNHJ3NF/A": "Kast van titanium • Groen Alpine-bandje (small)", + "MQFN3NF/A": "Kast van titanium • Groen Alpine-bandje (medium)", + "MQFP3NF/A": "Kast van titanium • Groen Alpine-bandje (large)", + "MNHH3NF/A": "Kast van titanium • Oranje Alpine-bandje (small)", + "MQFL3NF/A": "Kast van titanium • Oranje Alpine-bandje (medium)", + "MQFM3NF/A": "Kast van titanium • Oranje Alpine-bandje (large)" + }, + "trail": { + "MNHK3NF/A": "Kast van titanium • Geel/beige Trail-bandje (small/medium)", + "MQFU3NF/A": "Kast van titanium • Geel/beige Trail-bandje (medium/large)", + "MNHL3NF/A": "Kast van titanium • Blauw/grijs Trail-bandje (small/medium)", + "MQFV3NF/A": "Kast van titanium • Blauw/grijs Trail-bandje (medium/large)", + "MQFW3NF/A": "Kast van titanium • Zwart/grijs Trail-bandje (small/medium)", + "MQFX3NF/A": "Kast van titanium • Zwart/grijs Trail-bandje (medium/large)" + }, + "ocean": { + "MQFK3NF/A": "Kast van titanium • Middernacht Ocean-bandje (onesize)", + "MNHF3NF/A": "Kast van titanium • Wit Ocean-bandje (onesize)", + "MNHG3NF/A": "Kast van titanium • Geel Ocean-bandje (onesize)" + } + }, + "th": { + "alpine": { + "MQFQ3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีสตาร์ไลท์ (small)", + "MQFR3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีสตาร์ไลท์ (medium)", + "MQFT3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีสตาร์ไลท์ (large)", + "MNHJ3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีเขียว (small)", + "MQFN3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีเขียว (medium)", + "MQFP3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีเขียว (large)", + "MNHH3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีส้ม (small)", + "MQFL3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีส้ม (medium)", + "MQFM3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Alpine Loop สีส้ม (large)" + }, + "trail": { + "MNHK3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Trail Loop สีเหลือง/เบจ (small/medium)", + "MQFU3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Trail Loop สีเหลือง/เบจ (medium/large)", + "MNHL3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Trail Loop สีน้ำเงิน/เทา (small/medium)", + "MQFV3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Trail Loop สีน้ำเงิน/เทา (medium/large)", + "MQFW3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Trail Loop สีดำ/เทา (small/medium)", + "MQFX3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Trail Loop สีดำ/เทา (medium/large)" + }, + "ocean": { + "MQFK3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Ocean Band สีมิดไนท์ (onesize)", + "MNHF3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Ocean Band สีขาว (onesize)", + "MNHG3TH/A": "ตัวเรือนไทเทเนียม | สายแบบ Ocean Band สีเหลือง (onesize)" + } + } +} diff --git a/InventoryWatch/Model/Model.swift b/InventoryWatch/Model/Model.swift index aad9dea..1399d02 100644 --- a/InventoryWatch/Model/Model.swift +++ b/InventoryWatch/Model/Model.swift @@ -44,11 +44,19 @@ final class Model: ObservableObject { } } + private enum iPhoneModel: CaseIterable { + case thirteen, fourteen + } + @Published var availableParts: [(Store, [PartAvailability])] = [] @Published var isLoading = false @Published var hasLatestVersion = true @Published var errorState: ModelError? + private var cachedPhoneData13: [String: [String: [String: String]]]? + private var cachedPhoneData14: [String: [String: [String: String]]]? + private var cachedAppleWatchData: [String: [String: [String: String]]]? + lazy private(set) var allStores: [JsonStore] = { let location = "Stores" let fileType = "json" @@ -138,14 +146,7 @@ final class Model: ObservableObject { return models } - - private var cachedPhoneData13: [String: [String: [String: String]]]? - private var cachedPhoneData14: [String: [String: [String: String]]]? - - private enum iPhoneModel: CaseIterable { - case thirteen, fourteen - } - + // country: type: model: description private func loadIPhoneModels(for model: iPhoneModel) -> [String: [String: [String: String]]] { let location: String @@ -164,19 +165,78 @@ final class Model: ObservableObject { } } - let fileType = "json" - if let path = Bundle.main.path(forResource: location, ofType: fileType) { + if let path = Bundle.main.path(forResource: location, ofType: "json") { do { let data = try Data(contentsOf: URL(fileURLWithPath: path)) let decoder = JSONDecoder() - if let jsonStores = try? decoder.decode([String: [String: [String: String]]].self, from: data) { + if let iphoneData = try? decoder.decode([String: [String: [String: String]]].self, from: data) { switch model { - case .thirteen: cachedPhoneData13 = jsonStores - case .fourteen: cachedPhoneData14 = jsonStores + case .thirteen: cachedPhoneData13 = iphoneData + case .fourteen: cachedPhoneData14 = iphoneData } - return jsonStores + return iphoneData + } else { + return [:] + } + + } catch { + print(error) + return [:] + } + } else { + return [:] + } + } + + func appleWatchUltraModels(for country: Country) -> SKUData { + let rawData = loadAppleWatchUltraModels() + if rawData.isEmpty { + fatalError() + } + + var compiled: [Country: [String: [String: String]]] = [:] + for (countryCode, models) in rawData { + guard let foundCountry = Countries[countryCode.uppercased()] else { + self.updateErrorState(to: ModelError.invalidLocalModelStore) + return SKUData(orderedSKUs: [], lookup: [:]) + } + + compiled[foundCountry] = models + } + + guard let countryData = compiled[country] else { + self.updateErrorState(to: ModelError.invalidLocalModelStore) + return SKUData(orderedSKUs: [], lookup: [:]) + } + + var allSKUs = [String]() + var map = [String: String]() + for (_, models) in countryData { + for (sku, model) in models { + allSKUs.append(sku) + map[sku] = model + } + } + + return SKUData(orderedSKUs: allSKUs, lookup: map) + } + + private func loadAppleWatchUltraModels() -> [String: [String: [String: String]]] { + if let cachedAppleWatchData { + return cachedAppleWatchData + } + + if let path = Bundle.main.path(forResource: "AppleWatchUltra-intl", ofType: "json") { + do { + let data = try Data(contentsOf: URL(fileURLWithPath: path)) + let decoder = JSONDecoder() + + if let appleWatchData = try? decoder.decode([String: [String: [String: String]]].self, from: data) { + cachedAppleWatchData = appleWatchData + + return appleWatchData } else { return [:] } @@ -273,6 +333,8 @@ final class Model: ObservableObject { return phoneModels(for: country).toSkuData(\.pro14) case .iPhoneProMax14: return phoneModels(for: country).toSkuData(\.proMax14) + case .AppleWatchUltra: + return appleWatchUltraModels(for: country) } } diff --git a/InventoryWatch/Model/ProductType.swift b/InventoryWatch/Model/ProductType.swift index a99dc8e..0f5f88c 100644 --- a/InventoryWatch/Model/ProductType.swift +++ b/InventoryWatch/Model/ProductType.swift @@ -24,6 +24,7 @@ enum ProductType: String, Codable, CaseIterable, Identifiable { case iPhonePlus14 case iPhonePro14 case iPhoneProMax14 + case AppleWatchUltra var presentableName: String { switch self { @@ -55,6 +56,8 @@ enum ProductType: String, Codable, CaseIterable, Identifiable { return "iPhone 14 Pro" case .iPhoneProMax14: return "iPhone 14 Pro Max" + case.AppleWatchUltra: + return "Apple Watch Ultra" } } }