Browse Source

Merge branch 'core-data-sync-trio' of github.com:dnzxy/Trio-dev into settings-update

Deniz Cengiz 1 year ago
parent
commit
1d03d1b764

+ 2 - 2
FreeAPS/Resources/Info.plist

@@ -2,8 +2,6 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-	<key>TeamID</key>
-	<string>$(DEVELOPER_TEAM)</string>
 	<key>AppGroupID</key>
 	<string>$(APP_GROUP_ID)</string>
 	<key>BGTaskSchedulerPermittedIdentifiers</key>
@@ -88,6 +86,8 @@
 	<string>$(COPYRIGHT_NOTICE)</string>
 	<key>NSSupportsLiveActivities</key>
 	<true/>
+	<key>TeamID</key>
+	<string>$(DEVELOPMENT_TEAM)</string>
 	<key>UIApplicationSceneManifest</key>
 	<dict>
 		<key>UIApplicationSupportsMultipleScenes</key>

+ 29 - 0
FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorStateModel.swift

@@ -10,6 +10,7 @@ extension BasalProfileEditor {
         var items: [Item] = []
         var total: Decimal = 0.0
         var showAlert: Bool = false
+        var chartData: [BasalProfile]? = []
 
         let timeValues = stride(from: 0.0, to: 1.days.timeInterval, by: 30.minutes.timeInterval).map { $0 }
 
@@ -131,5 +132,33 @@ extension BasalProfileEditor {
 
             return (0 ..< timeValues.count).filter { !usedIndicesByOtherItems.contains($0) }
         }
+
+        func caluclateChartData() {
+            DispatchQueue.main.async {
+                var basals: [BasalProfile] = []
+                let tzOffset = TimeZone.current.secondsFromGMT() * -1
+
+                basals.append(contentsOf: self.items.enumerated().map { index, item in
+                    let startDate = Date(timeIntervalSinceReferenceDate: self.timeValues[item.timeIndex])
+                    var endDate = Date(timeIntervalSinceReferenceDate: self.timeValues.last!).addingTimeInterval(30 * 60)
+                    if self.items.count > index + 1 {
+                        let nextItem = self.items[index + 1]
+                        endDate = Date(timeIntervalSinceReferenceDate: self.timeValues[nextItem.timeIndex])
+                    }
+
+                    return BasalProfile(
+                        amount: Double(self.rateValues[item.rateIndex]),
+                        isOverwritten: false,
+                        startDate: startDate.addingTimeInterval(TimeInterval(tzOffset)),
+                        endDate: endDate.addingTimeInterval(TimeInterval(tzOffset))
+                    )
+                })
+                basals.sort(by: {
+                    $0.startDate > $1.startDate
+                })
+
+                self.chartData = basals
+            }
+        }
     }
 }

+ 95 - 22
FreeAPS/Sources/Modules/BasalProfileEditor/View/BasalProfileEditorRootView.swift

@@ -1,3 +1,4 @@
+import Charts
 import SwiftUI
 import Swinject
 
