A frienly package for people without hands
Friendly
Watch
How To Use
- Import
Friendly
- Change SwiftUI View to Frienly View.
Original:
WindowGroup {
ContentView()
}
Now:
WindowGroup {
Friendly {
ContentView()
}
}
What is Friendly View
Firendly View is Friendly {}
It contains your app view, cursor view, sheet view and command view.
So the root view of a friendly app must be Friendly View.
Frienly Element
BeFriend
All the frienly elements conform BeFriend
.
And BeFriend
has a value, that is eternalId
. We use eternalId
to identifier your view. And we can know where the views are, and other informations.
So every view has it’s own eternalId
.
FriendlyWrappedView
FriendlyWrappedView
can make all the SwiftUI views to BeFriend views. It requeires a eternal id for the view.
public init(_ id: String, ignore: Bool = false, @ViewBuilder content: () -> Content)
ignore
is abandoned
FriendlyStateButton
FriendlyStateButton
is not a BeFriend view. It only gives you a sign of the state of the friendly system, including the connection state and so on.
FriendlyButton
FriendlyButton
is a BeFriend view.
public init(_ id: String, ignore: Bool = false, action: @escaping (() -> Void), label: @escaping (() -> Content))
ignore
is abandoned
FriendlyButton
just like SwiftUI button. And when the cursor is above it, the cursor will change to a rect.
FriendlyTextField
FriendlyTextField
is a BeFriend view.
public init(_ id: String, _ title: String, text: Binding<String>, focused: FocusState<Bool>, shouldSpeech: Binding<Bool>)
You need give FriendlyTextField
a shouldSpeech
value.
FriendlyTextField
use speech, and only supports En-US
Once the speec finished, you can get text like this:
.onChange(of: speechManager.mainText) { value in
if speechManager.onRecord == "{your FriendlyTextField eternal ID}" {
task.text = value
}
}
FriendlyDatePicker
FriendlyDatePicker
is a BeFriend view.
public init(_ id: String, date: Binding<Date>, ex: Bool = false, hideEx: Binding<Bool>)
FriendlyDatePicker
will become a swiftui DatePicker
when the app is not in the Friendly Mode.
Because FriendlyDatePicker
has some buttons in it. So you need give a ex
value to tell it when the button is hideExclusion
.
FriendlyPreferenceView
FriendlyPreferenceView
is a SwiftUI view.
Users can change the value of cursor in this view.
FriendlyList
FriendlyList
is a BeFriend view.
public init(_ id: String, items: Int, visibleRows: Binding<Set<Int>>, ex: Bool = false, @ViewBuilder _ content: () -> Content)
It is quite difficult to use. And it provides two buttons for users to control the list.
Example:
@State var listVisible = Set<Int>()
FriendlyList("EventList", items: eventData.events.count + 1, visibleRows: $listVisible) {
Section {
HStack {
Label {
switch deviceState.state {
case .connect:
Text("Your AirPods is connected")
case .disconnect:
Text("Your AirPods is disconnected")
case .ignore:
Text("We ignore your motion")
case .notSupport:
Text("Your iPad or AirPods isn't support our App. Please use iPad with faceid and AirPods Pro or 3")
}
} icon: {
FriendlyStateButton()
}
Spacer()
if deviceState.state == .connect {
FriendlyButton("FriendlyPreferenceView - Button") {
FriendlySheet {
FriendlyPreferenceView()
}.present("FriendlyPreferenceView - sheet")
} label: {
Image(systemName: "gear")
}
}
}
.id(0)
.onAppear { listVisible.insert(0) }
.onDisappear { listVisible.remove(0) }
}
...
You need add id
to the listVisible
when the view appear, and delete it when the view disappear.
items
is all the items in the list.
FriendlySheet
You can use FriendlySheet
to present a sheet view.
FriendlySheet {
// your view
}.present("{eternalId}")
Dismiss View:
FriendlyDismiss().dismiss()
CommandView
CommandView is the menu view. It has a defualt command: Reset Cursor.
Friendly {
}
.commandView {
CommandGroup {
CommandItem(name: "Toggle SideBar", image: Image(systemName: "sidebar.left")) {
if isShowSiderBar {
splitViewController?.hide(.primary)
} else {
splitViewController?.show(.primary)
refresh = UUID()
}
}
CommandItem(name: "Refresh Cursor", image: Image(systemName: "circle")) {
refresh = UUID()
FriendlyManager.shared.refreshCursorData()
}
}
}
Gesture
onRight
public extension BeFriend where Self: View {
func onRight(_ action: @escaping () -> ()) -> some View {
onLeft
public extension BeFriend where Self: View {
func onLeft(_ action: @escaping () -> ()) -> some View {
Conflict
Always, there is a BeFriend view on another befriend view and Friendly don’t know cursor is on the which view.
hideExclusion
Sometimes, in the sheet view, frienly view automatically hide some view. So if you want some view is responsable, you need this.
func hideExclusion(_ when: Bool) -> FriendlyWrappedView<Self.Body>
other
There are some other solutions, but still WIP.