Jon Fawcett 6 年之前
父節點
當前提交
bb54ecf14c

+ 12 - 0
LoopFollow.xcodeproj/project.pbxproj

@@ -13,6 +13,9 @@
 		FC16A97D24996747003D6245 /* Alarms.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC16A97C24996747003D6245 /* Alarms.swift */; };
 		FC16A97D24996747003D6245 /* Alarms.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC16A97C24996747003D6245 /* Alarms.swift */; };
 		FC16A97F249969E2003D6245 /* Graphs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC16A97E249969E2003D6245 /* Graphs.swift */; };
 		FC16A97F249969E2003D6245 /* Graphs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC16A97E249969E2003D6245 /* Graphs.swift */; };
 		FC16A98124996C07003D6245 /* DateTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC16A98024996C07003D6245 /* DateTime.swift */; };
 		FC16A98124996C07003D6245 /* DateTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC16A98024996C07003D6245 /* DateTime.swift */; };
+		FC1BDD2B24A22650001B652C /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1BDD2A24A22650001B652C /* Stats.swift */; };
+		FC1BDD2D24A23204001B652C /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1BDD2C24A23204001B652C /* StatsView.swift */; };
+		FC1BDD3224A2585C001B652C /* DataStructs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1BDD2E24A232A3001B652C /* DataStructs.swift */; };
 		FC3AE7B5249E8E0E00AAE1E0 /* LoopFollow.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FC3AE7B3249E8E0E00AAE1E0 /* LoopFollow.xcdatamodeld */; };
 		FC3AE7B5249E8E0E00AAE1E0 /* LoopFollow.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FC3AE7B3249E8E0E00AAE1E0 /* LoopFollow.xcdatamodeld */; };
 		FC3CAB022493B6220068A152 /* BackgroundTaskAudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC688592489554800A0279D /* BackgroundTaskAudio.swift */; };
 		FC3CAB022493B6220068A152 /* BackgroundTaskAudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC688592489554800A0279D /* BackgroundTaskAudio.swift */; };
 		FC5A5C3D2497B229009C550E /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = FC5A5C3C2497B229009C550E /* Config.xcconfig */; };
 		FC5A5C3D2497B229009C550E /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = FC5A5C3C2497B229009C550E /* Config.xcconfig */; };
@@ -163,6 +166,9 @@
 		FC16A97C24996747003D6245 /* Alarms.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alarms.swift; sourceTree = "<group>"; };
 		FC16A97C24996747003D6245 /* Alarms.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alarms.swift; sourceTree = "<group>"; };
 		FC16A97E249969E2003D6245 /* Graphs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Graphs.swift; sourceTree = "<group>"; };
 		FC16A97E249969E2003D6245 /* Graphs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Graphs.swift; sourceTree = "<group>"; };
 		FC16A98024996C07003D6245 /* DateTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTime.swift; sourceTree = "<group>"; };
 		FC16A98024996C07003D6245 /* DateTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTime.swift; sourceTree = "<group>"; };
+		FC1BDD2A24A22650001B652C /* Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = "<group>"; };
+		FC1BDD2C24A23204001B652C /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
+		FC1BDD2E24A232A3001B652C /* DataStructs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStructs.swift; sourceTree = "<group>"; };
 		FC3AE7B4249E8E0E00AAE1E0 /* LoopFollow.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LoopFollow.xcdatamodel; sourceTree = "<group>"; };
 		FC3AE7B4249E8E0E00AAE1E0 /* LoopFollow.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LoopFollow.xcdatamodel; sourceTree = "<group>"; };
 		FC5A5C3C2497B229009C550E /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
 		FC5A5C3C2497B229009C550E /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
 		FC7CE4A9248ABE2B001F83B8 /* Siri_Alert_Calibration_Needed.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Siri_Alert_Calibration_Needed.caf; sourceTree = "<group>"; };
 		FC7CE4A9248ABE2B001F83B8 /* Siri_Alert_Calibration_Needed.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Siri_Alert_Calibration_Needed.caf; sourceTree = "<group>"; };
@@ -360,6 +366,8 @@
 				FC16A97924996673003D6245 /* NightScout.swift */,
 				FC16A97924996673003D6245 /* NightScout.swift */,
 				FC16A97C24996747003D6245 /* Alarms.swift */,
 				FC16A97C24996747003D6245 /* Alarms.swift */,
 				FC16A97E249969E2003D6245 /* Graphs.swift */,
 				FC16A97E249969E2003D6245 /* Graphs.swift */,