@@ -7,6 +8,9 @@ extension BasalProfileEditor {
         @State var state = StateModel()
         @State private var editMode = EditMode.inactive
 
+        let chartScale = Calendar.current
+            .date(from: DateComponents(year: 2001, month: 01, day: 01, hour: 0, minute: 0, second: 0))
+
         @Environment(\.colorScheme) var colorScheme
         var color: LinearGradient {
             colorScheme == .dark ? LinearGradient(
@@ -38,11 +42,92 @@ extension BasalProfileEditor {
             return formatter
         }
 
-        var body: some View {
-            Form {
+        var basalScheduleChart: some View {
+            Chart {
+                ForEach(state.chartData!, id: \.self) { profile in
+                    RectangleMark(
+                        xStart: .value("start", profile.startDate),
+                        xEnd: .value("end", profile.endDate!),
+                        yStart: .value("rate-start", profile.amount),
+                        yEnd: .value("rate-end", 0)
+                    ).foregroundStyle(
+                        .linearGradient(
+                            colors: [
+                                Color.insulin.opacity(0.6),
+                                Color.insulin.opacity(0.1)
+                            ],
+                            startPoint: .bottom,
+                            endPoint: .top
+                        )
+                    ).alignsMarkStylesWithPlotArea()
+
+                    LineMark(x: .value("End Date", profile.endDate!), y: .value("Amount", profile.amount))
+                        .lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.insulin)
+
+                    LineMark(x: .value("Start Date", profile.startDate), y: .value("Amount", profile.amount))
+                        .lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.insulin)
+                }
+            }
+            .chartXAxis {
+                AxisMarks(values: .automatic(desiredCount: 6)) { _ in
+                    AxisValueLabel(format: .dateTime.hour())
+                    AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1, dash: [2, 4]))
+                }
+            }
+            .chartYAxis {
+                AxisMarks(values: .automatic(desiredCount: 2)) { _ in
+                    AxisValueLabel()
+                    AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1, dash: [2, 4]))
+                }
+            }
+            .chartXScale(
+                domain: Calendar.current.startOfDay(for: chartScale!) ... Calendar.current.startOfDay(for: chartScale!)
+                    .addingTimeInterval(60 * 60 * 24)
+            )
+        }
+
+        var saveButton: some View {
+            ZStack {
                 let shouldDisableButton = state.syncInProgress || state.items.isEmpty || !state.hasChanges
 
+                Rectangle()
+                    .frame(width: UIScreen.main.bounds.width, height: 65)
+                    .foregroundStyle(colorScheme == .dark ? Color.bgDarkerDarkBlue : Color.white)
+                    .background(.thinMaterial)
+                    .opacity(0.8)
+                    .clipShape(Rectangle())
+
+                Group {
+                    HStack {
+                        Button {
+                            let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
+                            impactHeavy.impactOccurred()
+                            state.save()
+                        } label: {
+                            HStack {
+                                if state.syncInProgress {
+                                    ProgressView().padding(.trailing, 10)
+                                }
+                                Text(state.syncInProgress ? "Saving..." : "Save")
+                            }.padding(10)
+                        }
+                        .frame(width: UIScreen.main.bounds.width * 0.9, alignment: .center)
+                        .disabled(shouldDisableButton)
+                        .background(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
+                        .tint(.white)
+                        .clipShape(RoundedRectangle(cornerRadius: 8))
+                    }
+                }.padding(5)
+            }
+        }
+
+        var body: some View {
+            Form {
                 Section(header: Text("Schedule")) {
+                    if !state.items.isEmpty {
+                        basalScheduleChart.padding(.vertical)
+                    }
+
                     list
                 }.listRowBackground(Color.chart)
 
@@ -58,25 +143,8 @@ extension BasalProfileEditor {
                             .foregroundColor(.secondary)
                     }
                 }.listRowBackground(Color.chart)
-
-                Section {
-                    HStack {
-                        if state.syncInProgress {
-                            ProgressView().padding(.trailing, 10)
-                        }
-                        Button {
-                            let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
-                            impactHeavy.impactOccurred()
-                            state.save()
-                        } label: {
-                            Text(state.syncInProgress ? "Saving..." : "Save")
-                        }
-                        .disabled(shouldDisableButton)
-                        .frame(maxWidth: .infinity, alignment: .center)
-                        .tint(.white)
-                    }
-                }.listRowBackground(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
             }
+            .safeAreaInset(edge: .bottom, spacing: 30) { saveButton }
             .alert(isPresented: $state.showAlert) {
                 Alert(
                     title: Text("Unable to Save"),
@@ -84,9 +152,11 @@ extension BasalProfileEditor {
                     dismissButton: .default(Text("Close"))
                 )
             }
-            .onChange(of: state.items) { state.calcTotal() }
+            .onChange(of: state.items) {
+                state.calcTotal()
+                state.caluclateChartData()
+            }
             .scrollContentBackground(.hidden).background(color)
-            .onAppear(perform: configureView)
             .navigationTitle("Basal Profile")
             .navigationBarTitleDisplayMode(.automatic)
             .toolbar(content: {
@@ -99,7 +169,9 @@ extension BasalProfileEditor {
             })
             .environment(\.editMode, $editMode)
             .onAppear {
+                configureView()
                 state.validate()
+                state.caluclateChartData()
             }
         }
 
@@ -183,6 +255,7 @@ extension BasalProfileEditor {
             state.items.remove(atOffsets: offsets)
             state.validate()
             state.calcTotal()
+            state.caluclateChartData()
         }
     }
 }

+ 43 - 26
FreeAPS/Sources/Modules/CarbRatioEditor/View/CarbRatioEditorRootView.swift

@@ -38,10 +38,50 @@ extension CarbRatioEditor {
             return formatter
         }
 
-        var body: some View {
-            Form {
+        var saveButton: some View {
+            ZStack {
                 let shouldDisableButton = state.shouldDisplaySaving || state.items.isEmpty || !state.hasChanges
 
+                Rectangle()
+                    .frame(width: UIScreen.main.bounds.width, height: 65)
+                    .foregroundStyle(colorScheme == .dark ? Color.bgDarkerDarkBlue : Color.white)
+                    .background(.thinMaterial)
+                    .opacity(0.8)
+                    .clipShape(Rectangle())
+
+                Group {
+                    HStack {
+                        HStack {
+                            Button {
+                                let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
+                                impactHeavy.impactOccurred()
+                                state.save()
+
+                                // deactivate saving display after 1.25 seconds
+                                DispatchQueue.main.asyncAfter(deadline: .now() + 1.25) {
+                                    state.shouldDisplaySaving = false
+                                }
+                            } label: {
+                                HStack {
+                                    if state.shouldDisplaySaving {
+                                        ProgressView().padding(.trailing, 10)
+                                    }
+                                    Text(state.shouldDisplaySaving ? "Saving..." : "Save")
+                                }.padding(10)
+                            }
+                        }
+                        .frame(width: UIScreen.main.bounds.width * 0.9, alignment: .center)
+                        .disabled(shouldDisableButton)
+                        .background(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
+                        .tint(.white)
+                        .clipShape(RoundedRectangle(cornerRadius: 8))
+                    }
+                }.padding(5)
+            }
+        }
+
+        var body: some View {
+            Form {
                 if let autotune = state.autotune, !state.settingsManager.settings.onlyAutotuneBasals {
                     Section(header: Text("Autotune")) {
                         HStack {
@@ -56,31 +96,8 @@ extension CarbRatioEditor {
                 Section(header: Text("Schedule")) {
                     list
                 }.listRowBackground(Color.chart)
-
-                Section {
-                    HStack {
-                        if state.shouldDisplaySaving {
-                            ProgressView().padding(.trailing, 10)
-                        }
-
-                        Button {
-                            let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
-                            impactHeavy.impactOccurred()
-                            state.save()
-
-                            // deactivate saving display after 1.25 seconds
-                            DispatchQueue.main.asyncAfter(deadline: .now() + 1.25) {
-                                state.shouldDisplaySaving = false
-                            }
-                        } label: {
-                            Text(state.shouldDisplaySaving ? "Saving..." : "Save")
-                        }
-                        .disabled(shouldDisableButton)
-                        .frame(maxWidth: .infinity, alignment: .center)
-                        .tint(.white)
-                    }
-                }.listRowBackground(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
             }
+            .safeAreaInset(edge: .bottom, spacing: 30) { saveButton }
             .scrollContentBackground(.hidden).background(color)
             .onAppear(perform: configureView)
             .navigationTitle("Carb Ratios")

+ 8 - 10
FreeAPS/Sources/Modules/Home/View/Chart/BasalChart.swift

@@ -74,17 +74,15 @@ extension MainChartView {
                     yStart: .value("rate-start", 0),
                     yEnd: .value("rate-end", basal.rate)
                 ).foregroundStyle(
-                    LinearGradient(
-                        gradient: Gradient(
-                            colors: [
-                                Color.insulin.opacity(0.6),
-                                Color.insulin.opacity(0.1)
-                            ]
-                        ),
-                        startPoint: .top,
-                        endPoint: .bottom
+                    .linearGradient(
+                        colors: [
+                            Color.insulin.opacity(0.6),
+                            Color.insulin.opacity(0.1)
+                        ],
+                        startPoint: .bottom,
+                        endPoint: .top
                     )
-                )
+                ).alignsMarkStylesWithPlotArea()
 
                 LineMark(x: .value("Start Date", basal.start), y: .value("Amount", basal.rate))
                     .lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.insulin)

+ 42 - 26
FreeAPS/Sources/Modules/ISFEditor/View/ISFEditorRootView.swift

@@ -39,10 +39,49 @@ extension ISFEditor {
             return formatter
         }
 
-        var body: some View {
-            Form {
+        var saveButton: some View {
+            ZStack {
                 let shouldDisableButton = state.items.isEmpty || !state.hasChanges
 
+                Rectangle()
+                    .frame(width: UIScreen.main.bounds.width, height: 65)
+                    .foregroundStyle(colorScheme == .dark ? Color.bgDarkerDarkBlue : Color.white)
+                    .background(.thinMaterial)
+                    .opacity(0.8)
+                    .clipShape(Rectangle())
+
+                Group {
+                    HStack {
+                        HStack {
+                            if state.shouldDisplaySaving {
+                                ProgressView().padding(.trailing, 10)
+                            }
+
+                            Button {
+                                let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
+                                impactHeavy.impactOccurred()
+                                state.save()
+
+                                // deactivate saving display after 1.25 seconds
+                                DispatchQueue.main.asyncAfter(deadline: .now() + 1.25) {
+                                    state.shouldDisplaySaving = false
+                                }
+                            } label: {
+                                Text(state.shouldDisplaySaving ? "Saving..." : "Save").padding(10)
+                            }
+                        }
+                        .frame(width: UIScreen.main.bounds.width * 0.9, alignment: .center)
+                        .disabled(shouldDisableButton)
+                        .background(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
+                        .tint(.white)
+                        .clipShape(RoundedRectangle(cornerRadius: 8))
+                    }
+                }.padding(5)
+            }
+        }
+
+        var body: some View {
+            Form {
                 if let autotune = state.autotune, !state.settingsManager.settings.onlyAutotuneBasals {
                     Section(header: Text("Autotune")) {
                         HStack {
@@ -99,31 +138,8 @@ extension ISFEditor {
                 Section(header: Text("Schedule")) {
                     list
                 }.listRowBackground(Color.chart)
-
-                Section {
-                    HStack {
-                        if state.shouldDisplaySaving {
-                            ProgressView().padding(.trailing, 10)
-                        }
-
-                        Button {
-                            let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
-                            impactHeavy.impactOccurred()
-                            state.save()
-
-                            // deactivate saving display after 1.25 seconds
-                            DispatchQueue.main.asyncAfter(deadline: .now() + 1.25) {
-                                state.shouldDisplaySaving = false
-                            }
-                        } label: {
-                            Text(state.shouldDisplaySaving ? "Saving..." : "Save")
-                        }
-                        .disabled(shouldDisableButton)
-                        .frame(maxWidth: .infinity, alignment: .center)
-                        .tint(.white)
-                    }
-                }.listRowBackground(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
             }
+            .safeAreaInset(edge: .bottom, spacing: 30) { saveButton }
             .scrollContentBackground(.hidden).background(color)
             .onAppear(perform: configureView)
             .navigationTitle("Insulin Sensitivities")

+ 1 - 4
FreeAPS/Sources/Modules/RemoteControl/TrioRemoteControl+APNS.swift

@@ -28,9 +28,6 @@ extension TrioRemoteControl {
     }
 
     private func isRunningInAPNSProductionEnvironment() -> Bool {
-        if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL {
-            return appStoreReceiptURL.lastPathComponent != "sandboxReceipt"
-        }
-        return false
+        return BuildDetails.default.isTestFlightBuild()
     }
 }

+ 13 - 9
FreeAPS/Sources/Modules/RemoteControl/TrioRemoteControl+Override.swift

@@ -1,3 +1,4 @@
+import CoreData
 import Foundation
 
 extension TrioRemoteControl {
@@ -30,12 +31,12 @@ extension TrioRemoteControl {
     }
 
     @MainActor private func enactOverridePreset(preset: OverrideStored, pushMessage: PushMessage) async {
-        await disableAllActiveOverrides()
-
         preset.enabled = true
         preset.date = Date()
         preset.isUploadedToNS = false
 
+        await disableAllActiveOverrides(except: preset.objectID)
+
         do {
             if viewContext.hasChanges {
                 try viewContext.save()
@@ -43,17 +44,14 @@ extension TrioRemoteControl {
                 Foundation.NotificationCenter.default.post(name: .willUpdateOverrideConfiguration, object: nil)
                 await awaitNotification(.didUpdateOverrideConfiguration)
 
-                debug(
-                    .remoteControl,
-                    "Remote command processed successfully. \(pushMessage.humanReadableDescription())"
-                )
+                debug(.remoteControl, "Remote command processed successfully. \(pushMessage.humanReadableDescription())")
             }
         } catch {
             debug(.remoteControl, "Failed to enact override preset: \(error.localizedDescription)")
         }
     }
 
-    @MainActor private func disableAllActiveOverrides() async {
+    @MainActor private func disableAllActiveOverrides(except overrideID: NSManagedObjectID? = nil) async {
         let ids = await overrideStorage.loadLatestOverrideConfigurations(fetchLimit: 0) // 0 = no fetch limit
 
         let didPostNotification = await viewContext.perform { () -> Bool in
@@ -65,17 +63,23 @@ extension TrioRemoteControl {
                 guard !results.isEmpty else { return false }
 
                 for canceledOverride in results where canceledOverride.enabled {
+                    if let overrideID = overrideID, canceledOverride.objectID == overrideID {
+                        continue
+                    }
+
                     let newOverrideRunStored = OverrideRunStored(context: self.viewContext)
                     newOverrideRunStored.id = UUID()
                     newOverrideRunStored.name = canceledOverride.name
                     newOverrideRunStored.startDate = canceledOverride.date ?? .distantPast
                     newOverrideRunStored.endDate = Date()
-                    newOverrideRunStored
-                        .target = NSDecimalNumber(decimal: self.overrideStorage.calculateTarget(override: canceledOverride))
+                    newOverrideRunStored.target = NSDecimalNumber(
+                        decimal: self.overrideStorage.calculateTarget(override: canceledOverride)
+                    )
                     newOverrideRunStored.override = canceledOverride
                     newOverrideRunStored.isUploadedToNS = false
 
                     canceledOverride.enabled = false
+                    canceledOverride.isUploadedToNS = false
                 }
 
                 if self.viewContext.hasChanges {

+ 4 - 0
FreeAPS/Sources/Modules/RemoteControl/TrioRemoteControl.swift

@@ -74,6 +74,10 @@ class TrioRemoteControl: Injectable {
             await cancelTempTarget(pushMessage)
         case .meal:
             await handleMealCommand(pushMessage)
+
+            if pushMessage.bolusAmount != nil {
+                await handleBolusCommand(pushMessage)
+            }
         case .startOverride:
             await handleStartOverrideCommand(pushMessage)
         case .cancelOverride:

+ 38 - 21
FreeAPS/Sources/Modules/TargetsEditor/View/TargetsEditorRootView.swift

@@ -32,38 +32,55 @@ extension TargetsEditor {
             return formatter
         }
 
-        var body: some View {
-            Form {
+        var saveButton: some View {
+            ZStack {
                 let shouldDisableButton = state.shouldDisplaySaving || state.items.isEmpty || !state.hasChanges
 
-                Section(header: Text("Schedule")) {
-                    list
-                }.listRowBackground(Color.chart)
+                Rectangle()
+                    .frame(width: UIScreen.main.bounds.width, height: 65)
+                    .foregroundStyle(colorScheme == .dark ? Color.bgDarkerDarkBlue : Color.white)
+                    .background(.thinMaterial)
+                    .opacity(0.8)
+                    .clipShape(Rectangle())
 
-                Section {
+                Group {
                     HStack {
-                        if state.shouldDisplaySaving {
-                            ProgressView().padding(.trailing, 10)
-                        }
-
-                        Button {
-                            let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
-                            impactHeavy.impactOccurred()
-                            state.save()
+                        HStack {
+                            Button {
+                                let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
+                                impactHeavy.impactOccurred()
+                                state.save()
 
-                            // deactivate saving display after 1.25 seconds
-                            DispatchQueue.main.asyncAfter(deadline: .now() + 1.25) {
-                                state.shouldDisplaySaving = false
+                                // deactivate saving display after 1.25 seconds
+                                DispatchQueue.main.asyncAfter(deadline: .now() + 1.25) {
+                                    state.shouldDisplaySaving = false
+                                }
+                            } label: {
+                                HStack {
+                                    if state.shouldDisplaySaving {
+                                        ProgressView().padding(.trailing, 10)
+                                    }
+                                    Text(state.shouldDisplaySaving ? "Saving..." : "Save")
+                                }.padding(10)
                             }
-                        } label: {
-                            Text(state.shouldDisplaySaving ? "Saving..." : "Save")
                         }
+                        .frame(width: UIScreen.main.bounds.width * 0.9, alignment: .center)
                         .disabled(shouldDisableButton)
-                        .frame(maxWidth: .infinity, alignment: .center)
+                        .background(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
                         .tint(.white)
+                        .clipShape(RoundedRectangle(cornerRadius: 8))
                     }
-                }.listRowBackground(shouldDisableButton ? Color(.systemGray4) : Color(.systemBlue))
+                }.padding(5)
+            }
+        }
+
+        var body: some View {
+            Form {
+                Section(header: Text("Schedule")) {
+                    list
+                }.listRowBackground(Color.chart)
             }
+            .safeAreaInset(edge: .bottom, spacing: 30) { saveButton }
             .scrollContentBackground(.hidden).background(color)
             .onAppear(perform: configureView)
             .navigationTitle("Glucose Targets")

+ 21 - 17
Gemfile.lock

@@ -10,20 +10,20 @@ GEM
     artifactory (3.0.17)
     atomos (0.1.3)
     aws-eventstream (1.3.0)
-    aws-partitions (1.981.0)
-    aws-sdk-core (3.209.1)
+    aws-partitions (1.1007.0)
+    aws-sdk-core (3.213.0)
       aws-eventstream (~> 1, >= 1.3.0)
-      aws-partitions (~> 1, >= 1.651.0)
+      aws-partitions (~> 1, >= 1.992.0)
       aws-sigv4 (~> 1.9)
       jmespath (~> 1, >= 1.6.1)
-    aws-sdk-kms (1.94.0)
-      aws-sdk-core (~> 3, >= 3.207.0)
+    aws-sdk-kms (1.95.0)
+      aws-sdk-core (~> 3, >= 3.210.0)
       aws-sigv4 (~> 1.5)
-    aws-sdk-s3 (1.166.0)
-      aws-sdk-core (~> 3, >= 3.207.0)
+    aws-sdk-s3 (1.171.0)
+      aws-sdk-core (~> 3, >= 3.210.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.5)
-    aws-sigv4 (1.10.0)
+    aws-sigv4 (1.10.1)
       aws-eventstream (~> 1, >= 1.0.2)
     babosa (1.0.4)
     base64 (0.2.0)
@@ -69,7 +69,7 @@ GEM
     faraday_middleware (1.2.1)
       faraday (~> 1.0)
     fastimage (2.3.1)
-    fastlane (2.223.1)
+    fastlane (2.225.0)
       CFPropertyList (>= 2.3, < 4.0.0)
       addressable (>= 2.8, < 3.0.0)
       artifactory (~> 3.0)
@@ -85,6 +85,7 @@ GEM
       faraday-cookie_jar (~> 0.0.6)
       faraday_middleware (~> 1.0)
       fastimage (>= 2.1.0, < 3.0.0)
+      fastlane-sirp (>= 1.0.0)
       gh_inspector (>= 1.1.2, < 2.0.0)
       google-apis-androidpublisher_v3 (~> 0.3)
       google-apis-playcustomapp_v1 (~> 0.1)
@@ -110,6 +111,8 @@ GEM
       xcodeproj (>= 1.13.0, < 2.0.0)
       xcpretty (~> 0.3.0)
       xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
+    fastlane-sirp (1.0.0)
+      sysrandom (~> 1.0)
     gh_inspector (1.1.3)
     google-apis-androidpublisher_v3 (0.54.0)
       google-apis-core (>= 0.11.0, < 2.a)
@@ -152,17 +155,17 @@ GEM
       domain_name (~> 0.5)
     httpclient (2.8.3)
     jmespath (1.6.2)
-    json (2.7.2)
-    jwt (2.9.1)
+    json (2.7.6)
+    jwt (2.9.3)
       base64
     mini_magick (4.13.2)
     mini_mime (1.1.5)
     multi_json (1.15.0)
     multipart-post (2.4.1)
-    nanaimo (0.3.0)
+    nanaimo (0.4.0)
     naturally (2.2.1)
     nkf (0.2.0)
-    optparse (0.5.0)
+    optparse (0.6.0)
     os (1.1.4)
     plist (3.7.1)
     public_suffix (5.1.1)
@@ -172,7 +175,7 @@ GEM
       trailblazer-option (>= 0.1.1, < 0.2.0)
       uber (< 0.2.0)
     retriable (3.1.2)
-    rexml (3.3.7)
+    rexml (3.3.9)
     rouge (2.0.7)
     ruby2_keywords (0.0.5)
     rubyzip (2.3.2)
@@ -185,6 +188,7 @@ GEM
     simctl (1.6.10)
       CFPropertyList
       naturally
+    sysrandom (1.0.5)
     terminal-notifier (2.0.0)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
@@ -197,13 +201,13 @@ GEM
     unf (0.2.0)
     unicode-display_width (2.6.0)
     word_wrap (1.0.0)
-    xcodeproj (1.25.0)
+    xcodeproj (1.27.0)
       CFPropertyList (>= 2.3.3, < 4.0)
       atomos (~> 0.1.3)
       claide (>= 1.0.2, < 2.0)
       colored2 (~> 3.1)
-      nanaimo (~> 0.3.0)
-      rexml (>= 3.3.2, < 4.0)
+      nanaimo (~> 0.4.0)
+      rexml (>= 3.3.6, < 4.0)
     xcpretty (0.3.0)
       rouge (~> 2.0.7)
     xcpretty-travis-formatter (1.0.1)