Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testflight expire date #163

Merged
merged 2 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,3 @@ fastlane/test_output
fastlane/FastlaneRunner

ConfigOverride.xcconfig

branch.txt
27 changes: 16 additions & 11 deletions FreeAPS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@
A6F097A14CAAE0CE0D11BE1B /* AddCarbsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618E62C9757B2F95431B5DC0 /* AddCarbsProvider.swift */; };
AD3D2CD42CD01B9EB8F26522 /* PumpConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */; };
B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */ = {isa = PBXBuildFile; productRef = B958F1B62BA0711600484851 /* MKRingProgressView */; };
B9CAAEFC2AE70836000F68BC /* branch.txt in Resources */ = {isa = PBXBuildFile; fileRef = B9CAAEFB2AE70836000F68BC /* branch.txt */; };
BA00D96F7B2FF169A06FB530 /* CGMStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C018D1680307A31C9ED7120 /* CGMStateModel.swift */; };
BD2B464E0745FBE7B79913F4 /* NightscoutConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */; };
BDF530D82B40F8AC002CAF43 /* LockScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDF530D72B40F8AC002CAF43 /* LockScreenView.swift */; };
Expand Down Expand Up @@ -347,6 +346,8 @@
D6DEC113821A7F1056C4AA1E /* NightscoutConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2A13DF0EDEEEDC4106AA2A /* NightscoutConfigDataFlow.swift */; };
D76333C9256787610B3B4875 /* AutotuneConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D295A3F870E826BE371C0BB5 /* AutotuneConfigStateModel.swift */; };
DBA5254DBB2586C98F61220C /* ISFEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9F137F126D9F8DEB799F26 /* ISFEditorProvider.swift */; };
DD1DB7CC2BECCA1F0048B367 /* BuildDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */; };
DD1DB7CE2BED00CF0048B367 /* SettingsRootViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1DB7CD2BED00CF0048B367 /* SettingsRootViewModel.swift */; };
DD399FB31EACB9343C944C4C /* PreferencesEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA3E609094E064C99A4752C /* PreferencesEditorStateModel.swift */; };
E00EEC0327368630002FF094 /* ServiceAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = E00EEBFD27368630002FF094 /* ServiceAssembly.swift */; };
E00EEC0427368630002FF094 /* SecurityAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = E00EEBFE27368630002FF094 /* SecurityAssembly.swift */; };
Expand Down Expand Up @@ -873,6 +874,8 @@
D295A3F870E826BE371C0BB5 /* AutotuneConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AutotuneConfigStateModel.swift; sourceTree = "<group>"; };
D97F14812C1AFED3621165A5 /* PumpSettingsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpSettingsEditorProvider.swift; sourceTree = "<group>"; };
DC2C6489D29ECCCAD78E0721 /* NotificationsConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationsConfigStateModel.swift; sourceTree = "<group>"; };
DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildDetails.swift; sourceTree = "<group>"; };
DD1DB7CD2BED00CF0048B367 /* SettingsRootViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRootViewModel.swift; sourceTree = "<group>"; };
E00EEBFD27368630002FF094 /* ServiceAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceAssembly.swift; sourceTree = "<group>"; };
E00EEBFE27368630002FF094 /* SecurityAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecurityAssembly.swift; sourceTree = "<group>"; };
E00EEBFF27368630002FF094 /* StorageAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageAssembly.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1274,6 +1277,7 @@
children = (
3811DE3C25C9D4A100A708ED /* SettingsRootView.swift */,
CE1F6DE82BAF37C90064EB8D /* TidePoolConfigView.swift */,
DD1DB7CD2BED00CF0048B367 /* SettingsRootViewModel.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -1639,6 +1643,7 @@
FE66D16A291F74F8005D6F77 /* Bundle+Extensions.swift */,
FEFFA7A12929FE49007B8193 /* UIDevice+Extensions.swift */,
CEA4F62229BE10F70011ADF7 /* SavitzkyGolayFilter.swift */,
DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */,
);
path = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -2268,7 +2273,6 @@
isa = PBXNativeTarget;
buildConfigurationList = 388E596725AD948E0019842D /* Build configuration list for PBXNativeTarget "FreeAPS" */;
buildPhases = (
B9CAAEFA2AE6FDE6000F68BC /* Run Script: get branch name and commit ID */,
3811DEF525CA169200A708ED /* Swiftformat */,
388E595425AD948C0019842D /* Sources */,
388E595525AD948C0019842D /* Frameworks */,
Expand All @@ -2277,6 +2281,7 @@
38E8753D27554D5900975559 /* Embed Watch Content */,
6B1A8D122B14D88E00E76752 /* Embed Foundation Extensions */,
CE95BF582BA5F8F300DC3DE3 /* Install plugins */,
DD1DB7C92BEBF79B0048B367 /* Capture Build Details */,
);
buildRules = (
);
Expand Down Expand Up @@ -2456,7 +2461,6 @@
38DF178E27733E6800B3528F /* Assets.xcassets in Resources */,
19DA48E829CD339B00EEA1E7 /* Assets.xcassets in Resources */,
388E596F25AD96040019842D /* javascript in Resources */,
B9CAAEFC2AE70836000F68BC /* branch.txt in Resources */,
1927C8E62744606D00347C69 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -2516,43 +2520,42 @@
shellPath = /bin/sh;
shellScript = "source \"${SRCROOT}\"/scripts/swiftformat.sh\n\n";
};
B9CAAEFA2AE6FDE6000F68BC /* Run Script: get branch name and commit ID */ = {
CE95BF582BA5F8F300DC3DE3 /* Install plugins */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 12;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Run Script: get branch name and commit ID";
name = "Install plugins";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Prints a message\necho \"writing BRANCH to branch.txt\"\n\n# Retrieves version, branch, and tag information from Git\ngit_version=$(git log -1 --format=\"%h\" --abbrev=7)\ngit_branch=$(git symbolic-ref --short -q HEAD)\ngit_tag=$(git describe --tags --exact-match 2>/dev/null)\n\n# Determines branch or tag information\ngit_branch_or_tag=\"${git_branch:-${git_tag}}\"\ngit_branch_or_tag_version=\"${git_branch_or_tag} ${git_version}\"\n\necho \"BRANCH = ${git_branch_or_tag_version}\" > \"./branch.txt\"\n\n# Prints a message about the working directory and branch.txt\necho \"branch.txt is created/modified in ${PWD}\"\n";
shellScript = "\"${SRCROOT}/Scripts/copy-plugins.sh\"\n";
};
CE95BF582BA5F8F300DC3DE3 /* Install plugins */ = {
DD1DB7C92BEBF79B0048B367 /* Capture Build Details */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Install plugins";
name = "Capture Build Details";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Scripts/copy-plugins.sh\"\n";
shellScript = "\"${SRCROOT}/scripts/capture-build-details.sh\"\n";
};
/* End PBXShellScriptBuildPhase section */

