Created
May 4, 2022 23:24
-
-
Save kylehowells/a194288cce9b2501c8f2f26f0c527829 to your computer and use it in GitHub Desktop.
UIViewController subclass to show both the Settings app displayed free space, and the real free space.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// FreeSpaceViewController.swift | |
// Free Space | |
// | |
// Created by Kyle Howells on 04/05/2022. | |
// | |
import UIKit | |
class FreeSpaceViewController: UIViewController { | |
let byteFormatter:ByteCountFormatter = { | |
let formatter = ByteCountFormatter() | |
formatter.allowedUnits = .useAll | |
formatter.countStyle = .file | |
formatter.includesUnit = true | |
formatter.isAdaptive = true | |
return formatter | |
}() | |
private let textView:UITextView = { | |
let textView = UITextView() | |
textView.backgroundColor = UIColor.white | |
textView.textColor = UIColor.black | |
textView.font = UIFont.systemFont(ofSize: 14, weight: .medium) | |
textView.isEditable = false | |
textView.contentInsetAdjustmentBehavior = .never | |
return textView | |
}() | |
// MARK: - View Setup | |
let settingsTitleLabel:UILabel = { | |
let l = UILabel() | |
l.font = UIFont.systemFont(ofSize: 16, weight: .medium) | |
l.text = "Settings App (Important Files)" | |
return l | |
}() | |
let settingsStorageBar:KHFileStorageView = KHFileStorageView() | |
let realTitleLabel:UILabel = { | |
let l = UILabel() | |
l.font = UIFont.systemFont(ofSize: 16, weight: .medium) | |
l.text = "Real Storage Usage" | |
return l | |
}() | |
let realStorageBar:KHFileStorageView = KHFileStorageView() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// Do any additional setup after loading the view. | |
// formatter.string(fromByteCount: 123456789000) // '123.46 GB' | |
// formatter.string(fromByteCount: 0) // 'Zero KB' | |
// self.byteFormatter | |
self.view.addSubview(self.textView) | |
self.view.addSubview(self.settingsStorageBar) | |
self.view.addSubview(self.settingsTitleLabel) | |
self.view.addSubview(self.realStorageBar) | |
self.view.addSubview(self.realTitleLabel) | |
var text = "\n" | |
text += "Total Space: \( self.byteFormatter.string(fromByteCount: Int64(getTotalSpace() ?? 0))) \n" | |
text += "Total Real Free Space: \( self.byteFormatter.string(fromByteCount: Int64(getRealFreeSpace() ?? 0))) \n" | |
text += "Total Important Free Space: \( self.byteFormatter.string(fromByteCount: getImportantFreeSpace() ?? 0)) \n" | |
text += "Total Opportunistic Free Space: \( self.byteFormatter.string(fromByteCount: getOpportunisticFreeSpace() ?? 0)) \n" | |
self.textView.text = text | |
guard let _totalSpace = getTotalSpace() else { return } | |
guard let _freeSpace = getRealFreeSpace() else { return } | |
guard let importantFreeSpace = getImportantFreeSpace() else { return } | |
//guard let opportunisticFreeSpace = getOpportunisticFreeSpace() else { return } | |
let totalSpace = Int64(_totalSpace) | |
let freeSpace = Int64(_freeSpace) | |
self.settingsStorageBar.totalSpace = totalSpace | |
self.settingsStorageBar.usedSpace = (totalSpace - importantFreeSpace) | |
self.realStorageBar.totalSpace = totalSpace | |
self.realStorageBar.usedSpace = (totalSpace - freeSpace) | |
} | |
// MARK: - Layout | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
let size = self.view.bounds.size | |
//let safeArea = self.view.safeAreaInsets | |
let width = size.width * 0.9 | |
// - Settings | |
self.settingsTitleLabel.frame = { | |
var frame = CGRect() | |
frame.size.height = self.settingsTitleLabel.intrinsicContentSize.height | |
frame.size.width = width | |
frame.origin.x = (size.width - frame.width) * 0.5 | |
frame.origin.y = (size.height * 0.3) | |
return frame | |
}() | |
self.settingsStorageBar.frame = { | |
var frame = CGRect() | |
frame.size.height = self.settingsStorageBar.intrinsicContentSize.height | |
frame.size.width = width | |
frame.origin.x = (size.width - frame.width) * 0.5 | |
frame.origin.y = self.settingsTitleLabel.frame.maxY + 10 | |
return frame | |
}() | |
// - Real | |
self.realTitleLabel.frame = { | |
var frame = CGRect() | |
frame.size.height = self.settingsTitleLabel.intrinsicContentSize.height | |
frame.size.width = width | |
frame.origin.x = (size.width - frame.width) * 0.5 | |
frame.origin.y = self.settingsStorageBar.frame.maxY + 40 | |
return frame | |
}() | |
self.realStorageBar.frame = { | |
var frame = CGRect() | |
frame.size.width = width | |
frame.size.height = self.realStorageBar.intrinsicContentSize.height | |
frame.origin.x = (size.width - frame.width) * 0.5 | |
frame.origin.y = self.realTitleLabel.frame.maxY + 10 | |
return frame | |
}() | |
self.textView.frame = { | |
var frame = CGRect() | |
frame.origin.y = self.realStorageBar.frame.maxY + 30 | |
frame.size.height = size.height - frame.origin.y | |
frame.size.width = width | |
frame.origin.x = (size.width - frame.width) * 0.5 | |
return frame | |
}() | |
} | |
} | |
// MARK: - Get Free Space | |
func getTotalSpace() -> Int? { | |
let fileURL = URL(fileURLWithPath: NSHomeDirectory() as String) | |
do { | |
let values = try fileURL.resourceValues(forKeys: [.volumeTotalCapacityKey]) | |
if let capacity = values.volumeTotalCapacity { | |
print("Total capacity: \(capacity)") | |
return capacity | |
} else { | |
print("Capacity is unavailable") | |
} | |
} catch { | |
print("Error retrieving capacity: \(error.localizedDescription)") | |
} | |
return nil | |
} | |
func getRealFreeSpace() -> Int? { | |
let fileURL = URL(fileURLWithPath: NSHomeDirectory() as String) | |
do { | |
let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityKey]) | |
if let capacity = values.volumeAvailableCapacity { | |
print("Available capacity: \(capacity)") | |
return capacity | |
} else { | |
print("Capacity is unavailable") | |
} | |
} catch { | |
print("Error retrieving capacity: \(error.localizedDescription)") | |
} | |
return nil | |
} | |
func getImportantFreeSpace() -> Int64? { | |
let fileURL = URL(fileURLWithPath: NSHomeDirectory() as String) | |
do { | |
let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey]) | |
if let capacity: Int64 = values.volumeAvailableCapacityForImportantUsage { | |
print("Available capacity for important usage: \(capacity)") | |
return capacity | |
} else { | |
print("Capacity is unavailable") | |
} | |
} catch { | |
print("Error retrieving capacity: \(error.localizedDescription)") | |
} | |
return nil | |
} | |
func getOpportunisticFreeSpace() -> Int64? { | |
let fileURL = URL(fileURLWithPath: NSHomeDirectory() as String) | |
do { | |
let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForOpportunisticUsageKey]) | |
if let capacity: Int64 = values.volumeAvailableCapacityForOpportunisticUsage { | |
print("Available capacity for important usage: \(capacity)") | |
return capacity | |
} else { | |
print("Capacity is unavailable") | |
} | |
} catch { | |
print("Error retrieving capacity: \(error.localizedDescription)") | |
} | |
return nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// KHFileStorageView.swift | |
// Free Space | |
// | |
// Created by Kyle Howells on 05/05/2022. | |
// | |
import Foundation | |
import UIKit | |
class KHFileStorageView: UIView { | |
// MARK: - Properties | |
var totalSpace:Int64 = 100 { | |
didSet { | |
self.update() | |
} | |
} | |
var usedSpace:Int64 = 50 { | |
didSet { | |
self.update() | |
} | |
} | |
let byteFormatter:ByteCountFormatter = { | |
let formatter = ByteCountFormatter() | |
formatter.allowedUnits = .useAll | |
formatter.countStyle = .file | |
formatter.includesUnit = true | |
formatter.isAdaptive = true | |
return formatter | |
}() | |
// MARK: - Views | |
let usedBackgroundView:UIView = { | |
let view = UIView() | |
view.backgroundColor = UIColor(red: 44.0/255.0, green: 67.0/255.0, blue: 136.0/255.0, alpha: 1.0) | |
return view | |
}() | |
let usedSpaceLabel:UILabel = { | |
let l = UILabel() | |
l.textColor = UIColor(red: 44.0/255.0, green: 67.0/255.0, blue: 136.0/255.0, alpha: 1.0) | |
l.font = UIFont.systemFont(ofSize: 13, weight: .medium) | |
return l | |
}() | |
let freeBackgroundView:UIView = { | |
let view = UIView() | |
view.backgroundColor = UIColor(red: 206.0/255.0, green: 206.0/255.0, blue: 207.0/255.0, alpha: 1.0) | |
return view | |
}() | |
let freeSpaceLabel:UILabel = { | |
let l = UILabel() | |
l.textColor = UIColor(red: 206.0/255.0, green: 206.0/255.0, blue: 207.0/255.0, alpha: 1.0) | |
l.font = UIFont.systemFont(ofSize: 13, weight: .medium) | |
return l | |
}() | |
// MARK: - Setup | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
self.commonInit() | |
} | |
required init?(coder: NSCoder) { | |
super.init(coder: coder) | |
self.commonInit() | |
} | |
func commonInit() { | |
self.addSubview(self.freeSpaceLabel) | |
self.addSubview(self.freeBackgroundView) | |
self.addSubview(self.usedSpaceLabel) | |
self.addSubview(self.usedBackgroundView) | |
} | |
private func update() { | |
let usedSpaceString = self.byteFormatter.string(fromByteCount: self.usedSpace) | |
self.usedSpaceLabel.text = "Used: \(usedSpaceString)" | |
let freeSpaceString = self.byteFormatter.string(fromByteCount: self.totalSpace - self.usedSpace) | |
self.freeSpaceLabel.text = "Free: \(freeSpaceString)" | |
self.setNeedsLayout() | |
} | |
// MARK: - Size | |
private let barHeight:CGFloat = 30 | |
override func sizeThatFits(_ size: CGSize) -> CGSize { | |
return CGSize(width: size.width, height: self.barHeight + self.freeSpaceLabel.font.lineHeight) | |
} | |
override var intrinsicContentSize: CGSize { | |
return CGSize( | |
width: 320, | |
height: self.barHeight + self.freeSpaceLabel.font.lineHeight | |
) | |
} | |
// MARK: - Layout | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
let size = self.bounds.size | |
let usedPercent = CGFloat(self.usedSpace) / CGFloat(self.totalSpace) | |
let usedSpaceWidth = size.width * usedPercent | |
self.usedBackgroundView.frame = { | |
var frame = CGRect() | |
frame.size.width = usedSpaceWidth | |
frame.size.height = self.barHeight | |
frame.origin.x = 0 | |
frame.origin.y = 0 | |
return frame | |
}() | |
self.usedSpaceLabel.frame = { | |
var frame = CGRect() | |
frame.size = self.usedSpaceLabel.intrinsicContentSize | |
frame.origin.x = 0 | |
frame.origin.y = self.usedBackgroundView.frame.maxY | |
return frame | |
}() | |
let freePercent = CGFloat(self.totalSpace - self.usedSpace) / CGFloat(self.totalSpace) | |
let freeSpaceWidth = size.width * freePercent | |
self.freeBackgroundView.frame = { | |
var frame = CGRect() | |
frame.size.width = freeSpaceWidth | |
frame.size.height = self.barHeight | |
frame.origin.x = size.width - frame.width | |
frame.origin.y = 0 | |
return frame | |
}() | |
self.freeSpaceLabel.frame = { | |
var frame = CGRect() | |
frame.size = self.freeSpaceLabel.intrinsicContentSize | |
frame.origin.x = size.width - frame.width | |
frame.origin.y = self.freeBackgroundView.frame.maxY | |
return frame | |
}() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment