From 6b3964909f957ef30233cf5e1bdf618d5f73a577 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Tue, 7 Jan 2025 07:28:38 +0100
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 | 100 +++++++++++++
.github/workflows/danger.yml | 31 ++++
.swiftformat | 64 +++++++++
.swiftlint.yml | 135 ++++++++++++++++++
.../contents.xcworkspacedata | 7 +
CHANGELOG.md | 2 +
CODE_OF_CONDUCT.md | 74 ++++++++++
CONTRIBUTING.md | 61 ++++++++
Dangerfile | 1 +
Gemfile | 3 +
Makefile | 19 +++
Mintfile | 2 +
Package.swift | 15 ++
README.md | 66 ++++++++-
SEQURITY.md | 7 +
Sources/PageControl/Classes/PageControl.swift | 6 +
.../PageControlTests/page-controlTests.swift | 6 +
hooks/pre-commit | 38 +++++
23 files changed, 743 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 SEQURITY.md
create mode 100644 Sources/PageControl/Classes/PageControl.swift
create mode 100644 Tests/PageControlTests/page-controlTests.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..c32476c
--- /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 page-control, 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..92a240d
--- /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:
+ - ns_vasilev
+ reviewers:
+ - ns_vasilev
+
+
+ - package-ecosystem: swift
+ directory: /
+ open-pull-requests-limit: 10
+ schedule:
+ interval: daily
+ time: '07:00'
+ timezone: Europe/Berlin
+
+ assignees:
+ - ns_vasilev
+ reviewers:
+ - ns_vasilev
+
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..ac1b7b4
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,100 @@
+name: "page-control"
+
+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@v4
+ - 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@v4
+ - name: ${{ matrix.name }}
+ run: xcodebuild test -scheme "page-control" -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@v4
+ - name: ${{ matrix.name }}
+ run: swift build -c release --target "page-control"
+ 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..d40966e
--- /dev/null
+++ b/.swiftformat
@@ -0,0 +1,64 @@
+# Stream rules
+
+--swiftversion 5.3
+
+# Use 'swiftformat --options' to list all of the possible options
+
+--header "\npage-control\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..89efd09
--- /dev/null
+++ b/.swiftlint.yml
@@ -0,0 +1,135 @@
+excluded:
+ - Tests
+ - Package.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..5d0b437
--- /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/page-control/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/page-control/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..fdc7509
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,15 @@
+// swift-tools-version: 6.0
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "page-control",
+ products: [
+ .library(name: "PageControl", targets: ["PageControl"]),
+ ],
+ targets: [
+ .target(name: "PageControl"),
+ .testTarget(name: "PageControlTests", dependencies: ["PageControl"]),
+ ]
+)
diff --git a/README.md b/README.md
index 82d0d4c..e70728d 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,65 @@
-# page-control
\ No newline at end of file
+page-control
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Description
+`page-control` 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 `page-control` does support its use on supported platforms.
+
+Once you have your Swift package set up, adding `page-control` 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/page-control.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
+page-control 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/PageControl/Classes/PageControl.swift b/Sources/PageControl/Classes/PageControl.swift
new file mode 100644
index 0000000..602a9c9
--- /dev/null
+++ b/Sources/PageControl/Classes/PageControl.swift
@@ -0,0 +1,6 @@
+//
+// page-control
+// Copyright © 2025 Space Code. All rights reserved.
+//
+
+final class PageControl {}
diff --git a/Tests/PageControlTests/page-controlTests.swift b/Tests/PageControlTests/page-controlTests.swift
new file mode 100644
index 0000000..058028c
--- /dev/null
+++ b/Tests/PageControlTests/page-controlTests.swift
@@ -0,0 +1,6 @@
+//
+// page-control
+// Copyright © 2025 Space Code. All rights reserved.
+//
+
+import XCTest
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 8007941da4a6a6037ac6a4cf70522354c79e3e74 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Tue, 7 Jan 2025 18:41:59 +0100
Subject: [PATCH 2/7] Implement the `page-control` package
---
.swiftlint.yml | 6 +-
Package.swift | 1 +
.../Drawers/Implementations/BaseDrawer.swift | 132 +++++++++++++++++
.../Implementations/ExtendedLineDrawer.swift | 138 ++++++++++++++++++
.../Classes/Drawers/Interfaces/IDrawer.swift | 30 ++++
.../Classes/Helpers/Extensions/UIColor+.swift | 58 ++++++++
Sources/PageControl/Classes/PageControl.swift | 109 +++++++++++++-
...trolTests.swift => PageControlTests.swift} | 0
8 files changed, 468 insertions(+), 6 deletions(-)
create mode 100644 Sources/PageControl/Classes/Drawers/Implementations/BaseDrawer.swift
create mode 100644 Sources/PageControl/Classes/Drawers/Implementations/ExtendedLineDrawer.swift
create mode 100644 Sources/PageControl/Classes/Drawers/Interfaces/IDrawer.swift
create mode 100644 Sources/PageControl/Classes/Helpers/Extensions/UIColor+.swift
rename Tests/PageControlTests/{page-controlTests.swift => PageControlTests.swift} (100%)
diff --git a/.swiftlint.yml b/.swiftlint.yml
index 89efd09..757c73a 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -9,6 +9,7 @@ disabled_rules:
- trailing_comma
- todo
- opening_brace
+ - identifier_name
opt_in_rules: # some rules are only opt-in
- anyobject_protocol
@@ -94,11 +95,6 @@ opt_in_rules: # some rules are only opt-in
force_cast: warning
force_try: warning
-identifier_name:
- excluded:
- - id
- - URL
-
analyzer_rules:
- unused_import
- unused_declaration
diff --git a/Package.swift b/Package.swift
index fdc7509..e93ac95 100644
--- a/Package.swift
+++ b/Package.swift
@@ -5,6 +5,7 @@ import PackageDescription
let package = Package(
name: "page-control",
+ platforms: [.iOS(.v15)],
products: [
.library(name: "PageControl", targets: ["PageControl"]),
],
diff --git a/Sources/PageControl/Classes/Drawers/Implementations/BaseDrawer.swift b/Sources/PageControl/Classes/Drawers/Implementations/BaseDrawer.swift
new file mode 100644
index 0000000..eda03a5
--- /dev/null
+++ b/Sources/PageControl/Classes/Drawers/Implementations/BaseDrawer.swift
@@ -0,0 +1,132 @@
+//
+// page-control
+// Copyright © 2025 Space Code. All rights reserved.
+//
+
+import UIKit
+
+public class BaseDrawer: IDrawer {
+ // MARK: Properties
+
+ /// The size of the item, defined by its width and height.
+ public var size: CGSize
+ /// The index of the currently selected item, represented as a fractional value to support animations or transitions.
+ public var currentItem: CGFloat
+ /// The total number of items (pages) in the drawer.
+ public var numberOfPages: Int
+
+ /// The space between individual items in the drawer.
+ let space: CGFloat
+ /// The default color of the items, used for unselected items.
+ let itemColor: UIColor
+ /// The color of the currently selected item, often more prominent to indicate focus.
+ let selectedItemColor: UIColor
+ /// The corner radius of the items, used to give them rounded edges.
+ let radius: CGFloat
+
+ public var contentSize: CGSize {
+ CGSize(
+ width: CGFloat(numberOfPages - 1) * size.width + CGFloat(numberOfPages - 1) * space,
+ height: size.height + 16.0
+ )
+ }
+
+ // MARK: Initialization
+
+ /// Initializes a new instance of `BaseDrawer` with customizable properties.
+ /// - Parameters:
+ /// - currentItem: The initial index of the selected item. Defaults to `0.0`.
+ /// - numberOfPages: The total number of items (pages). Defaults to `5`.
+ /// - space: The space between individual items in the drawer. Defaults to `4.0`.
+ /// - width: The width of each item. Defaults to `16.0`.
+ /// - height: The height of each item. Defaults to `3.0`.
+ /// - itemColor: The default color for unselected items. Defaults to `UIColor.lightGray`.
+ /// - selectedItemColor: The color for the selected item. Defaults to a semi-transparent blue.
+ /// - radius: The corner radius of the items for rounded edges. Defaults to `2`.
+ public init(
+ currentItem: CGFloat = .zero,
+ numberOfPages: Int = .zero,
+ space: CGFloat = 4.0,
+ width: CGFloat = 16.0,
+ height: CGFloat = 3.0,
+ itemColor: UIColor = .lightGray,
+ selectedItemColor: UIColor = .blue.withAlphaComponent(0.8),
+ radius: CGFloat = 2
+ ) {
+ size = CGSize(width: width, height: height)
+ self.currentItem = currentItem
+ self.numberOfPages = numberOfPages
+ self.space = space
+ self.itemColor = itemColor
+ self.selectedItemColor = selectedItemColor
+ self.radius = radius
+ }
+
+ // MARK: IDrawer
+
+ public func draw(_: CGRect) {}
+
+ // MARK: Internal
+
+ /// Calculates the horizontal center position for an item in a layout.
+ ///
+ /// - Parameters:
+ /// - rect: The bounding rectangle of the container.
+ /// - position: The item's position index (e.g., 0 for the first item).
+ /// - size: The width of the item.
+ /// - space: The space between items.
+ /// - numberOfPages: The total number of items (pages) in the layout.
+ ///
+ /// - Returns: The `x` coordinate for the center of the item.
+ func centerX(
+ _ rect: CGRect,
+ position: CGFloat,
+ size: CGFloat,
+ space: CGFloat,
+ numberOfPages: Int
+ ) -> CGFloat {
+ let dotPosition = (position * (size + space))
+ let midX = rect.size.width / 2.0
+ let midXWithSpaces = ((CGFloat(numberOfPages) * (size + (space - 1))) / 2.0)
+
+ return dotPosition - midXWithSpaces + midX
+ }
+
+ /// Calculates the vertical center position for an item in a layout.
+ ///
+ /// - Parameters:
+ /// - rect: The bounding rectangle of the container.
+ /// - size: The height of the item.
+ ///
+ /// - Returns: The `y` coordinate for the center of the item.
+ func centerY(_ rect: CGRect, size: CGFloat) -> CGFloat {
+ let midY = rect.size.height / 2.0
+ let midDotY = size / 2.0
+ let centerY = midY - midDotY
+
+ return centerY
+ }
+
+ /// Draws a rounded rectangular item with optional border and fill color.
+ ///
+ /// - Parameters:
+ /// - rect: The rectangle defining the item's position and size.
+ /// - radius: The corner radius for the item's rounded edges.
+ /// - color: The fill color for the item.
+ /// - borderWidth: The width of the item's border. Defaults to `0`.
+ /// - borderColor: The color of the item's border. Defaults to `.clear`.
+ func drawItem(
+ _ rect: CGRect,
+ radius: CGFloat,
+ color: UIColor,
+ borderWidth: CGFloat = .zero,
+ borderColor: UIColor = .clear
+ ) {
+ let path = UIBezierPath(roundedRect: rect, cornerRadius: radius)
+ path.lineWidth = borderWidth
+ borderColor.setStroke()
+ path.stroke()
+ color.setFill()
+ path.fill()
+ }
+}
diff --git a/Sources/PageControl/Classes/Drawers/Implementations/ExtendedLineDrawer.swift b/Sources/PageControl/Classes/Drawers/Implementations/ExtendedLineDrawer.swift
new file mode 100644
index 0000000..4c23433
--- /dev/null
+++ b/Sources/PageControl/Classes/Drawers/Implementations/ExtendedLineDrawer.swift
@@ -0,0 +1,138 @@
+//
+// page-control
+// Copyright © 2025 Space Code. All rights reserved.
+//
+
+import UIKit
+
+// MARK: - ExtendedLineDrawer
+
+public final class ExtendedLineDrawer: BaseDrawer {
+ // MARK: Override
+
+ override public func draw(_ rect: CGRect) {
+ drawIndicators(rect)
+ drawCurrentItem(rect)
+ }
+
+ override public var contentSize: CGSize {
+ CGSize(
+ width: selectedItemWidth + CGFloat(numberOfPages - 1) * size.width + CGFloat(numberOfPages - 1) * space,
+ height: size.height + .extraSpace
+ )
+ }
+
+ // MARK: Private
+
+ // swiftlint:disable:next function_body_length
+ private func drawIndicators(_ rect: CGRect) {
+ let step = (space + size.width)
+
+ for index in 0 ... numberOfPages {
+ if index != Int(currentItem + 1), index != Int(currentItem) {
+ var newX: CGFloat = .zero
+ var newY: CGFloat = .zero
+ var newHeight: CGFloat = .zero
+ var newWidth: CGFloat = .zero
+
+ let progress = currentItem - floor(currentItem)
+
+ var itemColor = itemColor
+
+ if index == Int(currentItem + 2) {
+ itemColor = (self.itemColor * Double(1 - progress)) + (selectedItemColor * Double(progress))
+
+ let centerY = centerY(rect, size: size.height)
+
+ let currentProgress = currentItem - floor(currentItem)
+ let currentPosition = floor(currentItem + 2) - currentProgress
+
+ let x = centerX(
+ rect,
+ position: currentPosition,
+ size: size.width,
+ space: space,
+ numberOfPages: numberOfPages + 1
+ )
+
+ let ratio = 1 - currentProgress
+ let scale = step - (ratio * step)
+
+ newX = rect.origin.x + x
+ newY = rect.origin.y + centerY
+ newWidth = size.width + scale
+ newHeight = size.height
+ } else {
+ let centerY = centerY(rect, size: size.height)
+
+ let x = centerX(
+ rect,
+ position: CGFloat(index),
+ size: size.width,
+ space: space,
+ numberOfPages: numberOfPages + 1
+ )
+
+ newX = rect.origin.x + x
+ newY = rect.origin.y + centerY
+ newWidth = size.width
+ newHeight = size.height
+ }
+
+ drawItem(
+ CGRect(
+ x: newX,
+ y: newY,
+ width: newWidth,
+ height: newHeight
+ ),
+ radius: radius,
+ color: itemColor
+ )
+ }
+ }
+ }
+
+ private func drawCurrentItem(_ rect: CGRect) {
+ let progress = currentItem - floor(currentItem)
+ let color = (itemColor * Double(progress)) + (selectedItemColor * Double(1 - progress))
+
+ if currentItem >= 0 {
+ let step = (space + size.width)
+ let centerY = centerY(rect, size: size.height)
+ let position = floor(currentItem)
+
+ let centerX = centerX(
+ rect,
+ position: position,
+ size: size.width,
+ space: space,
+ numberOfPages: numberOfPages + 1
+ )
+
+ let rect = CGRect(
+ x: rect.origin.x + centerX,
+ y: rect.origin.y + centerY,
+ width: selectedItemWidth,
+ height: size.height
+ )
+
+ drawItem(rect, radius: radius, color: color)
+ }
+ }
+
+ private var selectedItemWidth: CGFloat {
+ let step = (space + size.width)
+ let currentProgress = currentItem - floor(currentItem)
+ let ratio = 1 - currentProgress
+ let desiredWidth = size.width + ratio * step
+
+ return desiredWidth
+ }
+}
+
+// MARK: Constants
+
+private extension CGFloat {
+ static let extraSpace: CGFloat = 16.0
+}
diff --git a/Sources/PageControl/Classes/Drawers/Interfaces/IDrawer.swift b/Sources/PageControl/Classes/Drawers/Interfaces/IDrawer.swift
new file mode 100644
index 0000000..cfa03d8
--- /dev/null
+++ b/Sources/PageControl/Classes/Drawers/Interfaces/IDrawer.swift
@@ -0,0 +1,30 @@
+//
+// page-control
+// Copyright © 2025 Space Code. All rights reserved.
+//
+
+import UIKit
+
+/// A protocol that defines the behavior for drawing a custom UI component, such as a pager or a carousel.
+public protocol IDrawer {
+ /// The index or position of the current item being displayed.
+ /// This property determines which item is currently in focus.
+ var currentItem: CGFloat { get set }
+
+ /// The size of each item in the drawer.
+ /// This could represent the width or height, depending on the layout.
+ var size: CGSize { get set }
+
+ /// The total number of pages or items in the drawer.
+ /// Used to calculate the range of drawable items or manage pagination logic.
+ var numberOfPages: Int { get set }
+
+ /// The content size of the element.
+ var contentSize: CGSize { get }
+
+ /// A method responsible for drawing the content within the specified rectangle.
+ ///
+ /// - Parameter rect: The area in which the content should be drawn.
+ /// This is typically provided by the rendering system (e.g., a `UIView` or `CALayer`).
+ func draw(_ rect: CGRect)
+}
diff --git a/Sources/PageControl/Classes/Helpers/Extensions/UIColor+.swift b/Sources/PageControl/Classes/Helpers/Extensions/UIColor+.swift
new file mode 100644
index 0000000..851ac3e
--- /dev/null
+++ b/Sources/PageControl/Classes/Helpers/Extensions/UIColor+.swift
@@ -0,0 +1,58 @@
+//
+// page-control
+// Copyright © 2025 Space Code. All rights reserved.
+//
+
+import UIKit
+
+extension UIColor {
+ /// Adds two `UIColor` objects together.
+ ///
+ /// - Parameters:
+ /// - color1: The first `UIColor`.
+ /// - color2: The second `UIColor`.
+ ///
+ /// - Returns: A new `UIColor` representing the sum of the two colors.
+ /// The resulting color's components are clamped to a maximum of 1.0.
+ /// If either color cannot be decomposed into RGBA components, `.clear` is returned.
+ static func + (color1: UIColor, color2: UIColor) -> UIColor {
+ var (r1, g1, b1, a1) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
+ var (r2, g2, b2, a2) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
+
+ guard color1.getRed(&r1, green: &g1, blue: &b1, alpha: &a1),
+ color2.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)
+ else {
+ return .clear
+ }
+
+ return UIColor(
+ red: min(r1 + r2, 1.0),
+ green: min(g1 + g2, 1.0),
+ blue: min(b1 + b2, 1.0),
+ alpha: (a1 + a2) / 2
+ )
+ }
+
+ /// Multiplies a `UIColor`'s RGB components by a scalar multiplier.
+ ///
+ /// - Parameters:
+ /// - color: The `UIColor` to modify.
+ /// - multiplier: The scalar multiplier applied to the RGB components. Values are clamped between 0 and 1.
+ ///
+ /// - Returns: A new `UIColor` with modified RGB components. The alpha remains unchanged.
+ /// If the color cannot be decomposed into RGBA components, `.clear` is returned.
+ static func * (color: UIColor, multiplier: CGFloat) -> UIColor {
+ var (r, g, b, a) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
+
+ guard color.getRed(&r, green: &g, blue: &b, alpha: &a) else {
+ return .clear
+ }
+
+ return UIColor(
+ red: min(max(r * multiplier, 0), 1.0),
+ green: min(max(g * multiplier, 0), 1.0),
+ blue: min(max(b * multiplier, 0), 1.0),
+ alpha: a
+ )
+ }
+}
diff --git a/Sources/PageControl/Classes/PageControl.swift b/Sources/PageControl/Classes/PageControl.swift
index 602a9c9..c9df5f0 100644
--- a/Sources/PageControl/Classes/PageControl.swift
+++ b/Sources/PageControl/Classes/PageControl.swift
@@ -3,4 +3,111 @@
// Copyright © 2025 Space Code. All rights reserved.
//
-final class PageControl {}
+import UIKit
+
+// MARK: - PageControl
+
+public final class PageControl: UIView {
+ // MARK: Properties
+
+ private var startTime: TimeInterval = .zero
+ private var nextCurrentItem: CGFloat = .zero
+ private var previousCurrentItem: CGFloat = .zero
+ private var displayLink: CADisplayLink?
+
+ public var drawer: IDrawer = ExtendedLineDrawer()
+
+ public var numberOfPages: Int {
+ get { drawer.numberOfPages }
+ set {
+ setNeedsDisplay()
+ drawer.numberOfPages = newValue
+ }
+ }
+
+ // MARK: Initialization
+
+ override public init(frame: CGRect) {
+ super.init(frame: frame)
+ setupUI()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ setupUI()
+ }
+
+ // MARK: Override
+
+ override public var intrinsicContentSize: CGSize {
+ sizeThatFits(.zero)
+ }
+
+ override public func sizeThatFits(_: CGSize) -> CGSize {
+ drawer.contentSize
+ }
+
+ override public func draw(_ rect: CGRect) {
+ drawer.draw(rect)
+ }
+
+ // MARK: Public
+
+ public func set(pageOffset: CGFloat) {
+ drawer.currentItem = pageOffset
+ setNeedsDisplay()
+ }
+
+ public func set(page index: Int) {
+ if nextCurrentItem != CGFloat(index) {
+ previousCurrentItem = round(drawer.currentItem)
+ nextCurrentItem = CGFloat(index)
+ runDisplayLink()
+ }
+ }
+
+ // MARK: Private
+
+ private func setupUI() {
+ backgroundColor = .clear
+ }
+
+ private func runDisplayLink() {
+ stopDisplayLink()
+
+ startTime = Date.timeIntervalSinceReferenceDate
+
+ displayLink = CADisplayLink(target: self, selector: #selector(displayLinkDidFire(_:)))
+ displayLink?.add(to: .current, forMode: .common)
+ }
+
+ private func stopDisplayLink() {
+ displayLink?.invalidate()
+ displayLink = nil
+ }
+
+ // MARK: Actions
+
+ @objc
+ private func displayLinkDidFire(_: CADisplayLink) {
+ var elapsed = Date.timeIntervalSinceReferenceDate - startTime
+
+ if elapsed > .animationDuration {
+ stopDisplayLink()
+ elapsed = .animationDuration
+ }
+
+ let progress = CGFloat(elapsed / .animationDuration)
+ let sign = nextCurrentItem - previousCurrentItem
+
+ drawer.currentItem = CGFloat(progress * sign + previousCurrentItem)
+
+ setNeedsDisplay()
+ }
+}
+
+// MARK: Constants
+
+private extension Double {
+ static let animationDuration = 0.2
+}
diff --git a/Tests/PageControlTests/page-controlTests.swift b/Tests/PageControlTests/PageControlTests.swift
similarity index 100%
rename from Tests/PageControlTests/page-controlTests.swift
rename to Tests/PageControlTests/PageControlTests.swift
From d3f4ac180c7b9032282e0aefc56db4f14bd1d2ee Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 7 Jan 2025 18:45:13 +0100
Subject: [PATCH 3/7] Bump actions/checkout from 2 to 4 (#1)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v4)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/ci.yml | 2 +-
.github/workflows/danger.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ac1b7b4..8063aeb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -91,7 +91,7 @@ jobs:
env:
DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Discover typos
run: |
export PATH="$PATH:/Library/Frameworks/Python.framework/Versions/3.11/bin"
diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
index 3f63d38..55a4794 100644
--- a/.github/workflows/danger.yml
+++ b/.github/workflows/danger.yml
@@ -18,7 +18,7 @@ jobs:
ruby-version: 3.1.4
bundler-cache: true
- name: Checkout code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Setup gems
run: |
gem install bundler
From 06d4d746545a630ffa95823e385bbfbb3de57609 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Tue, 7 Jan 2025 18:49:01 +0100
Subject: [PATCH 4/7] Update `ci.yml`
---
.github/workflows/ci.yml | 58 +++++++---------------------------------
1 file changed, 10 insertions(+), 48 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8063aeb..c3e04db 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -34,60 +34,22 @@ jobs:
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
+ - destination: "OS=18.1,name=iPhone 16 Pro"
+ name: "iOS 18.1"
+ xcode: "Xcode_16.1"
+ runsOn: macOS-14
+ - destination: "OS=18.0,name=iPhone 16 Pro"
+ name: "iOS 18.0"
+ xcode: "Xcode_16.0"
+ runsOn: macOS-14
steps:
- uses: actions/checkout@v4
- name: ${{ matrix.name }}
run: xcodebuild test -scheme "page-control" -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@v4
- - name: ${{ matrix.name }}
- run: swift build -c release --target "page-control"
- 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
+ runs-on: macOS-13
env:
DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
steps:
@@ -97,4 +59,4 @@ jobs:
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/*"
+ codespell --ignore-words-list="hart,inout,msdos,sur" --skip="./.build/*,./.git/*"
\ No newline at end of file
From 1b34b855c83997045a293a3306a531c9a6954c39 Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Tue, 7 Jan 2025 18:59:13 +0100
Subject: [PATCH 5/7] Update `README.md`
---
README.md | 43 +++++++++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index e70728d..8bc31ea 100644
--- a/README.md
+++ b/README.md
@@ -5,19 +5,10 @@
-
-
-
-
-
-
-
-
-
## Description
-`page-control` description.
+`page-control` is a highly customizable page control.
- [Usage](#usage)
- [Requirements](#requirements)
@@ -29,8 +20,40 @@
## Usage
+```swift
+import PageControl
+
+let pageControl = PageControl()
+
+pageControl.numberOfPages = 5
+pageControl.drawer = ExtendedLineDrawer(
+ itemColor: .lightGray,
+ selectedItemColor: .blue
+)
+```
+
+The custom drawer can be implemented, such as:
+
+```swift
+import PageControl
+
+final class MyCustomDrawer: BaseDrawer {
+ override public func draw(_ rect: CGRect) {
+ // Custom implementation for drawing content in the provided rectangle.
+ }
+
+ override public var contentSize: CGSize {
+ // Custom implementation for calculating the content size.
+ }
+}
+```
+
## Requirements
+- iOS 14.0+
+- Xcode 16.0
+- Swift 6.0
+
## Installation
### Swift Package Manager
From ebd1c083ae53e7b97568faafda2b566d205ab4da Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Tue, 7 Jan 2025 18:59:20 +0100
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 5d0b437..1c1705b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -58,4 +58,4 @@ See [CODE_OF_CONDUCT.md](https://github.com/space-code/page-control/blob/master/
---
-*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 fbecf0e6f14b7840524c63b182cf58d0f045617c Mon Sep 17 00:00:00 2001
From: Nikita Vasilev
Date: Tue, 7 Jan 2025 19:01:50 +0100
Subject: [PATCH 7/7] Update `CHANGELOG.md`
---
CHANGELOG.md | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e9885a..5e14798 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/page-control/releases/tag/1.0.0)
+Released on 2025-01-07.
+
+#### Added
+- Initial release of PageControl.
+ - Added by [Nikita Vasilev](https://github.com/ns-vasilev).
\ No newline at end of file