Expand Down Expand Up @@ -2656,6 +2659,7 @@
388358C825EEF6D200E024B2 /* BasalProfileEntry.swift in Sources */,
3811DE0B25C9D32F00A708ED /* BaseView.swift in Sources */,
3811DE3225C9D49500A708ED /* HomeDataFlow.swift in Sources */,
DD1DB7CE2BED00CF0048B367 /* SettingsRootViewModel.swift in Sources */,
38569347270B5DFB0002C50D /* CGMType.swift in Sources */,
3821ED4C25DD18BA00BC42AD /* Constants.swift in Sources */,
384E803425C385E60086DB71 /* JavaScriptWorker.swift in Sources */,
Expand Down Expand Up @@ -2722,6 +2726,7 @@
38C4D33A25E9A1ED00D30B77 /* NSObject+AssociatedValues.swift in Sources */,
38DF179027733EAD00B3528F /* SnowScene.swift in Sources */,
38AAF8712600C1B0004AF583 /* MainChartView.swift in Sources */,
DD1DB7CC2BECCA1F0048B367 /* BuildDetails.swift in Sources */,
19DC677F29CA675700FD9EC4 /* OverrideProfilesDataFlow.swift in Sources */,
1935364028496F7D001E0B16 /* Oref2_variables.swift in Sources */,
CE2FAD3A297D93F0001A872C /* BloodGlucoseExtensions.swift in Sources */,
Expand Down
24 changes: 2 additions & 22 deletions FreeAPS/Sources/APS/APSManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -941,31 +941,11 @@ final class BaseAPSManager: APSManager, Injectable {
}
let af = preferences.sigmoid ? preferences.adjustmentFactorSigmoid : preferences.adjustmentFactor
let insulin_type = preferences.curve
let buildDate = Bundle.main.buildDate
let buildDate = BuildDetails.default.buildDate() ?? Date()
let version = Bundle.main.releaseVersionNumber
let build = Bundle.main.buildVersionNumber