+				FC1BDD2A24A22650001B652C /* Stats.swift */,
+				FC1BDD2C24A23204001B652C /* StatsView.swift */,
 			);
 			);
 			path = Controllers;
 			path = Controllers;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -554,6 +562,7 @@
 				FC16A98024996C07003D6245 /* DateTime.swift */,
 				FC16A98024996C07003D6245 /* DateTime.swift */,
 				FCE537BB249A4D7D00F80BF8 /* carbBolusArrays.swift */,
 				FCE537BB249A4D7D00F80BF8 /* carbBolusArrays.swift */,
 				FCEF87AA24A1417900AE6FA0 /* bgUnits.swift */,
 				FCEF87AA24A1417900AE6FA0 /* bgUnits.swift */,
+				FC1BDD2E24A232A3001B652C /* DataStructs.swift */,
 			);
 			);
 			path = helpers;
 			path = helpers;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -822,6 +831,7 @@
 				FCFEECA2248857A600402A7F /* SettingsViewController.swift in Sources */,
 				FCFEECA2248857A600402A7F /* SettingsViewController.swift in Sources */,
 				FCFEECA02488157B00402A7F /* Chart.swift in Sources */,
 				FCFEECA02488157B00402A7F /* Chart.swift in Sources */,
 				FCEF87AC24A141A700AE6FA0 /* bgUnits.swift in Sources */,
 				FCEF87AC24A141A700AE6FA0 /* bgUnits.swift in Sources */,
+				FC1BDD3224A2585C001B652C /* DataStructs.swift in Sources */,
 				FCC6886524898EEE00A0279D /* UserDefaults.swift in Sources */,
 				FCC6886524898EEE00A0279D /* UserDefaults.swift in Sources */,
 				FC16A97F249969E2003D6245 /* Graphs.swift in Sources */,
 				FC16A97F249969E2003D6245 /* Graphs.swift in Sources */,
 				FC97881C2485969B00A7906C /* MainViewController.swift in Sources */,
 				FC97881C2485969B00A7906C /* MainViewController.swift in Sources */,
@@ -830,6 +840,8 @@
 				FCC6886B24898FD800A0279D /* ObservationToken.swift in Sources */,
 				FCC6886B24898FD800A0279D /* ObservationToken.swift in Sources */,
 				FCC6886D2489909D00A0279D /* AnyConvertible.swift in Sources */,
 				FCC6886D2489909D00A0279D /* AnyConvertible.swift in Sources */,
 				FC97881A2485969B00A7906C /* SceneDelegate.swift in Sources */,
 				FC97881A2485969B00A7906C /* SceneDelegate.swift in Sources */,
+				FC1BDD2B24A22650001B652C /* Stats.swift in Sources */,
+				FC1BDD2D24A23204001B652C /* StatsView.swift in Sources */,
 				FCE537BC249A4D7D00F80BF8 /* carbBolusArrays.swift in Sources */,
 				FCE537BC249A4D7D00F80BF8 /* carbBolusArrays.swift in Sources */,
 				FC16A98124996C07003D6245 /* DateTime.swift in Sources */,
 				FC16A98124996C07003D6245 /* DateTime.swift in Sources */,
 				FC3CAB022493B6220068A152 /* BackgroundTaskAudio.swift in Sources */,
 				FC3CAB022493B6220068A152 /* BackgroundTaskAudio.swift in Sources */,

+ 128 - 3
LoopFollow/Application/Base.lproj/Main.storyboard

