Skip to content

Commit 81e471d

Browse files
committed
Read TimeZones from UserDefaults
1 parent ced6c7f commit 81e471d

9 files changed

Lines changed: 173 additions & 88 deletions

File tree

Elsewhen.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
5E9BD44F26EE512E00383233 /* TimeZoneFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EE70E2126EC9AA500F3F164 /* TimeZoneFlags.swift */; };
11+
5E9BD45126EEA11900383233 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9BD45026EEA11900383233 /* UserDefaults.swift */; };
1012
5EAB48DD26E624CD00B04A60 /* TimezoneChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EAB48DC26E624CD00B04A60 /* TimezoneChoiceView.swift */; };
1113
5EB23B9D26E406B600203153 /* ElsewhenApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB23B9C26E406B600203153 /* ElsewhenApp.swift */; };
1214
5EB23B9F26E406B600203153 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB23B9E26E406B600203153 /* ContentView.swift */; };
@@ -70,6 +72,7 @@
7072
/* End PBXCopyFilesBuildPhase section */
7173

7274
/* Begin PBXFileReference section */
75+
5E9BD45026EEA11900383233 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = "<group>"; };
7376
5EAB48DC26E624CD00B04A60 /* TimezoneChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimezoneChoiceView.swift; sourceTree = "<group>"; };
7477
5EB23B9926E406B600203153 /* Elsewhen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Elsewhen.app; sourceTree = BUILT_PRODUCTS_DIR; };
7578
5EB23B9C26E406B600203153 /* ElsewhenApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElsewhenApp.swift; sourceTree = "<group>"; };
@@ -198,6 +201,7 @@
198201
children = (
199202
6378397D26EA5FD60055A10D /* UIApplication+clearLaunchScreenCache.swift */,
200203
637839CA26ED11360055A10D /* TimeZone+ItemProvider.swift */,
204+
5E9BD45026EEA11900383233 /* UserDefaults.swift */,
201205
);
202206
path = Extensions;
203207
sourceTree = "<group>";
@@ -395,6 +399,7 @@
395399
6378398726EBA7C60055A10D /* DateTimeSelection.swift in Sources */,
396400
637839CB26ED11360055A10D /* TimeZone+ItemProvider.swift in Sources */,
397401
6378398326EB80C30055A10D /* ResultSheet.swift in Sources */,
402+
5E9BD45126EEA11900383233 /* UserDefaults.swift in Sources */,
398403
6378398526EB80F50055A10D /* DateHelpers.swift in Sources */,
399404
635C8FA726E66E8300361B08 /* DiscordFormattedDate.swift in Sources */,
400405
5EB23B9D26E406B600203153 /* ElsewhenApp.swift in Sources */,
@@ -405,6 +410,7 @@
405410
isa = PBXSourcesBuildPhase;
406411
buildActionMask = 2147483647;
407412
files = (
413+
5E9BD44F26EE512E00383233 /* TimeZoneFlags.swift in Sources */,
408414
637839B026EBF4910055A10D /* Intents.intentdefinition in Sources */,
409415
6378399226EBF4750055A10D /* IntentHandler.swift in Sources */,
410416
637839B526EBF8130055A10D /* FormatCodeExtension.swift in Sources */,

Elsewhen/ContentView.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,14 @@ let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "times")
1414

