Skip to content

Commit cbf811a

Browse files
authored
Merge pull request #254 from surfstudio/feature/resolve_7.4_conflicts
Merge 7.4 and resolve conflicts
2 parents aa95890 + 7fd0ec7 commit cbf811a

File tree

179 files changed

+2547
-492
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

179 files changed

+2547
-492
lines changed

.github/workflows/Build.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ on:
1010
jobs:
1111

1212
build_iOS:
13-
runs-on: macOS-12
13+
runs-on: macOS-13
1414
steps:
1515
- uses: actions/checkout@v1
1616
- name: Generate projects
@@ -19,6 +19,8 @@ jobs:
1919
run: make build_lib_iOS
2020
- name: Run tests
2121
run: make test_lib_iOS
22+
- name: Check Log
23+
run: make check_test_log
2224
- name: Prepare Report
2325
run: make prepare_report
2426
- name: Upload Coverage
@@ -34,7 +36,7 @@ jobs:
3436

3537

3638
build_Example:
37-
runs-on: macOS-12
39+
runs-on: macOS-13
3840
steps:
3941
- uses: actions/checkout@v1
4042
- name: Generate projects
@@ -43,6 +45,8 @@ jobs:
4345
run: make build_example_iOS
4446
- name: Run tests
4547
run: make test_example_iOS
48+
- name: Check Log
49+
run: make check_test_log
4650
- name: Prepare Report
4751
run: make prepare_example_report
4852
- name: Upload Coverage
@@ -57,7 +61,7 @@ jobs:
5761
verbose: true
5862

5963
build_tvOS:
60-
runs-on: macOS-12
64+
runs-on: macOS-13
6165
steps:
6266
- uses: actions/checkout@v1
6367
- name: Generate projects

.swiftlint.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,6 @@ custom_rules:
8686
message: "Every MARK should be surrounded with 1 newline before and 1 after it"
8787
severity: warning
8888

89-
redundant_default_type:
90-
included: ".*.swift"
91-
name: "Redundant explicit type"
92-
regex: "(var|let) [0-9a-zA-Z_]*: (Int|String|Double|Bool)[ ]*= "
93-
message: "Redundant explicit declaration of default types should be avoided"
94-
9589
class_modificators_order:
9690
include: ".*.swift"
9791
name: "Class modificators order"

Components/Sources/Collection/CollectionWrappedCell.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,15 @@ public final class CollectionWrappedCell<View: ConfigurableItem>: UICollectionVi
2828
extension CollectionWrappedCell: CalculatableHeightItem where View: CalculatableHeightItem {
2929

3030
public static func getHeight(forWidth width: CGFloat, with model: Model) -> CGFloat {
31-
return View.getHeight(forWidth: width, with: model)
31+
let nestedViewHeight = View.getHeight(forWidth: width, with: model)
32+
if let alignment = (model as? AlignmentProvider)?.alignment {
33+
switch alignment {
34+
case .leading(let insets), .trailing(let insets), .all(let insets):
35+
return nestedViewHeight + insets.top + insets.bottom
36+
}
37+
} else {
38+
return nestedViewHeight
39+
}
3240
}
3341

3442
}
@@ -38,7 +46,15 @@ extension CollectionWrappedCell: CalculatableHeightItem where View: Calculatable
3846
extension CollectionWrappedCell: CalculatableWidthItem where View: CalculatableWidthItem {
3947

4048
public static func getWidth(forHeight height: CGFloat, with model: View.Model) -> CGFloat {
41-
return View.getWidth(forHeight: height, with: model)
49+
let nestedViewWidth = View.getWidth(forHeight: height, with: model)
50+
if let alignment = (model as? AlignmentProvider)?.alignment {
51+
switch alignment {
52+
case .leading(let insets), .trailing(let insets), .all(let insets):
53+
return nestedViewWidth + insets.left + insets.right
54+
}
55+
} else {
56+
return nestedViewWidth
57+
}
4258
}
4359

4460
}

