Skip to content

Commit

Permalink
Issue #416: Bug fixes & improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
mipolansk committed Sep 25, 2024
1 parent 96112f2 commit 9b345dc
Show file tree
Hide file tree
Showing 49 changed files with 360 additions and 228 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,18 @@ extension SuplaCore {

NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.removeObserver(self)
}

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
onViewDisappeared()
}

func observeNotification(name: NSNotification.Name?, selector: Selector) {
NotificationCenter.default.addObserver(self, selector: selector, name: name, object: nil)
}

private func setupConstraints() {
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
Expand Down
12 changes: 7 additions & 5 deletions SUPLA/Core/UI/Buttons/BaseControlButtonView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ class BaseControlButtonView: UIView {

var active: Bool = false {
didSet {
layer.shadowColor = active ? type.pressedColor.cgColor : UIColor.black.cgColor
layer.borderColor = active ? type.pressedColor.cgColor : UIColor.disabled.cgColor
textView.textColor = active ? type.textColor : type.inactiveColor
iconView.tintColor = active ? type.textColor : iconColor
traitCollection.performAsCurrent {
layer.shadowColor = active ? type.pressedColor.cgColor : UIColor.black.cgColor
layer.borderColor = active ? type.pressedColor.cgColor : UIColor.disabled.cgColor
textView.textColor = active ? type.textColor : type.inactiveColor
iconView.tintColor = active ? type.textColor : iconColor
}
innerShadowView.isHidden = !active

setNeedsLayout()
Expand Down Expand Up @@ -255,7 +257,7 @@ class BaseControlButtonView: UIView {
switch (self) {
case .positive: return .green
case .negative: return .negativeBorder
case .neutral: return .black
case .neutral: return .onBackground
}
}

Expand Down
4 changes: 2 additions & 2 deletions SUPLA/Core/UI/Details/StandardDetailVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ class StandardDetailVC<S : ViewState, E : ViewEvent, VM : StandardDetailVM<S, E>
private func thermostatList() -> UIViewController {
let vc = ThermostatSlavesFeature.ViewController.create(item: item)
vc.tabBarItem = UITabBarItem(
title: "List",
image: UIImage(named: "list"),
title: settings.showBottomLabels ? Strings.StandardDetail.tabList : nil,
image: .iconList,
tag: DetailTabTag.List.rawValue
)
return vc
Expand Down
30 changes: 16 additions & 14 deletions SUPLA/Core/UI/Views/ThermostatControlView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,18 @@ final class ThermostatControlView: UIView {
traitCollection.performAsCurrent {
temperatureCircleShape.operationalMode = operationalMode
}
indicatorHeatingShape.isHidden = operationalMode != .heating
indicatorCoolingShape.isHidden = operationalMode != .cooling
currentPowerLabel.isHidden = operationalMode != .heating && operationalMode != .cooling || currentPower <= 1
indicatorHeatingShape.isHidden = !operationalMode.isHeating
indicatorCoolingShape.isHidden = !operationalMode.isCooling
currentPowerLabel.isHidden = !operationalMode.isHeating && !operationalMode.isCooling || currentPower <= 1

if (oldValue == .heating && operationalMode != .heating) {
if (oldValue.isHeating && !operationalMode.isHeating) {
indicatorHeatingShape.removeAllAnimations()
} else if (operationalMode == .heating && oldValue != .heating) {
} else if (operationalMode.isHeating && !oldValue.isHeating) {
indicatorHeatingShape.add(blinkingAnimation, forKey: "heat blinking")
}
if (oldValue == .cooling && operationalMode != .cooling) {
if (oldValue.isCooling && !operationalMode.isCooling) {
indicatorCoolingShape.removeAllAnimations()
} else if (operationalMode == .cooling && oldValue != .cooling) {
} else if (operationalMode.isCooling && !oldValue.isCooling) {
indicatorCoolingShape.add(blinkingAnimation, forKey: "cool blinking")
}

Expand All @@ -129,7 +129,7 @@ final class ThermostatControlView: UIView {
var currentPower: Int = 0 {
didSet {
temperatureCircleShape.currentPower = currentPower
currentPowerLabel.isHidden = operationalMode != .heating && operationalMode != .cooling || currentPower <= 1
currentPowerLabel.isHidden = !operationalMode.isStrictHeating && !operationalMode.isStrictCooling || currentPower <= 1
currentPowerLabel.text = "\(currentPower - 1)%"

setNeedsLayout()
Expand Down Expand Up @@ -251,11 +251,11 @@ final class ThermostatControlView: UIView {
height: maxTemperatureView.intrinsicContentSize.height
)

let correction: CGFloat = currentPower > 1 ? 75 : 55
let correction: CGFloat = (operationalMode.isStrictCooling || operationalMode.isStrictHeating) && currentPower > 1 ? 75 : 55
indicatorHeatingShape.position = CGPoint(x: frame.width / 2, y: frame.height / 2 - correction)
indicatorCoolingShape.position = CGPoint(x: frame.width / 2, y: frame.height / 2 + correction)

let textCorrection: CGFloat = operationalMode == .heating ? -45 : 45
let textCorrection: CGFloat = operationalMode.isHeating ? -45 : 45
currentPowerLabel.frame = CGRect(
x: CGFloat(frame.width / 2 - currentPowerLabel.intrinsicContentSize.width / 2),
y: CGFloat(frame.height / 2 - currentPowerLabel.intrinsicContentSize.height / 2) + textCorrection,
Expand Down Expand Up @@ -416,8 +416,9 @@ private class TemperatureCircleLayer: CAShapeLayer {

var operationalMode: ThermostatOperationalMode = .offline {
didSet {
powerBackgroundSublayer.isHidden = operationalMode != .cooling && operationalMode != .heating || currentPower <= 1
powerIndicatorSublayer.isHidden = operationalMode != .cooling && operationalMode != .heating || currentPower <= 1
let powerHidden = !operationalMode.isStrictCooling && !operationalMode.isStrictHeating || currentPower <= 1
powerBackgroundSublayer.isHidden = powerHidden
powerIndicatorSublayer.isHidden = powerHidden

powerBackgroundSublayer.strokeColor = operationalMode.backgroundColor.cgColor
powerIndicatorSublayer.strokeColor = operationalMode.foregroundColor.cgColor
Expand All @@ -428,8 +429,9 @@ private class TemperatureCircleLayer: CAShapeLayer {

var currentPower: Int = 0 {
didSet {
powerBackgroundSublayer.isHidden = operationalMode != .cooling && operationalMode != .heating || currentPower <= 1
powerIndicatorSublayer.isHidden = operationalMode != .cooling && operationalMode != .heating || currentPower <= 1
let powerHidden = !operationalMode.isStrictCooling && !operationalMode.isStrictHeating || currentPower <= 1
powerBackgroundSublayer.isHidden = powerHidden
powerIndicatorSublayer.isHidden = powerHidden

updatePowerPath()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class SwitchGeneralVC : BaseViewControllerVM<SwitchGeneralViewState, SwitchGener
)
}

powerOnButtonView.isHidden = !state.showButtons
powerOffButtonView.isHidden = !state.showButtons
powerOnButtonView.isEnabled = state.deviceState?.isOnline == true
powerOffButtonView.isEnabled = state.deviceState?.isOnline == true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class SwitchGeneralVM: BaseViewModel<SwitchGeneralViewState, SwitchGeneralViewEv

self.updateView() {
$0.changing(path: \.deviceState, to: self.createDeviceState(from: channel))
.changing(path: \.showButtons, to: channel.switchWithButtons())
}
})
.disposed(by: self)
Expand All @@ -58,5 +59,6 @@ enum SwitchGeneralViewEvent: ViewEvent {

struct SwitchGeneralViewState: ViewState {
var deviceState: DeviceStateViewState? = nil
var showButtons: Bool = false
}

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ extension ThermostatSlavesFeature {
viewModel.loadData(item.remoteId)
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

observeNotification(
name: NSNotification.Name.saChannelValueChanged,
selector: #selector(handleValueChange)
)
}

func onIssueIconTapped(issueMessage: String) {
let alert = UIAlertController(title: "SUPLA", message: issueMessage, preferredStyle: .alert)
let okButton = UIAlertAction(title: Strings.General.ok, style: .default)
Expand All @@ -53,6 +62,17 @@ extension ThermostatSlavesFeature {
coordinator.present(alert, animated: true)
}

@objc
private func handleValueChange(notification: Notification) {
if
let isGroup = notification.userInfo?["isGroup"] as? NSNumber,
let remoteId = notification.userInfo?["remoteId"] as? NSNumber,
!isGroup.boolValue
{
viewModel.reloadData(item.remoteId, remoteId.int32Value)
}
}

static func create(item: ItemBundle) -> UIViewController {
ViewController(viewModel: ViewModel(), item: item)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,54 @@ extension ThermostatSlavesFeature {
readChannelWithChildrenTreeUseCase.invoke(remoteId: remoteId)
.asDriverWithoutError()
.drive(
onNext: { [weak self] in self?.handle(channel: $0) }
onNext: { [weak self] in self?.handle(channel: $0) },
onCompleted: { SALog.debug("Completed!!") }
)
.disposed(by: disposeBag)
}

func reloadData(_ remoteId: Int32, _ relatedId: Int32) {
if (state.relatedIds.contains(relatedId)) {
loadData(remoteId)
}
}

private func handle(channel: ChannelWithChildren) {
state.master = channel.toThermostatData()
state.slaves = channel.allDescendantFlat
.filter { $0.relationType == .masterThermostat }
.map { $0.toThermostatData() }

state.relatedIds = channel.relatedIds
state.relatedIds.append(
contentsOf: channel.allDescendantFlat
.filter { $0.relationType == .masterThermostat }
.flatMap { $0.relatedIds }
)
}
}
}

private extension ChannelChild {
var relatedIds: [Int32] {
var ids: [Int32] = []
ids.append(channel.remote_id)

if let thermometer = children.first(where: { $0.relationType == .mainThermometer }) {
ids.append(thermometer.channel.remote_id)
}

if let pumpSwitch = children.first(where: { $0.relationType == .pumpSwitch }) {
ids.append(pumpSwitch.channel.remote_id)
}

if let heatOrColdSourceSwitch = children.first(where: { $0.relationType == .heatOrColdSourceSwitch }) {
ids.append(heatOrColdSourceSwitch.channel.remote_id)
}

return ids
}

func toThermostatData() -> ThermostatSlavesFeature.ThermostatData {
@Singleton var getChannelCaptionUseCase: GetChannelBaseCaptionUseCase
@Singleton var getChannelIconUseCase: GetChannelBaseIconUseCase
Expand Down Expand Up @@ -78,11 +111,28 @@ private extension ChannelChild {
channel: channel
)
}


}

private extension ChannelWithChildren {
var relatedIds: [Int32] {
var ids: [Int32] = []
ids.append(channel.remote_id)

if let thermometer = children.first(where: { $0.relationType == .mainThermometer }) {
ids.append(thermometer.channel.remote_id)
}

if let pumpSwitch = children.first(where: { $0.relationType == .pumpSwitch }) {
ids.append(pumpSwitch.channel.remote_id)
}

if let heatOrColdSourceSwitch = children.first(where: { $0.relationType == .heatOrColdSourceSwitch }) {
ids.append(heatOrColdSourceSwitch.channel.remote_id)
}

return ids
}

func toThermostatData() -> ThermostatSlavesFeature.ThermostatData {
@Singleton var getChannelCaptionUseCase: GetChannelBaseCaptionUseCase
@Singleton var getChannelIconUseCase: GetChannelBaseIconUseCase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ extension ThermostatSlavesFeature {
@Published var master: ThermostatData? = nil
@Published var slaves: [ThermostatData] = []
@Published var scale: CGFloat = 1

var relatedIds: [Int32] = []
}

struct ThermostatData: Equatable, Identifiable {
Expand Down
Loading

0 comments on commit 9b345dc

Please sign in to comment.