@@ -106,11 +106,127 @@
                                 </subviews>
                                 </subviews>
                             </stackView>
                             </stackView>
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="51B-JU-npv" customClass="LineChartView" customModule="Charts">
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="51B-JU-npv" customClass="LineChartView" customModule="Charts">
-                                <rect key="frame" x="8" y="312" width="398" height="425"/>
+                                <rect key="frame" x="8" y="312" width="398" height="317"/>
                                 <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                                 <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                             </view>
                             </view>
+                            <stackView opaque="NO" contentMode="scaleToFill" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="XsT-6R-Vym">
+                                <rect key="frame" x="8" y="705" width="398" height="100"/>
+                                <subviews>
+                                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Hhh-F1-s1p" customClass="PieChartView" customModule="Charts">
+                                        <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
+                                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" constant="100" id="hv8-WM-AJ7"/>
+                                            <constraint firstAttribute="height" constant="100" id="yN0-Vb-FTT"/>
+                                        </constraints>
+                                    </view>
+                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="wy3-R2-YQR">
+                                        <rect key="frame" x="100" y="0.0" width="298" height="100"/>
+                                        <subviews>
+                                            <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="top" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="FTW-Gd-zoi">
+                                                <rect key="frame" x="0.0" y="0.0" width="298" height="50"/>
+                                                <subviews>
+                                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="Xt9-qX-IQe">
+                                                        <rect key="frame" x="0.0" y="0.0" width="92.666666666666671" height="50"/>
+                                                        <subviews>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Low:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sUB-nL-H1B">
+                                                                <rect key="frame" x="30.333333333333343" y="0.0" width="32" height="18"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TzL-hn-9qu">
+                                                                <rect key="frame" x="13.333333333333329" y="18" width="66.333333333333329" height="32"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                        </subviews>
+                                                    </stackView>
+                                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="n6P-oO-ivx">
+                                                        <rect key="frame" x="102.66666666666666" y="0.0" width="92.666666666666657" height="50"/>
+                                                        <subviews>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="In Range:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zBu-Uf-0IS">
+                                                                <rect key="frame" x="14.333333333333343" y="0.0" width="64" height="18"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7mH-Np-j0L">
+                                                                <rect key="frame" x="13.333333333333343" y="18" width="66.333333333333329" height="32"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                        </subviews>
+                                                    </stackView>
+                                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="K2J-AH-Hj1">
+                                                        <rect key="frame" x="205.33333333333331" y="0.0" width="92.666666666666686" height="50"/>
+                                                        <subviews>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="High:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Zq-6s-y8B">
+                                                                <rect key="frame" x="28.333333333333375" y="0.0" width="36.333333333333343" height="18"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HON-rt-8pC">
+                                                                <rect key="frame" x="13.333333333333371" y="18" width="66.333333333333329" height="32"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                        </subviews>
+                                                    </stackView>
+                                                </subviews>
+                                            </stackView>
+                                            <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="jwr-iC-EjI">
+                                                <rect key="frame" x="0.0" y="50" width="298" height="50"/>
+                                                <subviews>
+                                                    <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MsS-p8-G83">
+                                                        <rect key="frame" x="0.0" y="0.0" width="144" height="50"/>
+                                                        <subviews>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Avg BG:" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tpy-y3-B9A">
+                                                                <rect key="frame" x="0.0" y="0.0" width="87" height="50"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cDE-hR-Tao">
+                                                                <rect key="frame" x="87" y="0.0" width="57" height="50"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                        </subviews>
+                                                    </stackView>
+                                                    <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JF5-Vh-r16">
+                                                        <rect key="frame" x="154" y="0.0" width="144" height="50"/>
+                                                        <subviews>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Est A1C:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BSh-qP-ZnD">
+                                                                <rect key="frame" x="0.0" y="0.0" width="56.333333333333336" height="50"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vxv-1M-W8k">
+                                                                <rect key="frame" x="56.333333333333321" y="0.0" width="87.666666666666686" height="50"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                        </subviews>
+                                                    </stackView>
+                                                </subviews>
+                                            </stackView>
+                                        </subviews>
+                                    </stackView>
+                                </subviews>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="100" id="vSk-uf-eTS"/>
+                                </constraints>
+                            </stackView>
                             <view autoresizesSubviews="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Nml-lr-dgQ" userLabel="BGChartFull" customClass="LineChartView" customModule="Charts">
                             <view autoresizesSubviews="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Nml-lr-dgQ" userLabel="BGChartFull" customClass="LineChartView" customModule="Charts">