// Read branch information from branch.txt instead of infoDictionary
var branch = "Unknown"
if let branchFileURL = Bundle.main.url(forResource: "branch", withExtension: "txt"),
let branchFileContent = try? String(contentsOf: branchFileURL)
{
let lines = branchFileContent.components(separatedBy: .newlines)
for line in lines {
let components = line.components(separatedBy: "=")
if components.count == 2 {
let key = components[0].trimmingCharacters(in: .whitespaces)
let value = components[1].trimmingCharacters(in: .whitespaces)

if key == "BRANCH" {
branch = value
break
}
}
}
} else {
branch = "Unknown"
}
let branch = BuildDetails.default.branchAndSha

let copyrightNotice_ = Bundle.main.infoDictionary?["NSHumanReadableCopyright"] as? String ?? ""
let pump_ = pumpManager?.localizedTitle ?? ""
Expand Down
2 changes: 1 addition & 1 deletion FreeAPS/Sources/Application/FreeAPSApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import Swinject
init() {
debug(
.default,
"Trio Started: v\(Bundle.main.releaseVersionNumber ?? "")(\(Bundle.main.buildVersionNumber ?? "")) [buildDate: \(Bundle.main.buildDate)] [buildExpires: \(Bundle.main.profileExpiration)]"
"Trio Started: v\(Bundle.main.releaseVersionNumber ?? "")(\(Bundle.main.buildVersionNumber ?? "")) [buildDate: \(BuildDetails.default.buildDate())] [buildExpires: \(BuildDetails.default.calculateExpirationDate())]"
)
loadServices()
}
Expand Down
83 changes: 83 additions & 0 deletions FreeAPS/Sources/Helpers/BuildDetails.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
// BuildDetails.swift
// Trio
//
// Created by Jonas Björkert on 2024-05-09.
//
import Foundation

class BuildDetails {
static var `default` = BuildDetails()

let dict: [String: Any]

init() {
guard let url = Bundle.main.url(forResource: "BuildDetails", withExtension: "plist"),
let data = try? Data(contentsOf: url),
let parsed = try? PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any]
else {
dict = [:]
return
}
dict = parsed
}

var buildDateString: String? {
dict["com-trio-build-date"] as? String
}

var branchAndSha: String {
let branch = dict["com-trio-branch"] as? String ?? "Unknown"
let sha = dict["com-trio-commit-sha"] as? String ?? "Unknown"
return "\(branch) \(sha)"
}

// Determine if the build is from TestFlight
func isTestFlightBuild() -> Bool {
#if targetEnvironment(simulator)
return false
#else
if Bundle.main.url(forResource: "embedded", withExtension: "mobileprovision") != nil {
return false
}
guard let receiptName = Bundle.main.appStoreReceiptURL?.lastPathComponent else {
return false
}
return "sandboxReceipt".caseInsensitiveCompare(receiptName) == .orderedSame
#endif
}

// Parse the build date string into a Date object
func buildDate() -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEE MMM d HH:mm:ss 'UTC' yyyy"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(identifier: "UTC")

guard let dateString = buildDateString,
let date = dateFormatter.date(from: dateString)
else {
return nil
}
return date
}

// Calculate the expiration date based on the build type
func calculateExpirationDate() -> Date? {
if isTestFlightBuild(), let buildDate = buildDate() {
// For TestFlight, add 90 days to the build date
return Calendar.current.date(byAdding: .day, value: 90, to: buildDate)!
} else {
return Bundle.main.profileExpirationDate
}
}

