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

Feature: upgrade firmware option on NFC scan of df3 tag #1746

Merged
merged 5 commits into from
Dec 3, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@
"add_sensor_nfc_df3_error" = "This tag cannot be added with NFC due to old firmware. Please add the tag with Bluetooth and update firmware.";
"add_sensor_description" = "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it.";
"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone.";
"upgrade_firmware" = "Upgrade Firmware";
priyonto marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import RuuviLocal
import RuuviService
import RuuviCore
import RuuviPresenters
import RuuviFirmware

public struct RuuviDiscoverDependencies {
var errorPresenter: ErrorPresenter
Expand All @@ -15,6 +16,7 @@ public struct RuuviDiscoverDependencies {
var foreground: BTForeground
var ruuviReactor: RuuviReactor
var ruuviOwnershipService: RuuviServiceOwnership
var firmwareBuilder: RuuviFirmwareBuilder

public init(
errorPresenter: ErrorPresenter,
Expand All @@ -23,7 +25,8 @@ public struct RuuviDiscoverDependencies {
permissionPresenter: PermissionPresenter,
foreground: BTForeground,
ruuviReactor: RuuviReactor,
ruuviOwnershipService: RuuviServiceOwnership
ruuviOwnershipService: RuuviServiceOwnership,
firmwareBuilder: RuuviFirmwareBuilder
) {
self.errorPresenter = errorPresenter
self.activityPresenter = activityPresenter
Expand All @@ -32,6 +35,7 @@ public struct RuuviDiscoverDependencies {
self.foreground = foreground
self.ruuviReactor = ruuviReactor
self.ruuviOwnershipService = ruuviOwnershipService
self.firmwareBuilder = firmwareBuilder
}
}

Expand All @@ -47,6 +51,7 @@ public final class RuuviDiscoverFactory {
presenter.foreground = dependencies.foreground
presenter.ruuviReactor = dependencies.ruuviReactor
presenter.ruuviOwnershipService = dependencies.ruuviOwnershipService
presenter.firmwareBuilder = dependencies.firmwareBuilder
return presenter
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import RuuviLocal
import RuuviService
import RuuviCore
import RuuviPresenters
import RuuviFirmware
import CoreBluetooth
import CoreNFC

Expand Down Expand Up @@ -37,6 +38,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover {
var permissionPresenter: PermissionPresenter!
var ruuviReactor: RuuviReactor!
var ruuviOwnershipService: RuuviServiceOwnership!
var firmwareBuilder: RuuviFirmwareBuilder!

private weak var view: DiscoverViewInput?
private var accessQueue = DispatchQueue(
Expand Down Expand Up @@ -190,6 +192,7 @@ extension DiscoverPresenter: DiscoverViewOutput {
message: message,
showAddSensor: false,
showGoToSensor: true,
showUpgradeFirmware: false,
isDF3: false
)
return
Expand All @@ -208,6 +211,7 @@ extension DiscoverPresenter: DiscoverViewOutput {
message: message,
showAddSensor: true,
showGoToSensor: false,
showUpgradeFirmware: false,
isDF3: false
)
return
Expand All @@ -227,6 +231,7 @@ extension DiscoverPresenter: DiscoverViewOutput {
message: message,
showAddSensor: false,
showGoToSensor: false,
showUpgradeFirmware: true,
isDF3: nfcSensor?.firmwareVersion == "2.5.9"
)
}
Expand All @@ -252,6 +257,13 @@ extension DiscoverPresenter: DiscoverViewOutput {
}
}

func viewDidAskToUpgradeFirmware(of sensor: NFCSensor?) {
guard let sensor else { return }
let firmwareModule = firmwareBuilder.build(uuid: sensor.id, currentFirmware: sensor.firmwareVersion)
firmwareModule.output = self
viewController.present(firmwareModule.viewController, animated: true)
}

func viewDidACopyMacAddress(of sensor: NFCSensor?) {
UIPasteboard.general.string = sensor?.macId
}
Expand All @@ -261,6 +273,13 @@ extension DiscoverPresenter: DiscoverViewOutput {
}
}

// MARK: - RuuviFirmwareOutput
extension DiscoverPresenter: RuuviFirmwareOutput {
func ruuviFirmwareSuccessfullyUpgraded(_ ruuviDiscover: RuuviFirmware) {
ruuviDiscover.viewController.dismiss(animated: true)
}
}

// MARK: - Private
extension DiscoverPresenter {
private func startObservingPersistedRuuviSensors() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ protocol DiscoverViewInput: UIViewController, Localizable {
message: String,
showAddSensor: Bool,
showGoToSensor: Bool,
showUpgradeFirmware: Bool,
isDF3: Bool
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ protocol DiscoverViewOutput {
func viewDidGoToSensor(with sensor: NFCSensor?)
func viewDidACopyMacAddress(of sensor: NFCSensor?)
func viewDidACopySecret(of sensor: NFCSensor?)
func viewDidAskToUpgradeFirmware(of sensor: NFCSensor?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ extension DiscoverTableViewController: DiscoverViewInput {
message: String,
showAddSensor: Bool,
showGoToSensor: Bool,
showUpgradeFirmware: Bool,
isDF3: Bool
) {
let title = "sensor_details".localized(for: Self.self)
Expand Down Expand Up @@ -140,6 +141,13 @@ extension DiscoverTableViewController: DiscoverViewInput {
self?.output.viewDidGoToSensor(with: tag)
}))
}

if showUpgradeFirmware {
alertVC.addAction(UIAlertAction(title: "upgrade_firmware".localized(for: Self.self),
style: .default, handler: { [weak self] _ in
self?.output.viewDidAskToUpgradeFirmware(of: tag)
}))
}

alertVC.addAction(UIAlertAction(title: "close".localized(for: Self.self), style: .cancel, handler: nil))
present(alertVC, animated: true)
Expand Down
1 change: 1 addition & 0 deletions Modules/RuuviDiscover/target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ targets:
- target: RuuviService
- target: RuuviPresenters
- target: RuuviLocalization
- target: RuuviFirmware
8 changes: 8 additions & 0 deletions Modules/RuuviFirmware/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
22 changes: 22 additions & 0 deletions Modules/RuuviFirmware/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
23 changes: 23 additions & 0 deletions Modules/RuuviFirmware/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "RuuviFirmware",
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "RuuviFirmware",
targets: ["RuuviFirmware"]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "RuuviFirmware"),
.testTarget(
name: "RuuviFirmwareTests",
dependencies: ["RuuviFirmware"]),
]
)
38 changes: 38 additions & 0 deletions Modules/RuuviFirmware/RuuviFirmware.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Pod::Spec.new do |s|
s.name = 'RuuviDiscover'
s.version = '0.0.2'
s.summary = 'Ruuvi Discover'
s.homepage = 'https://ruuvi.com'
s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' }
s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' }
s.platform = :ios, '10.0'
s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' }
s.frameworks = 'Foundation'
s.requires_arc = true
s.ios.deployment_target = '10.0'
s.swift_version = '5.0'

s.default_subspecs = 'RuuviDiscover'

s.subspec 'RuuviDiscover' do |ss|
ss.source_files = 'Sources/RuuviDiscover/**/*.{h,m,swift}', 'Sources/RuuviDiscover/*.{h,m,swift}'
ss.resource_bundles = {
'RuuviDiscover' => ['Sources/**/Resources/**/*']
}

ss.dependency 'BTKit'
ss.dependency 'RuuviContext'
ss.dependency 'RuuviReactor'
ss.dependency 'RuuviLocal'
ss.dependency 'RuuviService'
ss.dependency 'RuuviCore'
ss.dependency 'RuuviLocalization'
ss.dependency 'RuuviPresenters'
end

s.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}'
end
end


Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Foundation
import Combine

struct Feedback<State, Event> {
let run: (AnyPublisher<State, Never>) -> AnyPublisher<Event, Never>
public struct Feedback<State, Event> {
public let run: (AnyPublisher<State, Never>) -> AnyPublisher<Event, Never>
public init(run: @escaping (AnyPublisher<State, Never>) -> AnyPublisher<Event, Never>) {
self.run = run
}
}

extension Feedback {
public extension Feedback {
init<Effect: Publisher>(
effects: @escaping (State) -> Effect
) where Effect.Output == Event, Effect.Failure == Never {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import SwiftUI

struct LargeButtonStyle: ButtonStyle {
public struct LargeButtonStyle: ButtonStyle {
let backgroundColor: Color
let foregroundColor: Color
let isDisabled: Bool

func makeBody(configuration: Self.Configuration) -> some View {
public init(backgroundColor: Color, foregroundColor: Color, isDisabled: Bool) {
self.backgroundColor = backgroundColor
self.foregroundColor = foregroundColor
self.isDisabled = isDisabled
}

public func makeBody(configuration: Self.Configuration) -> some View {
let currentForegroundColor
= isDisabled || configuration.isPressed
? foregroundColor.opacity(0.3)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import SwiftUI

struct ProgressBar: View {
public struct ProgressBar: View {
@Binding var value: Double

public init(value: Binding<Double>) {
self._value = value
}

var body: some View {
public var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
Expand All @@ -12,14 +16,14 @@ struct ProgressBar: View {
height: geometry.size.height
)
.opacity(0.3)
.foregroundColor(RuuviColor.green)
.foregroundColor(.green) // TODO: @rinat RuuviColor.green

Rectangle()
.frame(
width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width),
height: geometry.size.height
)
.foregroundColor(RuuviColor.green)
.foregroundColor(.green) // TODO: @rinat RuuviColor.green
.animation(.linear)
}.cornerRadius(6)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import SwiftUI

public struct RuuviBoardView: View {
@State private var isPortrait = false
private let boardImageName = "ruuvitag-b8-and-older-button-location"
public init() {}

public var body: some View {
HStack {
if isPortrait {
Image(boardImageName, bundle: .pod(RuuviFirmwareDummyClass.self))
.resizable()
.aspectRatio(contentMode: .fit)
} else {
Spacer()
Image(boardImageName, bundle: .pod(RuuviFirmwareDummyClass.self))
.resizable()
.aspectRatio(contentMode: .fit)
.scaledToFit()
.frame(width: 300, height: 147)
Spacer()
}
}
.padding()
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
guard let scene = UIApplication.shared.windows.first?.windowScene else { return }
self.isPortrait = scene.interfaceOrientation.isPortrait
}
}
}

private class RuuviFirmwareDummyClass {
}
26 changes: 26 additions & 0 deletions Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import SwiftUI
import UIKit

public struct Spinner: UIViewRepresentable {
public let isAnimating: Bool
public let style: UIActivityIndicatorView.Style

public init(isAnimating: Bool, style: UIActivityIndicatorView.Style) {
self.isAnimating = isAnimating
self.style = style
}

public func makeUIView(context: Context) -> UIActivityIndicatorView {
let spinner = UIActivityIndicatorView(style: style)
spinner.hidesWhenStopped = true
return spinner
}

public func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
if isAnimating {
uiView.startAnimating()
} else {
uiView.stopAnimating()
}
}
}
priyonto marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Foundation
import Combine

extension Publishers {
public extension Publishers {
static func system<State, Event, Scheduler: Combine.Scheduler>(
initial: State,
reduce: @escaping (State, Event) -> State,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import SwiftUI

public extension View {
func eraseToAnyView() -> AnyView { AnyView(self) }
}
Loading