-                                <rect key="frame" x="8" y="745" width="398" height="60"/>
+                                <rect key="frame" x="8" y="637" width="398" height="60"/>
                                 <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                                 <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                                 <constraints>
                                 <constraints>
                                     <constraint firstAttribute="height" priority="750" constant="60" id="qmO-ga-QWl"/>
                                     <constraint firstAttribute="height" priority="750" constant="60" id="qmO-ga-QWl"/>
@@ -121,11 +237,14 @@
                         <constraints>
                         <constraints>
                             <constraint firstItem="51B-JU-npv" firstAttribute="top" secondItem="mJy-Ly-Jze" secondAttribute="bottom" constant="8" id="2Qj-m5-4Yj"/>
                             <constraint firstItem="51B-JU-npv" firstAttribute="top" secondItem="mJy-Ly-Jze" secondAttribute="bottom" constant="8" id="2Qj-m5-4Yj"/>
                             <constraint firstItem="PQr-Ze-W5v" firstAttribute="trailing" secondItem="Nml-lr-dgQ" secondAttribute="trailing" constant="8" id="5dn-w0-XWn"/>
                             <constraint firstItem="PQr-Ze-W5v" firstAttribute="trailing" secondItem="Nml-lr-dgQ" secondAttribute="trailing" constant="8" id="5dn-w0-XWn"/>
+                            <constraint firstItem="PQr-Ze-W5v" firstAttribute="bottom" secondItem="XsT-6R-Vym" secondAttribute="bottom" constant="8" id="Baa-Eh-DAi"/>
                             <constraint firstItem="Nml-lr-dgQ" firstAttribute="leading" secondItem="PQr-Ze-W5v" secondAttribute="leading" constant="8" id="D6D-3r-YIy"/>
                             <constraint firstItem="Nml-lr-dgQ" firstAttribute="leading" secondItem="PQr-Ze-W5v" secondAttribute="leading" constant="8" id="D6D-3r-YIy"/>
+                            <constraint firstItem="XsT-6R-Vym" firstAttribute="top" secondItem="Nml-lr-dgQ" secondAttribute="bottom" constant="8" id="Gkd-ML-hdj"/>
                             <constraint firstItem="PQr-Ze-W5v" firstAttribute="trailing" secondItem="mJy-Ly-Jze" secondAttribute="trailing" constant="8" id="KcX-yW-Vnd"/>
                             <constraint firstItem="PQr-Ze-W5v" firstAttribute="trailing" secondItem="mJy-Ly-Jze" secondAttribute="trailing" constant="8" id="KcX-yW-Vnd"/>
-                            <constraint firstItem="PQr-Ze-W5v" firstAttribute="bottom" secondItem="Nml-lr-dgQ" secondAttribute="bottom" constant="8" id="Sb3-4z-Qup"/>
+                            <constraint firstItem="XsT-6R-Vym" firstAttribute="leading" secondItem="PQr-Ze-W5v" secondAttribute="leading" constant="8" id="N7t-TY-9hH"/>
                             <constraint firstItem="mJy-Ly-Jze" firstAttribute="leading" secondItem="PQr-Ze-W5v" secondAttribute="leading" constant="8" id="b30-Y0-qsu"/>
                             <constraint firstItem="mJy-Ly-Jze" firstAttribute="leading" secondItem="PQr-Ze-W5v" secondAttribute="leading" constant="8" id="b30-Y0-qsu"/>
                             <constraint firstItem="51B-JU-npv" firstAttribute="leading" secondItem="PQr-Ze-W5v" secondAttribute="leading" constant="8" id="dfE-Q6-SML"/>
                             <constraint firstItem="51B-JU-npv" firstAttribute="leading" secondItem="PQr-Ze-W5v" secondAttribute="leading" constant="8" id="dfE-Q6-SML"/>
