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

SwiftUI Version of Room Notification Settings V2 #4670

Merged
merged 33 commits into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
04d89a6
add swiftUI view for notification settings
langleyd Jul 26, 2021
b866f09
merge, finish swiftui and add theming
langleyd Aug 5, 2021
0865862
fix warning
langleyd Aug 6, 2021
b97e103
revert a few files that should not have been checked in
langleyd Aug 6, 2021
5672f17
Merge branch 'develop' of github.com:vector-im/element-ios into langl…
langleyd Aug 6, 2021
c6ba23e
Add theming support, and support for other top level configuration to…
langleyd Aug 12, 2021
7d1b893
Merge branch 'develop' of github.com:vector-im/element-ios into langl…
langleyd Aug 12, 2021
7fa2f13
add towncrier
langleyd Aug 12, 2021
33aea85
Remove visibility modifier
langleyd Aug 12, 2021
3dfdb0f
Fix avatar service not returning generated image on network error. Fi…
langleyd Aug 12, 2021
b792af6
Cleanup from comments
langleyd Aug 12, 2021
a20fa1c
Typo
langleyd Aug 12, 2021
a388db0
Fix header font size
langleyd Aug 12, 2021
dcfcdac
Update Riot/Managers/Theme/SwiftUI/ThemeKey.swift
langleyd Aug 13, 2021
57719fd
Update Riot/Modules/Common/Avatar/AvatarService.swift
langleyd Aug 13, 2021
6fae92c
Update Riot/Modules/Common/Avatar/AvatarService.swift
langleyd Aug 13, 2021
de2a1e5
Merge branch 'langleyd/4669_room_notification_settings_swiftui' of gi…
langleyd Aug 13, 2021
e70987d
Do avatar placeholder in SwiftUI, Add AvatarViewModel, Add dependency…
langleyd Aug 14, 2021
57969ea
Merge branch 'develop' of github.com:vector-im/element-ios into langl…
langleyd Aug 16, 2021
ef25ef5
Add dependency management, AvatarViewModel and placeholder rendering …
langleyd Aug 17, 2021
de33b60
Add activity indicator
langleyd Aug 17, 2021
b3a684e
Remove log
langleyd Aug 17, 2021
9655487
Fix Comment
langleyd Aug 17, 2021
666e836
Move SwiftUI version of ViewModel to a subclass
langleyd Aug 17, 2021
4b09985
Fix tests and try fix build error
langleyd Aug 17, 2021
b5cf3ae
Update Riot/Modules/Common/SwiftUI/Inject.swift
langleyd Aug 18, 2021
67e0900
Update Riot/Modules/Common/SwiftUI/DependencyContainerKey.swift
langleyd Aug 18, 2021
62d340a
Update Riot/Modules/Common/SwiftUI/DependencyContainerKey.swift
langleyd Aug 18, 2021
19ff75d
Fix imports and move logic to AvatarViewModel
langleyd Aug 18, 2021
f6ac4ca
Update Riot/Modules/Common/SwiftUI/Inject.swift
langleyd Aug 18, 2021
26278f1
indentation
langleyd Aug 18, 2021
d7030bc
Merge branch 'langleyd/4669_room_notification_settings_swiftui' of ht…
langleyd Aug 18, 2021
cbf6410
Fix problem showing error message on completion
langleyd Aug 18, 2021
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
35 changes: 35 additions & 0 deletions DesignKit/Source/AvatarSize.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import UIKit

// Figma Avatar Sizes: https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1258%3A19678
public enum AvatarSize: Int {
case xxSmall = 16
case xSmall = 32
case small = 36
case medium = 42
case large = 44
case xLarge = 52
case xxLarge = 80
}

extension AvatarSize {
public var size: CGSize {
return CGSize(width: self.rawValue, height: self.rawValue)
}
}
3 changes: 2 additions & 1 deletion Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
Expand Down
35 changes: 35 additions & 0 deletions Riot/Categories/Combine/Publisher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import Combine

