ironOS native ios app
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Revert iPad layout changes

Remove all iPad-specific UI code and restore simple iPhone-only layout.
The iPad implementation was poorly executed and the settings modal
should be redesigned as a collapsible side toolbar in the future.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>

+45 -143
+45 -143
ios/TinkCil/ContentView.swift
··· 14 14 @State private var isTopBarExpanded = false 15 15 @State private var showingSettings = false 16 16 @State private var showingError = false 17 - @Environment(\.horizontalSizeClass) var horizontalSizeClass 18 17 19 18 private var isHeating: Bool { 20 19 bleManager.liveData.mode?.isActive == true 21 20 } 22 21 23 - private var isIPad: Bool { 24 - horizontalSizeClass == .regular 25 - } 26 - 27 22 var body: some View { 28 23 ZStack { 29 - // Background graph (only show on iPhone) 30 - if !isIPad && bleManager.temperatureHistory.count > 0 { 24 + // Background graph 25 + if bleManager.temperatureHistory.count > 0 { 31 26 TemperatureGraph( 32 27 history: bleManager.temperatureHistoryArray, 33 28 currentSetpoint: Int(targetTemp) ··· 38 33 39 34 // Main content 40 35 if bleManager.connectionState.isConnected { 41 - if isIPad { 42 - connectedViewIPad 43 - } else { 44 - connectedView 45 - } 36 + connectedView 46 37 } else { 47 38 scanningView 48 39 } ··· 101 92 } 102 93 } 103 94 104 - // MARK: - Connected View iPad 105 - 106 - private var connectedViewIPad: some View { 107 - GeometryReader { geometry in 108 - HStack(spacing: 0) { 109 - // Left side: Temperature Graph 110 - if bleManager.temperatureHistory.count > 0 { 111 - TemperatureGraph( 112 - history: bleManager.temperatureHistoryArray, 113 - currentSetpoint: Int(targetTemp) 114 - ) 115 - .frame(width: geometry.size.width * 0.55) 116 - .padding(32) 117 - } else { 118 - // Placeholder when no data 119 - VStack { 120 - Image(systemName: "chart.line.uptrend.xyaxis") 121 - .font(.system(size: 60)) 122 - .foregroundStyle(.tertiary) 123 - Text("No temperature history yet") 124 - .font(.headline) 125 - .foregroundStyle(.secondary) 126 - } 127 - .frame(width: geometry.size.width * 0.55) 128 - } 129 - 130 - // Right side: Controls and Stats 131 - VStack(spacing: 0) { 132 - // Top bar with stats 133 - topBar 134 - .padding(.top, 32) 135 - 136 - Spacer() 137 - 138 - // Big temperature number 139 - VStack(spacing: 12) { 140 - temperatureDisplay 141 - 142 - // Target indicator 143 - if isHeating { 144 - HStack(spacing: 4) { 145 - Image(systemName: "arrow.right") 146 - .font(.body) 147 - Text("\(bleManager.liveData.setpoint)°") 148 - .font(.title2.monospacedDigit()) 149 - } 150 - .foregroundStyle(.secondary) 151 - } 152 - } 153 - 154 - Spacer() 155 - 156 - // Slider panel 157 - sliderPanel 158 - .padding(.horizontal, 32) 159 - .padding(.bottom, 32) 160 - } 161 - .frame(width: geometry.size.width * 0.45) 162 - } 163 - } 164 - } 165 - 166 95 // MARK: - Top Bar 167 96 168 97 private var topBar: some View { ··· 271 200 private var temperatureDisplay: some View { 272 201 let currentTemp = Double(bleManager.liveData.liveTemp) 273 202 let maxTemp = Double(bleManager.liveData.maxTemp) 274 - let fontSize: CGFloat = isIPad ? 160 : 120 275 - let degreeSize: CGFloat = isIPad ? 80 : 60 276 203 277 204 return HStack(alignment: .firstTextBaseline, spacing: 0) { 278 205 Text("\(bleManager.liveData.liveTemp)") 279 - .font(.system(size: fontSize, weight: .thin, design: .rounded)) 206 + .font(.system(size: 120, weight: .thin, design: .rounded)) 280 207 .contentTransition(.numericText()) 281 208 Text("°") 282 - .font(.system(size: degreeSize, weight: .ultraLight)) 209 + .font(.system(size: 60, weight: .ultraLight)) 283 210 .foregroundStyle(.secondary) 284 211 } 285 212 .foregroundStyle(colorForTemp(currentTemp, maxTemp: maxTemp)) ··· 288 215 // MARK: - Slider Panel 289 216 290 217 private var sliderPanel: some View { 291 - VStack(spacing: isIPad ? 20 : 0) { 292 - // iPad: Show label above slider 293 - if isIPad { 294 - HStack { 295 - Text("Target Temperature") 296 - .font(.headline) 297 - .foregroundStyle(.secondary) 298 - Spacer() 299 - // Target temperature display 300 - HStack(alignment: .firstTextBaseline, spacing: 1) { 301 - Text("\(Int(targetTemp))") 302 - .font(.system(size: 32, weight: .semibold, design: .rounded)) 303 - .contentTransition(.numericText()) 304 - Text("°") 305 - .font(.system(size: 18, weight: .regular)) 306 - .foregroundStyle(.secondary) 307 - } 308 - .foregroundStyle(colorForTemp(targetTemp, maxTemp: 450)) 309 - } 218 + HStack(spacing: 16) { 219 + // Target temperature display 220 + HStack(alignment: .firstTextBaseline, spacing: 1) { 221 + Text("\(Int(targetTemp))") 222 + .font(.system(size: 24, weight: .semibold, design: .rounded)) 223 + .contentTransition(.numericText()) 224 + Text("°") 225 + .font(.system(size: 14, weight: .regular)) 226 + .foregroundStyle(.secondary) 310 227 } 228 + .foregroundStyle(colorForTemp(targetTemp, maxTemp: 450)) 229 + .frame(width: 60) 311 230 312 - HStack(spacing: 16) { 313 - // iPhone: Target temperature display on the side 314 - if !isIPad { 315 - HStack(alignment: .firstTextBaseline, spacing: 1) { 316 - Text("\(Int(targetTemp))") 317 - .font(.system(size: 24, weight: .semibold, design: .rounded)) 318 - .contentTransition(.numericText()) 319 - Text("°") 320 - .font(.system(size: 14, weight: .regular)) 321 - .foregroundStyle(.secondary) 322 - } 323 - .foregroundStyle(colorForTemp(targetTemp, maxTemp: 450)) 324 - .frame(width: 60) 325 - } 326 - 327 - // Slider 328 - Slider( 329 - value: $targetTemp, 330 - in: 10...450, 331 - step: 5, 332 - onEditingChanged: { editing in 333 - isEditingSlider = editing 334 - if editing { 335 - bleManager.setSlowPolling() 336 - } else { 337 - // Only send if value changed 338 - if abs(targetTemp - lastSentTemp) >= 5 { 339 - bleManager.setTemperature(UInt32(targetTemp)) 340 - lastSentTemp = targetTemp 341 - } 342 - bleManager.setFastPolling() 231 + // Slider 232 + Slider( 233 + value: $targetTemp, 234 + in: 10...450, 235 + step: 5, 236 + onEditingChanged: { editing in 237 + isEditingSlider = editing 238 + if editing { 239 + bleManager.setSlowPolling() 240 + } else { 241 + // Only send if value changed 242 + if abs(targetTemp - lastSentTemp) >= 5 { 243 + bleManager.setTemperature(UInt32(targetTemp)) 244 + lastSentTemp = targetTemp 343 245 } 246 + bleManager.setFastPolling() 344 247 } 345 - ) 346 - .tint(colorForTemp(targetTemp, maxTemp: 450)) 347 - .accessibilityLabel("Target temperature") 348 - .accessibilityValue("\(Int(targetTemp)) degrees") 349 - } 248 + } 249 + ) 250 + .tint(colorForTemp(targetTemp, maxTemp: 450)) 251 + .accessibilityLabel("Target temperature") 252 + .accessibilityValue("\(Int(targetTemp)) degrees") 350 253 } 351 254 .padding(.horizontal, 20) 352 - .padding(.vertical, isIPad ? 20 : 14) 255 + .padding(.vertical, 14) 353 256 .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16)) 354 257 } 355 258 ··· 411 314 Color.black.opacity(0.4) 412 315 .ignoresSafeArea() 413 316 414 - VStack(spacing: isIPad ? 28 : 20) { 317 + VStack(spacing: 20) { 415 318 if bleManager.isScanning || bleManager.connectionState.isConnecting { 416 319 ProgressView() 417 - .scaleEffect(isIPad ? 2.0 : 1.2) 320 + .scaleEffect(1.2) 418 321 .padding(.bottom, 4) 419 322 420 323 Text(bleManager.connectionState.isConnecting ? "Connecting..." : "Scanning...") 421 - .font(isIPad ? .largeTitle : .headline) 324 + .font(.headline) 422 325 423 326 Text("Looking for your Tinkcil") 424 - .font(isIPad ? .title3 : .subheadline) 327 + .font(.subheadline) 425 328 .foregroundStyle(.secondary) 426 329 } else { 427 330 Image(systemName: "antenna.radiowaves.left.and.right.slash") 428 - .font(.system(size: isIPad ? 60 : 36)) 331 + .font(.system(size: 36)) 429 332 .foregroundStyle(.secondary) 430 333 .padding(.bottom, 4) 431 334 432 335 Text("No Device Found") 433 - .font(isIPad ? .largeTitle : .headline) 336 + .font(.headline) 434 337 435 338 Button("Scan Again") { 436 339 bleManager.startScanning() 437 340 } 438 341 .buttonStyle(.borderedProminent) 439 - .controlSize(isIPad ? .large : .regular) 440 342 } 441 343 } 442 - .padding(isIPad ? 48 : 32) 443 - .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: isIPad ? 32 : 24)) 344 + .padding(32) 345 + .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 24)) 444 346 .shadow(color: .black.opacity(0.2), radius: 20) 445 347 } 446 348 }