+                            <constraint firstItem="PQr-Ze-W5v" firstAttribute="trailing" secondItem="XsT-6R-Vym" secondAttribute="trailing" constant="8" id="kqo-fO-gPZ"/>
                             <constraint firstItem="PQr-Ze-W5v" firstAttribute="trailing" secondItem="51B-JU-npv" secondAttribute="trailing" constant="8" id="oqO-3J-e8a"/>
                             <constraint firstItem="PQr-Ze-W5v" firstAttribute="trailing" secondItem="51B-JU-npv" secondAttribute="trailing" constant="8" id="oqO-3J-e8a"/>
                             <constraint firstItem="Nml-lr-dgQ" firstAttribute="top" secondItem="51B-JU-npv" secondAttribute="bottom" constant="8" id="woM-1z-QyB"/>
                             <constraint firstItem="Nml-lr-dgQ" firstAttribute="top" secondItem="51B-JU-npv" secondAttribute="bottom" constant="8" id="woM-1z-QyB"/>
                             <constraint firstItem="mJy-Ly-Jze" firstAttribute="top" secondItem="PQr-Ze-W5v" secondAttribute="top" constant="8" id="xem-Lc-bdU"/>
                             <constraint firstItem="mJy-Ly-Jze" firstAttribute="top" secondItem="PQr-Ze-W5v" secondAttribute="top" constant="8" id="xem-Lc-bdU"/>
@@ -143,6 +262,12 @@
                         <outlet property="MinAgoText" destination="UkG-hw-DVo" id="Xd2-fL-qYC"/>
                         <outlet property="MinAgoText" destination="UkG-hw-DVo" id="Xd2-fL-qYC"/>
                         <outlet property="PredictionLabel" destination="oiR-SM-6sg" id="2Sw-TR-SFo"/>
                         <outlet property="PredictionLabel" destination="oiR-SM-6sg" id="2Sw-TR-SFo"/>
                         <outlet property="infoTable" destination="kTs-7g-lp9" id="Khq-sV-EZ1"/>
                         <outlet property="infoTable" destination="kTs-7g-lp9" id="Khq-sV-EZ1"/>
+                        <outlet property="statsAvgBG" destination="cDE-hR-Tao" id="SGK-z7-di4"/>
+                        <outlet property="statsEstA1C" destination="Vxv-1M-W8k" id="CpH-4t-haS"/>
+                        <outlet property="statsHighPercent" destination="HON-rt-8pC" id="283-3S-PCR"/>
+                        <outlet property="statsInRangePercent" destination="7mH-Np-j0L" id="vUp-Pv-Mva"/>
+                        <outlet property="statsLowPercent" destination="TzL-hn-9qu" id="0QR-Mz-KJe"/>
+                        <outlet property="statsPieChart" destination="Hhh-F1-s1p" id="Rhh-Up-Kr0"/>
                     </connections>
                     </connections>
                 </viewController>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>

+ 1 - 1
LoopFollow/Controllers/Alarms.swift