/**
Sams as `assign(to:on:)` but maintains a weak reference to object(Useful in cases where you want to pass self and not cause a retain cycle.)
- SeeAlso:
[assign(to:on:)](https://developer.apple.com/documentation/combine/just/assign(to:on:))
*/
@available(iOS 14.0, *)
extension Publisher where Failure == Never {
func weakAssign<T: AnyObject>(
to keyPath: ReferenceWritableKeyPath<T, Output>,
on object: T
) -> AnyCancellable {
sink { [weak object] value in
object?[keyPath: keyPath] = value
}
}
}
2 changes: 1 addition & 1 deletion Riot/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4014,7 +4014,7 @@ internal enum VectorL10n {
internal static var settingsAdd3pidPasswordMessage: String {
return VectorL10n.tr("Vector", "settings_add_3pid_password_message")
}
/// Add email adress
/// Add email address
internal static var settingsAdd3pidPasswordTitleEmail: String {
return VectorL10n.tr("Vector", "settings_add_3pid_password_title_email")
}
Expand Down
55 changes: 55 additions & 0 deletions Riot/Managers/Theme/SwiftUI/ThemeKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import SwiftUI

private struct ThemeKey: EnvironmentKey {
static let defaultValue = ThemeService.shared().theme
}

@available(iOS 14.0, *)
extension EnvironmentValues {
var theme: Theme {
get { self[ThemeKey.self] }
set { self[ThemeKey.self] = newValue }
}
}

/**
A theme modifier for setting the theme for this view and all its descendants in the hierarchy.
- Parameters:
- theme: a Theme to be set as the environment value.
*/
@available(iOS 14.0, *)
extension View {
func theme(_ theme: Theme) -> some View {
langleyd marked this conversation as resolved.
Show resolved Hide resolved
environment(\.theme, theme)
}
}

/**
A theme modifier for setting the theme by id for this view and all its descendants in the hierarchy.
- Parameters:
- themeId: ThemeIdentifier of a theme to be set as the environment value.
*/
@available(iOS 14.0, *)
extension View {
func theme(_ themeId: ThemeIdentifier) -> some View {
let theme = ThemeService.shared().theme(withThemeId: themeId.rawValue)
return environment(\.theme, theme)
}
}
31 changes: 31 additions & 0 deletions Riot/Managers/Theme/SwiftUI/ThemeObserver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import Combine

@available(iOS 14.0, *)
class ThemeObserver: ObservableObject {

static let shared = ThemeObserver()

init() {
NotificationCenter.default.publisher(for: NSNotification.Name.themeServiceDidChangeTheme).map { _ in
ThemeService.shared().theme
}.assign(to: &$theme)
langleyd marked this conversation as resolved.
Show resolved Hide resolved
}
@Published var theme: Theme = ThemeService.shared().theme
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import SwiftUI

/**
A visual cue to user that something is in progress.
*/
@available(iOS 14.0, *)
struct ActivityIndicator: View {

private enum Constants {
static let backgroundColor = Color(UIColor(white: 0.8, alpha: 0.9))
}

var body: some View {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: Color.white))
.padding()
.background(Constants.backgroundColor)
.cornerRadius(5)

}
}

@available(iOS 14.0, *)
struct ActivityIndicator_Previews: PreviewProvider {
static var previews: some View {
Group {
Text("Hello World!")
.activityIndicator(show: true)
Text("Hello World!")
.activityIndicator(show: false)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import SwiftUI

/**
A modifier for showing the activity indcator centered over a view.
*/
@available(iOS 14.0, *)
struct ActivityIndicatorModifier: ViewModifier {
var show: Bool

@ViewBuilder
func body(content: Content) -> some View {
if show {
content
.overlay(ActivityIndicator(), alignment: .center)
} else {
content
}
}
}

@available(iOS 14.0, *)
extension View {
@available(iOS 14.0, *)
func activityIndicator(show: Bool) -> some View {
self.modifier(ActivityIndicatorModifier(show: show))
}
}
34 changes: 34 additions & 0 deletions Riot/Modules/Common/Avatar/AvatarInputType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

protocol AvatarInputType {
var mxContentUri: String? { get }
var matrixItemId: String { get }
var displayName: String? { get }
}

struct AvatarInput: AvatarInputType {
let mxContentUri: String?
var matrixItemId: String
let displayName: String?
}

enum AvatarInputOption {
case swiftUI(AvatarInputType)
case uiKit(AvatarViewDataProtocol)
}
21 changes: 21 additions & 0 deletions Riot/Modules/Common/Avatar/Mock/MockAvatarInput.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

class MockAvatarInput {
static let example = AvatarInput(mxContentUri: "faveUri", matrixItemId: "id123", displayName: "Alice")
}
29 changes: 29 additions & 0 deletions Riot/Modules/Common/Avatar/Mock/MockAvatarService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import Combine
import DesignKit

@available(iOS 14.0, *)
class MockAvatarService: AvatarServiceType {
static let example: AvatarServiceType = MockAvatarService()
func avatarImage(mxContentUri: String, avatarSize: AvatarSize) -> Future<UIImage, Error> {
Future { promise in
promise(.success(Asset.Images.appSymbol.image))
}
}
}
Loading