// Expiration header based on build type
var expirationHeaderString: String {
if isTestFlightBuild() {
return "Beta (TestFlight) Expires"
} else {
return "App Expires"
}
}
}
50 changes: 19 additions & 31 deletions FreeAPS/Sources/Helpers/Bundle+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,7 @@ extension Bundle {
infoDictionary?["CFBundleVersion"] as? String
}

var buildDate: Date {
if let infoPath = Bundle.main.path(forResource: "Info", ofType: "plist"),
let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath),
let infoDate = infoAttr[.modificationDate] as? Date
{
return infoDate
}
return Date()
}

var profileExpiration: String? {
var profileExpirationDateString: String? {
guard
let profilePath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision"),
let profileData = try? Data(contentsOf: URL(fileURLWithPath: profilePath)),
Expand All @@ -32,30 +22,28 @@ extension Bundle {
return nil
}

// NOTE: We have the `[\\W]*?` check to make sure that variations in number of tabs or new lines in the future does not influence the result.
guard let regex = try? NSRegularExpression(pattern: "<key>ExpirationDate</key>[\\W]*?<date>(.*?)</date>", options: [])
let regexPattern = "<key>ExpirationDate</key>[\\W]*?<date>(.*?)</date>"
guard let regex = try? NSRegularExpression(pattern: regexPattern, options: []),
let match = regex.firstMatch(
in: profileNSString as String,
options: [],
range: NSRange(location: 0, length: profileNSString.length)
),
let range = Range(match.range(at: 1), in: profileNSString as String)
else {
print("Warning: Could not create regex.")
return nil
}

let regExMatches = regex.matches(
in: profileNSString as String,
options: [],
range: NSRange(location: 0, length: profileNSString.length)
)

// NOTE: range `0` corresponds to the full regex match, so to get the first capture group, we use range `1`
guard let rangeOfCapturedGroupForDate = regExMatches.first?.range(at: 1) else {
print("Warning: Could not find regex match or capture group.")
print("Warning: Could not create regex or find match.")
return nil
}

let dateWithTimeAsString = profileNSString.substring(with: rangeOfCapturedGroupForDate)
return String(profileNSString.substring(with: NSRange(range, in: profileNSString as String)))
}

guard let dateAsStringIndex = dateWithTimeAsString.firstIndex(of: "T") else {
return nil
}
return String(dateWithTimeAsString[..<dateAsStringIndex])
var profileExpirationDate: Date? {
guard let dateString = profileExpirationDateString else { return nil }
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return dateFormatter.date(from: dateString)
}
}
21 changes: 1 addition & 20 deletions FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,7 @@ extension Settings {

versionNumber = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"

// Read branch information from the branch.txt instead of infoDictionary
if let branchFileURL = Bundle.main.url(forResource: "branch", withExtension: "txt"),
let branchFileContent = try? String(contentsOf: branchFileURL)
{
let lines = branchFileContent.components(separatedBy: .newlines)
for line in lines {
let components = line.components(separatedBy: "=")
if components.count == 2 {
let key = components[0].trimmingCharacters(in: .whitespaces)
let value = components[1].trimmingCharacters(in: .whitespaces)

if key == "BRANCH" {
branch = value
break
}
}
}
} else {
branch = "Unknown"
}
branch = BuildDetails.default.branchAndSha

copyrightNotice = Bundle.main.infoDictionary?["NSHumanReadableCopyright"] as? String ?? ""

Expand Down
12 changes: 2 additions & 10 deletions FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,15 @@ extension Settings {
let resolver: Resolver
@StateObject var state = StateModel()
@State private var showShareSheet = false
@StateObject private var viewModel = SettingsRootViewModel()

var body: some View {
Form {
Section {
Toggle("Closed loop", isOn: $state.closedLoop)
}
header: {
if let expirationDate = Bundle.main.profileExpiration {
Text(
"Trio v\(state.versionNumber) (\(state.buildNumber))\nBranch: \(state.branch) \(state.copyrightNotice)" +
"\nBuild Expires: " + expirationDate
).textCase(nil)
} else {
Text(
"Trio v\(state.versionNumber) (\(state.buildNumber))\nBranch: \(state.branch) \(state.copyrightNotice)"
)
}
Text(viewModel.headerText).textCase(nil)
}

Section {
Expand Down
Loading