From 96806cd1305b337e7f4d5dc992a859fde6de00f6 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Sun, 30 Jun 2024 14:36:21 +0400
Subject: [PATCH 1/7] Initial commit
---
.github/ISSUE_TEMPLATE/bug_report.md | 41 ++++++
.github/ISSUE_TEMPLATE/feature_request.md | 11 ++
.github/PULL_REQUEST_TEMPLATE/bug_template.md | 9 ++
.../PULL_REQUEST_TEMPLATE/feature_template.md | 12 ++
.github/dependabot.yml | 34 +++++
.github/workflows/ci.yml | 126 ++++++++++++++++
.github/workflows/danger.yml | 31 ++++
.swiftformat | 64 ++++++++
.swiftlint.yml | 138 ++++++++++++++++++
.../contents.xcworkspacedata | 7 +
CHANGELOG.md | 2 +
CODE_OF_CONDUCT.md | 74 ++++++++++
CONTRIBUTING.md | 61 ++++++++
Dangerfile | 1 +
Gemfile | 3 +
Makefile | 19 +++
Mintfile | 2 +
Package.swift | 16 ++
Package@swift-5.7.swift | 16 ++
Package@swift-5.8.swift | 16 ++
Package@swift-5.9.swift | 16 ++
README.md | 59 +++++++-
SEQURITY.md | 7 +
.../Classes/OverlayContainer.swift | 6 +
.../OverlayContainerTests.swift | 8 +
hooks/pre-commit | 38 +++++
26 files changed, 816 insertions(+), 1 deletion(-)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
create mode 100644 .github/PULL_REQUEST_TEMPLATE/bug_template.md
create mode 100644 .github/PULL_REQUEST_TEMPLATE/feature_template.md
create mode 100644 .github/dependabot.yml
create mode 100644 .github/workflows/ci.yml
create mode 100644 .github/workflows/danger.yml
create mode 100644 .swiftformat
create mode 100644 .swiftlint.yml
create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
create mode 100644 CHANGELOG.md
create mode 100644 CODE_OF_CONDUCT.md
create mode 100644 CONTRIBUTING.md
create mode 100644 Dangerfile
create mode 100644 Gemfile
create mode 100644 Makefile
create mode 100644 Mintfile
create mode 100644 Package.swift
create mode 100644 Package@swift-5.7.swift
create mode 100644 Package@swift-5.8.swift
create mode 100644 Package@swift-5.9.swift
create mode 100644 SEQURITY.md
create mode 100644 Sources/OverlayContainer/Classes/OverlayContainer.swift
create mode 100644 Tests/OverlayContainerTests/OverlayContainerTests.swift
create mode 100755 hooks/pre-commit
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..8dc7e75
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,41 @@
+---
+name: "🐛 Bug Report"
+about: Report a reproducible bug or regression.
+title: 'Bug: '
+labels: 'bug'
+
+---
+
+
+
+Application version:
+
+## Steps To Reproduce
+
+1.
+2.
+
+
+
+Link to code example:
+
+
+
+## The current behavior
+
+
+## The expected behavior
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..6168df4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,11 @@
+---
+name: 🛠 Feature request
+about: If you have a feature request for the overlay-container, file it here.
+labels: 'type: enhancement'
+---
+
+**Feature description**
+Clearly and concisely describe the feature.
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
\ No newline at end of file
diff --git a/.github/PULL_REQUEST_TEMPLATE/bug_template.md b/.github/PULL_REQUEST_TEMPLATE/bug_template.md
new file mode 100644
index 0000000..7d6a149
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/bug_template.md
@@ -0,0 +1,9 @@
+## Bug description
+Clearly and concisely describe the problem.
+
+## Solution description
+Describe your code changes in detail for reviewers. Explain the technical solution you have provided and how it fixes the issue case.
+
+## Covered unit test cases
+- [x] yes
+- [x] no
\ No newline at end of file
diff --git a/.github/PULL_REQUEST_TEMPLATE/feature_template.md b/.github/PULL_REQUEST_TEMPLATE/feature_template.md
new file mode 100644
index 0000000..ab3978b
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/feature_template.md
@@ -0,0 +1,12 @@
+## Feature description
+Clearly and concisely describe the feature.
+
+## Solution description
+Describe your code changes in detail for reviewers.
+
+## Areas affected and ensured
+List out the areas affected by your code changes.
+
+## Covered unit test cases
+- [x] yes
+- [x] no
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..c3e658c
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,34 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ open-pull-requests-limit: 10
+ schedule:
+ interval: daily
+ time: '07:00'
+ timezone: Europe/Berlin
+
+ assignees:
+ - nik3212
+ reviewers:
+ - nik3212
+
+
+ - package-ecosystem: swift
+ directory: /
+ open-pull-requests-limit: 10
+ schedule:
+ interval: daily
+ time: '07:00'
+ timezone: Europe/Berlin
+
+ assignees:
+ - nik3212
+ reviewers:
+ - nik3212
+
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..fd45e5e
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,126 @@
+name: "overlay-container"
+
+on:
+ push:
+ branches:
+ - main
+ - dev
+ pull_request:
+ paths:
+ - '.swiftlint.yml'
+ - ".github/workflows/**"
+ - "Package.swift"
+ - "Source/**"
+ - "Tests/**"
+
+jobs:
+ SwiftLint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: GitHub Action for SwiftLint
+ uses: norio-nomura/action-swiftlint@3.2.1
+ with:
+ args: --strict
+ env:
+
+ DIFF_BASE: ${{ github.base_ref }}
+
+
+
+
+
+ iOS:
+
+ name: ${{ matrix.name }}
+ runs-on: ${{ matrix.runsOn }}
+
+ env:
+
+ DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
+
+ timeout-minutes: 20
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - destination: "OS=17.0.1,name=iPhone 14 Pro"
+ name: "iOS 17.0.1"
+ xcode: "Xcode_15.0"
+ runsOn: macos-13
+ - destination: "OS=16.4,name=iPhone 14 Pro"
+ name: "iOS 16.4"
+ xcode: "Xcode_14.3.1"
+ runsOn: macos-13
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: ${{ matrix.name }}
+ run: xcodebuild test -scheme "{{ cookiecutter.name }}" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
+
+ - uses: actions/upload-artifact@v4
+ with:
+
+ name: ${{ matrix.name }}
+ path: test_output
+
+
+
+
+
+
+
+ spm:
+
+ name: ${{ matrix.name }}
+ runs-on: ${{ matrix.runsOn }}
+
+ env:
+
+ DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
+
+ timeout-minutes: 20
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: "Xcode 15"
+ xcode: "Xcode_15.0"
+ runsOn: macos-13
+ - name: "Xcode 14"
+ xcode: "Xcode_14.3.1"
+ runsOn: macos-13
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: ${{ matrix.name }}
+ run: swift build -c release --target "{{ cookiecutter.name }}"
+
+ merge-test-reports:
+ needs: [iOS, macOS, watchOS, tvOS]
+ runs-on: macos-13
+ steps:
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: test_output
+ - run: xcrun xcresulttool merge test_output/**/*.xcresult --output-path test_output/final/final.xcresult
+ - name: Upload Merged Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: MergedResult
+ path: test_output/final
+
+ discover-typos:
+ name: Discover Typos
+ runs-on: macOS-12
+ env:
+ DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
+ steps:
+ - uses: actions/checkout@v2
+ - name: Discover typos
+ run: |
+ export PATH="$PATH:/Library/Frameworks/Python.framework/Versions/3.11/bin"
+ python3 -m pip install --upgrade pip
+ python3 -m pip install codespell
+ codespell --ignore-words-list="hart,inout,msdos,sur" --skip="./.build/*,./.git/*"
diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
new file mode 100644
index 0000000..3f63d38
--- /dev/null
+++ b/.github/workflows/danger.yml
@@ -0,0 +1,31 @@
+name: Danger
+
+on:
+ pull_request:
+ types: [synchronize, opened, reopened, labeled, unlabeled, edited]
+
+env:
+ LC_CTYPE: en_US.UTF-8
+ LANG: en_US.UTF-8
+
+jobs:
+ run-danger:
+ runs-on: ubuntu-latest
+ steps:
+ - name: ruby setup
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.1.4
+ bundler-cache: true
+ - name: Checkout code
+ uses: actions/checkout@v2
+ - name: Setup gems
+ run: |
+ gem install bundler
+ bundle install --clean --path vendor/bundle
+ - name: danger
+ env:
+
+ DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
+
+ run: bundle exec danger --verbose
\ No newline at end of file
diff --git a/.swiftformat b/.swiftformat
new file mode 100644
index 0000000..ba65f63
--- /dev/null
+++ b/.swiftformat
@@ -0,0 +1,64 @@
+# Stream rules
+
+--swiftversion 5.3
+
+# Use 'swiftformat --options' to list all of the possible options
+
+--header "\noverlay-container\nCopyright © {created.year} Space Code. All rights reserved.\n//"
+
+--enable blankLinesBetweenScopes
+--enable blankLinesAtStartOfScope
+--enable blankLinesAtEndOfScope
+--enable blankLinesAroundMark
+--enable anyObjectProtocol
+--enable consecutiveBlankLines
+--enable consecutiveSpaces
+--enable duplicateImports
+--enable elseOnSameLine
+--enable emptyBraces
+--enable initCoderUnavailable
+--enable leadingDelimiters
+--enable numberFormatting
+--enable preferKeyPath
+--enable redundantBreak
+--enable redundantExtensionACL
+--enable redundantFileprivate
+--enable redundantGet
+--enable redundantInit
+--enable redundantLet
+--enable redundantLetError
+--enable redundantNilInit
+--enable redundantObjc
+--enable redundantParens
+--enable redundantPattern
+--enable redundantRawValues
+--enable redundantReturn
+--enable redundantSelf
+--enable redundantVoidReturnType
+--enable semicolons
+--enable sortImports
+--enable sortSwitchCases
+--enable spaceAroundBraces
+--enable spaceAroundBrackets
+--enable spaceAroundComments
+--enable spaceAroundGenerics
+--enable spaceAroundOperators
+--enable spaceInsideBraces
+--enable spaceInsideBrackets
+--enable spaceInsideComments
+--enable spaceInsideGenerics
+--enable spaceInsideParens
+--enable strongOutlets
+--enable strongifiedSelf
+--enable todos
+--enable trailingClosures
+--enable unusedArguments
+--enable void
+--enable markTypes
+--enable isEmpty
+
+# format options
+
+--wraparguments before-first
+--wrapcollections before-first
+--maxwidth 140
\ No newline at end of file
diff --git a/.swiftlint.yml b/.swiftlint.yml
new file mode 100644
index 0000000..969b766
--- /dev/null
+++ b/.swiftlint.yml
@@ -0,0 +1,138 @@
+excluded:
+ - Tests
+ - Package.swift
+ - Package@swift-5.7.swift
+ - Package@swift-5.8.swift
+ - Package@swift-5.9.swift
+ - .build
+
+# Rules
+
+disabled_rules:
+ - trailing_comma
+ - todo
+ - opening_brace
+
+opt_in_rules: # some rules are only opt-in
+ - anyobject_protocol
+ - array_init
+ - attributes
+ - closure_body_length
+ - closure_end_indentation
+ - closure_spacing
+ - collection_alignment
+ - conditional_returns_on_newline
+ - contains_over_filter_count
+ - contains_over_filter_is_empty
+ - contains_over_first_not_nil
+ - contains_over_range_nil_comparison
+ - convenience_type
+ - discouraged_object_literal
+ - discouraged_optional_boolean
+ - empty_collection_literal
+ - empty_count
+ - empty_string
+ - empty_xctest_method
+ - enum_case_associated_values_count
+ - explicit_init
+ - fallthrough
+ - fatal_error_message
+ - file_name
+ - file_types_order
+ - first_where
+ - flatmap_over_map_reduce
+ - force_unwrapping
+ - ibinspectable_in_extension
+ - identical_operands
+ - implicit_return
+ - inert_defer
+ - joined_default_parameter
+ - last_where
+ - legacy_multiple
+ - legacy_random
+ - literal_expression_end_indentation
+ - lower_acl_than_parent
+ - multiline_arguments
+ - multiline_function_chains
+ - multiline_literal_brackets
+ - multiline_parameters
+ - multiline_parameters_brackets
+ - no_space_in_method_call
+ - operator_usage_whitespace
+ - optional_enum_case_matching
+ - orphaned_doc_comment
+ - overridden_super_call
+ - override_in_extension
+ - pattern_matching_keywords
+ - prefer_self_type_over_type_of_self
+ - prefer_zero_over_explicit_init
+ - prefixed_toplevel_constant
+ - private_action
+ - prohibited_super_call
+ - quick_discouraged_call
+ - quick_discouraged_focused_test
+ - quick_discouraged_pending_test
+ - reduce_into
+ - redundant_nil_coalescing
+ - redundant_objc_attribute
+ - redundant_type_annotation
+ - required_enum_case
+ - single_test_class
+ - sorted_first_last
+ - sorted_imports
+ - static_operator
+ - strict_fileprivate
+ - switch_case_on_newline
+ - toggle_bool
+ - unavailable_function
+ - unneeded_parentheses_in_closure_argument
+ - unowned_variable_capture
+ - untyped_error_in_catch
+ - vertical_parameter_alignment_on_call
+ - vertical_whitespace_closing_braces
+ - vertical_whitespace_opening_braces
+ - xct_specific_matcher
+ - yoda_condition
+
+force_cast: warning
+force_try: warning
+
+identifier_name:
+ excluded:
+ - id
+ - URL
+
+analyzer_rules:
+ - unused_import
+ - unused_declaration
+
+line_length:
+ warning: 130
+ error: 200
+
+type_body_length:
+ warning: 300
+ error: 400
+
+file_length:
+ warning: 500
+ error: 1200
+
+function_body_length:
+ warning: 30
+ error: 50
+
+large_tuple:
+ error: 3
+
+nesting:
+ type_level:
+ warning: 2
+ statement_level:
+ warning: 10
+
+
+type_name:
+ max_length:
+ warning: 40
+ error: 50
\ No newline at end of file
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..2e9885a
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,2 @@
+# Change Log
+All notable changes to this project will be documented in this file.
\ No newline at end of file
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..56c1661
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,74 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting one of the project maintainers https://github.com/orgs/space-code/people. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..f96b11f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,61 @@
+# Contributing Guidelines
+
+This document contains information and guidelines about contributing to this project.
+Please read it before you start participating.
+
+**Topics**
+
+* [Reporting Issues](#reporting-issues)
+* [Submitting Pull Requests](#submitting-pull-requests)
+* [Developers Certificate of Origin](#developers-certificate-of-origin)
+* [Code of Conduct](#code-of-conduct)
+
+## Reporting Issues
+
+A great way to contribute to the project is to send a detailed issue when you encounter a problem. We always appreciate a well-written, thorough bug report.
+
+Check that the project issues database doesn't already include that problem or suggestion before submitting an issue. If you find a match, feel free to vote for the issue by adding a reaction. Doing this helps prioritize the most common problems and requests.
+
+When reporting issues, please fill out our issue template. The information the template asks for will help us review and fix your issue faster.
+
+## Submitting Pull Requests
+
+You can contribute by fixing bugs or adding new features. For larger code changes, we recommend first discussing your ideas on our [GitHub Discussions](https://github.com/space-code/overlay-container/discussions). When submitting a pull request, please add relevant tests and ensure your changes don't break any existing tests.
+
+## Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+- (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+- (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+- (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+- (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+## Code of Conduct
+
+The Code of Conduct governs how we behave in public or in private
+whenever the project will be judged by our actions.
+We expect it to be honored by everyone who contributes to this project.
+
+See [CODE_OF_CONDUCT.md](https://github.com/space-code/overlay-container/blob/master/CODE_OF_CONDUCT.md) for details.
+
+---
+
+*Some of the ideas and wording for the statements above were based on work by the [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) and [Linux](https://elinux.org/Developer_Certificate_Of_Origin) communities. We commend them for their efforts to facilitate collaboration in their projects.*
\ No newline at end of file
diff --git a/Dangerfile b/Dangerfile
new file mode 100644
index 0000000..b266982
--- /dev/null
+++ b/Dangerfile
@@ -0,0 +1 @@
+danger.import_dangerfile(github: 'space-code/dangerfile')
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..20dff64
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem 'danger'
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..de1897f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+all: bootstrap
+
+bootstrap: hook
+ mint bootstrap
+
+hook:
+ ln -sf ../../hooks/pre-commit .git/hooks/pre-commit
+ chmod +x .git/hooks/pre-commit
+
+mint:
+ mint bootstrap
+
+lint:
+ mint run swiftlint
+
+fmt:
+ mint run swiftformat Sources Tests
+
+.PHONY: all bootstrap hook mint lint fmt
diff --git a/Mintfile b/Mintfile
new file mode 100644
index 0000000..e2cdefa
--- /dev/null
+++ b/Mintfile
@@ -0,0 +1,2 @@
+nicklockwood/SwiftFormat@0.52.7
+realm/SwiftLint@0.53.0
\ No newline at end of file
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..a513efa
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,16 @@
+// swift-tools-version: 5.10
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "overlay-container",
+ platforms: [.iOS(.v12)],
+ products: [
+ .library(name: "OverlayContainer", targets: ["OverlayContainer"]),
+ ],
+ targets: [
+ .target(name: "OverlayContainer"),
+ .testTarget(name: "OverlayContainerTests", dependencies: ["OverlayContainer"]),
+ ]
+)
diff --git a/Package@swift-5.7.swift b/Package@swift-5.7.swift
new file mode 100644
index 0000000..3062d29
--- /dev/null
+++ b/Package@swift-5.7.swift
@@ -0,0 +1,16 @@
+// swift-tools-version: 5.7
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "overlay-container",
+ platforms: [.iOS(.v12)],
+ products: [
+ .library(name: "OverlayContainer", targets: ["OverlayContainer"]),
+ ],
+ targets: [
+ .target(name: "OverlayContainer"),
+ .testTarget(name: "OverlayContainerTests", dependencies: ["OverlayContainer"]),
+ ]
+)
diff --git a/Package@swift-5.8.swift b/Package@swift-5.8.swift
new file mode 100644
index 0000000..48c09c9
--- /dev/null
+++ b/Package@swift-5.8.swift
@@ -0,0 +1,16 @@
+// swift-tools-version: 5.8
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "overlay-container",
+ platforms: [.iOS(.v12)],
+ products: [
+ .library(name: "OverlayContainer", targets: ["OverlayContainer"]),
+ ],
+ targets: [
+ .target(name: "OverlayContainer"),
+ .testTarget(name: "OverlayContainerTests", dependencies: ["OverlayContainer"]),
+ ]
+)
diff --git a/Package@swift-5.9.swift b/Package@swift-5.9.swift
new file mode 100644
index 0000000..b8b4ffb
--- /dev/null
+++ b/Package@swift-5.9.swift
@@ -0,0 +1,16 @@
+// swift-tools-version: 5.9
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "overlay-container",
+ platforms: [.iOS(.v12)],
+ products: [
+ .library(name: "OverlayContainer", targets: ["OverlayContainer"]),
+ ],
+ targets: [
+ .target(name: "OverlayContainer"),
+ .testTarget(name: "OverlayContainerTests", dependencies: ["OverlayContainer"]),
+ ]
+)
diff --git a/README.md b/README.md
index a78c898..76e0486 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,58 @@
-# overlay-container
\ No newline at end of file
+overlay-container
+
+
+
+
+
+
+
+
+
+
+## Description
+`overlay-container` description.
+
+- [Usage](#usage)
+- [Requirements](#requirements)
+- [Installation](#installation)
+- [Communication](#communication)
+- [Contributing](#contributing)
+- [Author](#author)
+- [License](#license)
+
+## Usage
+
+## Requirements
+
+## Installation
+### Swift Package Manager
+
+The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. It is in early development, but `overlay-container` does support its use on supported platforms.
+
+Once you have your Swift package set up, adding `overlay-container` as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
+
+```swift
+dependencies: [
+ .package(url: "https://github.com/space-code/overlay-container.git", .upToNextMajor(from: "1.0.0"))
+]
+```
+
+## Communication
+- If you **found a bug**, open an issue.
+- If you **have a feature request**, open an issue.
+- If you **want to contribute**, submit a pull request.
+
+## Contributing
+Bootstrapping development environment
+
+```
+make bootstrap
+```
+
+Please feel free to help out with this project! If you see something that could be made better or want a new feature, open up an issue or send a Pull Request!
+
+## Author
+Nikita Vasilev, nv3212@gmail.com
+
+## License
+overlay-container is available under the MIT license. See the LICENSE file for more info.
\ No newline at end of file
diff --git a/SEQURITY.md b/SEQURITY.md
new file mode 100644
index 0000000..20dffca
--- /dev/null
+++ b/SEQURITY.md
@@ -0,0 +1,7 @@
+# Reporting Security Vulnerabilities
+
+This software is built with security and data privacy in mind to ensure your data is safe. We are grateful for security researchers and users reporting a vulnerability to us, first. To ensure that your request is handled in a timely manner and non-disclosure of vulnerabilities can be assured, please follow the below guideline.
+
+**Please do not report security vulnerabilities directly on GitHub. GitHub Issues can be publicly seen and therefore would result in a direct disclosure.**
+
+* Please address questions about data privacy, security concepts, and other media requests to the nv3212@gmail.com mailbox.
\ No newline at end of file
diff --git a/Sources/OverlayContainer/Classes/OverlayContainer.swift b/Sources/OverlayContainer/Classes/OverlayContainer.swift
new file mode 100644
index 0000000..1e8bb90
--- /dev/null
+++ b/Sources/OverlayContainer/Classes/OverlayContainer.swift
@@ -0,0 +1,6 @@
+//
+// overlay-container
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+final class OverlayContainer {}
diff --git a/Tests/OverlayContainerTests/OverlayContainerTests.swift b/Tests/OverlayContainerTests/OverlayContainerTests.swift
new file mode 100644
index 0000000..0b39cc1
--- /dev/null
+++ b/Tests/OverlayContainerTests/OverlayContainerTests.swift
@@ -0,0 +1,8 @@
+//
+// overlay-container
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import XCTest
+
+final class OverlayContainerTests: XCTestCase {}
diff --git a/hooks/pre-commit b/hooks/pre-commit
new file mode 100755
index 0000000..956fdcb
--- /dev/null
+++ b/hooks/pre-commit
@@ -0,0 +1,38 @@
+#!/bin/bash
+git diff --diff-filter=d --staged --name-only | grep -e '\.swift$' | while read line; do
+ if [[ $line == *"/Generated"* ]]; then
+ echo "IGNORING GENERATED FILE: " "$line";
+ else
+ mint run swiftformat swiftformat "${line}";
+ git add "$line";
+ fi
+done
+
+LINT=$(which mint)
+if [[ -e "${LINT}" ]]; then
+ # Export files in SCRIPT_INPUT_FILE_$count to lint against later
+ count=0
+ while IFS= read -r file_path; do
+ export SCRIPT_INPUT_FILE_$count="$file_path"
+ count=$((count + 1))
+ done < <(git diff --name-only --cached --diff-filter=d | grep ".swift$")
+ export SCRIPT_INPUT_FILE_COUNT=$count
+
+ if [ "$count" -eq 0 ]; then
+ echo "No files to lint!"
+ exit 0
+ fi
+
+ echo "Found $count lintable files! Linting now.."
+ mint run swiftlint --use-script-input-files --strict --config .swiftlint.yml
+ RESULT=$? # swiftline exit value is number of errors
+
+ if [ $RESULT -eq 0 ]; then
+ echo "🎉 Well done. No violation."
+ fi
+ exit $RESULT
+else
+ echo "⚠️ WARNING: SwiftLint not found"
+ echo "⚠️ You might want to edit .git/hooks/pre-commit to locate your swiftlint"
+ exit 0
+fi
\ No newline at end of file
From e84e0e972ae5f30f95b27d9f81a27e473298ce3d Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Sun, 30 Jun 2024 20:00:01 +0400
Subject: [PATCH 2/7] Implement bottom sheet view
---
.swiftlint.yml | 3 +-
.../Classes/Core/Model/Configuration.swift | 46 ++++
.../Classes/OverlayContainer.swift | 158 +++++++++++-
.../BottomSheetAnimatedTransition.swift | 99 ++++++++
.../BottomSheetAnimatedTransitionDriver.swift | 83 ++++++
.../BottomSheetPresentationController.swift | 237 ++++++++++++++++++
.../Classes/Presentation/GrabberView.swift | 92 +++++++
7 files changed, 715 insertions(+), 3 deletions(-)
create mode 100644 Sources/OverlayContainer/Classes/Core/Model/Configuration.swift
create mode 100644 Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransition.swift
create mode 100644 Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransitionDriver.swift
create mode 100644 Sources/OverlayContainer/Classes/Presentation/BottomSheetPresentationController.swift
create mode 100644 Sources/OverlayContainer/Classes/Presentation/GrabberView.swift
diff --git a/.swiftlint.yml b/.swiftlint.yml
index 969b766..88a1ebe 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -21,7 +21,6 @@ opt_in_rules: # some rules are only opt-in
- closure_end_indentation
- closure_spacing
- collection_alignment
- - conditional_returns_on_newline
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
@@ -135,4 +134,4 @@ nesting:
type_name:
max_length:
warning: 40
- error: 50
\ No newline at end of file
+ error: 50
diff --git a/Sources/OverlayContainer/Classes/Core/Model/Configuration.swift b/Sources/OverlayContainer/Classes/Core/Model/Configuration.swift
new file mode 100644
index 0000000..59577f1
--- /dev/null
+++ b/Sources/OverlayContainer/Classes/Core/Model/Configuration.swift
@@ -0,0 +1,46 @@
+//
+// overlay-container
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import UIKit
+
+/// A struct to configure the appearance and behavior of a UI component.
+public struct Configuration {
+ // MARK: Properties
+
+ /// The dimming color for the component.
+ public let dimmingColor: UIColor
+ /// The background color of the component.
+ public let backgroundColor: UIColor
+ /// The duration of the animation for the component.
+ public let animationDuration: TimeInterval
+ /// The corner radius of the component.
+ public let cornerRadius: CGFloat
+ /// The color of the grabber pin view.
+ public let grabberColor: UIColor
+
+ // MARK: Initialization
+
+ /// Initializes a new `Configuration` instance with specified properties.
+ ///
+ /// - Parameters:
+ /// - dimmingColor: The dimming color for the component.
+ /// - backgroundColor: The background color of the component.
+ /// - animationDuration: The duration of the animation for the component.
+ /// - cornerRadius: The corner radius of the component.
+ /// - grabberColor: The color of the grabber pin view.
+ public init(
+ dimmingColor: UIColor = .black.withAlphaComponent(0.4),
+ backgroundColor: UIColor = .white,
+ animationDuration: TimeInterval = 0.35,
+ cornerRadius: CGFloat = 16.0,
+ grabberColor: UIColor = .gray
+ ) {
+ self.dimmingColor = dimmingColor
+ self.backgroundColor = backgroundColor
+ self.animationDuration = animationDuration
+ self.cornerRadius = cornerRadius
+ self.grabberColor = grabberColor
+ }
+}
diff --git a/Sources/OverlayContainer/Classes/OverlayContainer.swift b/Sources/OverlayContainer/Classes/OverlayContainer.swift
index 1e8bb90..5446d03 100644
--- a/Sources/OverlayContainer/Classes/OverlayContainer.swift
+++ b/Sources/OverlayContainer/Classes/OverlayContainer.swift
@@ -3,4 +3,160 @@
// Copyright © 2024 Space Code. All rights reserved.
//
-final class OverlayContainer {}
+import UIKit
+
+// MARK: - OverlayContainer
+
+public final class OverlayContainer: UIViewController {
+ // MARK: Properties
+
+ /// Controller responsible for managing the presentation of the bottom sheet.
+ private var bottomSheetController: BottomSheetPresentationController?
+ /// Driver responsible for handling the animated transitions of the bottom sheet.
+ private var transitionDriver: BottomSheetAnimatedTransitionDriver?
+ /// The view controller that contains the content to be presented in the bottom sheet.
+ private let contentContainer: UIViewController
+ /// The view that holds the content to be displayed in the bottom sheet.
+ private let contentView = UIView()
+ /// The view that provides a visual handle for dragging the bottom sheet.
+ private let grabberView = GrabberView()
+ /// Configuration settings for the appearance and behavior of the bottom sheet.
+ private let configuration: Configuration
+
+ // MARK: Initialization
+
+ /// Create a new `OverlayContainer` instance.
+ ///
+ /// - Parameters:
+ /// - contentContainer: The view controller that contains the content to be presented in the bottom sheet.
+ /// - configuration: Configuration settings for the appearance and behavior of the bottom sheet.
+ public init(contentContainer: UIViewController, configuration: Configuration = .init()) {
+ self.contentContainer = contentContainer
+ self.configuration = configuration
+
+ super.init(nibName: nil, bundle: nil)
+
+ modalPresentationStyle = .custom
+ transitioningDelegate = self
+ }
+
+ @available(*, unavailable)
+ required init?(coder _: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // MARK: Life Cycle
+
+ override public func viewDidLoad() {
+ super.viewDidLoad()
+
+ setupLayout()
+
+ transitionDriver = BottomSheetAnimatedTransitionDriver(controller: self)
+
+ view.layoutIfNeeded()
+ }
+
+ override public func systemLayoutFittingSizeDidChange(forChildContentContainer container: any UIContentContainer) {
+ super.systemLayoutFittingSizeDidChange(forChildContentContainer: container)
+ presentationController?.systemLayoutFittingSizeDidChange(forChildContentContainer: container)
+ }
+
+ override public func preferredContentSizeDidChange(forChildContentContainer container: any UIContentContainer) {
+ super.preferredContentSizeDidChange(forChildContentContainer: container)
+
+ let grabberHeight = grabberView.intrinsicContentSize.height
+ var preferredContentSize = container.preferredContentSize
+
+ preferredContentSize.height += grabberHeight
+ }
+
+ // MARK: Public
+
+ public func present(viewController: UIViewController) {
+ viewController.present(self, animated: true, completion: nil)
+ }
+
+ // MARK: Private
+
+ private func setupLayout() {
+ addChild(contentContainer)
+
+ view.addSubview(grabberView)
+ view.addSubview(contentView)
+
+ contentContainer.view.translatesAutoresizingMaskIntoConstraints = false
+ contentView.addSubview(contentContainer.view)
+
+ grabberView.backgroundColor = configuration.backgroundColor
+ grabberView.cornerRadius = configuration.cornerRadius
+ grabberView.grabberColor = configuration.grabberColor
+ grabberView.translatesAutoresizingMaskIntoConstraints = false
+
+ contentView.backgroundColor = configuration.backgroundColor
+ contentView.translatesAutoresizingMaskIntoConstraints = false
+
+ NSLayoutConstraint.activate(
+ [
+ grabberView.topAnchor.constraint(equalTo: view.topAnchor),
+ grabberView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+ view.trailingAnchor.constraint(equalTo: grabberView.trailingAnchor),
+
+ contentView.topAnchor.constraint(equalTo: grabberView.bottomAnchor),
+ contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+ view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
+ view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
+
+ contentContainer.view.topAnchor.constraint(equalTo: contentView.topAnchor),
+ contentContainer.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
+ contentView.trailingAnchor.constraint(equalTo: contentContainer.view.trailingAnchor),
+ contentView.bottomAnchor.constraint(equalTo: contentContainer.view.bottomAnchor),
+ ]
+ )
+
+ contentContainer.didMove(toParent: self)
+ }
+}
+
+// MARK: UIViewControllerTransitioningDelegate
+
+extension OverlayContainer: UIViewControllerTransitioningDelegate {
+ public func presentationController(
+ forPresented presented: UIViewController,
+ presenting: UIViewController?,
+ source _: UIViewController
+ ) -> UIPresentationController? {
+ bottomSheetController = BottomSheetPresentationController(
+ configuration: configuration,
+ presentedViewController: presented,
+ presentingViewController: presenting
+ )
+ return bottomSheetController
+ }
+
+ public func animationController(
+ forDismissed _: UIViewController
+ ) -> (any UIViewControllerAnimatedTransitioning)? {
+ BottomSheetAnimatedTransition(
+ transitionType: .dismiss,
+ animationDuration: configuration.animationDuration
+ )
+ }
+
+ public func animationController(
+ forPresented _: UIViewController,
+ presenting _: UIViewController,
+ source _: UIViewController
+ ) -> (any UIViewControllerAnimatedTransitioning)? {
+ BottomSheetAnimatedTransition(
+ transitionType: .present,
+ animationDuration: configuration.animationDuration
+ )
+ }
+
+ public func interactionControllerForDismissal(
+ using _: any UIViewControllerAnimatedTransitioning
+ ) -> (any UIViewControllerInteractiveTransitioning)? {
+ transitionDriver?.wantsInteractiveStart == true ? transitionDriver : nil
+ }
+}
diff --git a/Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransition.swift b/Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransition.swift
new file mode 100644
index 0000000..b1190fe
--- /dev/null
+++ b/Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransition.swift
@@ -0,0 +1,99 @@
+//
+// overlay-container
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import UIKit
+
+// MARK: - BottomSheetAnimatedTransition
+
+final class BottomSheetAnimatedTransition: NSObject {
+ // MARK: Types
+
+ /// Enum to define different types of transitions for view controllers
+ enum TransitionType {
+ /// Represents the transition type when presenting a view controller
+ case present
+ /// Represents the transition type when dismissing a view controller
+ case dismiss
+ }
+
+ // MARK: Properties
+
+ /// The animator responsible for performing the view transition animations.
+ private var animator: UIViewPropertyAnimator?
+ /// The type of transition to be performed (present or dismiss).
+ private let transitionType: TransitionType
+ /// The duration of the animation for the transition.
+ private let animationDuration: TimeInterval
+
+ // MARK: Initialization
+
+ /// Initializes a new instance of the transition animator.
+ ///
+ /// - Parameters:
+ /// - transitionType: The type of transition to be performed (present or dismiss).
+ /// - animationDuration: The type of transition to be performed (present or dismiss).
+ init(transitionType: TransitionType, animationDuration: TimeInterval) {
+ self.transitionType = transitionType
+ self.animationDuration = animationDuration
+ }
+}
+
+// MARK: UIViewControllerAnimatedTransitioning
+
+extension BottomSheetAnimatedTransition: UIViewControllerAnimatedTransitioning {
+ func transitionDuration(using _: (any UIViewControllerContextTransitioning)?) -> TimeInterval {
+ animationDuration
+ }
+
+ func animateTransition(using transitionContext: any UIViewControllerContextTransitioning) {
+ interruptibleAnimator(using: transitionContext).startAnimation()
+ }
+
+ func interruptibleAnimator(
+ using transitionContext: any UIViewControllerContextTransitioning
+ ) -> any UIViewImplicitlyAnimating {
+ if let animator { return animator }
+
+ if transitionType == .present {
+ if let controller = transitionContext.viewController(forKey: .to) {
+ let frame = transitionContext.finalFrame(for: controller)
+ controller.view.frame = frame
+
+ transitionContext.containerView.addSubview(controller.view)
+ transitionContext.containerView.layoutIfNeeded()
+
+ controller.view.transform = CGAffineTransform(translationX: .zero, y: frame.height)
+ }
+ }
+
+ let animator = UIViewPropertyAnimator(
+ duration: transitionDuration(using: transitionContext),
+ controlPoint1: CGPoint(x: 0.2, y: 1),
+ controlPoint2: CGPoint(x: 0.42, y: 1)
+ ) {
+ let key: UITransitionContextViewKey = self.transitionType == .present ? .to : .from
+ guard let view = transitionContext.view(forKey: key) else { return }
+
+ let isPresent = self.transitionType == .present
+ view.transform = isPresent ? .identity : CGAffineTransform(translationX: .zero, y: view.frame.height)
+ }
+
+ animator.addCompletion { _ in
+ if transitionContext.transitionWasCancelled, self.transitionType == .present {
+ transitionContext.view(forKey: .to)?.removeFromSuperview()
+ }
+
+ transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
+ }
+
+ self.animator = animator
+
+ return animator
+ }
+
+ func animationEnded(_: Bool) {
+ animator = nil
+ }
+}
diff --git a/Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransitionDriver.swift b/Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransitionDriver.swift
new file mode 100644
index 0000000..4579976
--- /dev/null
+++ b/Sources/OverlayContainer/Classes/Presentation/BottomSheetAnimatedTransitionDriver.swift
@@ -0,0 +1,83 @@
+//
+// overlay-container
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import UIKit
+
+// MARK: - BottomSheetAnimatedTransitionDriver
+
+final class BottomSheetAnimatedTransitionDriver: UIPercentDrivenInteractiveTransition {
+ // MARK: Private
+
+ private weak var controller: OverlayContainer?
+
+ private lazy var panGesture: UIPanGestureRecognizer = {
+ let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
+ panGesture.delegate = self
+ return panGesture
+ }()
+
+ // MARK: Initialization
+
+ init(controller: OverlayContainer) {
+ self.controller = controller
+ super.init()
+ wantsInteractiveStart = false
+ setupGesture()
+ }
+
+ // MARK: Private
+
+ private func setupGesture() {
+ controller?.view.addGestureRecognizer(panGesture)
+ }
+
+ // MARK: Actions
+
+ @objc
+ private func handlePan(_ sender: UIPanGestureRecognizer) {
+ guard let view = sender.view else { return }
+
+ let translation = sender.translation(in: view)
+ var progress = translation.y / view.frame.height
+ progress = min(max(progress, 0.0), 1.0)
+
+ switch sender.state {
+ case .began:
+ wantsInteractiveStart = true
+ controller?.dismiss(animated: true)
+ case .changed:
+ update(progress)
+ case .ended:
+ wantsInteractiveStart = false
+
+ let velocity = sender.velocity(in: view).y
+
+ if progress > 0.5 || velocity > 1000 {
+ finish()
+ } else {
+ cancel()
+ }
+ case .cancelled, .failed:
+ wantsInteractiveStart = false
+ cancel()
+ default:
+ break
+ }
+ }
+}
+
+// MARK: UIGestureRecognizerDelegate
+
+extension BottomSheetAnimatedTransitionDriver: UIGestureRecognizerDelegate {
+ func gestureRecognizerShouldBegin(_: UIGestureRecognizer) -> Bool {
+ let velocity = panGesture.velocity(in: nil)
+
+ if velocity.y > 0, abs(velocity.y) > abs(velocity.x) {
+ return true
+ } else {
+ return false
+ }
+ }
+}
diff --git a/Sources/OverlayContainer/Classes/Presentation/BottomSheetPresentationController.swift b/Sources/OverlayContainer/Classes/Presentation/BottomSheetPresentationController.swift
new file mode 100644
index 0000000..6f52ced
--- /dev/null
+++ b/Sources/OverlayContainer/Classes/Presentation/BottomSheetPresentationController.swift
@@ -0,0 +1,237 @@
+//
+// overlay-container
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import UIKit
+
+// MARK: - BottomSheetPresentationController
+
+/// A controller that manages the presentation of a bottom sheet.
+final class BottomSheetPresentationController: UIPresentationController {
+ // MARK: Types
+
+ /// Represents the different states of the bottom sheet presentation lifecycle.
+ private enum State {
+ /// The bottom sheet is dismissed and not visible.
+ case dismissed
+ /// The bottom sheet is in the process of being presented.
+ case presenting
+ /// The bottom sheet is fully presented and visible.
+ case presented
+ /// The bottom sheet is in the process of being dismissed.
+ case dismissing
+ }
+
+ // MARK: Properties
+
+ /// The current state of the bottom sheet's presentation lifecycle.
+ private var state: State = .dismissed
+ /// The current frame of the bottom sheet.
+ private var currentFrame: CGRect = .zero
+ /// A view that dims the background to highlight the bottom sheet.
+ private var dimmingView: UIView?
+
+ // Dependencies
+
+ /// The configuration settings for the appearance and behavior of the bottom sheet.
+ private let configuration: Configuration
+
+ // MARK: Initialization
+
+ /// Initializes a new instance of `BottomSheetPresentationController` with the specified configuration and view controllers.
+ ///
+ /// - Parameters:
+ /// - configuration: The configuration settings for the appearance and behavior of the bottom sheet.
+ /// - presentedViewController: The view controller being presented as a bottom sheet.
+ /// - presentingViewController: The view controller that is presenting the bottom sheet.
+ init(
+ configuration: Configuration,
+ presentedViewController: UIViewController,
+ presentingViewController: UIViewController?
+ ) {
+ self.configuration = configuration
+ super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
+ }
+
+ // MARK: UIPresentationController
+
+ override var shouldPresentInFullscreen: Bool {
+ false
+ }
+
+ override func presentationTransitionWillBegin() {
+ state = .presenting
+ setupDimmingView()
+
+ performAlongsideTransition {
+ self.dimmingView?.alpha = 1
+ }
+ }
+
+ override func presentationTransitionDidEnd(_ completed: Bool) {
+ if completed {
+ state = .presented
+ } else {
+ state = .dismissed
+
+ presentedView?.removeFromSuperview()
+ dimmingView?.removeFromSuperview()
+ }
+ }
+
+ override func dismissalTransitionWillBegin() {
+ state = .dismissing
+
+ performAlongsideTransition {
+ self.dimmingView?.alpha = 0
+ }
+ }
+
+ override func dismissalTransitionDidEnd(_ completed: Bool) {
+ if completed {
+ state = .dismissed
+ removeDimmingView()
+ } else {
+ state = .presented
+ }
+ }
+
+ override var frameOfPresentedViewInContainerView: CGRect {
+ guard let containerView else { return .zero }
+
+ let frame = super.frameOfPresentedViewInContainerView
+ let windowInsets = presentedView?.window?.safeAreaInsets ?? .zero
+
+ var preferredContentSize = presentedViewController.preferredContentSize
+
+ if preferredContentSize == .zero {
+ preferredContentSize = presentedViewController.view.systemLayoutSizeFitting(
+ CGSize(width: frame.width, height: UIView.layoutFittingCompressedSize.height),
+ withHorizontalFittingPriority: .required,
+ verticalFittingPriority: .fittingSizeLevel
+ )
+ }
+
+ let preferredHeight = preferredContentSize.height
+ let maxHeight = containerView.bounds.height - windowInsets.top
+
+ let height = min(preferredHeight, maxHeight)
+
+ return CGRect(
+ x: .zero,
+ y: containerView.bounds.height - height,
+ width: containerView.bounds.width,
+ height: height
+ )
+ }
+
+ override func containerViewWillLayoutSubviews() {
+ super.containerViewWillLayoutSubviews()
+
+ dimmingView?.frame = containerView?.frame ?? .zero
+ presentedView?.frame = frameOfPresentedViewInContainerView
+ }
+
+ override func preferredContentSizeDidChange(forChildContentContainer container: any UIContentContainer) {
+ super.preferredContentSizeDidChange(forChildContentContainer: container)
+ invalidateOverlayMetrics()
+ }
+
+ override func systemLayoutFittingSizeDidChange(forChildContentContainer container: any UIContentContainer) {
+ super.systemLayoutFittingSizeDidChange(forChildContentContainer: container)
+ invalidateOverlayMetrics()
+ }
+
+ override func willTransition(
+ to newCollection: UITraitCollection,
+ with coordinator: any UIViewControllerTransitionCoordinator
+ ) {
+ super.willTransition(to: newCollection, with: coordinator)
+ coordinator.animate { _ in
+ self.presentedView?.frame = self.frameOfPresentedViewInContainerView
+ }
+ }
+
+ // MARK: Private
+
+ private func setupDimmingView() {
+ guard let containerView else { return }
+
+ let dimmingView = UIView()
+ dimmingView.translatesAutoresizingMaskIntoConstraints = false
+ dimmingView.backgroundColor = configuration.dimmingColor
+ dimmingView.alpha = .zero
+
+ containerView.addSubview(dimmingView)
+
+ NSLayoutConstraint.activate(
+ [
+ dimmingView.topAnchor.constraint(equalTo: containerView.topAnchor),
+ dimmingView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
+ containerView.trailingAnchor.constraint(equalTo: dimmingView.trailingAnchor),
+ containerView.bottomAnchor.constraint(equalTo: dimmingView.bottomAnchor),
+ ]
+ )
+
+ let tapGesture = UITapGestureRecognizer()
+ dimmingView.addGestureRecognizer(tapGesture)
+
+ tapGesture.addTarget(self, action: #selector(handleTapGesture))
+
+ self.dimmingView = dimmingView
+ }
+
+ private func removeDimmingView() {
+ dimmingView?.removeFromSuperview()
+ dimmingView = nil
+ }
+
+ private func dismissIfPossible() {
+ let canBeDismissed = state == .presented
+
+ if canBeDismissed {
+ presentedViewController.dismiss(animated: true)
+ }
+ }
+
+ private func performAlongsideTransition(_ animation: @escaping () -> Void) {
+ guard let coordinator = presentedViewController.transitionCoordinator else {
+ animation()
+ return
+ }
+
+ coordinator.animate(alongsideTransition: { _ in
+ animation()
+ })
+ }
+
+ private func invalidateOverlayMetrics() {
+ guard let containerView else { return }
+
+ let frame = containerView.frame
+
+ if frame != currentFrame {
+ containerView.setNeedsLayout()
+
+ currentFrame = frame
+
+ UIView.animate(withDuration: .animationDuration) {
+ containerView.layoutIfNeeded()
+ }
+ }
+ }
+
+ // MARK: Actions
+
+ @objc
+ private func handleTapGesture() {
+ dismissIfPossible()
+ }
+}
+
+// MARK: - Constants
+
+private extension TimeInterval {
+ static let animationDuration = 0.25
+}
diff --git a/Sources/OverlayContainer/Classes/Presentation/GrabberView.swift b/Sources/OverlayContainer/Classes/Presentation/GrabberView.swift
new file mode 100644
index 0000000..394694f
--- /dev/null
+++ b/Sources/OverlayContainer/Classes/Presentation/GrabberView.swift
@@ -0,0 +1,92 @@
+//
+// overlay-container
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import UIKit
+
+// MARK: - GrabberView
+
+final class GrabberView: UIView {
+ // MARK: Properties
+
+ private let grabberLayer = CALayer()
+
+ var cornerRadius: CGFloat = 16.0 {
+ didSet {
+ layer.cornerRadius = cornerRadius
+ setNeedsLayout()
+ }
+ }
+
+ var grabberColor: UIColor = .systemGray {
+ didSet {
+ grabberLayer.backgroundColor = grabberColor.cgColor
+ setNeedsLayout()
+ }
+ }
+
+ // MARK: Initialization
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ configure()
+ }
+
+ @available(*, unavailable)
+ required init?(coder _: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // MARK: Internal
+
+ override var alignmentRectInsets: UIEdgeInsets {
+ UIEdgeInsets(top: .zero, left: .zero, bottom: max(cornerRadius * 2 - CGSize.size.height, 0), right: .zero)
+ }
+
+ override var intrinsicContentSize: CGSize {
+ .size
+ }
+
+ // MARK: Life Cycle
+
+ override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+ super.traitCollectionDidChange(previousTraitCollection)
+
+ if #available(iOS 13.0, *) {
+ if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
+ grabberLayer.backgroundColor = grabberColor.cgColor
+ }
+ }
+ }
+
+ override func layoutSublayers(of layer: CALayer) {
+ super.layoutSublayers(of: layer)
+
+ let origin = CGPoint(x: (layer.bounds.width - CGSize.grabberSize.width) / 2, y: 8)
+ grabberLayer.frame = CGRect(origin: origin, size: .grabberSize)
+ }
+
+ // MARK: Private
+
+ private func configure() {
+ layer.cornerRadius = cornerRadius
+ layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
+
+ if #available(iOS 13.0, *) {
+ layer.cornerCurve = .continuous
+ grabberLayer.cornerCurve = .continuous
+ }
+
+ grabberLayer.backgroundColor = grabberColor.cgColor
+ grabberLayer.cornerRadius = 2
+ layer.addSublayer(grabberLayer)
+ }
+}
+
+// MARK: - Constants
+
+private extension CGSize {
+ static let size = CGSize(width: 48, height: 20)
+ static let grabberSize = CGSize(width: 40, height: 4)
+}
From f2df3ab03ac716ed057ed717349beb97823b75ec Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Mon, 24 Mar 2025 20:39:08 +0400
Subject: [PATCH 3/7] Implement `OverlayContainer`
---
.github/workflows/ci.yml | 29 +----------
.swiftlint.yml | 1 +
Package.swift | 2 +-
Package@swift-5.10.swift | 16 ++++++
README.md | 24 ++++++++-
.../Classes/Core/Model/Configuration.swift | 35 +++++++++++--
.../Classes/OverlayContainer.swift | 52 +++++++++++++------
7 files changed, 108 insertions(+), 51 deletions(-)
create mode 100644 Package@swift-5.10.swift
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fd45e5e..a239d83 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,22 +23,12 @@ jobs:
with:
args: --strict
env:
-
DIFF_BASE: ${{ github.base_ref }}
-
-
-
-
-
iOS:
-
name: ${{ matrix.name }}
runs-on: ${{ matrix.runsOn }}
-
env:
-
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
-
timeout-minutes: 20
strategy:
fail-fast: false
@@ -54,31 +44,17 @@ jobs:
runsOn: macos-13
steps:
- uses: actions/checkout@v3
-
- name: ${{ matrix.name }}
run: xcodebuild test -scheme "{{ cookiecutter.name }}" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
-
- uses: actions/upload-artifact@v4
with:
-
name: ${{ matrix.name }}
path: test_output
-
-
-
-
-
-
-
spm:
-
name: ${{ matrix.name }}
runs-on: ${{ matrix.runsOn }}
-
env:
-
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
-
timeout-minutes: 20
strategy:
fail-fast: false
@@ -92,10 +68,8 @@ jobs:
runsOn: macos-13
steps:
- uses: actions/checkout@v3
-
- name: ${{ matrix.name }}
run: swift build -c release --target "{{ cookiecutter.name }}"
-
merge-test-reports:
needs: [iOS, macOS, watchOS, tvOS]
runs-on: macos-13
@@ -110,10 +84,9 @@ jobs:
with:
name: MergedResult
path: test_output/final
-
discover-typos:
name: Discover Typos
- runs-on: macOS-12
+ runs-on: macOS-13
env:
DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
steps:
diff --git a/.swiftlint.yml b/.swiftlint.yml
index 88a1ebe..8e2fe2b 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -4,6 +4,7 @@ excluded:
- Package@swift-5.7.swift
- Package@swift-5.8.swift
- Package@swift-5.9.swift
+ - Package@swift-5.10.swift
- .build
# Rules
diff --git a/Package.swift b/Package.swift
index a513efa..12da4e1 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version: 5.10
+// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
diff --git a/Package@swift-5.10.swift b/Package@swift-5.10.swift
new file mode 100644
index 0000000..a513efa
--- /dev/null
+++ b/Package@swift-5.10.swift
@@ -0,0 +1,16 @@
+// swift-tools-version: 5.10
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "overlay-container",
+ platforms: [.iOS(.v12)],
+ products: [
+ .library(name: "OverlayContainer", targets: ["OverlayContainer"]),
+ ],
+ targets: [
+ .target(name: "OverlayContainer"),
+ .testTarget(name: "OverlayContainerTests", dependencies: ["OverlayContainer"]),
+ ]
+)
diff --git a/README.md b/README.md
index 76e0486..8e6b188 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
## Description
-`overlay-container` description.
+`overlay-container` is a lightweight Swift library for managing overlays and bottom sheets in iOS applications. It provides a flexible and customizable way to present draggable, resizable, and interactive overlays, making it easy to implement bottom sheets, modals, and other layered UI components.
- [Usage](#usage)
- [Requirements](#requirements)
@@ -22,8 +22,28 @@
## Usage
+```swift
+import OverlayContainer
+
+func presentSheet(_ viewController: UIViewController) {
+ let sheetViewController = OverlayContainer(
+ contentContainer: viewController,
+ configuration: .init(
+ cornerRadius: 16,
+ insets: .zero,
+ grabberType: .hidden
+ )
+ )
+ present(sheetViewController, animated: true)
+}
+```
+
## Requirements
+- iOS 12.0+
+- Xcode 16.0
+- Swift 5.7
+
## Installation
### Swift Package Manager
@@ -55,4 +75,4 @@ Please feel free to help out with this project! If you see something that could
Nikita Vasilev, nv3212@gmail.com
## License
-overlay-container is available under the MIT license. See the LICENSE file for more info.
\ No newline at end of file
+overlay-container is available under the MIT license. See the LICENSE file for more info.
diff --git a/Sources/OverlayContainer/Classes/Core/Model/Configuration.swift b/Sources/OverlayContainer/Classes/Core/Model/Configuration.swift
index 59577f1..efcfe9a 100644
--- a/Sources/OverlayContainer/Classes/Core/Model/Configuration.swift
+++ b/Sources/OverlayContainer/Classes/Core/Model/Configuration.swift
@@ -7,6 +7,20 @@ import UIKit
/// A struct to configure the appearance and behavior of a UI component.
public struct Configuration {
+ public struct GrabberConfiguration {
+ /// The color of the grabber pin view.
+ public let grabberColor: UIColor
+
+ public init(grabberColor: UIColor = .gray) {
+ self.grabberColor = grabberColor
+ }
+ }
+
+ public enum GrabberType {
+ case hidden
+ case plain(GrabberConfiguration)
+ }
+
// MARK: Properties
/// The dimming color for the component.
@@ -17,8 +31,12 @@ public struct Configuration {
public let animationDuration: TimeInterval
/// The corner radius of the component.
public let cornerRadius: CGFloat
- /// The color of the grabber pin view.
- public let grabberColor: UIColor
+
+ public let maskedCorners: CACornerMask
+ /// The sheet insets.
+ public let insets: UIEdgeInsets
+
+ public let grabberType: GrabberType
// MARK: Initialization
@@ -35,12 +53,21 @@ public struct Configuration {
backgroundColor: UIColor = .white,
animationDuration: TimeInterval = 0.35,
cornerRadius: CGFloat = 16.0,
- grabberColor: UIColor = .gray
+ maskedCorners: CACornerMask = [
+ .layerMaxXMaxYCorner,
+ .layerMinXMinYCorner,
+ .layerMinXMaxYCorner,
+ .layerMaxXMinYCorner,
+ ],
+ insets: UIEdgeInsets = .zero,
+ grabberType: GrabberType = .plain(GrabberConfiguration())
) {
self.dimmingColor = dimmingColor
self.backgroundColor = backgroundColor
self.animationDuration = animationDuration
self.cornerRadius = cornerRadius
- self.grabberColor = grabberColor
+ self.maskedCorners = maskedCorners
+ self.insets = insets
+ self.grabberType = grabberType
}
}
diff --git a/Sources/OverlayContainer/Classes/OverlayContainer.swift b/Sources/OverlayContainer/Classes/OverlayContainer.swift
index 5446d03..38bc090 100644
--- a/Sources/OverlayContainer/Classes/OverlayContainer.swift
+++ b/Sources/OverlayContainer/Classes/OverlayContainer.swift
@@ -23,6 +23,13 @@ public final class OverlayContainer: UIViewController {
/// Configuration settings for the appearance and behavior of the bottom sheet.
private let configuration: Configuration
+ private var isGrabberHidden: Bool {
+ if case .hidden = configuration.grabberType {
+ return true
+ }
+ return false
+ }
+
// MARK: Initialization
/// Create a new `OverlayContainer` instance.
@@ -50,7 +57,7 @@ public final class OverlayContainer: UIViewController {
override public func viewDidLoad() {
super.viewDidLoad()
- setupLayout()
+ setupUI()
transitionDriver = BottomSheetAnimatedTransitionDriver(controller: self)
@@ -79,33 +86,46 @@ public final class OverlayContainer: UIViewController {
// MARK: Private
- private func setupLayout() {
+ // swiftlint:disable:next function_body_length
+ private func setupUI() {
addChild(contentContainer)
- view.addSubview(grabberView)
+ if case let .plain(data) = configuration.grabberType {
+ view.addSubview(grabberView)
+ grabberView.backgroundColor = configuration.backgroundColor
+ grabberView.grabberColor = data.grabberColor
+ grabberView.translatesAutoresizingMaskIntoConstraints = false
+ }
+
view.addSubview(contentView)
+ contentView.layer.cornerRadius = configuration.cornerRadius
+ contentView.layer.maskedCorners = configuration.maskedCorners
+ contentView.layer.masksToBounds = true
+ contentView.clipsToBounds = true
+
contentContainer.view.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(contentContainer.view)
- grabberView.backgroundColor = configuration.backgroundColor
- grabberView.cornerRadius = configuration.cornerRadius
- grabberView.grabberColor = configuration.grabberColor
- grabberView.translatesAutoresizingMaskIntoConstraints = false
-
contentView.backgroundColor = configuration.backgroundColor
contentView.translatesAutoresizingMaskIntoConstraints = false
+ if !isGrabberHidden {
+ NSLayoutConstraint.activate(
+ [
+ grabberView.topAnchor.constraint(equalTo: view.topAnchor, constant: configuration.insets.top),
+ grabberView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: configuration.insets.left),
+ view.trailingAnchor.constraint(equalTo: grabberView.trailingAnchor, constant: configuration.insets.right),
+ ]
+ )
+ }
+
NSLayoutConstraint.activate(
[
- grabberView.topAnchor.constraint(equalTo: view.topAnchor),
- grabberView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- view.trailingAnchor.constraint(equalTo: grabberView.trailingAnchor),
-
- contentView.topAnchor.constraint(equalTo: grabberView.bottomAnchor),
- contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
- view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
+ contentView.topAnchor.constraint(equalTo: isGrabberHidden ? view.topAnchor : grabberView.bottomAnchor),
+ contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: configuration.insets.left),
+ view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: configuration.insets.right),
+ view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: configuration.insets.bottom),
contentContainer.view.topAnchor.constraint(equalTo: contentView.topAnchor),
contentContainer.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
From 0024aafd5e4d2abdace110a61fefdbae27f161ed Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Mon, 24 Mar 2025 20:42:43 +0400
Subject: [PATCH 4/7] Update `ci.yml`
---
.github/workflows/ci.yml | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a239d83..e65611f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -45,7 +45,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: ${{ matrix.name }}
- run: xcodebuild test -scheme "{{ cookiecutter.name }}" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
+ run: xcodebuild test -scheme "overlay-container" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}
@@ -69,21 +69,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: ${{ matrix.name }}
- run: swift build -c release --target "{{ cookiecutter.name }}"
- merge-test-reports:
- needs: [iOS, macOS, watchOS, tvOS]
- runs-on: macos-13
- steps:
- - name: Download artifacts
- uses: actions/download-artifact@v4
- with:
- path: test_output
- - run: xcrun xcresulttool merge test_output/**/*.xcresult --output-path test_output/final/final.xcresult
- - name: Upload Merged Artifact
- uses: actions/upload-artifact@v4
- with:
- name: MergedResult
- path: test_output/final
+ run: swift build -c release --target "OverlayContainer"
discover-typos:
name: Discover Typos
runs-on: macOS-13
From 913407c4c975d301c5982672112c7be3a2192081 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Mon, 24 Mar 2025 20:59:35 +0400
Subject: [PATCH 5/7] Implement `ci.yml`
---
.github/workflows/ci.yml | 20 --------------------
1 file changed, 20 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e65611f..24f7bbe 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -50,26 +50,6 @@ jobs:
with:
name: ${{ matrix.name }}
path: test_output
- spm:
- name: ${{ matrix.name }}
- runs-on: ${{ matrix.runsOn }}
- env:
- DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
- timeout-minutes: 20
- strategy:
- fail-fast: false
- matrix:
- include:
- - name: "Xcode 15"
- xcode: "Xcode_15.0"
- runsOn: macos-13
- - name: "Xcode 14"
- xcode: "Xcode_14.3.1"
- runsOn: macos-13
- steps:
- - uses: actions/checkout@v3
- - name: ${{ matrix.name }}
- run: swift build -c release --target "OverlayContainer"
discover-typos:
name: Discover Typos
runs-on: macOS-13
From bfce76f44db367842d8d3b653335e2a3a6b4e772 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Mon, 24 Mar 2025 20:59:46 +0400
Subject: [PATCH 6/7] Update `CONTRIBUTING.md`
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f96b11f..5007a7f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -58,4 +58,4 @@ See [CODE_OF_CONDUCT.md](https://github.com/space-code/overlay-container/blob/ma
---
-*Some of the ideas and wording for the statements above were based on work by the [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) and [Linux](https://elinux.org/Developer_Certificate_Of_Origin) communities. We commend them for their efforts to facilitate collaboration in their projects.*
\ No newline at end of file
+*Some of the ideas and wording for the statements above were based on work by the [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) and [Linux](https://elinux.org/Developer_Certificate_Of_Origin) communities.
\ No newline at end of file
From 8e9804bb92428e397de50fafa7d8b0b327bff137 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Mon, 24 Mar 2025 21:11:36 +0400
Subject: [PATCH 7/7] Update `CHAGELOG.md`
---
CHANGELOG.md | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e9885a..360f376 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,2 +1,9 @@
# Change Log
-All notable changes to this project will be documented in this file.
\ No newline at end of file
+All notable changes to this project will be documented in this file.
+
+## [1.0.0](https://github.com/space-code/overlay-container/releases/tag/1.0.0)
+Released on 2025-03-24.
+
+#### Added
+- Initial release of overlay-container.
+ - Added by [Nikita Vasilev](https://github.com/ns-vasiev).
\ No newline at end of file