1515
struct ContentView: View {
1616

17-
@State private var selectedTab: Int = 1
18-
19-
@State private var selectedDate = Date()
20-
@State private var selectedTimeZone: TimeZone = TimeZone.current
17+
@State private var selectedTab: Int = 0
2118

2219
var body: some View {
2320
TabView(selection: $selectedTab) {
24-
TimeCodeGeneratorView(selectedDate: $selectedDate, selectedTimeZone: $selectedTimeZone)
21+
TimeCodeGeneratorView()
2522
.tabItem { Label("Time Codes", systemImage: "clock") }
2623
.tag(0)
27-
MykeMode(selectedDate: $selectedDate, selectedTimeZone: $selectedTimeZone)
24+
MykeMode()
2825
.tabItem { Label("Myke Mode", systemImage: "keyboard") }
2926
.tag(1)
3027
}

Elsewhen/Elements/DateTimeZonePicker.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct DateTimeZonePicker: View {
3636
Text("Time zone")
3737
.fontWeight(.semibold)
3838
Spacer()
39-
NavigationLink(destination: TimezoneChoiceView(selectedTimeZone: $selectedTimeZone)) {
39+
NavigationLink(destination: TimezoneChoiceView(selectedTimeZone: $selectedTimeZone, selectedTimeZones: .constant([]), selectedDate: $selectedDate, selectMultiple: false)) {
4040
Text(selectedTimeZone.identifier.replacingOccurrences(of: "_", with: " "))
4141
.foregroundColor(.primary)
4242
.padding(.vertical, 8)

Elsewhen/Elements/ResultSheet.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct ResultSheet: View {
133133
.background(
134134
Color(UIColor.secondarySystemBackground)
135135
.shadow(radius: 5, x: 0, y: -5)
136+
.opacity(0.5)
136137
)
137138
}
138139

Elsewhen/Elements/TimezoneChoiceView.swift

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ struct TimezoneChoiceView: View {
1212
@Environment(\.presentationMode) private var presentationMode
1313

1414
@Binding var selectedTimeZone: TimeZone
15+
@Binding var selectedTimeZones: [TimeZone]
16+
@Binding var selectedDate: Date
17+
var selectMultiple: Bool
1518
@State private var searchTerm: String = ""
1619

1720
private var filteredTimeZones: [TimeZone] {
@@ -20,24 +23,45 @@ struct TimezoneChoiceView: View {
2023
}.filter { $0.matches(searchTerm: searchTerm) }
2124
}
2225

26+
private func timeZoneIsSelected(_ tz: TimeZone) -> Bool {
27+
if selectMultiple {
28+
return selectedTimeZones.contains(tz)
29+
} else {
30+
return selectedTimeZone == tz
31+
}
32+
}
33+
2334
var body: some View {
2435
List {
2536
SearchBar(text: $searchTerm, placeholder: "Search...")
2637
.padding(.horizontal, -10)
2738
ForEach(filteredTimeZones, id: \.self) { tz in
2839
Button(action: {
29-
self.selectedTimeZone = tz
30-
presentationMode.wrappedValue.dismiss()
40+
if self.selectMultiple {
41+
if let index = self.selectedTimeZones.firstIndex(of: tz) {
42+
self.selectedTimeZones.remove(at: index)
43+
} else {
44+
self.selectedTimeZones.append(tz)
45+
}
46+
} else {
47+
self.selectedTimeZone = tz
48+
}
49+
if !selectMultiple {
50+
presentationMode.wrappedValue.dismiss()
51+
}
3152
}) {
3253
HStack {
3354
Text(tz.friendlyName)
3455
Spacer()
35-
if let abbreviation = tz.abbreviation() {
56+
if let abbreviation = tz.fudgedAbbreviation(for: selectedDate) {
3657
Text(abbreviation)
37-
.foregroundColor(selectedTimeZone == tz ? .accentColor : .secondary)
58+
.foregroundColor(.secondary)
59+
}
60+
if timeZoneIsSelected(tz) {
61+
Image(systemName: "checkmark")
3862
}
3963
}
40-
.foregroundColor(selectedTimeZone == tz ? .accentColor : .primary)
64+
.foregroundColor(timeZoneIsSelected(tz) ? .accentColor : .primary)
4165
}
4266
}
4367
}
@@ -48,6 +72,6 @@ struct TimezoneChoiceView: View {
4872

4973
struct TimezoneChoiceView_Previews: PreviewProvider {
5074
static var previews: some View {
51-
TimezoneChoiceView(selectedTimeZone: .constant(TimeZone(identifier: "Europe/London")!))
75+
TimezoneChoiceView(selectedTimeZone: .constant(TimeZone(identifier: "Africa/Accra")!), selectedTimeZones: .constant([TimeZone(identifier: "Africa/Algiers")!, TimeZone(identifier: "Africa/Bissau")!]), selectedDate: .constant(Date()), selectMultiple: true)
5276
}
5377
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// UserDefaults.swift
3+
// UserDefaults
4+
//
5+
// Created by Ben Cardy on 12/09/2021.
6+
//
7+
8+
import Foundation
9+
10+
extension UserDefaults {
11+
12+
static let mykeModeTimeZoneIdentifiersKey = "mykeModeTimeZoneIdentifiers"
13+
14+
@objc fileprivate var mykeModeTimeZoneIdentifiers: [String] {
15+
get { array(forKey: Self.mykeModeTimeZoneIdentifiersKey) as? [String] ?? [] }
16+
set { set(newValue, forKey: Self.mykeModeTimeZoneIdentifiersKey) }
17+
}
18+
19+
var mykeModeTimeZones: [TimeZone] {
20+
get {
21+
guard let identifiers = array(forKey: Self.mykeModeTimeZoneIdentifiersKey) as? [String] else { return [] }
22+
return identifiers.compactMap { TimeZone(identifier: $0) }
23+
}
24+
set {
25+
set(newValue.map { $0.identifier }, forKey: Self.mykeModeTimeZoneIdentifiersKey)
26+
}
27+
}
28+
29+
}

Elsewhen/Helpers/DateHelpers.swift

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,28 +38,6 @@ func convert(date: Date, from initialTimezone: TimeZone, to targetTimezone: Time
3838
return date.addingTimeInterval(offset)
3939
}
4040

41-
extension TimeZone {
42-
43-
var friendlyName: String {
44-
identifier.replacingOccurrences(of: "_", with: " ")
45-
}
46-
47-
func matches(searchTerm: String) -> Bool {
48-
let st = searchTerm.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
49-
if st == "" {
50-
return true
51-
}
52-
if identifier.lowercased().contains(st) || friendlyName.lowercased().contains(st) {
53-
return true
54-
}
55-
if let abbreviation = abbreviation(), abbreviation.lowercased().contains(st) {
56-
return true
57-
}
58-
return false
59-
}
60-
61-
}
62-
6341
func format(date: Date, in timezone: TimeZone, with formatCode: FormatCode) -> String {
6442
let dateFormatter = DateFormatter()
6543
switch formatCode {
@@ -84,3 +62,43 @@ func format(date: Date, in timezone: TimeZone, with formatCode: FormatCode) -> S
8462
}
8563
return dateFormatter.string(from: date)
8664
}
65+
66+
extension TimeZone {
67+
68+
var friendlyName: String {
69+
identifier.replacingOccurrences(of: "_", with: " ")
70+
}
71+
72+
var flag: String {
73+
flagForTimeZone(self)
74+
}
75+
76+
func matches(searchTerm: String) -> Bool {
77+
let st = searchTerm.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
78+
if st == "" {
79+
return true
80+
}
81+
if identifier.lowercased().contains(st) || friendlyName.lowercased().contains(st) {
82+
return true
83+
}
84+
if let abbreviation = abbreviation(), abbreviation.lowercased().contains(st) {
85+
return true
86+
}
87+
return false
88+
}
89+
90+
func fudgedAbbreviation(for selectedDate: Date) -> String? {
91+
guard let abbreviation = abbreviation(for: selectedDate) else { return nil }
92+
let isDaylightSavingTime = isDaylightSavingTime(for: selectedDate)
93+
if identifier == "Europe/London" && isDaylightSavingTime {
94+
return "BST"
95+
}
96+
if identifier.starts(with: "Europe") {
97+
if isDaylightSavingTime && abbreviation == "GMT+2" || !isDaylightSavingTime && abbreviation == "GMT+1" {
98+
return "CET"
99+
}
100+
}
101+
return abbreviation
102+
}
103+
104+
}

0 commit comments

Comments
 (0)