Skip to content

Commit

Permalink
Merge pull request #43 from soucolline/develop
Browse files Browse the repository at this point in the history
Version 2.2.0
  • Loading branch information
soucolline authored Nov 9, 2022
2 parents 26f4ad7 + e16d69b commit 4945627
Show file tree
Hide file tree
Showing 93 changed files with 1,169 additions and 1,012 deletions.
2 changes: 0 additions & 2 deletions .env.default.template

This file was deleted.

18 changes: 18 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: run-tests
on:
pull_request:
branches:
- 'develop'
jobs:
build:
runs-on: macos-12
steps:
- uses: swift-actions/setup-swift@v1
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '14.0.1'
- uses: actions/checkout@v3
- uses: maierj/[email protected]
with:
lane: 'tests'
subdirectory: 'swiftUV/fastlane'
1 change: 0 additions & 1 deletion .swift-version

This file was deleted.

63 changes: 63 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let tca: Target.Dependency = .product(name: "ComposableArchitecture", package: "swift-composable-architecture")
let tcaCoreLocation: Target.Dependency = .product(name: "ComposableCoreLocation", package: "composable-core-location")

let package = Package(
name: "uv-today-ios",
platforms: [.iOS(.v15)],
products: [
.library(name: "AppFeature", targets: ["AppFeature"]),
.library(name: "LocationManager", targets: ["LocationManager"]),
.library(name: "Models", targets: ["Models"]),
.library(name: "UVClient", targets: ["UVClient"])
],
dependencies: [
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", exact: "0.43.0"),
.package(url: "https://github.com/pointfreeco/composable-core-location", exact: "0.2.0"),
],
targets: [
.target(
name: "AppFeature",
dependencies: [
"LocationManager",
"Models",
"UVClient",
tca,
tcaCoreLocation
]
),
.target(
name: "LocationManager",
dependencies: [
tcaCoreLocation
]
),
.target(name: "Models"),
.target(
name: "UVClient",
dependencies: [
"Models",
tca
]
),
.testTarget(
name: "AppFeatureTests",
dependencies: [
"AppFeature",
"Models",
"UVClient",
tca
]
),
.testTarget(
name: "ModelsTests",
dependencies: [
"Models"
]
)
]
)
27 changes: 0 additions & 27 deletions Podfile

This file was deleted.

23 changes: 0 additions & 23 deletions Podfile.lock

This file was deleted.

5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# SwiftUV
Swift app to get current UV index depending on location
# uv-today-ios

A description of this package.
194 changes: 194 additions & 0 deletions Sources/AppFeature/AppReducer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
//
// AppReducer.swift
// swiftUV
//
// Created by Thomas Guilleminot on 03/08/2022.
// Copyright © 2022 Thomas Guilleminot. All rights reserved.
//

import ComposableArchitecture
import ComposableCoreLocation
import LocationManager
import Models
import UVClient

public struct AppReducer: ReducerProtocol {
public struct State: Equatable {
public var uvIndex: Index
public var cityName: String
public var weatherRequestInFlight: Bool
public var getCityNameRequestInFlight: Bool
public var attributionLogo: URL?
public var attributionLink: URL?
public var errorText: String
public var userLocation: Models.Location?
public var isRequestingCurrentLocation: Bool
public var hasAlreadyRequestLocation: Bool
public var isLocationRefused: Bool

@BindableState public var shouldShowErrorPopup: Bool

public init(
uvIndex: Index = 0,
cityName: String = "loading",
weatherRequestInFlight: Bool = false,
getCityNameRequestInFlight: Bool = false,
errorText: String = "",
userLocation: Models.Location? = nil,
isRequestingCurrentLocation: Bool = false,
hasAlreadyRequestLocation: Bool = false,
isLocationRefused: Bool = false,
shouldShowErrorPopup: Bool = false
) {
self.uvIndex = uvIndex
self.cityName = cityName
self.weatherRequestInFlight = weatherRequestInFlight
self.getCityNameRequestInFlight = getCityNameRequestInFlight
self.errorText = errorText
self.userLocation = userLocation
self.isRequestingCurrentLocation = isRequestingCurrentLocation
self.hasAlreadyRequestLocation = hasAlreadyRequestLocation
self.isLocationRefused = isLocationRefused
self.shouldShowErrorPopup = shouldShowErrorPopup
}
}

public enum Action: Equatable, BindableAction {
case getUVRequest
case getUVResponse(TaskResult<Index>)
case getCityNameResponse(TaskResult<String>)
case getAttribution
case getAttributionResponse(TaskResult<AttributionResponse>)

case onAppear
case onDisappear
case locationManager(LocationManager.Action)
case binding(BindingAction<State>)
}

@Dependency(\.uvClient) public var uvClient: UVClient
@Dependency(\.locationManager) public var locationManager: LocationManager

public init() {}

public var body: some ReducerProtocol<State, Action> {
BindingReducer()

Reduce { state, action in
switch action {
case .onAppear:
state.weatherRequestInFlight = true
state.getCityNameRequestInFlight = true
state.isRequestingCurrentLocation = true
state.isLocationRefused = false

switch locationManager.authorizationStatus() {
case .notDetermined:
return .merge(
locationManager
.delegate()
.map(AppReducer.Action.locationManager),

locationManager
.requestWhenInUseAuthorization()
.fireAndForget()
)

case .authorizedAlways, .authorizedWhenInUse:
return .merge(
locationManager
.delegate()
.map(AppReducer.Action.locationManager),

locationManager
.requestLocation()
.fireAndForget()
)

case .restricted, .denied:
state.shouldShowErrorPopup = true
state.errorText = "app.error.localisationDisabled".localized
state.isLocationRefused = true
return .none

@unknown default:
return .none
}

case .onDisappear:
state.hasAlreadyRequestLocation = false
return .none

case .getUVRequest:
state.weatherRequestInFlight = true
state.getCityNameRequestInFlight = true

guard let location = state.userLocation else {
state.shouldShowErrorPopup = true
state.errorText = "app.error.couldNotLocalise".localized
return .none
}

return .run { send in
async let fetchUV: Void = send(
.getUVResponse(TaskResult { try await uvClient.fetchUVIndex(UVClientRequest(lat: location.latitude, long: location.longitude)) })
)

async let fetchCityName: Void = send(
.getCityNameResponse(TaskResult { try await uvClient.fetchCityName(location) })
)

_ = await [fetchUV, fetchCityName]
}

case .getUVResponse(.success(let index)):
state.weatherRequestInFlight = false
state.uvIndex = index
return .none

case .getUVResponse(.failure(let error)):
state.weatherRequestInFlight = false
state.shouldShowErrorPopup = true
state.errorText = error.localizedDescription
state.uvIndex = 0
return .none

case .getCityNameResponse(.success(let city)):
state.getCityNameRequestInFlight = false
state.cityName = city
return .none

case .getCityNameResponse(.failure):
state.getCityNameRequestInFlight = false
state.cityName = "app.label.unknown".localized
return .none

case .getAttribution:
return .task {
await .getAttributionResponse(TaskResult { try await uvClient.fetchWeatherKitAttribution() })
}

case .getAttributionResponse(.success(let attribution)):
state.attributionLogo = attribution.logo
state.attributionLink = attribution.link
return .none

case .getAttributionResponse(.failure):
return .none

case .binding(\.$shouldShowErrorPopup):
state.shouldShowErrorPopup = false
return .none

case .binding:
return .none

case .locationManager:
return .none
}
}
._printChanges()

LocationReducer()
}
}
Loading

0 comments on commit 4945627

Please sign in to comment.