From 2551c0a14dfd23eefdc7a2f5a6828b9b2ed140bb Mon Sep 17 00:00:00 2001
From: david-swift
Date: Sun, 30 Jun 2024 12:08:02 +0200
Subject: [PATCH] Set up documentation
---
.github/ISSUE_TEMPLATE/component_request.yml | 29 ----
.github/PULL_REQUEST_TEMPLATE.md | 3 -
.github/workflows/docs.yml | 24 +---
Package.swift | 2 +-
README.md | 134 ++++--------------
Sources/Meta.docc/Meta.md | 18 +++
Sources/Meta.docc/theme-settings.json | 46 ++++++
Sources/Model/Data Flow/Binding.swift | 2 +-
Sources/Model/Extensions/Array.swift | 1 +
.../DefaultStringInterpolation.swift | 35 -----
Sources/Model/Extensions/String.swift | 4 +-
.../Model/User Interface/View/AnyView.swift | 2 +-
.../User Interface/View/ViewBuilder.swift | 2 +-
.../User Interface/View/ViewStorage.swift | 13 +-
.../Model/User Interface/View/Widget.swift | 5 +-
Sources/View/StateWrapper.swift | 14 +-
Sources/View/Wrapper.swift | 2 +-
Tests/DemoApp/DemoApp.swift | 5 +-
18 files changed, 122 insertions(+), 219 deletions(-)
delete mode 100644 .github/ISSUE_TEMPLATE/component_request.yml
create mode 100644 Sources/Meta.docc/Meta.md
create mode 100644 Sources/Meta.docc/theme-settings.json
delete mode 100644 Sources/Model/Extensions/DefaultStringInterpolation.swift
diff --git a/.github/ISSUE_TEMPLATE/component_request.yml b/.github/ISSUE_TEMPLATE/component_request.yml
deleted file mode 100644
index 63a6c7b..0000000
--- a/.github/ISSUE_TEMPLATE/component_request.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: Components request
-description: Suggest an idea for a new component
-title: Description of the component request
-labels: enhancement
-
-body:
- - type: textarea
- attributes:
- label: Why would you like to add a new component?
- placeholder: >-
- A clear and concise description of why the component should be added.
- validations:
- required: false
-
- - type: textarea
- attributes:
- label: Describe your idea for the implementation.
- placeholder: >-
- What could the implementation be like in Adwaita?
- validations:
- required: false
-
- - type: textarea
- attributes:
- label: Additional context
- placeholder: >-
- Add any other context about the component request here.
- validations:
- required: false
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index f0ed3f3..cce03ae 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,5 +1,4 @@
## Steps
-- [ ] Add your name or username and a link to your GitHub profile into the [Contributors.md][1] file.
- [ ] Build the project on your machine. If it does not compile, fix the errors.
- [ ] Describe the purpose and approach of your pull request below.
- [ ] Submit the pull request. Thank you very much for your contribution!
@@ -10,5 +9,3 @@ _If there is a related issue, add the link._
## Approach
_Describe how this pull request solves the problem or adds the feature._
-
-[1]: /Contributors.md
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 4390761..c7fa86d 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -3,7 +3,6 @@ name: Deploy Docs
on:
push:
branches: ["main"]
- workflow_dispatch:
permissions:
contents: read
@@ -22,31 +21,20 @@ jobs:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- - name: Install Libadwaita
- run: |
- brew update
- brew install libadwaita
- sed -i '' 's/-I..includedir.//g' $(brew --prefix)/Library/Homebrew/os/mac/pkgconfig/*/libffi.pc
- - name: Clone DocC Repo
- run: |
- git clone https://github.com/AparokshaUI/Adwaita.docc Sources/Adwaita/Adwaita.docc
- rm Sources/Adwaita/Adwaita.docc/LICENSE.md
- rm Sources/Adwaita/Adwaita.docc/README.md
- y | rm -r Sources/Adwaita/Adwaita.docc/.git
- name: Build Docs
run: |
xcrun xcodebuild docbuild \
- -scheme Adwaita \
+ -scheme Meta \
-destination 'generic/platform=macOS' \
- -derivedDataPath "$PWD/.derivedData"
+ -derivedDataPath "$PWD/.derivedData" \
+ -skipPackagePluginValidation
xcrun docc process-archive transform-for-static-hosting \
- "$PWD/.derivedData/Build/Products/Debug/Adwaita.doccarchive" \
+ "$PWD/.derivedData/Build/Products/Debug/Meta.doccarchive" \
--output-path "docs" \
- --hosting-base-path "adwaita-swift"
+ --hosting-base-path "Meta"
- name: Modify Docs
run: |
- echo "" > docs/index.html;
- sed -i '' 's/#06f/#ea3358/g' docs/css/documentation-topic~topic~tutorials-overview.d6f5411c.css
+ echo "" > docs/index.html;
sed -i '' 's/,2px/,10px/g' docs/css/index.038e887c.css
- name: Upload Artifact
uses: actions/upload-pages-artifact@v3
diff --git a/Package.swift b/Package.swift
index c40594d..f10cee9 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version: 5.10
+// swift-tools-version: 5.9
//
// Package.swift
// Meta
diff --git a/README.md b/README.md
index c77f65a..5c06f54 100644
--- a/README.md
+++ b/README.md
@@ -1,141 +1,57 @@
-
-
Adwaita for Swift
+ Meta
-
+
Documentation
·
-
+
GitHub
-_Adwaita_ is a framework for creating user interfaces for GNOME with an API similar to SwiftUI.
-
-The following code:
-
-```swift
-struct Counter: View {
-
- @State private var count = 0
-
- var view: Body {
- HStack {
- Button(icon: .default(icon: .goPrevious)) {
- count -= 1
- }
- Text("\(count)")
- .style("title-1")
- .frame(minWidth: 100)
- Button(icon: .default(icon: .goNext)) {
- count += 1
- }
- }
- }
-
-}
-```
-
-Describes a simple counter view:
-
-![Counter Example][image-1]
-
-More examples are available in the [demo app][1].
+_Meta_ is a framework allowing the creation of user interface (UI) frameworks in Swift.
## Table of Contents
-- [Goals][2]
-- [Widgets][3]
-- [Installation][4]
-- [Usage][5]
-- [Thanks][6]
+- [Overview](#overview)
+- [Usage](#usage)
+- [Thanks](#thanks)
-## Goals
+## Overview
-_Adwaita_’s main goal is to provide an easy-to-use interface for creating GNOME apps. The backend should stay as simple as possible, while not limiting the possibilities there are with [Libadwaita][7] and [GTK][8].
+_Meta_ follows the following principles:
-If you want to use _Adwaita_ in a project, but there are widgets missing, open an [issue on GitHub][9].
+- It is a **declarative** framework, meaning that instead of writing _how_ to construct a user interface, you write _what_ it looks like.
+- The user interface is treated as a function of its **state**. Instead of directly modifying the UI, modify its state to update views.
+- Multiple UI frameworks can be used in the same code, but the **selection of the framework** happens when executing the app. This enables the creation of cross-platform UI frameworks combining several UI frameworks rendering always with the same backend.
-Find more information about the project's motivation in [this blog post](https://www.swift.org/blog/adwaita-swift/).
+It knows the following layers of UI:
-## Widgets
+- An app is the entry point of the executable, containing the windows.
+- A window is a container holding one or multiple views.
+- A view is a part of the actual UI inside a window, another view or a menu.
+- A menu is a list of buttons, other menus, and views. Certain views (such as menu buttons) allow menus to be used.
-An overview of the widgets supported by _Adwaita_ is available [here](user-manual/Information/Widgets.md).
+Detailed information can be found in the [docs](https://aparokshaui.github.io/meta/).
-## Installation
-### Dependencies
-#### Flatpak
+## Usage
-It is recommended to develop apps inside of a Flatpak.
-That way, you don't have to install Swift or any of the dependencies on your system, and you always have access to the latest versions.
-Take a look at the [template repository](https://github.com/AparokshaUI/AdwaitaTemplate).
-This works on Linux only.
+_Meta_ can be used for creating UI frameworks in Swift which can then be used to create apps.
-#### Directly on System
+Follow those steps if you want to create a UI framework.
-You can also run your apps directly on the system.
-
-If you are using a Linux distribution, install `libadwaita-devel` or `libadwaita` (or something similar, based on the package manager) as well as `gtk4-devel`, `gtk4` or similar.
-
-On macOS, follow these steps:
-1. Install [Homebrew][11].
-2. Install Libadwaita (and thereby GTK 4):
-```
-brew install libadwaita
-```
-
-### Swift Package
1. Open your Swift package in GNOME Builder, Xcode, or any other IDE.
2. Open the `Package.swift` file.
3. Into the `Package` initializer, under `dependencies`, paste:
```swift
-.package(url: "https://github.com/AparokshaUI/Adwaita", from: "0.1.0")
+.package(url: "https://github.com/AparokshaUI/Meta", from: "0.1.0")
```
-## Usage
-
-I recommend using the [template repository](https://github.com/AparokshaUI/AdwaitaTemplate) as a starting point.
-
-Follow the [interactive tutorial](https://aparokshaui.github.io/adwaita-swift/tutorials/table-of-contents) or [read the docs](https://aparokshaui.github.io/adwaita-swift/documentation/adwaita) in order to get to know _Adwaita for Swift_.
-
## Thanks
-### Dependencies
-- [XMLCoder][18] licensed under the [MIT license][19]
-- [Levenshtein Transformations](https://github.com/david-swift/LevenshteinTransformations) licensed under the [MIT license](https://github.com/david-swift/LevenshteinTransformations/blob/main/LICENSE.md)
-
-### Other Thanks
-- The [contributors][20]
-- The auto-generation of widgets is based on [Swift Cross UI](https://github.com/stackotter/swift-cross-ui)
-- [SwiftLint][21] for checking whether code style conventions are violated
-- The programming language [Swift][22]
-
-[1]: Tests/
-[2]: #goals
-[3]: #widgets
-[4]: #installation
-[5]: #usage
-[6]: #thanks
-[7]: https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1-latest/index.html
-[8]: https://docs.gtk.org/gtk4/
-[9]: https://github.com/AparokshaUI/Adwaita/issues
-[10]: https://github.com/AparokshaUI/Libadwaita
-[11]: https://brew.sh
-[12]: user-manual/GettingStarted.md
-[13]: user-manual/Basics/HelloWorld.md
-[14]: user-manual/Basics/CreatingViews.md
-[15]: user-manual/Basics/Windows.md
-[16]: user-manual/Basics/KeyboardShortcuts.md
-[17]: user-manual/Advanced/CreatingWidgets.md
-[18]: https://github.com/CoreOffice/XMLCoder
-[19]: https://github.com/CoreOffice/XMLCoder/blob/main/LICENSE
-[20]: Contributors.md
-[21]: https://github.com/realm/SwiftLint
-[22]: https://github.com/apple/swift
-[23]: https://github.com/SourceDocs/SourceDocs
-
-[image-1]: Icons/Counter.png
-[image-2]: Icons/Demo.png
+- [DocC](https://github.com/apple/swift-docc) used for the documentation
+- [SwiftLint](https://github.com/realm/SwiftLint) for checking whether code style conventions are violated
+- The programming language [Swift](https://github.com/swiftlang/swift)
diff --git a/Sources/Meta.docc/Meta.md b/Sources/Meta.docc/Meta.md
new file mode 100644
index 0000000..e2d537c
--- /dev/null
+++ b/Sources/Meta.docc/Meta.md
@@ -0,0 +1,18 @@
+# ``Meta``
+
+_Meta_ is a framework allowing the creation of user interface (UI) frameworks in Swift.
+
+## Overview
+
+_Meta_ follows the following principles:
+
+- It is a **declarative** framework, meaning that instead of writing _how_ to construct a user interface, you write _what_ it looks like.
+- The user interface is treated as a function of its **state**. Instead of directly modifying the UI, modify its state to update views.
+- Multiple UI frameworks can be used in the same code, but the **selection of the framework** happens when executing the app. This enables the creation of cross-platform UI frameworks combining several UI frameworks rendering always with the same backend.
+
+It knows the following layers of UI:
+
+- An app is the entry point of the executable, containing the windows.
+- A window is a container holding one or multiple views.
+- A view is a part of the actual UI inside a window, another view or a menu.
+- A menu is a list of buttons, other menus, and views. Certain views (such as menu buttons) allow menus to be used.
diff --git a/Sources/Meta.docc/theme-settings.json b/Sources/Meta.docc/theme-settings.json
new file mode 100644
index 0000000..ccd8a86
--- /dev/null
+++ b/Sources/Meta.docc/theme-settings.json
@@ -0,0 +1,46 @@
+{
+ "theme": {
+ "border-radius": "10px",
+ "button": {
+ "border-radius": "20px"
+ },
+ "color": {
+ "button-background": "#ea3358",
+ "button-background-active": "#ea3358",
+ "button-background-hover": "#fc557a",
+ "button-text": "#ffffff",
+ "header": "#7f313b",
+ "documentation-intro-accent": "var(--color-header)",
+ "documentation-intro-fill": "radial-gradient(circle at top, var(--color-header) 30%, #000 100%)",
+ "link": "#ea3358",
+ "nav-link-color": "#ea3358",
+ "nav-dark-link-color": "#ea3358",
+ "tutorials-overview-link": "#fb4469",
+ "step-background": {
+ "light": "#fffaff",
+ "dark": "#302c2d"
+ },
+ "step-focused": "#ea3358",
+ "tabnav-item-border-color": "#ea3358",
+ "tutorial-background": {
+ "light": "",
+ "dark": "#1d1d1f"
+ },
+ "tutorials-overview-background": "linear-gradient(180deg, rgba(43,20,23,1) 0%, rgba(41, 3, 8, 0.808) 60%, rgba(0,0,0,1) 100%)",
+ "fill-light-blue-secondary": "#ea3358",
+ "fill-blue": "#ea3358",
+ "figure-blue": "#ea3358",
+ "standard-blue-documentation-intro-fill": "#ea3358",
+ "figure-blue": "#ea3358",
+ "tutorial-hero-background": "#100a0b",
+ "navigator-item-hover": {
+ "light": "#ea335815",
+ "dark": "#7f313b"
+ }
+ },
+ "additionalProperties": "#ea3358",
+ "tutorial-step": {
+ "border-radius": "15px"
+ }
+ }
+}
diff --git a/Sources/Model/Data Flow/Binding.swift b/Sources/Model/Data Flow/Binding.swift
index c8e2501..d0bd0d4 100644
--- a/Sources/Model/Data Flow/Binding.swift
+++ b/Sources/Model/Data Flow/Binding.swift
@@ -71,7 +71,7 @@ public struct Binding {
private var handlers: [(Value) -> Void] = []
/// Get a property of any content of a `Binding` as a `Binding`.
- /// - Parameter dynamicMember: The path to the member.
+ /// - Parameter keyPath: The path to the member.
/// - Returns: The binding.
public subscript(dynamicMember keyPath: WritableKeyPath) -> Binding {
.init {
diff --git a/Sources/Model/Extensions/Array.swift b/Sources/Model/Extensions/Array.swift
index c82c2f5..8c4b11a 100644
--- a/Sources/Model/Extensions/Array.swift
+++ b/Sources/Model/Extensions/Array.swift
@@ -54,6 +54,7 @@ extension Array: AnyView where Element == AnyView {
/// - Parameters:
/// - modifiers: Modify views before generating the storages.
/// - type: The type of the widgets.
+ /// - Returns: The storages.
public func storages(
modifiers: [(AnyView) -> AnyView],
type: WidgetType.Type
diff --git a/Sources/Model/Extensions/DefaultStringInterpolation.swift b/Sources/Model/Extensions/DefaultStringInterpolation.swift
deleted file mode 100644
index 0ff371e..0000000
--- a/Sources/Model/Extensions/DefaultStringInterpolation.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// DefaultStringInterpolation.swift
-// Meta
-//
-// Created by david-swift on 26.05.24.
-//
-// Thanks to Eneko Alonso, Pyry Jahkola, cukr for the comments in this Swift forum discussion:
-// "Multi-line string nested indentation with interpolation"
-// https://forums.swift.org/t/multi-line-string-nested-indentation-with-interpolation/36933
-//
-
-extension DefaultStringInterpolation {
-
- /// Preserve the indentation in a multi line string.
- /// - Parameter string: The string.
- ///
- /// Use it the following way:
- /// """
- /// Hello
- /// \(indented: "World\n Test")
- /// """
- public mutating func appendInterpolation(indented string: String) {
- // swiftlint:disable compiler_protocol_init
- let indent = String(stringInterpolation: self).reversed().prefix { " \t".contains($0) }
- // swiftlint:enable compiler_protocol_init
- if indent.isEmpty {
- appendInterpolation(string)
- } else {
- appendLiteral(
- string.split(separator: "\n", omittingEmptySubsequences: false).joined(separator: "\n" + indent)
- )
- }
- }
-
-}
diff --git a/Sources/Model/Extensions/String.swift b/Sources/Model/Extensions/String.swift
index 80986c5..7b0b9f2 100644
--- a/Sources/Model/Extensions/String.swift
+++ b/Sources/Model/Extensions/String.swift
@@ -7,7 +7,7 @@
extension String {
- /// A label for main content in a view storage.
- static var mainContent: Self { "main" }
+ /// An identifier for main content in a view storage.
+ public static var mainContent: Self { "main" }
}
diff --git a/Sources/Model/User Interface/View/AnyView.swift b/Sources/Model/User Interface/View/AnyView.swift
index fb4f3c8..3be5ccb 100644
--- a/Sources/Model/User Interface/View/AnyView.swift
+++ b/Sources/Model/User Interface/View/AnyView.swift
@@ -51,7 +51,7 @@ extension AnyView {
/// Wrap the view into a widget.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The widget.
- public func widget(modifiers: [(AnyView) -> AnyView]) -> Widget {
+ func widget(modifiers: [(AnyView) -> AnyView]) -> Widget {
let modified = getModified(modifiers: modifiers)
if let peer = modified as? Widget {
return peer
diff --git a/Sources/Model/User Interface/View/ViewBuilder.swift b/Sources/Model/User Interface/View/ViewBuilder.swift
index bfb5c9c..54fdae4 100644
--- a/Sources/Model/User Interface/View/ViewBuilder.swift
+++ b/Sources/Model/User Interface/View/ViewBuilder.swift
@@ -11,7 +11,7 @@ import Foundation
@resultBuilder
public enum ViewBuilder {
- /// A component used in the ``ArrayBuilder``.
+ /// A component used in the ``ViewBuilder``.
public enum Component {
/// A view as a component.
diff --git a/Sources/Model/User Interface/View/ViewStorage.swift b/Sources/Model/User Interface/View/ViewStorage.swift
index db80fe9..d24152e 100644
--- a/Sources/Model/User Interface/View/ViewStorage.swift
+++ b/Sources/Model/User Interface/View/ViewStorage.swift
@@ -5,19 +5,22 @@
// Created by david-swift on 26.05.24.
//
-/// Store a rendered view in a view storage.
+/// Store a reference to a rendered view in a view storage.
public class ViewStorage {
/// The pointer.
+ ///
+ /// It can be a C pointer, a Swift class, or other information depending on the backend.
+ /// Some convenience widgets do not need a pointer to a native framework at all.
public var pointer: Any?
- /// The view's content.
+ /// The view's content for container widgets.
public var content: [String: [ViewStorage]]
/// The view's state (used in `StateWrapper`).
var state: [String: StateProtocol] = [:]
- /// Other properties.
+ /// Various properties of a widget.
public var fields: [String: Any] = [:]
- /// The pointer as an opaque pointer.
+ /// The pointer as an opaque pointer, as this is needed with backends interoperating with C or C++.
public var opaquePointer: OpaquePointer? {
get {
pointer as? OpaquePointer
@@ -30,7 +33,7 @@ public class ViewStorage {
/// Initialize a view storage.
/// - Parameters:
/// - pointer: The pointer to the widget, its type depends on the backend.
- /// - content: The view's content.
+ /// - content: The view's content for container widgets.
public init(
_ pointer: Any?,
content: [String: [ViewStorage]] = [:]
diff --git a/Sources/Model/User Interface/View/Widget.swift b/Sources/Model/User Interface/View/Widget.swift
index 947510f..300064b 100644
--- a/Sources/Model/User Interface/View/Widget.swift
+++ b/Sources/Model/User Interface/View/Widget.swift
@@ -5,7 +5,10 @@
// Created by david-swift on 26.05.24.
//
-/// A widget is a view that know about its GTUI widget.
+/// A widget is a view that know about its native backend widget.
+///
+/// It enables the translation from the declarative definition to the creation
+/// and updating of widgets in an imperative way.
public protocol Widget: AnyView {
/// The view storage.
diff --git a/Sources/View/StateWrapper.swift b/Sources/View/StateWrapper.swift
index 45eda1f..89f9b47 100644
--- a/Sources/View/StateWrapper.swift
+++ b/Sources/View/StateWrapper.swift
@@ -8,19 +8,16 @@
import Observation
/// A storage for `@State` properties.
-public struct StateWrapper: ConvenienceWidget {
+struct StateWrapper: ConvenienceWidget {
/// The content.
var content: () -> Body
/// The state information (from properties with the `State` wrapper).
var state: [String: StateProtocol] = [:]
- /// The identifier of the field storing whether to update the wrapper's content.
- private var updateID: String { "update" }
-
/// Initialize a `StateWrapper`.
/// - Parameter content: The view content.
- public init(@ViewBuilder content: @escaping () -> Body) {
+ init(@ViewBuilder content: @escaping () -> Body) {
self.content = content
}
@@ -39,14 +36,13 @@ public struct StateWrapper: ConvenienceWidget {
/// - modifiers: Modify views before being updated.
/// - updateProperties: Whether to update properties.
/// - type: The type of the widgets.
- public func update(
+ func update(
_ storage: ViewStorage,
modifiers: [(AnyView) -> AnyView],
updateProperties: Bool,
type: WidgetType.Type
) {
- var updateProperties = updateProperties ? true : (storage.fields[updateID] as? Bool ?? false)
- storage.fields[updateID] = false
+ var updateProperties = updateProperties
for property in state {
if let oldID = storage.state[property.key]?.id {
StateManager.changeID(old: oldID, new: property.value.id)
@@ -68,7 +64,7 @@ public struct StateWrapper: ConvenienceWidget {
/// - modifiers: Modify views before being updated.
/// - type: The type of the widgets.
/// - Returns: The view storage.
- public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
+ func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
let content = content().storages(modifiers: modifiers, type: type)
let storage = ViewStorage(nil, content: [.mainContent: content])
storage.state = state
diff --git a/Sources/View/Wrapper.swift b/Sources/View/Wrapper.swift
index 77a3568..fa00877 100644
--- a/Sources/View/Wrapper.swift
+++ b/Sources/View/Wrapper.swift
@@ -5,7 +5,7 @@
// Created by david-swift on 27.05.24.
//
-/// Wrap a view into a single widget.
+/// Wrap a body into a single widget.
public struct Wrapper: ConvenienceWidget {
/// The content.
diff --git a/Tests/DemoApp/DemoApp.swift b/Tests/DemoApp/DemoApp.swift
index f41e7c6..993459a 100644
--- a/Tests/DemoApp/DemoApp.swift
+++ b/Tests/DemoApp/DemoApp.swift
@@ -65,12 +65,11 @@ struct DemoApp {
DemoView().updateStorage(storage, modifiers: [], updateProperties: true, type: backendType)
}
- StateManager.addUpdateHandler { _ in
- DemoView().updateStorage(storage, modifiers: [], updateProperties: false, type: backendType)
+ StateManager.addUpdateHandler { force in
+ DemoView().updateStorage(storage, modifiers: [], updateProperties: force, type: backendType)
}
sleep(2)
- DemoView().updateStorage(storage, modifiers: [], updateProperties: true, type: backendType)
}
}