Components/Sources/Common/Models/Styles/TextStyle.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public struct TextStyle: Equatable {
1212
public let color: UIColor
1313
public let font: UIFont
1414

15-
public init(color: UIColor = .black, font: UIFont = .systemFont(ofSize: 16)) {
15+
public init(color: UIColor = .black, font: UIFont = .preferredFont(forTextStyle: .body)) {
1616
self.color = color
1717
self.font = font
1818
}

Components/Sources/Table/TableWrappedCell.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,15 @@ public final class TableWrappedCell<View: ConfigurableItem>: UITableViewCell, Vi
2828
extension TableWrappedCell: CalculatableHeightItem where View: CalculatableHeightItem {
2929

3030
public static func getHeight(forWidth width: CGFloat, with model: Model) -> CGFloat {
31-
return View.getHeight(forWidth: width, with: model)
31+
let nestedViewHeight = View.getHeight(forWidth: width, with: model)
32+
if let alignment = (model as? AlignmentProvider)?.alignment {
33+
switch alignment {
34+
case .leading(let insets), .trailing(let insets), .all(let insets):
35+
return nestedViewHeight + insets.top + insets.bottom
36+
}
37+
} else {
38+
return nestedViewHeight
39+
}
3240
}
3341

3442
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Overview
2+
3+
- [UIAccessibility Basics](Pages/UIAccessibility%20Basics.md)
4+
- [Usage](Pages/Usage.md)
5+
- [Invalidation](Pages/Invalidation.md)
6+
- [Debugging](Pages/Debugging.md)
7+
- [Advanced Usage](Pages/Advanced%20Usage.md)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
[⏎ Overview](../Overview.md)
2+
3+
# Advanced Usage
4+
5+
## How it works
6+
7+
The main logic is located in `TableAccessibilityPlugin` and `CollectionAccessibilityPlugin`. It automatically added to all builders to be ready work with `AccessibilityItems`. It's a common plugin that works with delgate events.
8+
9+
**Only each `AccessibilityItem` will be processed by these plugins.**
10+
11+
On `willDisplay` event every time 2 steps are happens:
12+
13+
1. Element will be passed to its defined modifier through corresponding methods `modify(item: accessibilityItem)` or `modify(item: accessibilityItem, generator: generator)` if generator implements `AccessibilityStrategyProvider`.
14+
2. A new invalidator instance is setted with provided `indexPath` if supports invalidation mechanism. Its invalidate method calls delegate to pass the new event `invalidatedAccessibility` which will execute step 1.
15+
16+
On `didEndDisplay` event the plugin will remove invalidator if it exists.
17+
18+
<img src="https://i.ibb.co/SfbfzZJ/2023-06-16-18-43-17.png" alt="Plugin Example">
19+
20+
<br>
21+
22+
This is the essence how accessibility works in **RDDM**, so you don't have access to its functionality. Instead, you may have full control under modify and invalidate processes.
23+
24+
***
25+
26+
<br>
27+
28+
## Modify custom accessibility parameters
29+
30+
If you need to set a parameter which is not presented or change the way how they setting, you need to define your own strategy provider (or custom accessibility item) and modifier. You can combine your custom logic with base functionality.
31+
32+
*Example:*
33+
```swift
34+
enum CustomAccessibilityModifier: AccessibilityModifier {
35+
static func modify(item: AccessibilityItem) {
36+
// set base parameters
37+
BaseAccessibilityModifier.modify(item)
38+
39+
// additional logic for custom item
40+
guard let item = item as? CustomAccessibilityItem else { return }
41+
item.accessibilityIdentifier = item.identifier.value
42+
item.accessibilityHint = item.hintStrategy.value
43+
}
44+
45+
// corresponding method implementation with generator
46+
}
47+
48+
protocol CustomAccessibilityItem: AccessibilityItem {
49+
var modifierType: AccessibilityModifierType { CustomAccessibilityModifier.self }
50+
51+
// expand base accessibility item with new parameters using string strategy
52+
var identifier: AccessibilityStringStrategy { get }
53+
var hintStrategy: AccessibilityStringStrategy { get }
54+
}
55+
```
56+
57+
By this way you can add any other functionality to accessibility items.
58+
59+
***
60+
61+
<br>
62+
63+
## Customize invalidation
64+
65+
66+
### in table or collection
67+
If you want to perform additional logic on invalidate, you can implement your own `AccessibilityItemInvalidator` and set `AccessibilityInvalidatorCreationBlock`
68+
69+
**For example**
70+
```swift
71+
72+
private lazy var adapter = collectionView.rddm.baseBuilder
73+
.add(plugin: .accessibility({ item, kind, delegate in
74+
return CustomInvalidator(item, kind, delegate)
75+
}))
76+
.build()
77+
```
78+
79+
*Note that we have `DelegatedAccessibilityItemInvalidator` which could be used as base for your custom invalidator. This class is needed to combine strategies from item and generator.*
80+
81+
### in other view
82+
83+
Any view can implement `AccessibilityItem`, but you need adittionaly call `AccessibilityItem.modifySelf()` to setup accessibility-properties for real.
84+
85+
`AcessibilityInvalidatable.setBasicInvalidator` is also available for invalidation.
86+
87+
*Note that is recomended to call*
88+
- `setBasicInvalidator` when view become **visible**
89+
- `removeInvalidator` when view become **invisible**
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
[⏎ Overview](../Overview.md)
2+
3+
# Debugging
4+
5+
## Accessibility Inspector
6+
7+
Accessibility Inspector is an instrument provided with Xcode, so this is most common insturment to see accessibility parameters. It can be opened in Menu Bar: `Xcode -> Open Developer Tool -> Accessibility Inspector`.
8+
9+
<img src="https://i.ibb.co/wMkh1rG/2023-06-16-16-25-02.png" alt="Accessibility Inspector">
10+
11+
Here you can see common acceessibility parameters and perform accessibility actions. To select an element you need fisrt select a running simulator. Then you click target button on the right and select an element or click arrorws "<" and ">" to navigate through all elements. Optionally, you can enable reading for selected elements.
12+
13+
Be aware that not all accessibility parameters are displayed as they VoiceOver is reading. For example, if the element is `UISwitch`, in inspector you can see values 0 or 1, but VoiceOver will localize these values into "enabled" and "disabled". So it's better to also check elements with VoiceOver.
14+
15+
*Note: Accessibility parameters also can be seen in a view debugger, but it's non interactive.*
16+
<img src="https://i.ibb.co/RQxVPGg/2023-06-16-16-32-20.png" alt="View Debugger">
17+
18+
***
19+
20+
<br>
21+
22+
## Accessibility Audit
23+
24+
Accessibility Inspector allows you to run audit of current screen to find and different accessibility issues if they exists. The second tab in right corner navigates you to audit window.
25+
26+
<img src="https://i.ibb.co/LPfx62N/2023-06-16-16-57-17.png" alt="Accessibility Audit">
27+
28+
***
29+
30+
<br>
31+
32+
## VoiceOver
33+
34+
If you will test your app on a device with VoiceOver you can enable some useful options.
35+
36+
<img src="https://i.ibb.co/TWJGG77/2023-06-16-17-07-42.jpg" alt="Caption Panel" width=49%>
37+
<img src="https://i.ibb.co/8Prs6r6/2023-06-16-17-07-17.jpg" alt="Accessibility Shortcut" width=49%>
38+
39+
Caption panel allows you to read instead of listen to VoiceOver. And Accessibility Shortcut allows you to fast enable or disable VoiceOver by triple-click the lock button.
40+
41+
It also useful to read an article how to use VoiceOver gestures https://support.apple.com/guide/iphone/iph3e2e2281/ios
42+
43+
***
44+
45+
<br>
46+
47+
## UI Tests
48+
49+
Accessibility elements are also used for UI tests. So changing traits affects on `XCUIElement` type (any element with trait `.button` becomes a button `XCUIElement`).
50+
51+
If you manually change collection or table classes to become an accessibility elements your UI tests may fail, if they will not contains required accessibility.
52+
53+
<img src="https://i.ibb.co/gz049gW/2023-06-16-17-31-51.png" alt="UI test failure">
54+
55+
To fix this issue **RDDM** provides a built-in modifier for UI tests. You only need to provide the command line argument `"-rddm.XCUITestsCompatible"`
56+
57+
<img src="https://i.ibb.co/XbzffYF/2023-06-16-17-36-30.png" alt="UI tests modifier">
58+
59+
This modifier will add traits `.button` to all cells and `.staticText` to all headers and footers to prevent UI tests failures.
60+
61+
***
62+
63+
<br>
64+
65+
## UI Tests Accessibility Audit
66+
67+
In Xcode 15 you can run automatic accessibility audit with just a line of code:
68+
69+
```swift
70+
try app.performAccessibilityAudit()
71+
```
72+
73+
It's the same audit from Accessibility Inspector. If there will be any issues test will fail and you can see these issues in logs. See more at https://developer.apple.com/videos/play/wwdc2023/10035/.
74+
75+
<br>
76+
77+
Next [Advanced Usage →](./Advanced%20Usage.md)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[⏎ Overview](../Overview.md)
2+
3+
# Invalidation
4+
5+
**RDDM**'s accessibility plugin allows you to use your dynamic properties in accessibility strategies and so on. But if some properties will changed while the cell is on screen, you need to invalidate current accessibility parameters. For these needs you need implement `AccessibilityInvalidatable` protocol.
6+
7+
```swift
8+
protocol AccessibilityInvalidatable: AccessibilityItem {
9+
var accessibilityInvalidator: AccessibilityItemInvalidator? { get set }
10+
}
11+
```
12+
13+
This protocol required you to define an invalidatior property. Through this invalidator you can call `invalidateParameters()` method which triggers re-set of all accessibility parameters.
14+
15+
*Important: this property is fully managed by accessibility plugin, so you don't need to set it. But if you want to add your own funtionality, see [Advanced Usage](./Advanced%20Usage.md). Invalidator may be `nil` if cell isn't on screen, so the latest parameters will be applied on `willDisplay` after the `configure()` method.*
16+
17+
*Example:*
18+
19+
```swift
20+
func updateState(state: String, isSelected: Bool) {
21+
valueStrategy = .just(state)
22+
isSelected ? traitsStrategy.insert(.selected) : traitsStrategy.remove(.selected)
23+
accessibilityInvalidator?.invalidateParameters()
24+
}
25+
```
26+
27+
<br>
28+
29+
If you manage cell states like `isSelected`, `isEnabled`, you may use corresponding accessibility traits. But in a default `AccessibilityItem` these states wouldn't be changes because of `shouldOverrideStateTraits` property which by default is `false`. So you need to define this property as `true`.
30+
31+
*Example:*
32+
33+
```swift
34+
var labelStrategy: AccessibilityStringStrategy { .from(object: titleLabel) }
35+
var valueStrategy: AccessibilityStringStrategy = .just(nil)
36+
lazy var traitsStrategy: AccessibilityTraitsStrategy = .from(object: titleLabel)
37+
var shouldOverrideStateTraits: Bool { true }
38+
39+
var accessibilityInvalidator: AccessibilityItemInvalidator?
40+
```
41+
42+
<br>
43+
44+
Next [Debugging →](./Debugging.md)

0 commit comments

Comments
 (0)