@@ -12,7 +12,7 @@ import AVFoundation
 extension MainViewController {
 extension MainViewController {
     
     
     
     
-    func checkAlarms(bgs: [sgvData]) {
+    func checkAlarms(bgs: [DataStructs.sgvData]) {
            print("ALARMS --- Checking")
            print("ALARMS --- Checking")
            // Don't check or fire alarms within 1 minute of prior alarm
            // Don't check or fire alarms within 1 minute of prior alarm
            if checkAlarmTimer.isValid {  return }
            if checkAlarmTimer.isValid {  return }

+ 11 - 10
LoopFollow/Controllers/NightScout.swift

@@ -11,13 +11,13 @@ import UIKit
 
 
 
 
 extension MainViewController {
 extension MainViewController {
-    
-    //NS BG Struct
-    struct sgvData: Codable {
-        var sgv: Int
-        var date: TimeInterval
-        var direction: String?
-    }
+//
+//    //NS BG Struct
+//    struct sgvData: Codable {
+//        var sgv: Int
+//        var date: TimeInterval
+//        var direction: String?
+//    }
     
     
     //NS Cage Struct
     //NS Cage Struct
     struct cageData: Codable {
     struct cageData: Codable {
@@ -155,7 +155,7 @@ extension MainViewController {
             }
             }
             
             
             let decoder = JSONDecoder()
             let decoder = JSONDecoder()
-            let entriesResponse = try? decoder.decode([sgvData].self, from: data)
+            let entriesResponse = try? decoder.decode([DataStructs.sgvData].self, from: data)
             if let entriesResponse = entriesResponse {
             if let entriesResponse = entriesResponse {
                 DispatchQueue.main.async {
                 DispatchQueue.main.async {
                     // trigger the processor for the data after downloading.
                     // trigger the processor for the data after downloading.
@@ -171,7 +171,7 @@ extension MainViewController {
     }
     }
     
     
     // NS BG Data Response processor
     // NS BG Data Response processor
-    func ProcessNSBGData(data: [sgvData], onlyPullLastRecord: Bool){
+    func ProcessNSBGData(data: [DataStructs.sgvData], onlyPullLastRecord: Bool){
         print("Enter BG Processor")
         print("Enter BG Processor")
         
         
         var pullDate = data[data.count - 1].date / 1000
         var pullDate = data[data.count - 1].date / 1000
@@ -198,7 +198,7 @@ extension MainViewController {
         for i in 0..<data.count{
         for i in 0..<data.count{
             var dateString = data[data.count - 1 - i].date / 1000
             var dateString = data[data.count - 1 - i].date / 1000
             dateString.round(FloatingPointRoundingRule.toNearestOrEven)
             dateString.round(FloatingPointRoundingRule.toNearestOrEven)
-            let reading = sgvData(sgv: data[data.count - 1 - i].sgv, date: dateString, direction: data[data.count - 1 - i].direction)
+            let reading = DataStructs.sgvData(sgv: data[data.count - 1 - i].sgv, date: dateString, direction: data[data.count - 1 - i].direction)
             bgData.append(reading)
             bgData.append(reading)
         }
         }
         
         
@@ -253,6 +253,7 @@ extension MainViewController {
         }
         }
         updateBGGraph()
         updateBGGraph()
         updateMinAgo()
         updateMinAgo()
+        updateStats()
     }
     }
     
     
     // NS Device Status Web Call
     // NS Device Status Web Call

+ 116 - 0
LoopFollow/Controllers/Stats.swift

@@ -0,0 +1,116 @@
+//
+//  Stats.swift
+//  LoopFollow
+//
+//  Created by Jon Fawcett on 6/23/20.
+//  Copyright © 2020 Jon Fawcett. All rights reserved.
+//
+
+import Foundation
+
+
+class StatsData {
+    
+    var countLow: Int
+    var percentLow: Float
+    var percentRange: Float
+    var percentHigh: Float
+    var countRange: Int
+    var countHigh: Int
+    var totalGlucose: Int
+    var avgBG: Float
+    var a1C: Float
+    var pie: [DataStructs.pieData]
+    
+    init(bgData: [DataStructs.sgvData]) {
+        
+        self.countLow = 0
+        self.countRange = 0
+        self.countHigh = 0
+        self.totalGlucose = 0
+        self.a1C = 0.0
+        
+        for i in 0..<bgData.count {
+            // Set low/range/high counts for pie chart and %'s
+            if Float(bgData[i].sgv) <= UserDefaultsRepository.lowLine.value {
+                self.countLow += 1
+            } else if Float(bgData[i].sgv) >= UserDefaultsRepository.highLine.value {
+                self.countHigh += 1
+            } else {
+                self.countRange += 1
+            }
+            
+            // set total bg for average
+            totalGlucose += bgData[i].sgv
+        }
+        
+        // Set Percents
+        percentLow = Float(countLow) / Float(bgData.count) * 100
+        percentRange = Float(countRange) / Float(bgData.count) * 100
+        percentHigh = Float(countHigh) / Float(bgData.count) * 100
+        
+        pie = [
+            DataStructs.pieData(name: "low", value: Double(percentLow)),
+            DataStructs.pieData(name: "range", value: Double(percentRange)),
+            DataStructs.pieData(name: "high", value: Double(percentHigh))]
+        
+        
+        
+        // Set Average
+        avgBG = Float(totalGlucose / bgData.count)
+        
+        if UserDefaultsRepository.units.value == "mg/dL" {
+            a1C = (46.7 + Float(avgBG)) / 28.7
+        } else {
+            a1C = (((46.7 + Float(avgBG)) / 28.7) - 2.152) / 0.09148
+        }
+    }
+
+    /*
+    func countLowResults() -> Int {
+        var count = 0
+        for i in 0..<bgData.count {
+            if Float(bgData[i].sgv) >= UserDefaultsRepository.lowLine.value {
+                count += 1
+            }
+        }
+        return count
+    }
+    
+    func countHighResults() -> Int{
+        var count = 0
+        for i in 0..<bgData.count {
+            if Float(bgData[i].sgv) >= UserDefaultsRepository.highLine.value {
+                count += 1
+            }
+        }
+        return count
+    }
+    
+    func totalGlucoseResult() -> Int {
+        var total = 0
+        for i in 0..<bgData.count {
+            total += bgData[i].sgv
+        }
+        return total
+    }
+    
+    func totalGlucoseCount() -> Int {
+        return bgData.count
+    }
+    
+    func averageBGResults() -> Int {
+        return totalGlucose() / totalGlucoseCount()
+    }
+    
+   func a1CResults() -> Double {
+        if UserDefaultsRepository.units.value == "mg/dL" {
+            return (46.7 + Double(averageBGResults())) / 28.7
+        } else {
+            return (((46.7 + Double(averageBGResults())) / 28.7) - 2.152) / 0.09148
+        }
+    }
+
+*/
+
+}

+ 78 - 0
LoopFollow/Controllers/StatsView.swift

@@ -0,0 +1,78 @@
+//
+//  StatsView.swift
+//  LoopFollow
+//
+//  Created by Jon Fawcett on 6/23/20.
+//  Copyright © 2020 Jon Fawcett. All rights reserved.
+//
+
+import Foundation
+import Charts
+import UIKit
+
+
+extension MainViewController {
+
+    func updateStats()
+    {
+        if bgData.count > 0 {
+           var stats = StatsData(bgData: bgData)
+            
+            statsLowPercent.text = String(format:"%.1f%", stats.percentLow) + "%"
+            statsInRangePercent.text = String(format:"%.1f%", stats.percentRange) + "%"
+            statsHighPercent.text = String(format:"%.1f%", stats.percentHigh) + "%"
+            statsAvgBG.text = bgUnits.toDisplayUnits(String(format:"%.0f%", stats.avgBG))
+            statsEstA1C.text = String(format:"%.1f%", stats.a1C)
+            
+            createStatsPie(pieData: stats.pie)
+        }
+        
+    }
+    
+    func createStatsPie(pieData: [DataStructs.pieData]) {
+        statsPieChart.legend.enabled = false
+        statsPieChart.drawEntryLabelsEnabled = false
+        statsPieChart.drawHoleEnabled = false
+        
+        var chartEntry = [PieChartDataEntry]()
+        var colors = [NSUIColor]()
+        
+        for i in 0..<pieData.count{
+            var slice = Double(pieData[i].value)
+            if slice == 0 { slice = 0.1 }
+            let value = PieChartDataEntry(value: slice)
+            chartEntry.append(value)
+
+             if pieData[i].name == "high" {
+                colors.append(NSUIColor.systemYellow)
+            } else if pieData[i].name == "low" {
+               colors.append(NSUIColor.systemRed)
+            } else {
+                colors.append(NSUIColor.systemGreen)
+            }
+        }
+        
+        let set = PieChartDataSet(entries: chartEntry, label: "")
+        
+        
+        
+        set.drawIconsEnabled = false
+        set.sliceSpace = 2
+        set.drawValuesEnabled = false
+        set.valueLineWidth = 0
+        set.formLineWidth = 0
+        set.sliceSpace = 0
+        
+        set.colors.removeAll()
+        if colors.count > 0 {
+            for i in 0..<colors.count{
+                set.addColor(colors[i])
+            }
+        }
+        
+        let data = PieChartData(dataSet: set)
+        statsPieChart.data = data
+        
+    }
+
+}

+ 8 - 2
LoopFollow/ViewControllers/MainViewController.swift

@@ -24,6 +24,12 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
     @IBOutlet weak var DragBar: UIImageView!
     @IBOutlet weak var DragBar: UIImageView!
     @IBOutlet weak var PredictionLabel: UILabel!
     @IBOutlet weak var PredictionLabel: UILabel!
     @IBOutlet weak var LoopStatusLabel: UILabel!
     @IBOutlet weak var LoopStatusLabel: UILabel!
+    @IBOutlet weak var statsPieChart: PieChartView!
+    @IBOutlet weak var statsLowPercent: UILabel!
+    @IBOutlet weak var statsInRangePercent: UILabel!
+    @IBOutlet weak var statsHighPercent: UILabel!
+    @IBOutlet weak var statsAvgBG: UILabel!
+    @IBOutlet weak var statsEstA1C: UILabel!
     
     
     
     
     
     
@@ -60,7 +66,7 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
     
     
     // View Delay Timer
     // View Delay Timer
     var viewTimer = Timer()
     var viewTimer = Timer()
-    let viewTimeInterval: TimeInterval = 15.0
+    let viewTimeInterval: TimeInterval = 5.0
     
     
     // Check Alarms Timer
     // Check Alarms Timer
     // Don't check within 1 minute of alarm triggering to give the snoozer time to save data
     // Don't check within 1 minute of alarm triggering to give the snoozer time to save data
@@ -79,7 +85,7 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
         infoData(name: "CAGE", value: "") //7
         infoData(name: "CAGE", value: "") //7
     ]
     ]
     
     
-    var bgData: [sgvData] = []
+    var bgData: [DataStructs.sgvData] = []
     var basalProfile: [basalProfileStruct] = []
     var basalProfile: [basalProfileStruct] = []
     var basalData: [basalGraphStruct] = []
     var basalData: [basalGraphStruct] = []
     var bolusData: [bolusCarbGraphStruct] = []
     var bolusData: [bolusCarbGraphStruct] = []

+ 27 - 0
LoopFollow/helpers/DataStructs.swift

@@ -0,0 +1,27 @@
+//
+//  Enums.swift
+//  LoopFollow
+//
+//  Created by Jon Fawcett on 6/23/20.
+//  Copyright © 2020 Jon Fawcett. All rights reserved.
+//
+
+import Foundation
+
+class DataStructs {
+    
+    //NS BG Struct
+    struct sgvData: Codable {
+        var sgv: Int
+        var date: TimeInterval
+        var direction: String?
+    }
+    
+    // Pie Chart Data
+    struct pieData: Codable {
+        var name: String
+        var value: Double
+    }
+    
+    
+}

+ 1 - 1
LoopFollow/helpers/carbBolusArrays.swift

@@ -11,7 +11,7 @@ import Foundation
 
 
 extension MainViewController {
 extension MainViewController {
     
     
-    func findNearestBGbyTime(needle: TimeInterval, haystack: [sgvData], startingIndex: Int) -> (sgv: Double, foundIndex: Int) {
+    func findNearestBGbyTime(needle: TimeInterval, haystack: [DataStructs.sgvData], startingIndex: Int) -> (sgv: Double, foundIndex: Int) {
         
         
         // If we can't find a match or things fail, put it at 100 BG
         // If we can't find a match or things fail, put it at 100 BG
         for i in startingIndex..<haystack.count {
         for i in startingIndex..<haystack.count {