mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
working - trying to fix cpu graphs
This commit is contained in:
parent
5603ce4c1e
commit
fc522ccf84
4 changed files with 227 additions and 104 deletions
|
|
@ -205,6 +205,10 @@
|
||||||
"comment" : "A label displaying the duration of the current song. The argument is the duration of the song in seconds.",
|
"comment" : "A label displaying the duration of the current song. The argument is the duration of the song in seconds.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
},
|
},
|
||||||
|
"—" : {
|
||||||
|
"comment" : "A placeholder text used when GPU usage is not available.",
|
||||||
|
"isCommentAutoGenerated" : true
|
||||||
|
},
|
||||||
"'Now Playing' was the only option on previous versions and works with all media apps." : {
|
"'Now Playing' was the only option on previous versions and works with all media apps." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"ar" : {
|
"ar" : {
|
||||||
|
|
@ -6803,6 +6807,10 @@
|
||||||
},
|
},
|
||||||
"Enable timer live activity" : {
|
"Enable timer live activity" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Engines" : {
|
||||||
|
"comment" : "A label describing the GPU engine gauges.",
|
||||||
|
"isCommentAutoGenerated" : true
|
||||||
},
|
},
|
||||||
"Enhance your experience with HUDs" : {
|
"Enhance your experience with HUDs" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|
|
||||||
48
DynamicIsland/components/Stats/CircularGaugeView.swift
Normal file
48
DynamicIsland/components/Stats/CircularGaugeView.swift
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct CircularGaugeView: View {
|
||||||
|
let title: String
|
||||||
|
let value: Double
|
||||||
|
let tint: Color
|
||||||
|
let centerPrimaryText: String
|
||||||
|
var centerSecondaryText: String? = nil
|
||||||
|
var subtitle: String? = nil
|
||||||
|
var size: CGFloat = 72
|
||||||
|
var lineWidth: CGFloat = 8
|
||||||
|
var backgroundTint: Color = Color.primary.opacity(0.08)
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.stroke(backgroundTint, lineWidth: lineWidth)
|
||||||
|
.frame(width: size, height: size)
|
||||||
|
if value > 0 {
|
||||||
|
RingArc(start: 0, end: min(max(value, 0), 1), color: tint, lineWidth: lineWidth)
|
||||||
|
.frame(width: size, height: size)
|
||||||
|
}
|
||||||
|
VStack(spacing: 2) {
|
||||||
|
Text(centerPrimaryText)
|
||||||
|
.font(.system(size: 16, weight: .semibold, design: .rounded))
|
||||||
|
.foregroundColor(tint)
|
||||||
|
if let centerSecondaryText, !centerSecondaryText.isEmpty {
|
||||||
|
Text(centerSecondaryText)
|
||||||
|
.font(.system(size: 11, weight: .medium))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VStack(spacing: 2) {
|
||||||
|
Text(title)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
if let subtitle, !subtitle.isEmpty {
|
||||||
|
Text(subtitle)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,15 +31,15 @@ struct GPUStatsDetailView: View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StatsCard(title: "Top Processes", padding: 16, background: cardBackground, cornerRadius: 12) {
|
||||||
|
CPUProcessList(processes: topProcesses, accentColor: accentColor, displayLimit: processDisplayLimit)
|
||||||
|
}
|
||||||
|
|
||||||
if !statsManager.gpuDevices.isEmpty {
|
if !statsManager.gpuDevices.isEmpty {
|
||||||
StatsCard(title: "Devices", padding: 16, background: cardBackground, cornerRadius: 12) {
|
StatsCard(title: "Devices", padding: 16, background: cardBackground, cornerRadius: 12) {
|
||||||
GPUDeviceList(devices: statsManager.gpuDevices, accentColor: accentColor)
|
GPUDeviceList(devices: statsManager.gpuDevices, accentColor: accentColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatsCard(title: "Top Processes", padding: 16, background: cardBackground, cornerRadius: 12) {
|
|
||||||
CPUProcessList(processes: topProcesses, accentColor: accentColor, displayLimit: processDisplayLimit)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.padding(16)
|
.padding(16)
|
||||||
}
|
}
|
||||||
|
|
@ -65,49 +65,15 @@ private struct GPUUsageDashboard: View {
|
||||||
let primaryDevice: GPUDeviceMetrics?
|
let primaryDevice: GPUDeviceMetrics?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center, spacing: 24) {
|
ViewThatFits(in: .horizontal) {
|
||||||
ZStack {
|
HStack(alignment: .top, spacing: 20) {
|
||||||
Circle()
|
leftColumn
|
||||||
.stroke(accentColor.opacity(0.25), lineWidth: 14)
|
breakdownAndMeta
|
||||||
.frame(width: 120, height: 120)
|
|
||||||
|
|
||||||
RingArc(start: 0, end: CGFloat(min(max(usage / 100, 0), 1)), color: accentColor, lineWidth: 14)
|
|
||||||
.frame(width: 120, height: 120)
|
|
||||||
|
|
||||||
VStack(spacing: 4) {
|
|
||||||
Text(StatsFormatting.percentage(usage))
|
|
||||||
.font(.system(size: 28, weight: .bold, design: .rounded))
|
|
||||||
Text("Active")
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
leftColumn
|
||||||
DetailRow(color: accentColor.opacity(0.9), label: "Render", value: StatsFormatting.percentage(breakdown.render))
|
breakdownAndMeta
|
||||||
DetailRow(color: accentColor.opacity(0.7), label: "Compute", value: StatsFormatting.percentage(breakdown.compute))
|
|
||||||
DetailRow(color: accentColor.opacity(0.55), label: "Video", value: StatsFormatting.percentage(breakdown.video))
|
|
||||||
DetailRow(color: accentColor.opacity(0.45), label: "Other", value: StatsFormatting.percentage(breakdown.other))
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
|
||||||
Text("Averages")
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
DetailRow(color: nil, label: "Session Avg", value: StatsFormatting.percentage(averageUsage))
|
|
||||||
DetailRow(color: nil, label: "Last Update", value: formattedTimestamp(lastUpdated))
|
|
||||||
if let device = primaryDevice {
|
|
||||||
Divider().padding(.vertical, 4)
|
|
||||||
DetailRow(color: nil, label: "Active GPU", value: device.formattedVendorModel)
|
|
||||||
DetailRow(color: nil, label: "Status", value: device.isActive ? "Active" : "Idle")
|
|
||||||
DetailRow(color: nil, label: "Temperature", value: device.temperatureText)
|
|
||||||
if let cores = device.cores {
|
|
||||||
DetailRow(color: nil, label: "Cores", value: "\(cores)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,6 +83,143 @@ private struct GPUUsageDashboard: View {
|
||||||
formatter.timeStyle = .medium
|
formatter.timeStyle = .medium
|
||||||
return formatter.string(from: date)
|
return formatter.string(from: date)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var leftColumn: some View {
|
||||||
|
VStack(alignment: .center, spacing: 16) {
|
||||||
|
usageRing
|
||||||
|
GPUEngineGauges(render: renderEngineUtilization, tiler: tilerUtilization, accentColor: accentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var breakdownAndMeta: some View {
|
||||||
|
ViewThatFits(in: .horizontal) {
|
||||||
|
HStack(alignment: .top, spacing: 20) {
|
||||||
|
breakdownSection
|
||||||
|
metaSection
|
||||||
|
}
|
||||||
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
|
breakdownSection
|
||||||
|
Divider().padding(.vertical, 4)
|
||||||
|
metaSection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var usageRing: some View {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.stroke(accentColor.opacity(0.25), lineWidth: 12)
|
||||||
|
.frame(width: 108, height: 108)
|
||||||
|
|
||||||
|
RingArc(start: 0, end: CGFloat(min(max(usage / 100, 0), 1)), color: accentColor, lineWidth: 12)
|
||||||
|
.frame(width: 108, height: 108)
|
||||||
|
|
||||||
|
VStack(spacing: 4) {
|
||||||
|
Text(StatsFormatting.percentage(usage))
|
||||||
|
.font(.system(size: 28, weight: .bold, design: .rounded))
|
||||||
|
Text("Active")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var breakdownSection: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
|
DetailRow(color: accentColor.opacity(0.9), label: "Render", value: StatsFormatting.percentage(breakdown.render))
|
||||||
|
DetailRow(color: accentColor.opacity(0.7), label: "Compute", value: StatsFormatting.percentage(breakdown.compute))
|
||||||
|
DetailRow(color: accentColor.opacity(0.55), label: "Video", value: StatsFormatting.percentage(breakdown.video))
|
||||||
|
DetailRow(color: accentColor.opacity(0.45), label: "Other", value: StatsFormatting.percentage(breakdown.other))
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var metaSection: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
Text("Averages")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
DetailRow(color: nil, label: "Session Avg", value: StatsFormatting.percentage(averageUsage))
|
||||||
|
DetailRow(color: nil, label: "Last Update", value: formattedTimestamp(lastUpdated))
|
||||||
|
if let device = primaryDevice {
|
||||||
|
Divider().padding(.vertical, 4)
|
||||||
|
DetailRow(color: nil, label: "Active GPU", value: device.formattedVendorModel)
|
||||||
|
DetailRow(color: nil, label: "Status", value: device.isActive ? "Active" : "Idle")
|
||||||
|
DetailRow(color: nil, label: "Temperature", value: device.temperatureText)
|
||||||
|
if let cores = device.cores {
|
||||||
|
DetailRow(color: nil, label: "Cores", value: "\(cores)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var renderEngineUtilization: Double? {
|
||||||
|
primaryDevice?.renderUtilization ?? breakdown.render
|
||||||
|
}
|
||||||
|
|
||||||
|
private var tilerUtilization: Double? {
|
||||||
|
primaryDevice?.tilerUtilization
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct GPUEngineGauges: View {
|
||||||
|
let render: Double?
|
||||||
|
let tiler: Double?
|
||||||
|
let accentColor: Color
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
|
Text("Engines")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
HStack(alignment: .center, spacing: 16) {
|
||||||
|
EngineGaugeView(title: "Render", value: render, tint: accentColor)
|
||||||
|
EngineGaugeView(title: "Tiler", value: tiler, tint: accentColor.opacity(0.75))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct EngineGaugeView: View {
|
||||||
|
let title: String
|
||||||
|
let value: Double?
|
||||||
|
let tint: Color
|
||||||
|
private let size: CGFloat = 68
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if let value {
|
||||||
|
CircularGaugeView(
|
||||||
|
title: title,
|
||||||
|
value: min(max(value / 100, 0), 1),
|
||||||
|
tint: tint,
|
||||||
|
centerPrimaryText: StatsFormatting.percentage(value),
|
||||||
|
centerSecondaryText: nil,
|
||||||
|
subtitle: nil,
|
||||||
|
size: size,
|
||||||
|
lineWidth: 7,
|
||||||
|
backgroundTint: tint.opacity(0.18)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
placeholder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var placeholder: some View {
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.stroke(Color.primary.opacity(0.08), lineWidth: 7)
|
||||||
|
.frame(width: size, height: size)
|
||||||
|
Text("—")
|
||||||
|
.font(.system(size: 18, weight: .semibold))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
Text(title)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct GPUDeviceList: View {
|
private struct GPUDeviceList: View {
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,6 @@ struct MemoryStatsDetailView: View {
|
||||||
MemoryHealthView(breakdown: statsManager.memoryBreakdown, accentColor: accentColor)
|
MemoryHealthView(breakdown: statsManager.memoryBreakdown, accentColor: accentColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
StatsCard(title: "Details", padding: 16, background: cardBackground, cornerRadius: 12) {
|
|
||||||
MemoryDetailsGrid(breakdown: statsManager.memoryBreakdown, accentColor: accentColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatsCard(title: "Top Processes", padding: 16, background: cardBackground, cornerRadius: 12) {
|
StatsCard(title: "Top Processes", padding: 16, background: cardBackground, cornerRadius: 12) {
|
||||||
CPUProcessList(processes: topProcesses, accentColor: accentColor, displayLimit: processDisplayLimit)
|
CPUProcessList(processes: topProcesses, accentColor: accentColor, displayLimit: processDisplayLimit)
|
||||||
}
|
}
|
||||||
|
|
@ -78,46 +74,13 @@ private struct MemoryUsageDashboard: View {
|
||||||
|
|
||||||
return ViewThatFits(in: .horizontal) {
|
return ViewThatFits(in: .horizontal) {
|
||||||
VStack(alignment: .leading, spacing: 20) {
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
ZStack {
|
usageRing
|
||||||
Circle()
|
|
||||||
.stroke(freeColor.opacity(0.35), lineWidth: 14)
|
|
||||||
.frame(width: 128, height: 128)
|
|
||||||
|
|
||||||
MemoryUsageRing(breakdown: breakdown, usedColor: accentColor, freeColor: freeColor)
|
|
||||||
.frame(width: 128, height: 128)
|
|
||||||
|
|
||||||
VStack(spacing: 4) {
|
|
||||||
Text(StatsFormatting.percentage(breakdown.usedPercentage))
|
|
||||||
.font(.system(size: 30, weight: .bold, design: .rounded))
|
|
||||||
Text("Used")
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
|
|
||||||
totalsSection
|
totalsSection
|
||||||
Divider().padding(.vertical, 4)
|
Divider().padding(.vertical, 4)
|
||||||
breakdownSection
|
breakdownSection
|
||||||
}
|
}
|
||||||
HStack(alignment: .top, spacing: 28) {
|
HStack(alignment: .top, spacing: 28) {
|
||||||
ZStack {
|
usageRing
|
||||||
Circle()
|
|
||||||
.stroke(freeColor.opacity(0.35), lineWidth: 14)
|
|
||||||
.frame(width: 128, height: 128)
|
|
||||||
|
|
||||||
MemoryUsageRing(breakdown: breakdown, usedColor: accentColor, freeColor: freeColor)
|
|
||||||
.frame(width: 128, height: 128)
|
|
||||||
|
|
||||||
VStack(spacing: 4) {
|
|
||||||
Text(StatsFormatting.percentage(breakdown.usedPercentage))
|
|
||||||
.font(.system(size: 30, weight: .bold, design: .rounded))
|
|
||||||
Text("Used")
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalsSection
|
totalsSection
|
||||||
breakdownSection
|
breakdownSection
|
||||||
}
|
}
|
||||||
|
|
@ -127,6 +90,26 @@ private struct MemoryUsageDashboard: View {
|
||||||
private func formattedBytes(_ value: UInt64) -> String {
|
private func formattedBytes(_ value: UInt64) -> String {
|
||||||
StatsFormatting.bytes(value)
|
StatsFormatting.bytes(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var usageRing: some View {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.stroke(freeColor.opacity(0.35), lineWidth: 14)
|
||||||
|
.frame(width: 128, height: 128)
|
||||||
|
|
||||||
|
MemoryUsageRing(breakdown: breakdown, usedColor: accentColor, freeColor: freeColor)
|
||||||
|
.frame(width: 128, height: 128)
|
||||||
|
|
||||||
|
VStack(spacing: 4) {
|
||||||
|
Text(StatsFormatting.percentage(breakdown.usedPercentage))
|
||||||
|
.font(.system(size: 30, weight: .bold, design: .rounded))
|
||||||
|
Text("Used")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct MemoryUsageRing: View {
|
private struct MemoryUsageRing: View {
|
||||||
|
|
@ -159,31 +142,12 @@ private struct MemoryBreakdownRow: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct MemoryDetailsGrid: View {
|
|
||||||
let breakdown: MemoryBreakdown
|
|
||||||
let accentColor: Color
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(spacing: 10) {
|
|
||||||
DetailRow(color: accentColor.opacity(0.85), label: "App Memory", value: StatsFormatting.bytes(breakdown.appBytes))
|
|
||||||
DetailRow(color: accentColor.opacity(0.7), label: "Cached Files", value: StatsFormatting.bytes(breakdown.cacheBytes))
|
|
||||||
DetailRow(color: accentColor.opacity(0.6), label: "Active", value: StatsFormatting.bytes(breakdown.activeBytes))
|
|
||||||
DetailRow(color: accentColor.opacity(0.45), label: "Inactive", value: StatsFormatting.bytes(breakdown.inactiveBytes))
|
|
||||||
DetailRow(color: accentColor.opacity(0.35), label: "Wired", value: StatsFormatting.bytes(breakdown.wiredBytes))
|
|
||||||
DetailRow(color: accentColor.opacity(0.25), label: "Compressed", value: StatsFormatting.bytes(breakdown.compressedBytes))
|
|
||||||
DetailRow(color: accentColor.opacity(0.18), label: "Free", value: StatsFormatting.bytes(breakdown.freeBytes))
|
|
||||||
Divider().padding(.vertical, 4)
|
|
||||||
DetailRow(color: nil, label: "Total Memory", value: StatsFormatting.bytes(breakdown.totalBytes))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct MemoryHealthView: View {
|
private struct MemoryHealthView: View {
|
||||||
let breakdown: MemoryBreakdown
|
let breakdown: MemoryBreakdown
|
||||||
let accentColor: Color
|
let accentColor: Color
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 14) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
MemoryPressureIndicator(pressure: breakdown.pressure)
|
MemoryPressureIndicator(pressure: breakdown.pressure)
|
||||||
Divider().padding(.vertical, 4)
|
Divider().padding(.vertical, 4)
|
||||||
SwapUsageView(swap: breakdown.swap, accentColor: accentColor)
|
SwapUsageView(swap: breakdown.swap, accentColor: accentColor)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue