├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
└── workflows
│ └── dependabot.yml
├── .gitignore
├── .husky
├── .gitignore
└── commit-msg
├── .swiftlint.yml
├── .travis.yml
├── CHANGELOG.md
├── Gemfile
├── Gemfile.lock
├── LICENSE.md
├── README.md
├── WIKI.md
├── commitlint.config.js
├── example.apns
├── fastlane
├── .env
├── Appfile
├── Fastfile
└── README.md
├── package-lock.json
├── package.json
├── screenshots
├── 01.png
├── 02.png
└── 03.png
├── swiftgen.yml
├── waosSwift.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
└── xcshareddata
│ └── xcschemes
│ └── waosSwift.xcscheme
├── waosSwift.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ └── swiftpm
│ └── Package.resolved
├── waosSwift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-40.png
│ │ ├── Icon-40@2x.png
│ │ ├── Icon-40@3x.png
│ │ ├── Icon-60@2x.png
│ │ ├── Icon-60@3x.png
│ │ ├── Icon-72.png
│ │ ├── Icon-72@2x.png
│ │ ├── Icon-76.png
│ │ ├── Icon-76@2x.png
│ │ ├── Icon-83.5@2x.png
│ │ ├── Icon-Small-50.png
│ │ ├── Icon-Small-50@2x.png
│ │ ├── Icon-Small.png
│ │ ├── Icon-Small@2x.png
│ │ ├── Icon-Small@3x.png
│ │ ├── Icon.png
│ │ ├── Icon@2x.png
│ │ ├── NotificationIcon@2x.png
│ │ ├── NotificationIcon@3x.png
│ │ ├── NotificationIcon~ipad.png
│ │ ├── NotificationIcon~ipad@2x.png
│ │ └── ios-marketing.png
│ ├── Contents.json
│ ├── LaunchImage.launchimage
│ │ ├── Contents.json
│ │ ├── Default-568h@2x.png
│ │ ├── Default-667h@2x.png
│ │ ├── Default-Landscape-1792h@3x.png
│ │ ├── Default-Landscape-2436h@3x.png
│ │ ├── Default-Landscape-2688h@3x.png
│ │ ├── Default-Landscape-736h@3x.png
│ │ ├── Default-Portrait-1792h@3x.png
│ │ ├── Default-Portrait-2436h@3x.png
│ │ ├── Default-Portrait-2688h@3x.png
│ │ ├── Default-Portrait-736h@3x.png
│ │ ├── Default.png
│ │ ├── Default@2x.png
│ │ ├── Default~ipad.png
│ │ ├── Default~ipad@2x.png
│ │ ├── Default~ipad~landscape.png
│ │ ├── Default~ipad~landscape@2x.png
│ │ ├── Default~ipad~landscape~nostatusbar.png
│ │ ├── Default~ipad~landscape~nostatusbar@2x.png
│ │ ├── Default~ipad~nostatusbar.png
│ │ └── Default~ipad~nostatusbar@2x.png
│ ├── authBackground.imageset
│ │ ├── 14.jpg
│ │ └── Contents.json
│ ├── first.imageset
│ │ ├── Contents.json
│ │ └── first.pdf
│ ├── second.imageset
│ │ ├── Contents.json
│ │ └── second.pdf
│ ├── waosBackground.colorset
│ │ └── Contents.json
│ ├── waosError.colorset
│ │ └── Contents.json
│ ├── waosFacebook.colorset
│ │ └── Contents.json
│ ├── waosInstagram.colorset
│ │ └── Contents.json
│ ├── waosLink.colorset
│ │ └── Contents.json
│ ├── waosLinkedin.colorset
│ │ └── Contents.json
│ ├── waosOnBackground.colorset
│ │ └── Contents.json
│ ├── waosOnError.colorset
│ │ └── Contents.json
│ ├── waosOnPrimary.colorset
│ │ └── Contents.json
│ ├── waosOnSecondary.colorset
│ │ └── Contents.json
│ ├── waosOnSurface.colorset
│ │ └── Contents.json
│ ├── waosPrimary.colorset
│ │ └── Contents.json
│ ├── waosSecondary.colorset
│ │ └── Contents.json
│ ├── waosSurface.colorset
│ │ └── Contents.json
│ └── waosTwitter.colorset
│ │ └── Contents.json
├── Info.plist
├── config
│ ├── default
│ │ ├── development.json
│ │ ├── production.json
│ │ └── release.json
│ ├── fonts
│ │ ├── Font Awesome 5 Brands-Regular-400.otf
│ │ ├── Font Awesome 5 Free-Regular-400.otf
│ │ └── Font Awesome 5 Free-Solid-900.otf
│ └── localizations
│ │ ├── Strings.swift
│ │ ├── en.lproj
│ │ └── Localizable.strings
│ │ └── fr.lproj
│ │ └── Localizable.strings
├── lib
│ ├── helpers
│ │ ├── CookiePlugin.swift
│ │ ├── Errors.swift
│ │ ├── Extensions
│ │ │ ├── ASAuthorizationControllerProxy.swift
│ │ │ ├── Array+SectionModel.swift
│ │ │ ├── Data.swift
│ │ │ ├── Eureka.swift
│ │ │ ├── KeyboardConstraints.swift
│ │ │ ├── L10n.swift
│ │ │ ├── String.swift
│ │ │ ├── UIButton.swift
│ │ │ ├── UIColor.swift
│ │ │ ├── UIImage.swift
│ │ │ ├── UILabel.swift
│ │ │ ├── UILocalizations.swift
│ │ │ ├── UINavigationController.swift
│ │ │ ├── UIScrollView.swift
│ │ │ ├── UISegmentedControl.swift
│ │ │ ├── UITextField.swift
│ │ │ └── UserDefaults.swift
│ │ ├── Libs
│ │ │ ├── PopupView
│ │ │ │ ├── File.swift
│ │ │ │ └── PopupView.swift
│ │ │ ├── ReusableKit
│ │ │ │ ├── ReusableKit.swift
│ │ │ │ ├── UICollectionView+ReusableKit.swift
│ │ │ │ ├── UICollectionView+RxReusableKit.swift
│ │ │ │ ├── UITableView+ReusableKit.swift
│ │ │ │ └── UITableView+RxReusableKit.swift
│ │ │ └── Then
│ │ │ │ └── Then.swift
│ │ ├── MarkDown.swift
│ │ ├── MyResult.swift
│ │ ├── Rx
│ │ │ ├── ASAuthorizationAppleIDButton+Rx.swift
│ │ │ ├── Eureka+Valid+Rx.swift
│ │ │ ├── NSViewController+Rx.swift
│ │ │ ├── ObservableType+Extras.swift
│ │ │ ├── SwiftSpinner+Rx.swift
│ │ │ ├── UIAlertController+Rx.swift
│ │ │ ├── UIImageView+Kingfisher.swift
│ │ │ ├── UIScrollView+Rx.swift
│ │ │ └── UIViewController+Rx.swift
│ │ ├── Stubbed.swift
│ │ ├── UITricks.swift
│ │ ├── Url.swift
│ │ ├── Users.swift
│ │ └── Validations.swift
│ └── services
│ │ ├── Configuration.swift
│ │ ├── Logger.swift
│ │ ├── Networking.swift
│ │ └── Preferences.swift
├── modules
│ ├── app
│ │ ├── AppDelegate.swift
│ │ ├── AppFlow.swift
│ │ ├── AppServicesProvider.swift
│ │ ├── AppSteps.swift
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ └── fr.lproj
│ │ │ └── LaunchScreen.strings
│ ├── auth
│ │ ├── controllers
│ │ │ ├── AuthForgotController.swift
│ │ │ ├── AuthSigninController.swift
│ │ │ └── AuthSignupController.swift
│ │ ├── flow
│ │ │ └── AuthFlow.swift
│ │ ├── models
│ │ │ └── AuthResponses.swift
│ │ ├── reactors
│ │ │ ├── AuthForgotReactor.swift
│ │ │ ├── AuthSigninReactor.swift
│ │ │ └── AuthSignupReactor.swift
│ │ └── services
│ │ │ ├── AuthService.swift
│ │ │ └── api
│ │ │ ├── AuthApi.swift
│ │ │ └── stubbed
│ │ │ ├── forgot.json
│ │ │ ├── oauth.json
│ │ │ ├── signIn.json
│ │ │ ├── signUp.json
│ │ │ └── token.json
│ ├── core
│ │ ├── controllers
│ │ │ ├── CoreCollectionViewCellController.swift
│ │ │ ├── CoreController.swift
│ │ │ ├── CoreFormController.swift
│ │ │ └── CoreTableViewCellController.swift
│ │ ├── flows
│ │ │ └── CoreFlow.swift
│ │ ├── models
│ │ │ ├── CoreModel.swift
│ │ │ └── CoreResponses.swift
│ │ ├── services
│ │ │ └── CoreService.swift
│ │ └── ui
│ │ │ ├── CoreUIButton.swift
│ │ │ ├── CoreUILabel.swift
│ │ │ ├── CoreUITableView.swift
│ │ │ ├── CoreUITextField.swift
│ │ │ └── CoreUiRefreshControl.swift
│ ├── home
│ │ ├── controllers
│ │ │ ├── HomePageController.swift
│ │ │ └── HomeTermsController.swift
│ │ ├── models
│ │ │ ├── PagesModel.swift
│ │ │ └── PagesResponses.swift
│ │ ├── reactors
│ │ │ ├── HomePageReactor.swift
│ │ │ └── HomeTermsReactor.swift
│ │ └── services
│ │ │ ├── HomeService.swift
│ │ │ └── api
│ │ │ ├── HomeApi.swift
│ │ │ └── stubbed
│ │ │ └── changelogs.json
│ ├── onBoarding
│ │ ├── controllers
│ │ │ └── OnBoardingController.swift
│ │ ├── flows
│ │ │ └── OnBoardingFlow.swift
│ │ └── reactors
│ │ │ └── OnBoardingReactor.swift
│ ├── secondController
│ │ ├── controllers
│ │ │ └── SecondController.swift
│ │ ├── flows
│ │ │ └── SecondFlow.swift
│ │ └── reactors
│ │ │ └── SecondReactor.swift
│ ├── tasks
│ │ ├── controllers
│ │ │ ├── TasksCellController.swift
│ │ │ ├── TasksListController.swift
│ │ │ └── TasksViewController.swift
│ │ ├── flows
│ │ │ └── TasksFlow.swift
│ │ ├── models
│ │ │ ├── TasksModel.swift
│ │ │ └── TasksResponses.swift
│ │ ├── reactors
│ │ │ ├── TasksCellReactor.swift
│ │ │ ├── TasksListReactor.swift
│ │ │ └── TasksViewReactor.swift
│ │ └── services
│ │ │ ├── TasksService.swift
│ │ │ └── api
│ │ │ ├── TasksApi.swift
│ │ │ └── stubbed
│ │ │ ├── create.json
│ │ │ ├── delete.json
│ │ │ ├── get.json
│ │ │ ├── list.json
│ │ │ └── update.json
│ └── users
│ │ ├── controllers
│ │ ├── UserController.swift
│ │ ├── UserMoreController.swift
│ │ ├── UserPreferenceController.swift
│ │ └── UserViewController.swift
│ │ ├── flows
│ │ └── UserFlow.swift
│ │ ├── models
│ │ ├── ComplementaryModel.swift
│ │ ├── UserModel.swift
│ │ └── UserPolicyModel.swift
│ │ ├── reactors
│ │ ├── UserMoreReactor.swift
│ │ ├── UserPreferenceReactor.swift
│ │ ├── UserReactor.swift
│ │ └── UserViewReactor.swift
│ │ └── services
│ │ ├── UserService.swift
│ │ └── api
│ │ ├── UserApi.swift
│ │ └── stubbed
│ │ └── me.json
├── waosSwift.entitlements
├── waosSwiftRelease.entitlements
└── waosSwiftdevelopment.entitlements
├── waosSwiftTests
├── Info.plist
└── waosSwiftTests.swift
└── waosSwiftUITests
├── Info.plist
└── waosSwiftUITests.swift
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | open_collective: weareopensource
4 | ko_fi: weareopensource
5 |
6 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
7 | # open_collective: weareopensource
8 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
9 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
10 | # liberapay: # Replace with a single Liberapay username
11 | # issuehunt: # Replace with a single IssueHunt username
12 | # otechie: # Replace with a single Otechie username
13 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: 'bug(context): title '
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: 'feat(context): title'
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "04:00"
8 | open-pull-requests-limit: 10
9 |
--------------------------------------------------------------------------------
/.github/workflows/dependabot.yml:
--------------------------------------------------------------------------------
1 | name: Dependabot auto-merge
2 | on: pull_request
3 |
4 | permissions:
5 | contents: write
6 | pull-requests: write
7 |
8 | jobs:
9 | auto-merge:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: ahmadnassri/action-dependabot-auto-merge@v2
14 | with:
15 | target: minor
16 | github-token: ${{ secrets.WAOS }}
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS
2 | # ===========
3 | .DS_Store
4 | ehthumbs.db
5 | Icon?
6 | Thumbs.db
7 |
8 | # Node and related ecosystem
9 | # ==========================
10 | node_modules/
11 |
12 | # Swift and related ecosystem
13 | # ==========================
14 | .coveralls.yml
15 | reports/
16 | coverage
17 | *.hmap
18 | *.ipa
19 | *.dSYM.zip
20 | *.dSYM
21 | timeline.xctimeline
22 | playground.xcworkspace
23 | fastlane/report.xml
24 | fastlane/Preview.html
25 | fastlane/screenshots/**/*.png
26 | fastlane/test_output
27 | iOSInjectionProject/
28 |
29 | # waos Swift app and assets
30 | # ======================
31 |
32 |
33 | # Build
34 | # ============================
35 | build/
36 | DerivedData/
37 | Carthage/Build
38 | Carthage/Checkouts
39 |
40 | # Ignoring waos Node's gh-pages branch for documenation
41 | _site/
42 |
43 | # General
44 | # =======
45 | *.log
46 | *.csv
47 | *.dat
48 | *.out
49 | *.pid
50 | *.gz
51 | *.tmp
52 | *.bak
53 | *.swp
54 | *.moved-aside
55 | *.xccheckout
56 | *.xcscmblueprint
57 | logs/
58 |
59 | # Various editor
60 | # ==============
61 | *.pbxuser
62 | !default.pbxuser
63 | *.mode1v3
64 | !default.mode1v3
65 | *.mode2v3
66 | !default.mode2v3
67 | *.perspectivev3
68 | !default.perspectivev3
69 | xcuserdata/
70 | *.suo
71 | *.ntvs*
72 | *.njsproj
73 | *.sln
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx --no-install commitlint --edit "$1"
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | included:
2 | - waosSwift
3 | - waosSwiftTests
4 | - waosSwiftUITests
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: swift
2 | osx_image: xcode12
3 | xcode_workspace: waosSwift.xcworkspace
4 | xcode_scheme: waosSwift
5 | xcode_destination: platform=iOS Simulator,OS=13.2.2,name=iPhone 11
6 | before_install:
7 | - rvm use $RVM_RUBY_VERSION #slather
8 | install: bundle install --without=documentation
9 | after_success:
10 | - fastlane lint
11 | - fastlane build_and_test
12 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6 |
7 | # gem "rails"
8 | gem "fastlane", ">= 2.187.0"
9 | gem "slather", ">= 2.7.2"
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | ## License
2 | (The MIT License)
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | 'Software'), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/WIKI.md:
--------------------------------------------------------------------------------
1 | ## Introduction
2 |
3 | Welcome to the Swift wiki! Here you will find various information about this repo.
4 |
5 | ## Menu
6 |
7 | #### Swift Wiki
8 |
9 | - in construction
10 |
11 | #### WAOS
12 |
13 | * [Mindset and what we would like to create](https://weareopensource.me/)
14 | * [How to start a project and maintain updates from stacks](https://blog.weareopensource.me/start-a-project-and-maintain-updates/)
15 | * [Global roadmap and ideas about stacks](https://github.com/weareopensource/weareopensource.github.io/projects/1)
16 | * [How to contribute and help us](https://blog.weareopensource.me/how-to-contribute/)
17 |
18 | # Swift WIKI
19 |
20 | - in construction
21 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = { extends: ['@commitlint/config-conventional'] };
2 |
--------------------------------------------------------------------------------
/example.apns:
--------------------------------------------------------------------------------
1 | {
2 | "aps" : {
3 | "alert" : {
4 | "title" : "sarunw.com",
5 | "body" : "A weekly blog about iOS development",
6 | "link_url": "openTask:5f5d562f71cbbaf22bad3b13"
7 | },
8 | "badge" : 1
9 | },
10 | "Simulator Target Bundle": "me.weareopensoruce.vue.testing",
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/fastlane/.env:
--------------------------------------------------------------------------------
1 | # Project Info
2 | WORKSPACE=waosSwift.xcworkspace
3 | PROJECT=waosSwift.xcodeproj
4 | SCHEME=waosSwift
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | # app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app
2 | # apple_id("[[APPLE_ID]]") # Your Apple email address
3 |
4 |
5 | # For more information about the Appfile, see:
6 | # https://docs.fastlane.tools/advanced/#appfile
7 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:ios)
17 |
18 | platform :ios do
19 |
20 | before_all do
21 | sh 'mkdir ../reports || true'
22 | end
23 |
24 | desc "Lint the project - .swiftlint.yml"
25 | lane :lint do
26 | swiftlint(
27 | mode: :lint,
28 | output_file: './reports/swiftlint.txt',
29 | config_file: '.swiftlint.yml'
30 | )
31 | end
32 |
33 | desc "buil and test the project - .swiftlint.yml"
34 | lane :build_and_test do
35 | # Run tests
36 | scan({
37 | workspace: ENV["WORKSPACE"],
38 | scheme: ENV["SCHEME"],
39 | cloned_source_packages_path: "SourcePackages"
40 | clean: true,
41 | code_coverage: true,
42 | output_types: "html, junit",
43 | devices: [
44 | "iPhone 11 (13.2)",
45 | ],
46 | })
47 |
48 | # Generate code coverage report
49 | slather_ignore = ['ExamplePodCode/*', 'ProjectTestsGroup/*']
50 | slather({
51 | scheme: ENV["SCHEME"],
52 | proj: ENV["PROJECT"],
53 | workspace: ENV["WORKSPACE"],
54 | coveralls: true,
55 | ignore: slather_ignore,
56 | output_directory: "./coverage"
57 | })
58 | end
59 |
60 | end
61 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ================
3 | # Installation
4 |
5 | Make sure you have the latest version of the Xcode command line tools installed:
6 |
7 | ```
8 | xcode-select --install
9 | ```
10 |
11 | Install _fastlane_ using
12 | ```
13 | [sudo] gem install fastlane -NV
14 | ```
15 | or alternatively using `brew cask install fastlane`
16 |
17 | # Available Actions
18 | ## iOS
19 | ### ios lint
20 | ```
21 | fastlane ios lint
22 | ```
23 | Lint the project - .swiftlint.yml
24 | ### ios test
25 | ```
26 | fastlane ios test
27 | ```
28 | test the project - .swiftlint.yml
29 |
30 | ----
31 |
32 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
33 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
34 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@weareopensource/swift",
3 | "description": "Swift - Boilerplate Front : RxSwift, JWT (WIP)",
4 | "version": "0.1.1",
5 | "private": false,
6 | "author": "https://github.com/weareopensource/Swift/graphs/contributors",
7 | "license": "MIT",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/weareopensource/Swift.git"
11 | },
12 | "engines": {
13 | "node": ">=9.11.2",
14 | "npm": ">=6.4.1",
15 | "yarn": ">=1.13.0"
16 | },
17 | "scripts": {
18 | "commit": "npx cz",
19 | "release": "standard-version",
20 | "release:auto": "npx semantic-release"
21 | },
22 | "devDependencies": {
23 | "@commitlint/cli": "^19.3.0",
24 | "@commitlint/config-conventional": "^19.2.2",
25 | "@semantic-release/changelog": "^6.0.3",
26 | "@semantic-release/git": "^10.0.1",
27 | "@weareopensource/conventional-changelog": "^1.7.0",
28 | "commitizen": "^4.3.0",
29 | "husky": "^9.0.11",
30 | "semantic-release": "^24.0.0",
31 | "standard-version": "^9.5.0"
32 | },
33 | "release": {
34 | "branches": [
35 | {
36 | "name": "master"
37 | }
38 | ],
39 | "ci": false,
40 | "repositoryUrl": "https://github.com/weareopensource/Swift.git",
41 | "plugins": [
42 | "@semantic-release/commit-analyzer",
43 | "@semantic-release/release-notes-generator",
44 | "@semantic-release/changelog",
45 | [
46 | "@semantic-release/github",
47 | {
48 | "successComment": false,
49 | "failComment": false
50 | }
51 | ],
52 | [
53 | "@semantic-release/git",
54 | {
55 | "message": "chore(release): ${nextRelease.version} \n\n${nextRelease.notes}"
56 | }
57 | ]
58 | ]
59 | },
60 | "config": {
61 | "commitizen": {
62 | "path": "./node_modules/@weareopensource/conventional-changelog"
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/screenshots/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/screenshots/01.png
--------------------------------------------------------------------------------
/screenshots/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/screenshots/02.png
--------------------------------------------------------------------------------
/screenshots/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/screenshots/03.png
--------------------------------------------------------------------------------
/swiftgen.yml:
--------------------------------------------------------------------------------
1 | strings:
2 | inputs: ./waosSwift/config/localizations/en.lproj/Localizable.strings
3 | outputs:
4 | templateName: structured-swift4
5 | output: ./waosSwift/config/localizations/Strings.swift
--------------------------------------------------------------------------------
/waosSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/waosSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/waosSwift.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/waosSwift.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-40.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-72.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/Icon@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/AppIcon.appiconset/ios-marketing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/AppIcon.appiconset/ios-marketing.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-1792h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-1792h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-2436h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-2436h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-2688h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-2688h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-1792h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-1792h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-2436h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-2436h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-2688h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-2688h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape~nostatusbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape~nostatusbar.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape~nostatusbar@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~landscape~nostatusbar@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~nostatusbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~nostatusbar.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~nostatusbar@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/LaunchImage.launchimage/Default~ipad~nostatusbar@2x.png
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/authBackground.imageset/14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/authBackground.imageset/14.jpg
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/authBackground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "14.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/first.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "first.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/first.imageset/first.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/first.imageset/first.pdf
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/second.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "second.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/second.imageset/second.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/Assets.xcassets/second.imageset/second.pdf
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0xF9",
13 | "alpha" : "1.000",
14 | "blue" : "0xF9",
15 | "green" : "0xF9"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0xF9",
31 | "alpha" : "1.000",
32 | "blue" : "0xF9",
33 | "green" : "0xF9"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0x1E",
49 | "alpha" : "1.000",
50 | "blue" : "0x23",
51 | "green" : "0x20"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosError.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.125",
9 | "green" : "0.000",
10 | "red" : "0.690"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "light"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "0.125",
27 | "green" : "0.000",
28 | "red" : "0.690"
29 | }
30 | },
31 | "idiom" : "universal"
32 | },
33 | {
34 | "appearances" : [
35 | {
36 | "appearance" : "luminosity",
37 | "value" : "dark"
38 | }
39 | ],
40 | "color" : {
41 | "color-space" : "srgb",
42 | "components" : {
43 | "alpha" : "1.000",
44 | "blue" : "0.153",
45 | "green" : "0.153",
46 | "red" : "0.890"
47 | }
48 | },
49 | "idiom" : "universal"
50 | }
51 | ],
52 | "info" : {
53 | "author" : "xcode",
54 | "version" : 1
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosFacebook.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.698",
9 | "green" : "0.404",
10 | "red" : "0.259"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosInstagram.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.424",
9 | "green" : "0.188",
10 | "red" : "0.882"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosLink.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "1.000",
9 | "green" : "0.478",
10 | "red" : "0.000"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "light"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "0.478",
28 | "red" : "0.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | },
33 | {
34 | "appearances" : [
35 | {
36 | "appearance" : "luminosity",
37 | "value" : "dark"
38 | }
39 | ],
40 | "color" : {
41 | "color-space" : "srgb",
42 | "components" : {
43 | "alpha" : "1.000",
44 | "blue" : "1.000",
45 | "green" : "0.478",
46 | "red" : "0.000"
47 | }
48 | },
49 | "idiom" : "universal"
50 | }
51 | ],
52 | "info" : {
53 | "author" : "xcode",
54 | "version" : 1
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosLinkedin.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xB5",
9 | "green" : "0x77",
10 | "red" : "0x00"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosOnBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.000",
13 | "alpha" : "1.000",
14 | "blue" : "0.000",
15 | "green" : "0.000"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0.000",
31 | "alpha" : "1.000",
32 | "blue" : "0.000",
33 | "green" : "0.000"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0xFF",
49 | "alpha" : "1.000",
50 | "blue" : "0xFF",
51 | "green" : "0xFF"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosOnError.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "1.000",
13 | "alpha" : "1.000",
14 | "blue" : "1.000",
15 | "green" : "1.000"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "1.000",
31 | "alpha" : "1.000",
32 | "blue" : "1.000",
33 | "green" : "1.000"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0x00",
49 | "alpha" : "1.000",
50 | "blue" : "0x00",
51 | "green" : "0x00"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosOnPrimary.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0xFF",
13 | "alpha" : "1.000",
14 | "blue" : "0xFF",
15 | "green" : "0xFF"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0xFF",
31 | "alpha" : "1.000",
32 | "blue" : "0xFF",
33 | "green" : "0xFF"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0xFF",
49 | "alpha" : "1.000",
50 | "blue" : "0xFF",
51 | "green" : "0xFF"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosOnSecondary.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.000",
13 | "alpha" : "1.000",
14 | "blue" : "0.000",
15 | "green" : "0.000"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0.000",
31 | "alpha" : "1.000",
32 | "blue" : "0.000",
33 | "green" : "0.000"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0.000",
49 | "alpha" : "1.000",
50 | "blue" : "0.000",
51 | "green" : "0.000"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosOnSurface.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.000",
13 | "alpha" : "1.000",
14 | "blue" : "0.000",
15 | "green" : "0.000"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0.000",
31 | "alpha" : "1.000",
32 | "blue" : "0.000",
33 | "green" : "0.000"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0xFE",
49 | "alpha" : "1.000",
50 | "blue" : "0xFE",
51 | "green" : "0xFE"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosPrimary.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0x1A",
13 | "alpha" : "1.000",
14 | "blue" : "0x9C",
15 | "green" : "0xBC"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0x1A",
31 | "alpha" : "1.000",
32 | "blue" : "0x9C",
33 | "green" : "0xBC"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0x16",
49 | "alpha" : "1.000",
50 | "blue" : "0x85",
51 | "green" : "0xA0"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosSecondary.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0x34",
13 | "alpha" : "1.000",
14 | "blue" : "0xDB",
15 | "green" : "0x98"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0x34",
31 | "alpha" : "1.000",
32 | "blue" : "0xDB",
33 | "green" : "0x98"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0x29",
49 | "alpha" : "1.000",
50 | "blue" : "0xB9",
51 | "green" : "0x80"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosSurface.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0xFF",
13 | "alpha" : "1.000",
14 | "blue" : "0xFF",
15 | "green" : "0xFF"
16 | }
17 | }
18 | },
19 | {
20 | "idiom" : "universal",
21 | "appearances" : [
22 | {
23 | "appearance" : "luminosity",
24 | "value" : "light"
25 | }
26 | ],
27 | "color" : {
28 | "color-space" : "srgb",
29 | "components" : {
30 | "red" : "0xFF",
31 | "alpha" : "1.000",
32 | "blue" : "0xFF",
33 | "green" : "0xFF"
34 | }
35 | }
36 | },
37 | {
38 | "idiom" : "universal",
39 | "appearances" : [
40 | {
41 | "appearance" : "luminosity",
42 | "value" : "dark"
43 | }
44 | ],
45 | "color" : {
46 | "color-space" : "srgb",
47 | "components" : {
48 | "red" : "0x28",
49 | "alpha" : "1.000",
50 | "blue" : "0x2E",
51 | "green" : "0x2A"
52 | }
53 | }
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/waosSwift/Assets.xcassets/waosTwitter.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.949",
9 | "green" : "0.631",
10 | "red" : "0.114"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/waosSwift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | Configuration
22 | $(CONFIGURATION)
23 | LSApplicationQueriesSchemes
24 |
25 | linkedin
26 | instagram
27 | twitter
28 | fb
29 |
30 | LSRequiresIPhoneOS
31 |
32 | NSAppTransportSecurity
33 |
34 | NSAllowsArbitraryLoads
35 |
36 |
37 | NSPhotoLibraryUsageDescription
38 | This app requires access to your photos for alerts customizations and profil avatar.
39 | UIBackgroundModes
40 |
41 | remote-notification
42 |
43 | UILaunchStoryboardName
44 | LaunchScreen
45 | UIMainStoryboardFile
46 | LaunchScreen
47 | UIRequiredDeviceCapabilities
48 |
49 | armv7
50 |
51 | UIStatusBarTintParameters
52 |
53 | UINavigationBar
54 |
55 | Style
56 | UIBarStyleDefault
57 | Translucent
58 |
59 |
60 |
61 | UISupportedInterfaceOrientations
62 |
63 | UIInterfaceOrientationPortrait
64 | UIInterfaceOrientationLandscapeLeft
65 | UIInterfaceOrientationLandscapeRight
66 |
67 | UISupportedInterfaceOrientations~ipad
68 |
69 | UIInterfaceOrientationPortrait
70 | UIInterfaceOrientationPortraitUpsideDown
71 | UIInterfaceOrientationLandscapeLeft
72 | UIInterfaceOrientationLandscapeRight
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/waosSwift/config/default/production.json:
--------------------------------------------------------------------------------
1 | {
2 | "api": {
3 | "protocol": "https",
4 | "host": "node.weareopensource.me",
5 | "port": "",
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/waosSwift/config/default/release.json:
--------------------------------------------------------------------------------
1 | {
2 | "api": {
3 | "protocol": "https",
4 | "host": "node.weareopensource.me",
5 | "port": "",
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/waosSwift/config/fonts/Font Awesome 5 Brands-Regular-400.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/config/fonts/Font Awesome 5 Brands-Regular-400.otf
--------------------------------------------------------------------------------
/waosSwift/config/fonts/Font Awesome 5 Free-Regular-400.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/config/fonts/Font Awesome 5 Free-Regular-400.otf
--------------------------------------------------------------------------------
/waosSwift/config/fonts/Font Awesome 5 Free-Solid-900.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weareopensource/Swift/e18b06ca2be8790c99e2039f32ae4da7f25884aa/waosSwift/config/fonts/Font Awesome 5 Free-Solid-900.otf
--------------------------------------------------------------------------------
/waosSwift/config/localizations/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /**
2 | * Modules
3 | */
4 |
5 | // links
6 | "links_us" = "https://weareopensource.me/us/";
7 | "links_support" = "https://developer.apple.com/support/";
8 | "links_terms" = "terms";
9 | "links_privacy" = "https://www.apple.com/legal/privacy/en-ww/";
10 | "links_legal" = "legal";
11 |
12 | // popup
13 | "popup_signfail" = "Wrong Password or Email.";
14 | "popup_logout" = "You have been logged out !";
15 |
16 | // modals
17 | "modal_confirmation_message" = "are you sure ?";
18 | "modal_confirmation_ok" = "Ok";
19 | "modal_confirmation_remove" = "Remove";
20 | "modal_confirmation_cancel" = "Cancel";
21 | "modal_requirement_title" = "Validation required";
22 | "modal_requirement_accept" = "Accept";
23 |
24 | // onBoarding
25 | "onBoarding_title"= "Welcome !";
26 | "onBoarding_introduction"= "this is the first page of the application, it will only be affixed once after installation. We call it onBoarding. We will not be able to recover them.";
27 | "onBoarding_validation"= "I'm in !";
28 |
29 | // auth
30 | "authSignIn_title"= "Sign In";
31 | "authSignUp_title"= "Sign Up";
32 | "auth_mail"= "Email";
33 | "auth_password"= "Password";
34 | "auth_firstname"= "Firstname";
35 | "auth_lastname"= "Lastname";
36 | "auth_forgot"= "Forgot password?";
37 | "auth_reset"= "Reset password";
38 |
39 | // task
40 | "tasks_title"= "Tasks";
41 |
42 | // example
43 | "second_title"= "Example";
44 |
45 | // user
46 | "user_title"= "Profile";
47 |
48 | "user_edit"= "Edit";
49 | "user_edit_section_account"= "Account";
50 | "user_edit_mail"= "Email";
51 | "user_edit_firstname"= "Firstname";
52 | "user_edit_lastname"= "Lastname";
53 | "user_edit_section_profile"= "Profile";
54 | "user_edit_bio"= "Biography";
55 | "user_edit_section_image"= "Profile picture";
56 | "user_edit_image"= "iPhone Gallery";
57 | "user_edit_image_gravatar"= "Gravatar";
58 | "user_edit_section_socialnetworks"= "Social networks";
59 | "user_edit_socialnetworks_instagram"= "Instagram account name";
60 | "user_edit_socialnetworks_twitter"= "Twitter account name";
61 | "user_edit_socialnetworks_facebook"= "Facebook account name";
62 |
63 | "user_preferences"= "Preferences";
64 | "user_preferences_section"= "Style";
65 | "user_preferences_background"= "Dynamique wallpaper";
66 |
67 | "user_section_app"= "Waos";
68 | "user_blog"= "Blog";
69 | "user_site"= "Website";
70 | "user_us"= "Us ?";
71 | "user_more"= "More informations";
72 |
73 | "user_section_socialnetworks"= "Follow us !";
74 |
75 | "user_section_about"= "About";
76 | "user_support"= "Support";
77 | "user_terms_of_use"= "Terms of use";
78 | "user_privacy_policy"= "Privacy policy";
79 | "user_legal_notice"= "Waos legal";
80 |
81 | "user_section_contact"= "Contact";
82 | "user_report"= "Report a bug";
83 | "user_contact"= "Contact us";
84 | "user_data"= "Request my data";
85 |
86 | "user_section_actions"= "Other";
87 | "user_logout"= "Logout";
88 | "user_delete"= "Delete account and data";
89 |
90 | "user_error_mail"= "You must configure mail on your phone for this.";
91 |
92 | "user_modal_confirmation_delete_message" = "Are you sure? your account and all your data will be deleted.";
93 | "user_modal_confirmation_data_message" = "We will send you all of your data by email. Do not hesitate to write to us if necessary.";
94 |
--------------------------------------------------------------------------------
/waosSwift/config/localizations/fr.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /**
2 | * Modules
3 | */
4 |
5 | // links
6 | "links_us" = "https://weareopensource.me/us/";
7 | "links_support" = "https://developer.apple.com/support/";
8 | "links_terms" = "terms";
9 | "links_privacy" = "https://www.apple.com/legal/privacy/en-ww/";
10 | "links_legal" = "legal";
11 |
12 | // popup
13 | "popup_signfail" = "Mot de passe ou adresse e-mail incorrect.";
14 | "popup_logout" = "Vous avez été déconnecté !";
15 |
16 | // modals
17 | "modal_confirmation_message" = "êtes-vous sûrs ?";
18 | "modal_confirmation_ok" = "Ok";
19 | "modal_confirmation_remove" = "Supprimer";
20 | "modal_confirmation_cancel" = "Annuler";
21 | "modal_requirement_title" = "Validation requise";
22 | "modal_requirement_accept" = "Accepter";
23 |
24 | // onBoarding
25 | "onBoarding_title"= "Bienvenue !";
26 | "onBoarding_introduction"= "ceci est la première page de l'application, elle ne sera affihcée qu'une fois après l'installation. Nous appelons cela onBoarding. Nous ne pourrons pas les récupérer.";
27 | "onBoarding_validation"= "J'en suis !";
28 |
29 | // auth
30 | "authSignIn_title"= "Connexion";
31 | "authSignUp_title"= "Inscription";
32 | "auth_mail"= "Email";
33 | "auth_password"= "Mot de passe";
34 | "auth_firstname"= "Prénom";
35 | "auth_lastname"= "Nom";
36 | "auth_forgot"= "Mot de passe oublié?";
37 | "auth_reset"= "Reset du mot de passe";
38 |
39 | // task
40 | "tasks_title"= "Tasks";
41 |
42 | // example
43 | "second_title"= "Example";
44 |
45 | // user
46 | "user_title"= "Profil";
47 |
48 | "user_edit"= "Editer";
49 | "user_edit_section_account"= "Compte";
50 | "user_edit_mail"= "Email";
51 | "user_edit_firstname"= "Prénom";
52 | "user_edit_lastname"= "Nom";
53 | "user_edit_section_profile"= "Profil";
54 | "user_edit_bio"= "Biographie";
55 | "user_edit_section_image"= "Photo de profil";
56 | "user_edit_image"= "Galerie de l'iPhone";
57 | "user_edit_image_gravatar"= "Gravatar";
58 | "user_edit_section_socialnetworks"= "Réseaux sociaux";
59 | "user_edit_socialnetworks_instagram"= "Nom de compte Instagram";
60 | "user_edit_socialnetworks_twitter"= "Nom de compte Twitter";
61 | "user_edit_socialnetworks_facebook"= "Nom de compte Facebook";
62 |
63 | "user_preferences"= "Préférences";
64 | "user_preferences_section"= "Style";
65 | "user_preferences_background"= "Fond d'écran dynamique";
66 |
67 | "user_section_app"= "Waos";
68 | "user_blog"= "Blog";
69 | "user_site"= "Site web";
70 | "user_us"= "Qui sommes-nous ?";
71 | "user_more"= "Plus d'informations";
72 |
73 | "user_section_socialnetworks"= "Suivez-nous !";
74 |
75 | "user_section_about"= "À propos";
76 | "user_support"= "Aide";
77 | "user_terms_of_use"= "Conditions d'utilisation";
78 | "user_privacy_policy"= "Politique de confidentialité";
79 | "user_legal_notice"= "Mentions légales";
80 |
81 | "user_section_contact"= "Contact";
82 | "user_report"= "Remonter un bug";
83 | "user_contact"= "Nous contacter";
84 | "user_data"= "Demander ma donnée";
85 |
86 | "user_section_actions"= "Autre";
87 | "user_logout"= "Se déconnecter";
88 | "user_delete"= "Supprimer mon compte et mes données";
89 |
90 | "user_error_mail"= "Vous devez configurer mail sur votre téléphone pour cela.";
91 |
92 | "user_modal_confirmation_delete_message" = "êtes-vous sûrs ? votre compte et toutes vos données seront supprimées.";
93 | "user_modal_confirmation_data_message" = "We will send you all of your data by email. Do not hesitate to write to us if necessary.";
94 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/CookiePlugin.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Moya
7 | import KeychainAccess
8 | import Kingfisher
9 |
10 | let keychain = Keychain(service: config["app"]["service"].string ?? "localhost").synchronizable(true)
11 |
12 | /**
13 | * Moya Plugin
14 | */
15 |
16 | struct CookiePlugin: PluginType {
17 | func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
18 | var request = request
19 | if let cookie = CookieStorager.cookie as? String {
20 | request.addValue(cookie, forHTTPHeaderField: "Cookie")
21 | }
22 | return request
23 | }
24 |
25 | func didReceive(_ result: Swift.Result, target: TargetType) {
26 | switch result {
27 | case .success(let response):
28 | guard let response = response.response else {
29 | return
30 | }
31 | _ = CookieStorager.save(httpReq: response)
32 | case .failure:
33 | return
34 | }
35 | }
36 | }
37 |
38 | struct CookieStorager {
39 | static var cookie: Any? {
40 | do {
41 | return try keychain.get("Cookie")
42 | } catch let error {
43 | print(error)
44 | return nil
45 | }
46 | }
47 |
48 | static func save(httpReq: HTTPURLResponse) -> Bool {
49 | guard let cookie = httpReq.allHeaderFields["Set-Cookie"] as? String else {
50 | return false
51 | }
52 | if(cookie.contains("TOKEN")) {
53 | do {
54 | try keychain.set(cookie, key: "Cookie")
55 | } catch let error {
56 | print(error)
57 | return false
58 | }
59 | }
60 | return false
61 | }
62 | }
63 |
64 | /**
65 | * Kingfisher Modifier
66 | */
67 |
68 | let cookieModifier = AnyModifier { request in
69 | var request = request
70 | if let cookie = CookieStorager.cookie as? String {
71 | request.addValue(cookie, forHTTPHeaderField: "Cookie")
72 | }
73 | return request
74 | }
75 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/ASAuthorizationControllerProxy.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import AuthenticationServices
6 | import RxCocoa
7 | import RxSwift
8 | import UIKit
9 | import AuthenticationServices
10 |
11 | /**
12 | * Extension
13 | */
14 |
15 | @available(iOS 13.0, *)
16 | extension ASAuthorizationController: HasDelegate {
17 | public typealias Delegate = ASAuthorizationControllerDelegate
18 | }
19 |
20 | @available(iOS 13.0, *)
21 | class ASAuthorizationControllerProxy: DelegateProxy,
22 | DelegateProxyType,
23 | ASAuthorizationControllerDelegate,
24 | ASAuthorizationControllerPresentationContextProviding {
25 |
26 | var presentationWindow: UIWindow = UIWindow()
27 |
28 | public init(controller: ASAuthorizationController) {
29 | super.init(parentObject: controller, delegateProxy: ASAuthorizationControllerProxy.self)
30 | }
31 |
32 | // MARK: - DelegateProxyType
33 | public static func registerKnownImplementations() {
34 | register { ASAuthorizationControllerProxy(controller: $0) }
35 | }
36 |
37 | // MARK: - Proxy Subject
38 | internal lazy var didComplete = PublishSubject()
39 |
40 | // MARK: - ASAuthorizationControllerDelegate
41 | func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
42 | didComplete.onNext(authorization)
43 | didComplete.onCompleted()
44 | }
45 |
46 | func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
47 | didComplete.onCompleted()
48 | }
49 |
50 | // MARK: - ASAuthorizationControllerPresentationContextProviding
51 | func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
52 | return presentationWindow
53 | }
54 |
55 | // MARK: - Completed
56 | deinit {
57 | self.didComplete.onCompleted()
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/Array+SectionModel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxDataSources
7 |
8 | /**
9 | * Extension
10 | */
11 |
12 | extension Array where Element: SectionModelType {
13 |
14 | public subscript(indexPath: IndexPath) -> Element.Item {
15 | get {
16 | return self[indexPath.section].items[indexPath.item]
17 | }
18 | mutating set {
19 | self.update(section: indexPath.section) { items in
20 | items[indexPath.item] = newValue
21 | }
22 | }
23 | }
24 |
25 | public mutating func insert(_ newElement: Element.Item, at indexPath: IndexPath) {
26 | self.update(section: indexPath.section) { items in
27 | items.insert(newElement, at: indexPath.item)
28 | }
29 | }
30 |
31 | @discardableResult
32 | public mutating func remove(at indexPath: IndexPath) -> Element.Item {
33 | return self.update(section: indexPath.section) { items in
34 | return items.remove(at: indexPath.item)
35 | }
36 | }
37 |
38 | private mutating func replace(section: Int, items: [Element.Item]) {
39 | self[section] = Element.init(original: self[section], items: items)
40 | }
41 |
42 | private mutating func update(section: Int, mutate: (inout [Element.Item]) -> T) -> T {
43 | var items = self[section].items
44 | let value = mutate(&items)
45 | self[section] = Element.init(original: self[section], items: items)
46 | return value
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/Data.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * Extension
9 | */
10 |
11 | extension Data {
12 | private static let mimeTypeSignatures: [UInt8: String] = [
13 | 0xFF: "image/jpeg",
14 | 0x89: "image/png",
15 | 0x47: "image/gif",
16 | 0x49: "image/tiff",
17 | 0x4D: "image/tiff",
18 | 0x25: "application/pdf",
19 | 0xD0: "application/vnd",
20 | 0x46: "text/plain"
21 | ]
22 |
23 | var mimeType: String {
24 | var c: UInt8 = 0
25 | copyBytes(to: &c, count: 1)
26 | return Data.mimeTypeSignatures[c] ?? "application/octet-stream"
27 | }
28 |
29 | var imgExtension: String {
30 | var c: UInt8 = 0
31 | copyBytes(to: &c, count: 1)
32 | return String(Data.mimeTypeSignatures[c]?.split(separator: "/")[1] ?? "unknown")
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/Eureka.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Eureka
7 | import FontAwesome
8 |
9 | /**
10 | * Extension
11 | */
12 |
13 | extension Form {
14 | /**
15 | * @desc merge error of sections to footer of it
16 | */
17 | public func mergeErrorToFooter() {
18 | for section in allSections {
19 | section.footer?.title = ""
20 | for row in section {
21 | if(row.validationErrors.count > 0) {
22 | section.footer?.title = "\(section.footer?.title ?? "") \(row.validationErrors.compactMap({ $0.msg }).joined(separator: ". ")). "
23 | }
24 | }
25 | section.reload()
26 | }
27 | }
28 |
29 | }
30 |
31 | extension TextRow {
32 | /**
33 | * @desc set left font awesome icon on
34 | * @param {String} icon code,
35 | * @param {FontAwesomeStyle} icon style,
36 | * @param {UIColor} icon color,
37 | * @param {Int} icon padding,
38 | * @param {Int} icon size,
39 | * @param {CGFloat} icon opacity,
40 | */
41 | public func setFontAwesomeIcon(_ code: String = "", style: FontAwesomeStyle = .solid, color: UIColor = .lightGray, padding: Int = 5, size: Int = 22, opacity: CGFloat = 0.5) {
42 | let outerView = UIView(frame: CGRect(x: 0, y: 0, width: size+padding*2, height: size) )
43 | let iconView = UIImageView(frame: CGRect(x: 0, y: 0, width: size, height: size))
44 | iconView.image = UIImage.fontAwesomeIcon(code: code, style: style, textColor: color, size: CGSize(width: 22, height: 22))
45 | iconView.alpha = opacity
46 | outerView.addSubview(iconView)
47 | cell.textField.leftView = outerView
48 | cell.textField.leftViewMode = .always
49 | }
50 |
51 | }
52 |
53 | extension EmailRow {
54 | /**
55 | * @desc set left font awesome icon on
56 | * @param {String} icon code,
57 | * @param {FontAwesomeStyle} icon style,
58 | * @param {UIColor} icon color,
59 | * @param {Int} icon padding,
60 | * @param {Int} icon size,
61 | * @param {CGFloat} icon opacity,
62 | */
63 | public func setFontAwesomeIcon(_ code: String = "", style: FontAwesomeStyle = .solid, color: UIColor = .lightGray, padding: Int = 5, size: Int = 22, opacity: CGFloat = 0.5) {
64 | let outerView = UIView(frame: CGRect(x: 0, y: 0, width: size+padding*2, height: size) )
65 | let iconView = UIImageView(frame: CGRect(x: 0, y: 0, width: size, height: size))
66 | iconView.image = UIImage.fontAwesomeIcon(code: code, style: style, textColor: color, size: CGSize(width: 22, height: 22))
67 | iconView.alpha = opacity
68 | outerView.addSubview(iconView)
69 | cell.textField.leftView = outerView
70 | cell.textField.leftViewMode = .always
71 | }
72 |
73 | }
74 |
75 | extension ButtonRow {
76 | /**
77 | * @desc set left font awesome icon on
78 | * @param {String} icon code,
79 | * @param {FontAwesomeStyle} icon style,
80 | * @param {UIColor} icon color,
81 | * @param {Int} icon size,
82 | * @param {CGFloat} icon opacity,
83 | */
84 | public func setFontAwesomeIcon(_ code: String = "", style: FontAwesomeStyle = .solid, color: UIColor = .lightGray, size: Int = 22, opacity: CGFloat = 0.5) {
85 | cell.imageView?.image = UIImage.fontAwesomeIcon(code: code, style: style, textColor: color.withAlphaComponent(opacity), size: CGSize(width: size, height: size))
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/L10n.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * Extension
9 | */
10 |
11 | extension L10n {
12 |
13 | static func get(_ table: String, _ key: String) -> String {
14 | // swiftlint:disable:next nslocalizedstring_key
15 | let format = NSLocalizedString(key, tableName: table, comment: "")
16 | return String(format: format, locale: Locale.current)
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/String.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Foundation
7 | import CommonCrypto
8 |
9 | /**
10 | * extension
11 | */
12 |
13 | extension String {
14 | var md5: String {
15 | let data = Data(self.utf8)
16 | let hash = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> [UInt8] in
17 | var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
18 | CC_MD5(bytes.baseAddress, CC_LONG(data.count), &hash)
19 | return hash
20 | }
21 | return hash.map { String(format: "%02x", $0) }.joined()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UIButton.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * extension
9 | */
10 |
11 | extension UIButton {
12 | /**
13 | * @desc setBackgroundColor
14 | * @param {UIColor} UIControl,
15 | * @param {UIControl.state} forState,
16 | */
17 | func setBackgroundColor(color: UIColor, forState: UIControl.State) {
18 | self.clipsToBounds = true // add this to maintain corner radius
19 | UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
20 | if let context = UIGraphicsGetCurrentContext() {
21 | context.setFillColor(color.cgColor)
22 | context.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
23 | let colorImage = UIGraphicsGetImageFromCurrentImageContext()
24 | UIGraphicsEndImageContext()
25 | self.setBackgroundImage(colorImage, for: forState)
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UIColor.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * Extension
9 | */
10 |
11 | extension UIColor {
12 |
13 | /**
14 | * @desc lighter color
15 | * @param {CGFloat} percentage,
16 | */
17 | func lighter(by percentage: CGFloat = 30.0) -> UIColor? {
18 | return self.adjust(by: abs(percentage) )
19 | }
20 |
21 | /**
22 | * @desc darker color
23 | * @param {CGFloat} percentage,
24 | */
25 | func darker(by percentage: CGFloat = 30.0) -> UIColor? {
26 | return self.adjust(by: -1 * abs(percentage) )
27 | }
28 |
29 | /**
30 | * @desc adjust color darkness / lightness from coefficient
31 | * @param {CGFloat} percentage,
32 | */
33 | func adjust(by percentage: CGFloat = 30.0) -> UIColor? {
34 | var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
35 | if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
36 | return UIColor(red: min(red + percentage/100, 1.0),
37 | green: min(green + percentage/100, 1.0),
38 | blue: min(blue + percentage/100, 1.0),
39 | alpha: alpha)
40 | } else {
41 | return nil
42 | }
43 | }
44 |
45 | func toHex(alpha: Bool = false) -> String? {
46 | guard let components = cgColor.components, components.count >= 3 else {
47 | return nil
48 | }
49 |
50 | let r = Float(components[0])
51 | let g = Float(components[1])
52 | let b = Float(components[2])
53 | var a = Float(1.0)
54 |
55 | if components.count >= 4 {
56 | a = Float(components[3])
57 | }
58 |
59 | if alpha {
60 | return String(format: "%02lX%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255), lroundf(a * 255))
61 | } else {
62 | return String(format: "%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255))
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UIImage.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * extension
9 | */
10 |
11 | extension UIImage {
12 | /**
13 | * @desc set blur effect on UIImageView with a radius coefficient
14 | * @param {CGFloat} radius,
15 | */
16 | func blurred(radius: CGFloat) -> UIImage {
17 | let ciContext = CIContext(options: nil)
18 | guard let cgImage = cgImage else { return self }
19 | let inputImage = CIImage(cgImage: cgImage)
20 | guard let clampFilter = CIFilter(name: "CIAffineClamp") else { return self }
21 | clampFilter.setDefaults()
22 | clampFilter.setValue(inputImage, forKey: kCIInputImageKey)
23 | guard let ciFilter = CIFilter(name: "CIGaussianBlur") else { return self }
24 | ciFilter.setValue(clampFilter.outputImage, forKey: kCIInputImageKey)
25 | ciFilter.setValue(radius, forKey: "inputRadius")
26 | guard let resultImage = ciFilter.value(forKey: kCIOutputImageKey) as? CIImage else { return self }
27 | guard let cgImage2 = ciContext.createCGImage(resultImage, from: inputImage.extent) else { return self }
28 | return UIImage(cgImage: cgImage2)
29 | }
30 |
31 | /**
32 | * @desc lighter image
33 | * @param {CGFloat} percentage,
34 | */
35 | func lighter(by percentage: CGFloat = 30) -> UIImage? {
36 | return self.adjust(by: abs(percentage) )
37 | }
38 |
39 | /**
40 | * @desc darker image
41 | * @param {CGFloat} percentage,
42 | */
43 | func darker(by percentage: CGFloat = 30) -> UIImage? {
44 | return self.adjust(by: -1 * abs(percentage) )
45 | }
46 |
47 | /**
48 | * @desc adjust image darkness / lightness from coefficient
49 | * @param {CGFloat} percentage,
50 | */
51 | func adjust(by percentage: CGFloat = 30) -> UIImage? {
52 | let ciContext = CIContext(options: nil)
53 | guard let cgImage = cgImage else { return self }
54 | let inputImage = CIImage(cgImage: cgImage)
55 | guard let ciFilter = CIFilter(name: "CIExposureAdjust") else { return self }
56 | ciFilter.setValue(inputImage, forKey: "inputImage")
57 | ciFilter.setValue(percentage/100, forKey: "inputEV")
58 | guard let resultImage = ciFilter.value(forKey: kCIOutputImageKey) as? CIImage else { return self }
59 | guard let cgImage2 = ciContext.createCGImage(resultImage, from: inputImage.extent) else { return self }
60 | return UIImage(cgImage: cgImage2)
61 | }
62 |
63 | /**
64 | * @desc adjust image orientation if needed in exif
65 | */
66 | func adjustOrientation() -> UIImage? {
67 | switch imageOrientation {
68 | case .up:
69 | return self
70 | default:
71 | UIGraphicsBeginImageContextWithOptions(size, false, scale)
72 | draw(in: CGRect(origin: .zero, size: size))
73 | let result = UIGraphicsGetImageFromCurrentImageContext()
74 | UIGraphicsEndImageContext()
75 | return result
76 | }
77 | }
78 |
79 | /**
80 | * @desc resizeImage width max target Size
81 | */
82 | func resizeImage(targetSize: CGSize) -> UIImage? {
83 | let size = self.size
84 | let widthRatio = targetSize.width / size.width
85 | let heightRatio = targetSize.height / size.height
86 | let newSize = widthRatio > heightRatio ? CGSize(width: size.width * heightRatio, height: size.height * heightRatio) : CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
87 | let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
88 |
89 | UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
90 | self.draw(in: rect)
91 | let newImage = UIGraphicsGetImageFromCurrentImageContext()
92 | UIGraphicsEndImageContext()
93 |
94 | return newImage
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UILabel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * extension
9 | */
10 |
11 | extension UILabel {
12 | /**
13 | * @desc set new spacing for uilabel, line and letters
14 | * @param {CGFloat} lineSpacing,
15 | * @param {CGFloat} letterSpacing,
16 | */
17 | func setSpacing(lineSpacing: CGFloat = 0.0, letterSpacing: CGFloat = 1.15) {
18 | if let labelText = text, labelText.count > 0 {
19 | let paragraphStyle = NSMutableParagraphStyle()
20 | paragraphStyle.lineSpacing = lineSpacing
21 | paragraphStyle.lineHeightMultiple = lineSpacing
22 | let attributedString = NSMutableAttributedString(string: labelText)
23 | attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
24 | attributedString.addAttribute(NSAttributedString.Key.kern, value: letterSpacing, range: NSRange(location: 0, length: attributedString.length - 1))
25 | self.attributedText = attributedString
26 | }
27 | }
28 |
29 | /**
30 | * @desc set bold text in uilabel
31 | * @param {String} regualText,
32 | * @param {String} boldiText,
33 | **/
34 | public func setBold(string: String, bold: String) {
35 | let attrs = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: font.pointSize)]
36 | let regularString = NSMutableAttributedString(string: string)
37 | let range = (string as NSString).range(of: bold)
38 | regularString.addAttributes(attrs, range: range)
39 | attributedText = regularString
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UILocalizations.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * @desc Extension of UILabel which allows to select a localization string "localizableText" from the storyboard
9 | */
10 | extension UILabel {
11 | @IBInspectable var localizableText: String? {
12 | get { return "" }
13 | set(value) { text = NSLocalizedString(value!, comment: "") }
14 | }
15 | }
16 |
17 | /**
18 | * @desc Extension of String which allows to select a localization string "localizableText" from the storyboard
19 | */
20 | extension String {
21 | var localized: String {
22 | get { return NSLocalizedString(self, comment: "") }
23 | }
24 | }
25 |
26 | /**
27 | * @desc Extension of UIButton which allows to select a localization string "localizableText" from the storyboard
28 | */
29 | extension UIButton {
30 | @IBInspectable var localizedTitle: String {
31 | get { return "" }
32 | set { self.setTitle(newValue.localized, for: .normal) }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UINavigationController.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * extension
9 | */
10 |
11 | extension UINavigationController {
12 | /**
13 | * @desc clear navigation controller background
14 | */
15 | func clear() {
16 | self.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
17 | self.navigationBar.shadowImage = UIImage()
18 | self.navigationBar.isTranslucent = true
19 | self.view.backgroundColor = .clear
20 | self.navigationBar.backgroundColor = .clear
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UIScrollView.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * Dependencies
9 | */
10 |
11 | extension UIScrollView {
12 |
13 | func isBottom(toleranceHeight: CGFloat) -> Bool {
14 | return contentOffset.y > contentSize.height - frame.height + contentInset.bottom - toleranceHeight
15 | }
16 |
17 | func isNeedScroll() -> Bool {
18 | return (contentSize.width > self.frame.width) ||
19 | (contentSize.height > self.frame.height)
20 | }
21 |
22 | func scrollToBottom(animation: Bool) {
23 | scrollToBottom(offset: 0, animation: animation)
24 | }
25 |
26 | func scrollToBottom(offset: CGFloat, animation: Bool) {
27 | UIView.animate(withDuration: animation ? 0.25 : 0) {
28 | self.contentOffset = CGPoint(x: self.contentOffset.x,
29 | y: self.contentSize.height - self.frame.size.height + self.contentInset.bottom + offset)
30 | }
31 | }
32 |
33 | var remaining: CGPoint {
34 | let horizontal = self.contentSize.width - self.frame.width - self.contentOffset.x
35 | let vertical = self.contentSize.height - self.frame.height - self.contentOffset.y
36 | return CGPoint(x: horizontal, y: vertical)
37 | }
38 |
39 | func setCurrentPage(_ page: Int, animated: Bool) {
40 | var rect = bounds
41 | rect.origin.x = rect.width * CGFloat(page)
42 | rect.origin.y = 0
43 | scrollRectToVisible(rect, animated: animated)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UISegmentedControl.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * extension
9 | */
10 |
11 | extension UISegmentedControl {
12 |
13 | func updateTitle(_ titles: [String?]) {
14 | removeAllSegments()
15 | for t in titles {
16 | insertSegment(withTitle: t, at: numberOfSegments, animated: true)
17 | }
18 |
19 | }
20 |
21 | }
22 |
23 | func fixBackgroundSegmentControl( _ segmentControl: UISegmentedControl) {
24 | if #available(iOS 13.0, *) {
25 | //just to be sure it is full loaded
26 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
27 | for i in 0...(segmentControl.numberOfSegments-1) {
28 | let backgroundSegmentView = segmentControl.subviews[i]
29 | //it is not enogh changing the background color. It has some kind of shadow layer
30 | backgroundSegmentView.isHidden = true
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UITextField.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import FontAwesome
7 |
8 | /**
9 | * extension
10 | */
11 |
12 | extension UITextField {
13 | // MARK: Constants
14 |
15 | struct Metric {
16 | static let error = UIColor(named: config["theme"]["themes"]["waos"]["error"].string ?? "")
17 | }
18 |
19 | /**
20 | * @desc set left font awesome icon on
21 | * @param {String} icon code,
22 | * @param {FontAwesomeStyle} icon style,
23 | * @param {UIColor} icon color,
24 | * @param {Int} icon padding,
25 | * @param {Int} icon size,
26 | * @param {CGFloat} icon opacity,
27 | */
28 | public func setFontAwesomeIcon(_ code: String = "", style: FontAwesomeStyle = .solid, _ color: UIColor = .gray, padding: Int = 10, size: Int = 22, opacity: CGFloat = 0.5) {
29 | let outerView = UIView(frame: CGRect(x: 0, y: 0, width: size+padding*2, height: size) )
30 | let iconView = UIImageView(frame: CGRect(x: padding, y: 0, width: size, height: size))
31 | iconView.image = UIImage.fontAwesomeIcon(code: code, style: style, textColor: color, size: CGSize(width: 22, height: 22))
32 | iconView.alpha = opacity
33 | outerView.addSubview(iconView)
34 | leftView = outerView
35 | leftViewMode = .always
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Extensions/UserDefaults.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * Extension
9 | */
10 |
11 | extension UserDefaults {
12 |
13 | subscript(key: String) -> T? {
14 | get {
15 | return value(forKey: key) as? T
16 | }
17 | set {
18 | set(newValue, forKey: key)
19 | }
20 | }
21 |
22 | subscript(key: String) -> T? {
23 | get {
24 | if let rawValue = value(forKey: key) as? T.RawValue {
25 | return T(rawValue: rawValue)
26 | }
27 | return nil
28 | }
29 | set {
30 | set(newValue?.rawValue, forKey: key)
31 | }
32 | }
33 |
34 | func contains(_ key: String) -> Bool {
35 | return UserDefaults.standard.object(forKey: key) != nil
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Libs/ReusableKit/ReusableKit.swift:
--------------------------------------------------------------------------------
1 | #if os(iOS)
2 | import UIKit
3 |
4 | public protocol CellType: AnyObject {
5 | var reuseIdentifier: String? { get }
6 | }
7 |
8 | /// A generic class that represents reusable cells.
9 | public struct ReusableCell {
10 | public typealias Class = Cell
11 |
12 | public let `class`: Class.Type = Class.self
13 | public let identifier: String
14 | public let nib: UINib?
15 |
16 | /// Create and returns a new `ReusableCell` instance.
17 | ///
18 | /// - parameter identifier: A reuse identifier. Use random UUID string if identifier is not provided.
19 | /// - parameter nib: A `UINib` instance. Use this when registering from xib.
20 | public init(identifier: String? = nil, nib: UINib? = nil) {
21 | self.identifier = nib?.instantiate(withOwner: nil, options: nil).lazy
22 | .compactMap { ($0 as? CellType)?.reuseIdentifier }
23 | .first ?? identifier ?? UUID().uuidString
24 | self.nib = nib
25 | }
26 |
27 | /// A convenience initializer.
28 | ///
29 | /// - parameter identifier: A reuse identifier. Use random UUID string if identifier is not provided.
30 | /// - parameter nibName: A name of nib.
31 | public init(identifier: String? = nil, nibName: String) {
32 | let nib = UINib(nibName: nibName, bundle: nil)
33 | self.init(identifier: identifier, nib: nib)
34 | }
35 | }
36 |
37 | public protocol ViewType: AnyObject {
38 | }
39 |
40 | /// A generic class that represents reusable views.
41 | public struct ReusableView {
42 | public typealias Class = View
43 |
44 | public let `class`: Class.Type = Class.self
45 | public let identifier: String
46 | public let nib: UINib?
47 |
48 | /// Create and returns a new `ReusableView` instance.
49 | ///
50 | /// - parameter identifier: A reuse identifier. Use random UUID string if identifier is not provided.
51 | /// - parameter nib: A `UINib` instance. Use this when registering from xib.
52 | public init(identifier: String? = nil, nib: UINib? = nil) {
53 | self.identifier = identifier ?? UUID().uuidString
54 | self.nib = nib
55 | }
56 |
57 | /// A convenience initializer.
58 | ///
59 | /// - parameter identifier: A reuse identifier. Use random UUID string if identifier is not provided.
60 | /// - parameter nibName: A name of nib.
61 | public init(identifier: String? = nil, nibName: String) {
62 | let nib = UINib(nibName: nibName, bundle: nil)
63 | self.init(identifier: identifier, nib: nib)
64 | }
65 | }
66 | #endif
67 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Libs/ReusableKit/UICollectionView+ReusableKit.swift:
--------------------------------------------------------------------------------
1 | #if os(iOS)
2 | import UIKit
3 |
4 | /// An enumeration that represents UICollectionView supplementary view kind.
5 | public enum SupplementaryViewKind: String {
6 | case header, footer
7 |
8 | public init?(rawValue: String) {
9 | switch rawValue {
10 | case UICollectionView.elementKindSectionHeader: self = .header
11 | case UICollectionView.elementKindSectionFooter: self = .footer
12 | default: return nil
13 | }
14 | }
15 |
16 | public var rawValue: String {
17 | switch self {
18 | case .header: return UICollectionView.elementKindSectionHeader
19 | case .footer: return UICollectionView.elementKindSectionFooter
20 | }
21 | }
22 | }
23 |
24 | extension UICollectionViewCell: CellType {
25 | }
26 |
27 | extension UIView: ViewType {
28 | }
29 |
30 | extension UICollectionView {
31 |
32 | // MARK: Cell
33 | /// Registers a generic cell for use in creating new collection view cells.
34 | public func register(_ cell: ReusableCell) {
35 | if let nib = cell.nib {
36 | self.register(nib, forCellWithReuseIdentifier: cell.identifier)
37 | } else {
38 | self.register(Cell.self, forCellWithReuseIdentifier: cell.identifier)
39 | }
40 | }
41 |
42 | /// Returns a generic reusable cell located by its identifier.
43 | public func dequeue(_ cell: ReusableCell, for indexPath: IndexPath) -> Cell {
44 | return self.dequeueReusableCell(withReuseIdentifier: cell.identifier, for: indexPath) as! Cell
45 | }
46 |
47 | // MARK: Supplementary View
48 | /// Registers a generic view for use in creating new supplementary views for the collection view.
49 | public func register(_ view: ReusableView, kind: SupplementaryViewKind) {
50 | self.register(view, kind: kind.rawValue)
51 | }
52 |
53 | /// Registers a generic view for use in creating new supplementary views for the collection view.
54 | public func register(_ view: ReusableView, kind: String) {
55 | if let nib = view.nib {
56 | self.register(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: view.identifier)
57 | } else {
58 | self.register(View.self, forSupplementaryViewOfKind: kind, withReuseIdentifier: view.identifier)
59 | }
60 | }
61 |
62 | /// Returns a generic reusable supplementary view located by its identifier and kind.
63 | public func dequeue(_ view: ReusableView, kind: String, for indexPath: IndexPath) -> View {
64 | return self.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: view.identifier, for: indexPath) as! View
65 | }
66 |
67 | /// Returns a generic reusable supplementary view located by its identifier and kind.
68 | public func dequeue(_ view: ReusableView, kind: SupplementaryViewKind, for indexPath: IndexPath) -> View {
69 | return self.dequeue(view, kind: kind.rawValue, for: indexPath)
70 | }
71 | }
72 | #endif
73 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Libs/ReusableKit/UICollectionView+RxReusableKit.swift:
--------------------------------------------------------------------------------
1 | import RxCocoa
2 | import RxSwift
3 |
4 | #if os(iOS)
5 | import UIKit
6 |
7 | extension Reactive where Base: UICollectionView {
8 | public func items(
9 | _ reusableCell: ReusableCell
10 | ) -> (_ source: O)
11 | -> (_ configureCell: @escaping (Int, S.Iterator.Element, Cell) -> Void)
12 | -> Disposable
13 | where O.Element == S {
14 | return { source in
15 | return { configureCell in
16 | return self.items(cellIdentifier: reusableCell.identifier, cellType: Cell.self)(source)(configureCell)
17 | }
18 | }
19 | }
20 | }
21 | #endif
22 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Libs/ReusableKit/UITableView+ReusableKit.swift:
--------------------------------------------------------------------------------
1 | #if os(iOS)
2 | import UIKit
3 |
4 | extension UITableViewCell: CellType {
5 | }
6 |
7 | extension UITableView {
8 |
9 | // MARK: Cell
10 | /// Registers a generic cell for use in creating new table cells.
11 | public func register(_ cell: ReusableCell) {
12 | if let nib = cell.nib {
13 | self.register(nib, forCellReuseIdentifier: cell.identifier)
14 | } else {
15 | self.register(Cell.self, forCellReuseIdentifier: cell.identifier)
16 | }
17 | }
18 |
19 | /// Returns a generic reusable cell located by its identifier.
20 | public func dequeue(_ cell: ReusableCell) -> Cell? {
21 | return self.dequeueReusableCell(withIdentifier: cell.identifier) as? Cell
22 | }
23 |
24 | /// Returns a generic reusable cell located by its identifier.
25 | public func dequeue(_ cell: ReusableCell, for indexPath: IndexPath) -> Cell {
26 | return self.dequeueReusableCell(withIdentifier: cell.identifier, for: indexPath) as! Cell
27 | }
28 |
29 | // MARK: View
30 | /// Registers a generic view for use in creating new table header or footer views.
31 | public func register(_ cell: ReusableView) {
32 | if let nib = cell.nib {
33 | self.register(nib, forHeaderFooterViewReuseIdentifier: cell.identifier)
34 | } else {
35 | self.register(View.self, forHeaderFooterViewReuseIdentifier: cell.identifier)
36 | }
37 | }
38 |
39 | /// Returns a generic reusable header of footer view located by its identifier.
40 | public func dequeue(_ view: ReusableView) -> View? {
41 | return self.dequeueReusableHeaderFooterView(withIdentifier: view.identifier) as? View
42 | }
43 | }
44 | #endif
45 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Libs/ReusableKit/UITableView+RxReusableKit.swift:
--------------------------------------------------------------------------------
1 | import RxCocoa
2 | import RxSwift
3 |
4 | #if os(iOS)
5 | import UIKit
6 |
7 | extension Reactive where Base: UITableView {
8 | public func items(
9 | _ reusableCell: ReusableCell
10 | ) -> (_ source: O)
11 | -> (_ configureCell: @escaping (Int, S.Iterator.Element, Cell) -> Void)
12 | -> Disposable
13 | where O.Element == S {
14 | return { source in
15 | return { configureCell in
16 | return self.items(cellIdentifier: reusableCell.identifier, cellType: Cell.self)(source)(configureCell)
17 | }
18 | }
19 | }
20 | }
21 | #endif
22 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Libs/Then/Then.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Suyeol Jeon (xoul.kr)
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 | import CoreGraphics
25 | #if os(iOS) || os(tvOS)
26 | import UIKit.UIGeometry
27 | #endif
28 |
29 | public protocol Then {}
30 |
31 | extension Then where Self: Any {
32 |
33 | /// Makes it available to set properties with closures just after initializing and copying the value types.
34 | ///
35 | /// let frame = CGRect().with {
36 | /// $0.origin.x = 10
37 | /// $0.size.width = 100
38 | /// }
39 | public func with(_ block: (inout Self) throws -> Void) rethrows -> Self {
40 | var copy = self
41 | try block(©)
42 | return copy
43 | }
44 |
45 | /// Makes it available to execute something with closures.
46 | ///
47 | /// UserDefaults.standard.do {
48 | /// $0.set("devxoul", forKey: "username")
49 | /// $0.set("devxoul@gmail.com", forKey: "email")
50 | /// $0.synchronize()
51 | /// }
52 | public func `do`(_ block: (Self) throws -> Void) rethrows {
53 | try block(self)
54 | }
55 |
56 | }
57 |
58 | extension Then where Self: AnyObject {
59 |
60 | /// Makes it available to set properties with closures just after initializing.
61 | ///
62 | /// let label = UILabel().then {
63 | /// $0.textAlignment = .Center
64 | /// $0.textColor = UIColor.blackColor()
65 | /// $0.text = "Hello, World!"
66 | /// }
67 | public func then(_ block: (Self) throws -> Void) rethrows -> Self {
68 | try block(self)
69 | return self
70 | }
71 |
72 | }
73 |
74 | extension NSObject: Then {}
75 |
76 | extension CGPoint: Then {}
77 | extension CGRect: Then {}
78 | extension CGSize: Then {}
79 | extension CGVector: Then {}
80 |
81 | #if os(iOS) || os(tvOS)
82 | extension UIEdgeInsets: Then {}
83 | extension UIOffset: Then {}
84 | extension UIRectEdge: Then {}
85 | #endif
86 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/MyResult.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Result
3 | */
4 |
5 | public enum MyResult {
6 | case success(T)
7 | case error(E)
8 | }
9 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/ASAuthorizationAppleIDButton+Rx.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import AuthenticationServices
6 | import UIKit
7 | import RxSwift
8 |
9 | /**
10 | * extension
11 | */
12 |
13 | @available(iOS 13.0, *)
14 | extension Reactive where Base: ASAuthorizationAppleIDProvider {
15 | public func login(scope: [ASAuthorization.Scope]? = nil) -> Observable {
16 | let request = base.createRequest()
17 | request.requestedScopes = scope
18 |
19 | let controller = ASAuthorizationController(authorizationRequests: [request])
20 |
21 | let proxy = ASAuthorizationControllerProxy.proxy(for: controller)
22 |
23 | controller.presentationContextProvider = proxy
24 | controller.performRequests()
25 |
26 | return proxy.didComplete
27 | }
28 | }
29 |
30 | @available(iOS 13.0, *)
31 | extension Reactive where Base: ASAuthorizationAppleIDButton {
32 | public func loginOnTap(scope: [ASAuthorization.Scope]? = nil) -> Observable {
33 | return controlEvent(.touchUpInside)
34 | .flatMap {
35 | ASAuthorizationAppleIDProvider().rx.login(scope: scope)
36 | }
37 | }
38 |
39 | public func login(scope: [ASAuthorization.Scope]? = nil) -> Observable {
40 | return ASAuthorizationAppleIDProvider().rx.login(scope: scope)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/Eureka+Valid+Rx.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import Eureka
6 | import RxSwift
7 | import RxCocoa
8 |
9 | /**
10 | * extentsion
11 | */
12 |
13 | extension BaseRow: ReactiveCompatible { }
14 |
15 | var extensionPropertyStorage: [String: [String: Any]] = [:]
16 |
17 | public extension Reactive where Base: BaseRow, Base: RowType {
18 |
19 | var text: ControlProperty {
20 | let source = Observable.create { [weak base] observer in
21 | if let strongBase = base {
22 | observer.onNext(strongBase.value)
23 | strongBase.onChange { row in
24 | observer.onNext(row.value)
25 | }
26 | }
27 | return Disposables.create(with: observer.onCompleted)
28 | }
29 | let bindingObserver = Binder(base) { (row, value) in
30 | row.value = value
31 | }
32 | return ControlProperty(values: source, valueSink: bindingObserver)
33 | }
34 |
35 | var tap: ControlEvent<()> {
36 | // let source = methodInvoked(#selector(Base.onCellSelection(_:))).map { _ in }
37 | let source = Observable<()>.create { [weak base] observer in
38 | if let _base = base {
39 | _base.onCellSelection({ (_, _) in
40 | observer.onNext(())
41 | })
42 | }
43 | return Disposables.create {
44 | observer.onCompleted()
45 | }
46 | }
47 | return ControlEvent(events: source)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/NSViewController+Rx.swift:
--------------------------------------------------------------------------------
1 | #if os(macOS)
2 |
3 | /**
4 | * Dependencies
5 | */
6 |
7 | import AppKit
8 | import RxCocoa
9 | import RxSwift
10 |
11 | /**
12 | * extension
13 | */
14 |
15 | public extension Reactive where Base: NSViewController {
16 | var viewDidLoad: ControlEvent {
17 | let source = self.methodInvoked(#selector(Base.viewDidLoad)).map { _ in }
18 | return ControlEvent(events: source)
19 | }
20 |
21 | var viewWillAppear: ControlEvent {
22 | let source = self.methodInvoked(#selector(Base.viewWillAppear)).map { _ in }
23 | return ControlEvent(events: source)
24 | }
25 | var viewDidAppear: ControlEvent {
26 | let source = self.methodInvoked(#selector(Base.viewDidAppear)).map { _ in }
27 | return ControlEvent(events: source)
28 | }
29 |
30 | var viewWillDisappear: ControlEvent {
31 | let source = self.methodInvoked(#selector(Base.viewWillDisappear)).map { _ in }
32 | return ControlEvent(events: source)
33 | }
34 | var viewDidDisappear: ControlEvent {
35 | let source = self.methodInvoked(#selector(Base.viewDidDisappear)).map { _ in }
36 | return ControlEvent(events: source)
37 | }
38 |
39 | var viewWillLayout: ControlEvent {
40 | let source = self.methodInvoked(#selector(Base.viewWillLayout)).map { _ in }
41 | return ControlEvent(events: source)
42 | }
43 | var viewDidLayout: ControlEvent {
44 | let source = self.methodInvoked(#selector(Base.viewDidLayout)).map { _ in }
45 | return ControlEvent(events: source)
46 | }
47 | }
48 | #endif
49 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/ObservableType+Extras.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import Foundation
6 | import RxSwift
7 | import RxCocoa
8 |
9 | /**
10 | * extension
11 | */
12 |
13 | extension ObservableType {
14 |
15 | func ignoreAll() -> Observable {
16 | return map { _ in }
17 | }
18 |
19 | func unwrap() -> Observable where Element == Optional {
20 | return filter { $0 != nil }.map { $0! }
21 | }
22 |
23 | func execute(_ selector: @escaping (Element) -> Void) -> Observable {
24 | return flatMap { result in
25 | return Observable
26 | .just(selector(result))
27 | .map { _ in result }
28 | .take(1)
29 | }
30 | }
31 |
32 | func count() -> Observable<(Element, Int)> {
33 | var numberOfTimesCalled = 0
34 | let result = map { _ -> Int in
35 | numberOfTimesCalled += 1
36 | return numberOfTimesCalled
37 | }
38 |
39 | return Observable.combineLatest(self, result)
40 | }
41 |
42 | func merge(with other: Observable) -> Observable {
43 | return Observable.merge(self.asObservable(), other)
44 | }
45 |
46 | }
47 | extension Observable where Element == String {
48 |
49 | func mapToURL() -> Observable {
50 | return map { URL(string: $0) }
51 | .filter { $0 != nil }
52 | .map { $0! }
53 | }
54 | }
55 | extension Observable where Element == Data {
56 | func map( _ type: D.Type) -> Observable {
57 | return map { try JSONDecoder().decode(type, from: $0) }
58 | }
59 | }
60 |
61 | extension Observable where Element == Bool {
62 |
63 | func negate() -> Observable {
64 | return map { !$0 }
65 | }
66 |
67 | }
68 |
69 | extension Observable where Element: Sequence, Element.Iterator.Element: Comparable {
70 |
71 | /**
72 | Transforms an observable of sequences into an observable of ordered arrays by using the sequence element's
73 | natural comparator.
74 | */
75 |
76 | func sorted() -> Observable<[T]> where Element.Iterator.Element == T {
77 | return map { $0.sorted() }
78 | }
79 |
80 | func sorted(_ areInIncreasingOrder: @escaping (T, T) -> Bool) -> Observable<[T]>
81 | where Element.Iterator.Element == T {
82 | return map { $0.sorted(by: areInIncreasingOrder) }
83 | }
84 | }
85 |
86 | extension ObservableType where Element: Collection {
87 |
88 | func mapMany(_ transform: @escaping (Self.Element.Element) -> T) -> Observable<[T]> {
89 | return self.map { collection -> [T] in
90 | collection.map(transform)
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/SwiftSpinner+Rx.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxSwift
7 | import ReactorKit
8 | import SwiftSpinner
9 |
10 | /**
11 | * Extension
12 | */
13 |
14 | extension Reactive where Base: UIViewController {
15 |
16 | /// Bindable sink for `startAnimating()`, `stopAnimating()` methods.
17 | public var isAnimating: Binder {
18 | return Binder(self.base) { _, active in
19 | if active {
20 | SwiftSpinner.show(delay: Double(config["theme"]["loader"]["minimumDisplayTime"].int ?? 2000)/1000, title: [
21 | "Swapping time and space...",
22 | "Loading the Loading message...",
23 | "E.T phone loading...",
24 | "Swapping time and space...",
25 | "Have a good day.",
26 | "May the force be with you!",
27 | "Don't panic...",
28 | "We're making you a cookie.",
29 | "Is this Windows?",
30 | "Spinning the hamster...",
31 | "Dividing by zero...",
32 | "Winter is coming...",
33 | "Pushing pixels...",
34 | "Change the world by being yourself."
35 | ].randomElement()!)
36 | } else {
37 | SwiftSpinner.hide()
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/UIAlertController+Rx.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxSwift
7 |
8 | /**
9 | * Extention
10 | */
11 |
12 | struct AlertAction {
13 | var title: String
14 | var style: UIAlertAction.Style
15 |
16 | static func action(title: String, style: UIAlertAction.Style = .default) -> AlertAction {
17 | return AlertAction(title: title, style: style)
18 | }
19 | }
20 |
21 | extension UIViewController {
22 |
23 | func showAlert(title: String?, message: String?, style: UIAlertController.Style, actions: [AlertAction], maxHeight: CGFloat? = 0)
24 | -> Observable {
25 | return Observable.create { observer in
26 | let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
27 | // heigth
28 | if(maxHeight != nil && maxHeight ?? 0 > 0) {
29 | let height: NSLayoutConstraint = NSLayoutConstraint(item: alertController.view!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: maxHeight!)
30 | alertController.view.addConstraint(height)
31 | }
32 | // actions
33 | actions.enumerated().forEach { index, action in
34 | let action = UIAlertAction(title: action.title, style: action.style) { _ in
35 | observer.onNext(index)
36 | observer.onCompleted()
37 | }
38 | alertController.addAction(action)
39 | }
40 | // present
41 | self.present(alertController, animated: true, completion: nil)
42 | return Disposables.create { alertController.dismiss(animated: true, completion: nil) }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/UIImageView+Kingfisher.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Kingfisher
7 |
8 | /**
9 | * Extension
10 | */
11 |
12 | typealias ImageOptions = KingfisherOptionsInfo
13 |
14 | enum imageStyle {
15 | case blured
16 | case bw
17 | case bwBlured
18 | case animated
19 | }
20 |
21 | extension UIImageView {
22 |
23 | struct Metric {
24 | static let imgStylesBlured = CGFloat(config["img"]["styles"]["blured"].float ?? 10)
25 | static let imgStylesOverlayFraction = CGFloat(config["img"]["styles"]["overlayFraction"].float ?? 0.9)
26 | }
27 |
28 | @discardableResult
29 | func setImage(
30 | url: String?,
31 | placeholder: UIImage? = nil,
32 | options: ImageOptions? = nil,
33 | style: imageStyle? = nil,
34 | defaultImage: String? = nil, // should be a Bundle.main.path image png
35 | progressBlock: DownloadProgressBlock? = nil,
36 | completionHandler: ((Result) -> Void)? = nil) -> DownloadTask? {
37 |
38 | // Custome Filters add
39 | var options = options ?? []
40 | switch style {
41 | case .animated:
42 | options.append(.cacheSerializer(FormatIndicatedCacheSerializer.gif))
43 | options.append(.forceRefresh)
44 | case .blured:
45 | options.append(.processor(
46 | OverlayImageProcessor(overlay: .black, fraction: Metric.imgStylesOverlayFraction)
47 | |> BlurImageProcessor(blurRadius: Metric.imgStylesBlured)
48 | ))
49 | case .bw:
50 | options.append(.processor(
51 | OverlayImageProcessor(overlay: .black, fraction: Metric.imgStylesOverlayFraction)
52 | |> BlackWhiteProcessor()
53 | ))
54 | case .bwBlured:
55 | options.append(.processor(
56 | OverlayImageProcessor(overlay: .black, fraction: Metric.imgStylesOverlayFraction)
57 | |> BlurImageProcessor(blurRadius: Metric.imgStylesBlured)
58 | |> BlackWhiteProcessor()
59 | ))
60 | default:
61 | break
62 | }
63 |
64 | // GIF will only animates in the AnimatedImageView
65 | if self is AnimatedImageView == false {
66 | options.append(.onlyLoadFirstFrame)
67 | }
68 |
69 | if(defaultImage != nil && (url == "default" || url == "default.png" || url == "default.jpg" || url == "")) {
70 | let provider = LocalFileImageDataProvider(fileURL: URL(fileURLWithPath: Bundle.main.path(forResource: defaultImage, ofType: "png") ?? ""))
71 | return self.kf.setImage(
72 | with: provider,
73 | placeholder: placeholder,
74 | options: options,
75 | progressBlock: progressBlock,
76 | completionHandler: completionHandler
77 | )
78 | } else {
79 | // return image else
80 | return self.kf.setImage(
81 | with: URL(string: url ?? ""),
82 | placeholder: placeholder,
83 | options: options,
84 | progressBlock: progressBlock,
85 | completionHandler: completionHandler
86 | )
87 | }
88 |
89 | }
90 |
91 | func deleteImageCache(url: String) {
92 | ImageCache.default.removeImage(forKey: url)
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/UIScrollView+Rx.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 | import UIKit
5 | import RxCocoa
6 | import RxSwift
7 |
8 | /**
9 | * Dependencies
10 | */
11 |
12 | extension Reactive where Base: UIScrollView {
13 |
14 | var currentPage: Observable {
15 | return didEndDecelerating.map({
16 | let pageWidth = self.base.frame.width
17 | let pageHorizontal = floor((self.base.contentOffset.x - pageWidth / 2) / pageWidth) + 1
18 | let pageHeight = self.base.frame.height
19 | let pageVertical = floor((self.base.contentOffset.y - pageHeight / 2) / pageHeight) + 1
20 | return Int(pageHorizontal != 0 ? pageHorizontal : pageVertical != 0 ? pageVertical : 0 )
21 | })
22 | }
23 |
24 | var isReachedBottom: ControlEvent {
25 | let source = self.contentOffset
26 | .filter { [weak base = self.base] _ in
27 | guard let base = base else { return false }
28 | return base.isBottom(toleranceHeight: base.frame.height / 2)
29 | }
30 | .map { _ in Void() }
31 | return ControlEvent(events: source)
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Rx/UIViewController+Rx.swift:
--------------------------------------------------------------------------------
1 | #if os(iOS) || os(tvOS)
2 |
3 | /**
4 | * Dependencies
5 | */
6 |
7 | import UIKit
8 | import RxCocoa
9 | import RxSwift
10 |
11 | /**
12 | * extension
13 | */
14 |
15 | public extension Reactive where Base: UIViewController {
16 | var viewDidLoad: ControlEvent {
17 | let source = self.methodInvoked(#selector(Base.viewDidLoad)).map { _ in }
18 | return ControlEvent(events: source)
19 | }
20 |
21 | var viewWillAppear: ControlEvent {
22 | let source = self.methodInvoked(#selector(Base.viewWillAppear)).map { $0.first as? Bool ?? false }
23 | return ControlEvent(events: source)
24 | }
25 | var viewDidAppear: ControlEvent {
26 | let source = self.methodInvoked(#selector(Base.viewDidAppear)).map { $0.first as? Bool ?? false }
27 | return ControlEvent(events: source)
28 | }
29 |
30 | var viewWillDisappear: ControlEvent {
31 | let source = self.methodInvoked(#selector(Base.viewWillDisappear)).map { $0.first as? Bool ?? false }
32 | return ControlEvent(events: source)
33 | }
34 | var viewDidDisappear: ControlEvent {
35 | let source = self.methodInvoked(#selector(Base.viewDidDisappear)).map { $0.first as? Bool ?? false }
36 | return ControlEvent(events: source)
37 | }
38 |
39 | var viewWillLayoutSubviews: ControlEvent {
40 | let source = self.methodInvoked(#selector(Base.viewWillLayoutSubviews)).map { _ in }
41 | return ControlEvent(events: source)
42 | }
43 | var viewDidLayoutSubviews: ControlEvent {
44 | let source = self.methodInvoked(#selector(Base.viewDidLayoutSubviews)).map { _ in }
45 | return ControlEvent(events: source)
46 | }
47 |
48 | var willMoveToParentViewController: ControlEvent {
49 | let source = self.methodInvoked(#selector(Base.willMove)).map { $0.first as? UIViewController }
50 | return ControlEvent(events: source)
51 | }
52 | var didMoveToParentViewController: ControlEvent {
53 | let source = self.methodInvoked(#selector(Base.didMove)).map { $0.first as? UIViewController }
54 | return ControlEvent(events: source)
55 | }
56 |
57 | var didReceiveMemoryWarning: ControlEvent {
58 | let source = self.methodInvoked(#selector(Base.didReceiveMemoryWarning)).map { _ in }
59 | return ControlEvent(events: source)
60 | }
61 |
62 | /// Rx observable, triggered when the ViewController appearance state changes (true if the View is being displayed, false otherwise)
63 | var isVisible: Observable {
64 | let viewDidAppearObservable = self.base.rx.viewDidAppear.map { _ in true }
65 | let viewWillDisappearObservable = self.base.rx.viewWillDisappear.map { _ in false }
66 | return Observable.merge(viewDidAppearObservable, viewWillDisappearObservable)
67 | }
68 |
69 | /// Rx observable, triggered when the ViewController is being dismissed
70 | var isDismissing: ControlEvent {
71 | let source = self.sentMessage(#selector(Base.dismiss)).map { $0.first as? Bool ?? false }
72 | return ControlEvent(events: source)
73 | }
74 |
75 | }
76 | #endif
77 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Stubbed.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * functions
9 | */
10 |
11 | /**
12 | * @desc return stubbed json response mock
13 | * @param {String} filename
14 | * @return {Data} file
15 | */
16 | func stubbed(_ filename: String) -> Data! {
17 | @objc class TestClass: NSObject {}
18 |
19 | let bundle = Bundle(for: TestClass.self)
20 | let path = bundle.path(forResource: filename, ofType: "json")
21 | return (try? Data(contentsOf: URL(fileURLWithPath: path!)))
22 | }
23 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/UITricks.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * Functions
9 | */
10 |
11 | /**
12 | * @desc make CircleUIButton
13 | */
14 | class CircleUIButton: UIButton {
15 | override func layoutSubviews() {
16 | super.layoutSubviews()
17 | layer.cornerRadius = bounds.height / 2
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Url.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * functions
9 | */
10 |
11 | /**
12 | * @desc generate api url
13 | * @param {String} _protocol,
14 | * @param {String} _host,
15 | * @param {String} _port,
16 | * @param {String} _path,
17 | * @return {URL}
18 | */
19 | func getUrl(_protocol: String, _host: String, _port: String, _path: String) -> URL! {
20 | var port = ""
21 | if(_port.count > 0) {
22 | port = ":\(_port)"
23 | }
24 | guard let url = URL(string: "\(_protocol)://\(_host)\(port)/\(_path)") else { fatalError("baseUrl could not be configured." ) }
25 | return url
26 | }
27 |
28 | /**
29 | * @desc generate an upload image url with options (from http://toto.png to http://toto-300-blur.png)
30 | * @param {String} image,
31 | * @param {[Int]} sizes,
32 | * @param {String} operation,
33 | * @return {String}
34 | */
35 | func setUploadImageUrl(_ image: String, sizes: [Int]? = [], operation: String? = nil) -> String! {
36 |
37 | let baseUrl: String = getUrl(_protocol: config["api"]["protocol"].string ?? "http",
38 | _host: config["api"]["host"].string ?? "localhost",
39 | _port: config["api"]["port"].string ?? "3000",
40 | _path: config["api"]["endPoints"]["basePath"].string ?? "api").absoluteString
41 |
42 | let apiPathUploads = config["api"]["endPoints"]["uploads"].string ?? "uploads"
43 |
44 | var _image: String
45 | let base = image.split {$0 == "."}
46 | if(base.count != 2) {
47 | return image
48 | } else {
49 | _image = "\(base[0])"
50 | }
51 | if sizes?.count ?? 0 > 0 {
52 | if(sizes!.count == 2) {
53 | if(UIDevice.current.userInterfaceIdiom == .phone) {
54 | _image = "\(_image)-\(sizes![0])"
55 | } else {
56 | _image = "\(_image)-\(sizes![1])"
57 | }
58 | } else {
59 | _image = "\(_image)-\(sizes![0])"
60 | }
61 | }
62 | if let _operation = operation {
63 | _image = "\(_image)-\(_operation)"
64 | }
65 | _image = "\(_image).\(base[1])"
66 | return baseUrl + "/" + apiPathUploads + "/images/" + _image
67 | }
68 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Users.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * functions
9 | */
10 |
11 | /**
12 | * @desc Calc and return the state of the token absed on CookieExpire var
13 | * @return {TokenState}
14 | */
15 | func getTokenStatus() -> TokenState {
16 | if let result = UserDefaults.standard.value(forKey: "CookieExpire") {
17 | let expireIn = config["jwt"]["expireIn"].int ?? (7 * 24 * 60 * 60)
18 | let renewIn = config["jwt"]["renewIn"].int ?? (60 * 60)
19 |
20 | let tokenLife = Int64(expireIn * 1000)
21 | let limitToReset = Int64(renewIn * 1000)
22 | let currentTime = Int64(NSDate().timeIntervalSince1970 * 1000)
23 | let expireTime = result as! Int64
24 | let tokenTimeSpent = tokenLife-(expireTime-currentTime)
25 |
26 | if (currentTime > expireTime) {
27 | return TokenState.toDefine
28 | } else if( tokenTimeSpent > limitToReset ) {
29 | return TokenState.toRenew
30 | } else {
31 | return TokenState.isOk
32 | }
33 | } else {
34 | return TokenState.toDefine
35 | }
36 | }
37 |
38 | enum TokenState {
39 | case toDefine
40 | case isOk
41 | case toRenew
42 | }
43 |
44 | /**
45 | * @desc Calc and return the state of the terms , last version signed or not
46 | * @return {Bool}
47 | */
48 | func getTermsStatus(terms: String?) -> Bool {
49 | let dateFormatter = DateFormatter()
50 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
51 |
52 | // if terms undefined
53 | if (terms == nil || terms == "") {
54 | log.error("No terms updated date available, couldn't check user terms")
55 | return true
56 | }
57 | if let user = UserDefaults.standard.value(forKey: "Terms") {
58 | if let _terms = dateFormatter.date(from: terms!) {
59 | if let user = dateFormatter.date(from: user as! String) {
60 | return user > _terms
61 | }
62 | }
63 | }
64 | return false
65 | }
66 |
--------------------------------------------------------------------------------
/waosSwift/lib/helpers/Validations.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Validator
7 |
8 | /**
9 | * functions
10 | */
11 |
12 | public struct NameValidationPattern: ValidationPattern {
13 | public var pattern: String {
14 | return "[a-zA-ZàáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçčšžÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ∂ð ,.'-]*"
15 | }
16 | }
17 |
18 | public struct AccountValidationPattern: ValidationPattern {
19 | public var pattern: String {
20 | return "[a-zA-ZàáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçčšžÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ∂ð,.'-_]*"
21 | }
22 | }
23 |
24 | public struct UpperCaseValidationPattern: ValidationPattern {
25 | public var pattern: String {
26 | return "(?s)[^A-Z]*[A-Z].*"
27 | }
28 | }
29 |
30 | public struct DigitValidationPattern: ValidationPattern {
31 | public var pattern: String {
32 | return "(?s)[^0-9]*[0-9].*"
33 | }
34 | }
35 |
36 | func SpecialCharValidationCondition(_ string: String?) -> Bool {
37 | let characterset = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
38 | if string?.rangeOfCharacter(from: characterset.inverted) != nil {
39 | return true
40 | }
41 | return false
42 | }
43 |
--------------------------------------------------------------------------------
/waosSwift/lib/services/Configuration.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import SwiftyJSON
7 |
8 | /**
9 | * class
10 | */
11 |
12 | final class Config {
13 |
14 | let global: JSON = {
15 | // init development config
16 | let pathDev = Bundle.main.path(forResource: "development", ofType: "json")!
17 | let jsonStringDev = try? String(contentsOfFile: pathDev, encoding: String.Encoding.utf8)
18 | var result = JSON(parseJSON: jsonStringDev!)
19 | if let configuration = Bundle.main.infoDictionary?["Configuration"] as? String {
20 | if configuration.range(of: "development") != nil {
21 | return result
22 | }
23 | }
24 | // merge with production config if needed
25 | let pathProd = Bundle.main.path(forResource: "production", ofType: "json")!
26 | do {
27 | let jsonStringProd = try? String(contentsOfFile: pathProd, encoding: String.Encoding.utf8)
28 | try result.merge(with: JSON(parseJSON: jsonStringProd!))
29 | result = try result.merged(with: JSON(parseJSON: jsonStringProd!))
30 | } catch {
31 | log.error(error)
32 | }
33 | if let configuration = Bundle.main.infoDictionary?["Configuration"] as? String {
34 | if configuration.range(of: "production") != nil {
35 | return result
36 | }
37 | }
38 |
39 | // merge with release config if needed
40 | let pathRelease = Bundle.main.path(forResource: "release", ofType: "json")!
41 | do {
42 | let jsonStringRelease = try? String(contentsOfFile: pathRelease, encoding: String.Encoding.utf8)
43 | try result.merge(with: JSON(parseJSON: jsonStringRelease!))
44 | result = try result.merged(with: JSON(parseJSON: jsonStringRelease!))
45 | } catch {
46 | log.error(error)
47 | }
48 | return result
49 | }()
50 | }
51 |
52 | let config = Config().global
53 |
--------------------------------------------------------------------------------
/waosSwift/lib/services/Networking.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import RxSwift
6 | import Moya
7 | import RxMoya
8 | import UIKit
9 |
10 | /**
11 | * class
12 | */
13 |
14 | final class Networking: MoyaProvider {
15 | // init(plugins: [PluginType] = []) {
16 | // let configuration = URLSessionConfiguration.default
17 | // configuration.httpAdditionalHeaders = Manager.defaultHTTPHeaders
18 | // configuration.timeoutIntervalForRequest = 10
19 | //
20 | // let manager = Manager(configuration: configuration)
21 | // manager.startRequestsImmediately = false
22 | // super.init(manager: manager, plugins: plugins)
23 | // }
24 |
25 | func request(
26 | _ target: Target,
27 | file: StaticString = #file,
28 | function: StaticString = #function,
29 | line: UInt = #line
30 | ) -> Single {
31 | let requestString = "\(target.method) \(target.path)"
32 |
33 | return self.rx.request(target)
34 | .filterSuccessfulStatusCodes()
35 | .do(
36 | onSuccess: { value in
37 | let message = "🌎 success -> \(requestString) (\(value.statusCode))"
38 | log.debug(message, file: file, function: function, line: line)
39 | },
40 | onError: { error in
41 | if let response = (error as? MoyaError)?.response {
42 | // .mapJson()
43 | if let jsonObject = try? response.mapString() {
44 | let message = "🌎 failure -> \(requestString) (\(response.statusCode)) : \(jsonObject) (\(target))"
45 | log.warning(message, file: file, function: function, line: line)
46 | } else if let rawString = String(data: response.data, encoding: .utf8) {
47 | let message = "🌎 failure -> \(requestString) (\(response.statusCode)) : \(rawString) (\(target))"
48 | log.warning(message, file: file, function: function, line: line)
49 | } else {
50 | let message = "🌎 failure -> \(requestString) (\(response.statusCode)) (\(target))"
51 | log.warning(message, file: file, function: function, line: line)
52 | }
53 | } else {
54 | let message = "🌎 failure -> \(requestString)\n\(error)"
55 | log.warning(message, file: file, function: function, line: line)
56 | }
57 | },
58 | onSubscribed: {
59 | let message = "🌎 request -> \(requestString)"
60 | log.debug(message, file: file, function: function, line: line)
61 | }
62 | )
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/waosSwift/lib/services/Preferences.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import RxSwift
6 | import KeychainAccess
7 | import UIKit
8 |
9 | /**
10 | * Struct
11 | */
12 |
13 | struct Status {
14 | var onBoarded: Bool
15 | var isLogged: Bool
16 |
17 | init(onBoarded: Bool, isLogged: Bool) {
18 | self.onBoarded = onBoarded
19 | self.isLogged = isLogged
20 | }
21 | }
22 |
23 | /**
24 | * protocol
25 | */
26 |
27 | protocol PreferencesServiceType {
28 | // global
29 | var onBoarded: Bool { get set }
30 | var isLogged: Bool { get set }
31 | // status
32 | var status: Status { get }
33 | // options
34 | var isBackground: Bool { get set }
35 | }
36 |
37 | /**
38 | * class
39 | */
40 |
41 | class PreferencesService: PreferencesServiceType {
42 | // global
43 | var onBoarded: Bool {
44 | get {
45 | return UserDefaults.standard[#function] ?? true
46 | }
47 | set {
48 | UserDefaults.standard[#function] = newValue
49 | }
50 | }
51 | var isLogged: Bool {
52 | get {
53 | return UserDefaults.standard[#function] ?? true
54 | }
55 | set {
56 | if(!newValue) {
57 | do {
58 | try keychain.remove("Cookie")
59 | } catch let error {
60 | log.error(error)
61 | }
62 | }
63 | UserDefaults.standard[#function] = newValue
64 | }
65 | }
66 | // status
67 | var status: Status {
68 | get {
69 | return Status(onBoarded: onBoarded, isLogged: isLogged)
70 | }
71 | }
72 | // options
73 | var isBackground: Bool {
74 | get {
75 | return UserDefaults.standard[#function] ?? true
76 | }
77 | set {
78 | UserDefaults.standard[#function] = newValue
79 | }
80 | }
81 | }
82 |
83 | /**
84 | * extension
85 | */
86 |
87 | extension PreferencesService: ReactiveCompatible {}
88 | extension Reactive where Base: PreferencesService {
89 | // global
90 | var onBoarded: Observable {
91 | return UserDefaults.standard
92 | .rx
93 | .observe(Bool.self, #function)
94 | .map { $0 ?? false }
95 | }
96 | var isLogged: Observable {
97 | return UserDefaults.standard
98 | .rx
99 | .observe(Bool.self, #function)
100 | .map { $0 ?? false }
101 | }
102 | // status
103 | var status: Observable {
104 | return Observable.combineLatest(
105 | onBoarded, isLogged,
106 | resultSelector: { onBoarded, isLogged in
107 | return Status(onBoarded: onBoarded, isLogged: isLogged)
108 | }
109 | )
110 | }
111 | // options
112 | var isBackground: Observable {
113 | return UserDefaults.standard
114 | .rx
115 | .observe(Bool.self, #function)
116 | .map { $0 ?? true }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/waosSwift/modules/app/AppServicesProvider.swift:
--------------------------------------------------------------------------------
1 | protocol AppServicesProviderType: AnyObject {
2 | var tasksService: TasksServiceType { get }
3 | var authService: AuthServiceType { get }
4 | var userService: UserServiceType { get }
5 | var homeService: HomeServiceType { get }
6 | var preferencesService: PreferencesService { get }
7 | }
8 |
9 | final class AppServicesProvider: AppServicesProviderType {
10 | lazy var tasksService: TasksServiceType = TasksService(provider: self)
11 | lazy var authService: AuthServiceType = AuthService(provider: self)
12 | lazy var userService: UserServiceType = UserService(provider: self)
13 | lazy var homeService: HomeServiceType = HomeService(provider: self)
14 | lazy var preferencesService: PreferencesService = PreferencesService()
15 | }
16 |
--------------------------------------------------------------------------------
/waosSwift/modules/app/AppSteps.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import RxFlow
6 |
7 | /**
8 | * Steps
9 | */
10 |
11 | enum Steps: Step {
12 | case onboardingIsRequired
13 | case onboardingIsComplete
14 |
15 | case authIsRequired
16 | case authIsComplete
17 |
18 | case dashboardIsRequired
19 |
20 | case tasksIsRequired
21 |
22 | case secondIsRequired
23 |
24 | case userIsRequired
25 | }
26 |
--------------------------------------------------------------------------------
/waosSwift/modules/app/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/waosSwift/modules/app/fr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/flow/AuthFlow.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxFlow
7 |
8 | /**
9 | * Flow
10 | */
11 |
12 | final class AuthFlow: Flow {
13 | var root: Presentable {
14 | return self.rootViewController
15 | }
16 |
17 | private let rootViewController = UINavigationController()
18 | private let services: AppServicesProvider
19 |
20 | init(withServices services: AppServicesProvider) {
21 | self.services = services
22 | }
23 |
24 | deinit {
25 | log.info("🗑 \(type(of: self))")
26 | }
27 |
28 | func navigate(to step: Step) -> FlowContributors {
29 | guard let step = step as? Steps else { return .none }
30 | switch step {
31 | case .authIsRequired:
32 | return navigateToAuthScreen()
33 | case .authIsComplete:
34 | return .end(forwardToParentFlowWithStep: Steps.authIsComplete)
35 | default:
36 | return .none
37 | }
38 | }
39 |
40 | private func navigateToAuthScreen() -> FlowContributors {
41 | let reactor = AuthSigninReactor(provider: self.services)
42 | let viewController = AuthSignInController(reactor: reactor)
43 | self.rootViewController.pushViewController(viewController, animated: false)
44 | return .one(flowContributor: .contribute(withNextPresentable: viewController, withNextStepper: viewController))
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/models/AuthResponses.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Signin Response
3 | */
4 |
5 | struct SignResponse {
6 | var user: User
7 | var tokenExpiresIn: Int
8 | }
9 | extension SignResponse: Codable {
10 | enum SignResponseCodingKeys: String, CodingKey {
11 | case user
12 | case tokenExpiresIn
13 | }
14 | }
15 |
16 | /**
17 | * Model Token Response
18 | */
19 |
20 | struct TokenResponse {
21 | var user: User
22 | var tokenExpiresIn: Int
23 | }
24 | extension TokenResponse: Codable {
25 | enum TokenResponseCodingKeys: String, CodingKey {
26 | case user
27 | case tokenExpiresIn
28 | }
29 | }
30 |
31 | /**
32 | * Model forgot Response
33 | */
34 |
35 | struct Forgot {
36 | var status: Bool
37 | init(status: Bool = false) {
38 | self.status = status
39 | }
40 | }
41 |
42 | extension Forgot: Hashable, Codable {
43 | enum TasksCodingKeys: String, CodingKey {
44 | case status
45 | }
46 | init(from decoder: Decoder) throws {
47 | let container = try decoder.container(keyedBy: TasksCodingKeys.self)
48 | status = try container.decode(Bool.self, forKey: .status)
49 | }
50 | }
51 |
52 | struct ForgotResponse {
53 | var message: String
54 | }
55 | extension ForgotResponse: Codable {
56 | enum TasksResponseCodingKeys: String, CodingKey {
57 | case message
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/services/api/AuthApi.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Moya
7 |
8 | /**
9 | * Api
10 | */
11 |
12 | enum AuthApi {
13 | case signUp(firstName: String, lastName: String, email: String, password: String)
14 | case signIn(email: String, password: String)
15 | case token
16 | case forgot(email: String)
17 | case oauth(strategy: Bool, key: String, value: String, firstName: String, lastName: String, email: String)
18 | }
19 |
20 | extension AuthApi: TargetType {
21 |
22 | public var baseURL: URL {
23 | return getUrl(_protocol: config["api"]["protocol"].string ?? "http",
24 | _host: config["api"]["host"].string ?? "localhost",
25 | _port: config["api"]["port"].string ?? "3000",
26 | _path: config["api"]["endPoints"]["basePath"].string ?? "api")
27 | }
28 |
29 | var path: String {
30 | let apiPathAuth = config["api"]["endPoints"]["auth"].string ?? "auth"
31 |
32 | switch self {
33 | case .signUp :
34 | return "/" + apiPathAuth + "/signup"
35 | case .signIn :
36 | return "/" + apiPathAuth + "/signin"
37 | case .token :
38 | return "/" + apiPathAuth + "/token"
39 | case .forgot :
40 | return "/" + apiPathAuth + "/forgot"
41 | case .oauth :
42 | return "/" + apiPathAuth + "/apple/callback"
43 | }
44 | }
45 |
46 | var method: Moya.Method {
47 | switch self {
48 | case .signUp, .signIn, .forgot, .oauth:
49 | return .post
50 | case .token:
51 | return .get
52 | }
53 | }
54 |
55 | var sampleData: Data {
56 | switch self {
57 | case .signUp: return stubbed("signup")
58 | case .signIn: return stubbed("signin")
59 | case .token: return stubbed("token")
60 | case .forgot: return stubbed("forgot")
61 | case .oauth: return stubbed("oauth")
62 | }
63 | }
64 |
65 | var task: Task {
66 | switch self {
67 | case .signUp(let firstName, let lastName, let email, let password):
68 | return .requestParameters(parameters: ["firstName": firstName, "lastName": lastName, "email": email, "password": password], encoding: JSONEncoding.default)
69 | case .signIn(let email, let password):
70 | return .requestParameters(parameters: ["email": email, "password": password], encoding: JSONEncoding.default)
71 | case .token:
72 | return .requestPlain
73 | case .forgot(let email):
74 | return .requestParameters(parameters: ["email": email], encoding: JSONEncoding.default)
75 | case .oauth(let strategy, let key, let value, let firstName, let lastName, let email):
76 | return .requestParameters(parameters: ["strategy": strategy, "key": key, "value": value, "firstName": firstName, "lastName": lastName, "email": email], encoding: JSONEncoding.default)
77 | }
78 | }
79 |
80 | var headers: [String: String]? {
81 | return ["Content-Type": "application/json"]
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/services/api/stubbed/forgot.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "roles": [
4 | "user"
5 | ],
6 | "_id": "5ce3eb6236bb3afbb77dcaae",
7 | "username": "seeduser",
8 | "provider": "local",
9 | "email": "user@localhost.com",
10 | "firstName": "User",
11 | "lastName": "Local",
12 | "displayName": "User Local",
13 | "password": "$2b$10$iZbH86I1cn.U2j07QiWkoO6ZBZzymjpPOnCnbbTRqB5dQkrMmsleq",
14 | "__v": 0,
15 | "id": "5ce3eb6236bb3afbb77dcaae"
16 | },
17 | "tokenExpiresIn": 1558603098841
18 | }
19 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/services/api/stubbed/oauth.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "roles": [
4 | "user"
5 | ],
6 | "_id": "5ce3eb6236bb3afbb77dcaae",
7 | "username": "seeduser",
8 | "provider": "local",
9 | "email": "user@localhost.com",
10 | "firstName": "User",
11 | "lastName": "Local",
12 | "displayName": "User Local",
13 | "password": "$2b$10$iZbH86I1cn.U2j07QiWkoO6ZBZzymjpPOnCnbbTRqB5dQkrMmsleq",
14 | "__v": 0,
15 | "id": "5ce3eb6236bb3afbb77dcaae"
16 | },
17 | "tokenExpiresIn": 1558603098841
18 | }
19 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/services/api/stubbed/signIn.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "roles": [
4 | "user"
5 | ],
6 | "_id": "5ce3eb6236bb3afbb77dcaae",
7 | "username": "seeduser",
8 | "provider": "local",
9 | "email": "user@localhost.com",
10 | "firstName": "User",
11 | "lastName": "Local",
12 | "displayName": "User Local",
13 | "password": "$2b$10$iZbH86I1cn.U2j07QiWkoO6ZBZzymjpPOnCnbbTRqB5dQkrMmsleq",
14 | "__v": 0,
15 | "id": "5ce3eb6236bb3afbb77dcaae"
16 | },
17 | "tokenExpiresIn": 1558603098841
18 | }
19 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/services/api/stubbed/signUp.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "roles": [
4 | "user"
5 | ],
6 | "_id": "5ce3eb6236bb3afbb77dcaae",
7 | "username": "seeduser",
8 | "provider": "local",
9 | "email": "user@localhost.com",
10 | "firstName": "User",
11 | "lastName": "Local",
12 | "displayName": "User Local",
13 | "password": "$2b$10$iZbH86I1cn.U2j07QiWkoO6ZBZzymjpPOnCnbbTRqB5dQkrMmsleq",
14 | "__v": 0,
15 | "id": "5ce3eb6236bb3afbb77dcaae"
16 | },
17 | "tokenExpiresIn": 1558603098841
18 | }
19 |
--------------------------------------------------------------------------------
/waosSwift/modules/auth/services/api/stubbed/token.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "roles": [
4 | "user"
5 | ],
6 | "_id": "5ce3eb6236bb3afbb77dcaae",
7 | "username": "seeduser",
8 | "provider": "local",
9 | "email": "user@localhost.com",
10 | "firstName": "User",
11 | "lastName": "Local",
12 | "displayName": "User Local",
13 | "password": "$2b$10$iZbH86I1cn.U2j07QiWkoO6ZBZzymjpPOnCnbbTRqB5dQkrMmsleq",
14 | "__v": 0,
15 | "id": "5ce3eb6236bb3afbb77dcaae"
16 | },
17 | "tokenExpiresIn": 1558603098841
18 | }
19 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/controllers/CoreCollectionViewCellController.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxSwift
7 | import SwiftMessages
8 | import MessageUI
9 |
10 | /**
11 | * Controller
12 | */
13 |
14 | class CoreCollectionViewCellController: UICollectionViewCell {
15 |
16 | // MARK: UI
17 |
18 | let error = MessageView.viewFromNib(layout: .cardView).then {
19 | $0.configureTheme(.error, iconStyle: .subtle)
20 | $0.backgroundView.backgroundColor = UIColor(named: config["theme"]["themes"]["waos"]["error"].string ?? "")?.withAlphaComponent(CGFloat(config["theme"]["popup"]["alpha"].float ?? 0.9))
21 | $0.button?.backgroundColor = .clear
22 | $0.button?.tintColor = UIColor.white.withAlphaComponent(0.5)
23 | $0.button?.setTitle("", for: .normal)
24 | $0.button?.setImage(UIImage.fontAwesomeIcon(code: "fa-paper-plane", style: .solid, textColor: .white, size: CGSize(width: 22, height: 22)), for: .normal)
25 | }
26 | var popupConfig = SwiftMessages.defaultConfig
27 |
28 | // MARK: Initializing
29 |
30 | override init(frame: CGRect) {
31 | super.init(frame: frame)
32 | // popup
33 | popupConfig.duration = .seconds(seconds: TimeInterval(Int(config["theme"]["popup"]["duration"].int ?? 3)))
34 | // constraints
35 | self.updateConstraintsIfNeeded()
36 | }
37 |
38 | required convenience init?(coder aDecoder: NSCoder) {
39 | self.init(frame: .zero)
40 | }
41 |
42 | func initialize() {
43 | // Override point
44 | }
45 |
46 | // MARK: Rx
47 |
48 | var disposeBag: DisposeBag = DisposeBag()
49 |
50 | // MARK: Layout Constraints
51 |
52 | private(set) var didSetupConstraints = false
53 |
54 | override func updateConstraints() {
55 | if !self.didSetupConstraints {
56 | self.setupConstraints()
57 | self.didSetupConstraints = true
58 | }
59 | super.updateConstraints()
60 | }
61 |
62 | func setupConstraints() {
63 | // Override point
64 | }
65 | }
66 |
67 | /**
68 | * Extension
69 | */
70 |
71 | extension CoreCollectionViewCellController: MFMailComposeViewControllerDelegate {
72 | func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
73 | controller.dismiss(animated: true, completion: nil)
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/controllers/CoreTableViewCellController.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxSwift
7 | import SwiftMessages
8 | import MessageUI
9 |
10 | /**
11 | * Controller
12 | */
13 |
14 | class CoreTableViewCellController: UITableViewCell {
15 |
16 | // MARK: UI
17 |
18 | let error = MessageView.viewFromNib(layout: .cardView).then {
19 | $0.configureTheme(.error, iconStyle: .subtle)
20 | $0.backgroundView.backgroundColor = UIColor(named: config["theme"]["themes"]["waos"]["error"].string ?? "")?.withAlphaComponent(CGFloat(config["theme"]["popup"]["alpha"].float ?? 0.9))
21 | $0.button?.backgroundColor = .clear
22 | $0.button?.tintColor = UIColor.white.withAlphaComponent(0.5)
23 | $0.button?.setTitle("", for: .normal)
24 | $0.button?.setImage(UIImage.fontAwesomeIcon(code: "fa-paper-plane", style: .solid, textColor: .white, size: CGSize(width: 22, height: 22)), for: .normal)
25 | }
26 | var popupConfig = SwiftMessages.defaultConfig
27 |
28 | // MARK: Initializing
29 |
30 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
31 | super.init(style: style, reuseIdentifier: reuseIdentifier)
32 | self.initialize()
33 | // popup
34 | popupConfig.duration = .seconds(seconds: TimeInterval(Int(config["theme"]["popup"]["duration"].int ?? 3)))
35 | // constraints
36 | self.updateConstraintsIfNeeded()
37 | }
38 |
39 | required init?(coder aDecoder: NSCoder) {
40 | fatalError("init(coder:) has not been implemented")
41 | }
42 |
43 | func initialize() {
44 | // Override point
45 | }
46 |
47 | // MARK: Rx
48 |
49 | var disposeBag: DisposeBag = DisposeBag()
50 |
51 | // MARK: Layout Constraints
52 |
53 | private(set) var didSetupConstraints = false
54 |
55 | override func updateConstraints() {
56 | if !self.didSetupConstraints {
57 | self.setupConstraints()
58 | self.didSetupConstraints = true
59 | }
60 | super.updateConstraints()
61 | }
62 |
63 | func setupConstraints() {
64 | // Override point
65 | }
66 |
67 | }
68 |
69 | /**
70 | * Extension
71 | */
72 |
73 | extension CoreTableViewCellController: MFMailComposeViewControllerDelegate {
74 | func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
75 | controller.dismiss(animated: true, completion: nil)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/flows/CoreFlow.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxFlow
7 |
8 | /**
9 | * Flow
10 | */
11 |
12 | final class CoreFlow: Flow {
13 | var root: Presentable {
14 | return self.rootViewController
15 | }
16 |
17 | let rootViewController = UITabBarController()
18 | private let services: AppServicesProvider
19 |
20 | init(withServices services: AppServicesProvider) {
21 | self.services = services
22 | }
23 |
24 | deinit {
25 | log.info("🗑 \(type(of: self))")
26 | }
27 |
28 | func navigate(to step: Step) -> FlowContributors {
29 | guard let step = step as? Steps else { return FlowContributors.none }
30 |
31 | switch step {
32 | case .dashboardIsRequired:
33 | return navigateToDashboard()
34 | default:
35 | return .none
36 | }
37 | }
38 |
39 | private func navigateToDashboard() -> FlowContributors {
40 | let tasksFlow = TasksFlow(withServices: self.services)
41 | let secondFlow = SecondFlow(withServices: self.services)
42 | let profilFlow = UserFlow(withServices: self.services)
43 |
44 | Flows.use([tasksFlow, secondFlow, profilFlow], when: .ready) { [unowned self] (root: [UINavigationController]) in
45 |
46 | for (index, route) in root.enumerated() {
47 | route.tabBarItem = UITabBarItem(title: L10n.get("Localizable", config["router"][index]["name"].string ?? ""), image: UIImage.fontAwesomeIcon(code: "fa-" + (config["router"][index]["meta"]["icon"].string ?? ""), style: .solid, textColor: .blue, size: CGSize(width: config["router"][index]["meta"]["width"].int ?? 0, height: config["router"][index]["meta"]["height"].int ?? 0)), selectedImage: nil)
48 | }
49 |
50 | self.rootViewController.setViewControllers(root, animated: false)
51 | }
52 |
53 | return .multiple(flowContributors: [.contribute(withNextPresentable: tasksFlow,
54 | withNextStepper: OneStepper(withSingleStep: Steps.tasksIsRequired)),
55 | .contribute(withNextPresentable: secondFlow,
56 | withNextStepper: OneStepper(withSingleStep: Steps.secondIsRequired)),
57 | .contribute(withNextPresentable: profilFlow,
58 | withNextStepper: OneStepper(withSingleStep: Steps.userIsRequired))])
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/models/CoreModel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Delete
3 | */
4 |
5 | struct Delete {
6 | var id: String?
7 | var deletedCount: Int?
8 | var n: Int?
9 | var ok: Int?
10 | }
11 |
12 | extension Delete: Codable {
13 | enum DeleteCodingKeys: String, CodingKey {
14 | case id
15 | case deletedCount
16 | case n
17 | case ok
18 | }
19 |
20 | init(from decoder: Decoder) throws {
21 | let container = try decoder.container(keyedBy: DeleteCodingKeys.self)
22 |
23 | id = try container.decodeIfPresent(String.self, forKey: .id)
24 | deletedCount = try container.decodeIfPresent(Int.self, forKey: .deletedCount)
25 | n = try container.decodeIfPresent(Int.self, forKey: .n)
26 | ok = try container.decodeIfPresent(Int.self, forKey: .ok)
27 | }
28 | }
29 |
30 | /**
31 | * Model DeleteData
32 | */
33 |
34 | struct DeleteData {
35 | var user: Delete?
36 | var tasks: Delete?
37 | var uploads: Delete?
38 | }
39 |
40 | extension DeleteData: Codable {
41 | enum DeleteDataCodingKeys: String, CodingKey {
42 | case user
43 | case tasks
44 | case uploads
45 | }
46 |
47 | init(from decoder: Decoder) throws {
48 | let container = try decoder.container(keyedBy: DeleteDataCodingKeys.self)
49 |
50 | user = try container.decodeIfPresent(Delete.self, forKey: .user)
51 | tasks = try container.decodeIfPresent(Delete.self, forKey: .tasks)
52 | uploads = try container.decodeIfPresent(Delete.self, forKey: .uploads)
53 | }
54 | }
55 |
56 | /**
57 | * Model Mail
58 | */
59 |
60 | struct Mail {
61 | var status: Bool
62 | }
63 |
64 | extension Mail: Codable {
65 | enum MailCodingKeys: String, CodingKey {
66 | case status
67 | }
68 |
69 | init(from decoder: Decoder) throws {
70 | let container = try decoder.container(keyedBy: MailCodingKeys.self)
71 |
72 | status = try container.decode(Bool.self, forKey: .status)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/models/CoreResponses.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Delete Response
3 | */
4 |
5 | struct DeleteResponse {
6 | var data: Delete
7 | }
8 | extension DeleteResponse: Codable {
9 | enum DeleteResponseCodingKeys: String, CodingKey {
10 | case data
11 | }
12 | }
13 |
14 | /**
15 | * Model Delete Data Response
16 | */
17 |
18 | struct DeleteDataResponse {
19 | var data: DeleteData
20 | }
21 | extension DeleteDataResponse: Codable {
22 | enum DeleteDataResponseCodingKeys: String, CodingKey {
23 | case data
24 | }
25 | }
26 |
27 | /**
28 | * Model Mail Response
29 | */
30 |
31 | struct MailResponse {
32 | var data: Mail
33 | }
34 | extension MailResponse: Codable {
35 | enum MailResponseCodingKeys: String, CodingKey {
36 | case Mail
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/services/CoreService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Service.swift
3 | // RxTodo
4 | //
5 | // Created by Suyeol Jeon on 12/01/2017.
6 | // Copyright © 2017 Suyeol Jeon. All rights reserved.
7 | //
8 |
9 | class CoreService {
10 | unowned let provider: AppServicesProviderType
11 |
12 | init(provider: AppServicesProviderType) {
13 | self.provider = provider
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/ui/CoreUIButton.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * IBDesignable
9 | */
10 |
11 | @IBDesignable class CoreUIButton: UIButton {
12 |
13 | // MARK: Constants
14 |
15 | struct Metric {
16 | static let surface = UIColor(named: config["theme"]["themes"]["waos"]["surface"].string ?? "")
17 | static let onSurface = UIColor(named: config["theme"]["themes"]["waos"]["onSurface"].string ?? "")
18 | static let radius = CGFloat(config["theme"]["global"]["radius"].int ?? 0)
19 | }
20 |
21 | // MARK: Initializing
22 |
23 | override init(frame: CGRect) {
24 | super.init(frame: frame)
25 | shared()
26 | }
27 | required init?(coder aDecoder: NSCoder) {
28 | super.init(coder: aDecoder)
29 | shared()
30 | }
31 |
32 | override func prepareForInterfaceBuilder() {
33 | super.prepareForInterfaceBuilder()
34 | shared()
35 | }
36 |
37 | override var isHighlighted: Bool {
38 | didSet {
39 | if isHighlighted {
40 | self.highlightBtn()
41 | } else {
42 | self.clearHighlighted()
43 | }
44 | }
45 | }
46 |
47 | open override var isEnabled: Bool {
48 | didSet {
49 | alpha = isEnabled ? 1.0 : 0.4
50 | }
51 | }
52 |
53 | func highlightBtn() {
54 | if traitCollection.userInterfaceStyle == .light {
55 | self.backgroundColor = Metric.surface!.darker(by: 5)
56 | } else {
57 | self.backgroundColor = Metric.surface!.lighter(by: 5)
58 | }
59 |
60 | }
61 |
62 | func clearHighlighted() {
63 | self.backgroundColor = Metric.surface
64 | }
65 |
66 | func shared() {
67 | self.layer.cornerRadius = Metric.radius
68 | self.backgroundColor = Metric.surface
69 | self.setTitleColor(Metric.onSurface, for: .normal)
70 |
71 | // animation at first launch
72 | self.transform = CGAffineTransform.init(scaleX: 0.8, y: 0.8)
73 | UIView.animate(withDuration: 0.2, animations: { () -> Void in
74 | self.transform = CGAffineTransform.init(scaleX: 1, y: 1)
75 | })
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/ui/CoreUILabel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * IBDesignable
9 | */
10 |
11 | @IBDesignable class CoreUILabel: UILabel {
12 |
13 | // MARK: Constants
14 |
15 | struct Metric {
16 | static let onSurface = UIColor(named: config["theme"]["themes"]["waos"]["onSurface"].string ?? "")
17 | }
18 |
19 | // MARK: Initializing
20 |
21 | override init(frame: CGRect) {
22 | super.init(frame: frame)
23 | shared()
24 | }
25 | required init?(coder aDecoder: NSCoder) {
26 | super.init(coder: aDecoder)
27 | shared()
28 | }
29 |
30 | override func prepareForInterfaceBuilder() {
31 | super.prepareForInterfaceBuilder()
32 | shared()
33 | }
34 |
35 | func shared() {
36 | self.textColor = Metric.onSurface
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/ui/CoreUITableView.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * IBDesignable
9 | */
10 |
11 | @IBDesignable class CoreUITableView: UITableView {
12 |
13 | // MARK: Constants
14 |
15 | struct Metric {
16 | static let background = UIColor(named: config["theme"]["themes"]["waos"]["background"].string ?? "")
17 | static let surface = UIColor(named: config["theme"]["themes"]["waos"]["surface"].string ?? "")
18 | static let tableViewRowHeight = CGFloat(config["theme"]["tableView"]["rowHeight"].int ?? 0)
19 | static let tableViewSectionHeaderHeight = CGFloat(config["theme"]["tableView"]["sectionHeaderHeight"].int ?? 0)
20 | static let tableViewSectionFooterHeight = CGFloat(config["theme"]["tableView"]["sectionFooterHeight"].int ?? 0)
21 | }
22 |
23 | // MARK: Initializing
24 |
25 | override init(frame: CGRect, style: UITableView.Style) {
26 | super.init(frame: frame, style: style)
27 | shared()
28 | }
29 | required init?(coder aDecoder: NSCoder) {
30 | super.init(coder: aDecoder)
31 | shared()
32 | }
33 |
34 | override func prepareForInterfaceBuilder() {
35 | super.prepareForInterfaceBuilder()
36 | shared()
37 | }
38 |
39 | override func layoutSubviews() {
40 | super.layoutSubviews()
41 | sharedCalc()
42 | }
43 |
44 | func shared() {
45 | // tableView
46 | self.backgroundColor = Metric.background
47 | self.rowHeight = Metric.tableViewRowHeight
48 | self.sectionHeaderHeight = Metric.tableViewSectionHeaderHeight
49 | self.sectionFooterHeight = Metric.tableViewSectionFooterHeight
50 | // $0.separatorStyle = .none // no border
51 | }
52 |
53 | func sharedCalc() {
54 | // tableView
55 | self.separatorColor = Metric.surface?.darker(by: 8)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/ui/CoreUITextField.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * IBDesignable
9 | */
10 |
11 | @IBDesignable class CoreUITextField: UITextField {
12 |
13 | // MARK: Constants
14 |
15 | var icon: String = ""
16 | struct Metric {
17 | static let surface = UIColor(named: config["theme"]["themes"]["waos"]["surface"].string ?? "")
18 | static let error = UIColor(named: config["theme"]["themes"]["waos"]["error"].string ?? "")
19 | static let radius = CGFloat(config["theme"]["global"]["radius"].int ?? 0)
20 | }
21 |
22 | // MARK: Initializing
23 |
24 | override init(frame: CGRect) {
25 | super.init(frame: frame)
26 | shared()
27 | }
28 | required init?(coder aDecoder: NSCoder) {
29 | super.init(coder: aDecoder)
30 | shared()
31 | }
32 |
33 | override func prepareForInterfaceBuilder() {
34 | super.prepareForInterfaceBuilder()
35 | shared()
36 | }
37 |
38 | override func didMoveToSuperview() {
39 | if(self.icon != "") {
40 | self.setFontAwesomeIcon(self.icon)
41 | }
42 | }
43 |
44 | func shared() {
45 | self.backgroundColor = Metric.surface
46 | self.borderStyle = .none
47 | self.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 20))
48 | self.leftViewMode = .always
49 | self.layer.cornerRadius = Metric.radius
50 | // prepare for error
51 | self.layer.borderColor = Metric.error?.withAlphaComponent(0.75).cgColor
52 | }
53 |
54 | public func error() {
55 | self.layer.borderWidth = 1.0
56 | self.setFontAwesomeIcon(icon, Metric.error?.lighter() ?? .red)
57 | }
58 |
59 | public func valid() {
60 | self.layer.borderWidth = 0
61 | self.setFontAwesomeIcon(icon, .gray)
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/waosSwift/modules/core/ui/CoreUiRefreshControl.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller
3 | */
4 |
5 | import UIKit
6 |
7 | /**
8 | * IBDesignable
9 | */
10 |
11 | @IBDesignable class CoreUIRefreshControl: UIRefreshControl {
12 |
13 | // MARK: Constants
14 |
15 | struct Metric {
16 | static let onBackground = UIColor(named: config["theme"]["themes"]["waos"]["onBackground"].string ?? "")
17 | }
18 |
19 | // MARK: Initializing
20 |
21 | override init() {
22 | super.init()
23 | shared()
24 | }
25 | required init?(coder aDecoder: NSCoder) {
26 | super.init(coder: aDecoder)
27 | shared()
28 | }
29 |
30 | override func prepareForInterfaceBuilder() {
31 | super.prepareForInterfaceBuilder()
32 | shared()
33 | }
34 |
35 | func shared() {
36 | self.tintColor = Metric.onBackground
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/waosSwift/modules/home/models/PagesModel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Tasks
3 | */
4 |
5 | struct Pages {
6 | var title: String
7 | var markdown: String
8 | var updatedAt: String?
9 |
10 | init(title: String = "", markdown: String = "", updatedAt: String? = "") {
11 | self.title = title
12 | self.markdown = markdown
13 | self.updatedAt = updatedAt
14 | }
15 | }
16 |
17 | extension Pages: Hashable, Codable {
18 | enum PagesCodingKeys: String, CodingKey {
19 | case title
20 | case markdown
21 | case updatedAt
22 | }
23 |
24 | init(from decoder: Decoder) throws {
25 | let container = try decoder.container(keyedBy: PagesCodingKeys.self)
26 |
27 | title = try container.decode(String.self, forKey: .title)
28 | markdown = try container.decode(String.self, forKey: .markdown)
29 | updatedAt = try container.decodeIfPresent(String.self, forKey: .updatedAt)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/waosSwift/modules/home/models/PagesResponses.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Tasks Responses
3 | */
4 |
5 | struct PagesResponse {
6 | var data: [Pages]
7 | }
8 | extension PagesResponse: Codable {
9 | enum PagesResponseCodingKeys: String, CodingKey {
10 | case data
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/waosSwift/modules/home/reactors/HomeTermsReactor.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import ReactorKit
7 |
8 | /**
9 | * Reactor
10 | */
11 |
12 | final class HomeTermsReactor: Reactor {
13 |
14 | // MARK: Constants
15 |
16 | // user actions
17 | enum Action {
18 | // default
19 | case done
20 | }
21 |
22 | // state changes
23 | enum Mutation {
24 | // inputs
25 | case dismiss
26 | case success(String)
27 | case error(CustomError)
28 | }
29 |
30 | // the current view state
31 | struct State {
32 | // terms
33 | var pages: [Pages]
34 | // settings
35 | var displayLinks: Bool
36 | var style: markDownStyles
37 | // work
38 | var isDismissed: Bool
39 | var errors: [DisplayError]
40 | var error: DisplayError?
41 |
42 | init(terms: Pages, style: markDownStyles, displayLinks: Bool) {
43 | // pages
44 | self.pages = [terms]
45 | // settings
46 | self.style = style
47 | self.displayLinks = displayLinks
48 | // work
49 | self.isDismissed = false
50 | self.errors = []
51 | }
52 | }
53 |
54 | // MARK: Properties
55 |
56 | let provider: AppServicesProviderType
57 | let initialState: State
58 |
59 | // MARK: Initialization
60 |
61 | init(provider: AppServicesProviderType, terms: Pages, style: markDownStyles = .air, displayLinks: Bool = true) {
62 | self.provider = provider
63 | self.initialState = State(terms: terms, style: style, displayLinks: displayLinks)
64 | }
65 |
66 | // MARK: Action -> Mutation (mutate() receives an Action and generates an Observable)
67 |
68 | func mutate(action: Action) -> Observable {
69 | switch action {
70 | // done
71 | case .done:
72 | return self.provider.userService
73 | .terms()
74 | .map { result in
75 | switch result {
76 | case let .success(response):
77 | UserDefaults.standard.set(response.data.terms ?? nil, forKey: "Terms")
78 | return .dismiss
79 | case let .error(err): return .error(err)
80 | }
81 | }
82 | }
83 | }
84 |
85 | // MARK: Mutation -> State (reduce() generates a new State from a previous State and a Mutation)
86 |
87 | func reduce(state: State, mutation: Mutation) -> State {
88 | var state = state
89 | switch mutation {
90 | // dissmiss
91 | case .dismiss:
92 | log.verbose("♻️ Mutation -> State : dismiss")
93 | state.isDismissed = true
94 | state.errors = []
95 | // success
96 | case let .success(success):
97 | log.verbose("♻️ Mutation -> State : succes \(success)")
98 | state.error = nil
99 | state.errors = purgeErrors(errors: state.errors, specificTitles: [success])
100 | // error
101 | case let .error(error):
102 | log.verbose("♻️ Mutation -> State : error \(error)")
103 | let _error: DisplayError = getDisplayError(error, self.provider.preferencesService.isLogged)
104 | self.provider.preferencesService.isLogged = _error.code == 401 ? false : true
105 | state.error = _error
106 | }
107 | return state
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/waosSwift/modules/home/services/HomeService.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import RxSwift
6 |
7 | /**
8 | * Service
9 | */
10 |
11 | protocol HomeServiceType {
12 | var pages: Observable<[Pages]?> { get }
13 |
14 | func getPages(_ api: HomeApi) -> Observable>
15 | }
16 |
17 | final class HomeService: CoreService, HomeServiceType {
18 | fileprivate let networking = Networking(plugins: [CookiePlugin()])
19 |
20 | // temporary array
21 | var defaultPages: [Pages] = [Pages()]
22 |
23 | fileprivate let pagesSubject = ReplaySubject<[Pages]?>.create(bufferSize: 1)
24 | lazy var pages: Observable<[Pages]?> = self.pagesSubject.asObservable()
25 | .startWith(nil)
26 | .share(replay: 1)
27 |
28 | func getPages(_ api: HomeApi) -> Observable> {
29 | log.verbose("🔌 service : get Pages")
30 | return self.networking
31 | .request(api)
32 | .map(PagesResponse.self)
33 | .map { response in
34 | self.defaultPages = response.data
35 | return response
36 | }
37 | .asObservable()
38 | .map(MyResult.success)
39 | .catch { err in .just(.error(getError(err)))}
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/waosSwift/modules/home/services/api/HomeApi.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Moya
7 |
8 | /**
9 | * Api
10 | */
11 |
12 | enum HomeApi {
13 | case changelogs
14 | case page(_ name: String)
15 | }
16 |
17 | extension HomeApi: TargetType {
18 |
19 | public var baseURL: URL {
20 | return getUrl(_protocol: config["api"]["protocol"].string ?? "http",
21 | _host: config["api"]["host"].string ?? "localhost",
22 | _port: config["api"]["port"].string ?? "3000",
23 | _path: config["api"]["endPoints"]["basePath"].string ?? "api")
24 | }
25 |
26 | var path: String {
27 | let apiPathHome = config["api"]["endPoints"]["home"].string ?? "home"
28 |
29 | switch self {
30 | case .changelogs:
31 | return "/" + apiPathHome + "/changelogs"
32 | case .page(let name):
33 | return "/" + apiPathHome + "/pages/" + (name )
34 |
35 | }
36 | }
37 |
38 | var method: Moya.Method {
39 | switch self {
40 | case .changelogs:
41 | return .get
42 | case .page:
43 | return .get
44 | }
45 | }
46 |
47 | var sampleData: Data {
48 | switch self {
49 | case .changelogs: return stubbed("changelogs")
50 | case .page: return stubbed("getPages")
51 | }
52 | }
53 |
54 | var task: Task {
55 | switch self {
56 | case .changelogs, .page:
57 | return .requestPlain
58 |
59 | }
60 | }
61 |
62 | var headers: [String: String]? {
63 | return ["Content-Type": "application/json"]
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/waosSwift/modules/home/services/api/stubbed/changelogs.json:
--------------------------------------------------------------------------------
1 | {"type":"success","message":"task deleted","data":{"title":"title1","description":"do something about something else","user":"5cdbd2c554b9e1f85c922603","id":"5cdbd2c654b9e1f85c922605"}}
2 |
--------------------------------------------------------------------------------
/waosSwift/modules/onBoarding/flows/OnBoardingFlow.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import RxFlow
6 | import UIKit
7 |
8 | /**
9 | * Flow
10 | */
11 |
12 | final class OnboardingFlow: Flow {
13 | var root: Presentable {
14 | return self.rootViewController
15 | }
16 |
17 | private let rootViewController = UINavigationController()
18 | private let services: AppServicesProvider
19 |
20 | init(withServices services: AppServicesProvider) {
21 | self.services = services
22 | }
23 |
24 | deinit {
25 | log.info("🗑 \(type(of: self))")
26 | }
27 |
28 | func navigate(to step: Step) -> FlowContributors {
29 | guard let step = step as? Steps else { return .none }
30 | switch step {
31 | case .onboardingIsRequired:
32 | return navigationToOnboardingScreen()
33 | case .onboardingIsComplete:
34 | return .end(forwardToParentFlowWithStep: Steps.onboardingIsComplete)
35 | default:
36 | return .none
37 | }
38 | }
39 |
40 | private func navigationToOnboardingScreen() -> FlowContributors {
41 | let provider = AppServicesProvider()
42 | let reactor = OnboardingReactor(provider: provider)
43 | let viewController = OnboardingController(reactor: reactor)
44 | viewController.title = L10n.onBoardingTitle
45 | self.rootViewController.pushViewController(viewController, animated: false)
46 | return .one(flowContributor: .contribute(withNextPresentable: viewController, withNextStepper: viewController))
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/waosSwift/modules/onBoarding/reactors/OnBoardingReactor.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import ReactorKit
6 |
7 | let contents: [String] = [L10n.onBoardingIntroduction, "toto", "titi"]
8 |
9 | /**
10 | * Reactor
11 | */
12 |
13 | final class OnboardingReactor: Reactor {
14 |
15 | // MARK: Constants
16 |
17 | // user actions
18 | enum Action {
19 | case complete
20 | case update(Int)
21 | }
22 |
23 | // state changes
24 | enum Mutation {
25 | case setContent(Int)
26 | case dismiss
27 | }
28 |
29 | // the current view state
30 | struct State {
31 | var content: String
32 | var isDismissed: Bool
33 |
34 | init() {
35 | self.content = contents[0]
36 | self.isDismissed = false
37 | }
38 | }
39 |
40 | // MARK: Properties
41 |
42 | let provider: AppServicesProviderType
43 | let initialState: State
44 |
45 | // MARK: Initialization
46 |
47 | init(provider: AppServicesProviderType) {
48 | self.provider = provider
49 | self.initialState = State()
50 | }
51 |
52 | // MARK: Action -> Mutation (mutate() receives an Action and generates an Observable)
53 |
54 | func mutate(action: Action) -> Observable {
55 | switch action {
56 | case .complete:
57 | self.provider.preferencesService.onBoarded = true
58 | return .just(.dismiss)
59 | case let .update(page):
60 | return .just(.setContent(page))
61 | }
62 | }
63 |
64 | // MARK: Mutation -> State (reduce() generates a new State from a previous State and a Mutation)
65 |
66 | func reduce(state: State, mutation: Mutation) -> State {
67 | var state = state
68 | switch mutation {
69 | case let .setContent(page):
70 | state.content = contents[page]
71 | case .dismiss:
72 | state.isDismissed = true
73 | }
74 | return state
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/waosSwift/modules/secondController/controllers/SecondController.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import ReactorKit
7 |
8 | /**
9 | * Controller
10 | */
11 |
12 | class SecondController: CoreController, View {
13 |
14 | // MARK: UI
15 |
16 | let label = CoreUILabel().then {
17 | $0.text = L10n.secondTitle
18 | $0.textAlignment = .center
19 | }
20 |
21 | // MARK: Initializing
22 |
23 | init(reactor: SecondReactor) {
24 | super.init()
25 | self.reactor = reactor
26 | }
27 |
28 | required init?(coder aDecoder: NSCoder) {
29 | fatalError("init(coder:) has not been implemented")
30 | }
31 |
32 | // MARK: View Life Cycle
33 |
34 | override func viewDidLoad() {
35 | super.viewDidLoad()
36 | self.view.addSubview(self.label)
37 | }
38 |
39 | override func setupConstraints() {
40 | label.snp.makeConstraints { (make) -> Void in
41 | make.width.height.equalTo(250)
42 | make.center.equalTo(self.view)
43 | }
44 | }
45 |
46 | // MARK: Binding
47 |
48 | func bind(reactor: SecondReactor) {
49 | bindView(reactor)
50 | bindAction(reactor)
51 | bindState(reactor)
52 | }
53 | }
54 |
55 | /**
56 | * Extensions
57 | */
58 |
59 | private extension SecondController {
60 |
61 | // MARK: views (View -> View)
62 |
63 | func bindView(_ reactor: SecondReactor) {}
64 |
65 | // MARK: actions (View -> Reactor)
66 |
67 | func bindAction(_ reactor: SecondReactor) {}
68 |
69 | // MARK: states (Reactor -> View)
70 |
71 | func bindState(_ reactor: SecondReactor) {}
72 | }
73 |
--------------------------------------------------------------------------------
/waosSwift/modules/secondController/flows/SecondFlow.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxFlow
7 | /**
8 | * Flow
9 | */
10 |
11 | final class SecondFlow: Flow {
12 | var root: Presentable {
13 | return self.rootViewController
14 | }
15 |
16 | private let rootViewController = UINavigationController()
17 | private let services: AppServicesProvider
18 |
19 | init(withServices services: AppServicesProvider) {
20 | self.services = services
21 | }
22 |
23 | deinit {
24 | log.info("🗑 \(type(of: self))")
25 | }
26 |
27 | func navigate(to step: Step) -> FlowContributors {
28 | guard let step = step as? Steps else { return .none }
29 | switch step {
30 | case .secondIsRequired:
31 | return navigateToSecondScreen()
32 | default:
33 | return .none
34 | }
35 | }
36 |
37 | private func navigateToSecondScreen() -> FlowContributors {
38 | let reactor = SecondReactor()
39 | let viewController = SecondController(reactor: reactor)
40 | viewController.title = L10n.secondTitle
41 | self.rootViewController.pushViewController(viewController, animated: true)
42 | return .one(flowContributor: .contribute(withNextPresentable: viewController, withNextStepper: OneStepper(withSingleStep: Steps.secondIsRequired)))
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/waosSwift/modules/secondController/reactors/SecondReactor.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import ReactorKit
6 |
7 | /**
8 | * Reactor
9 | */
10 |
11 | final class SecondReactor: Reactor {
12 |
13 | // MARK: Constants
14 |
15 | // user actions
16 | enum Action {
17 | }
18 |
19 | // state changes
20 | enum Mutation {
21 | }
22 |
23 | // the current view state
24 | struct State {
25 |
26 | init() {
27 | }
28 | }
29 |
30 | // MARK: Properties
31 |
32 | let initialState = State()
33 |
34 | // MARK: Initialization
35 |
36 | init() {
37 | }
38 |
39 | // MARK: Action -> Mutation (mutate() receives an Action and generates an Observable)
40 |
41 | // func mutate(action: Action) -> Observable {
42 | // switch action {
43 | //
44 | // }
45 | // }
46 |
47 | // MARK: Mutation -> State (reduce() generates a new State from a previous State and a Mutation)
48 |
49 | // func reduce(state: State, mutation: Mutation) -> State {
50 | // var state = state
51 | // switch mutation {
52 | //
53 | // }
54 | // return state
55 | // }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/controllers/TasksCellController.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import ReactorKit
7 |
8 | /**
9 | * Controller
10 | */
11 |
12 | final class TasksCellController: CoreTableViewCellController, View {
13 |
14 | typealias Reactor = TasksCellReactor
15 |
16 | // MARK: Constants
17 |
18 | struct Metric {
19 | static let surface = UIColor(named: config["theme"]["themes"]["waos"]["surface"].string ?? "")
20 | }
21 |
22 | // MARK: UI
23 |
24 | let labelTitle = CoreUILabel().then {
25 | $0.numberOfLines = 2
26 | }
27 |
28 | // MARK: Initializing
29 |
30 | override func initialize() {
31 | self.contentView.addSubview(self.labelTitle)
32 | self.contentView.backgroundColor = Metric.surface
33 | }
34 |
35 | // MARK: Layout
36 | override func setupConstraints() {
37 | self.labelTitle.snp.makeConstraints { make in
38 | make.left.equalTo(25)
39 | make.centerY.equalToSuperview()
40 | }
41 | }
42 |
43 | // MARK: Binding
44 |
45 | func bind(reactor: Reactor) {
46 | self.labelTitle.text = reactor.currentState.title
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/flows/TasksFlow.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxFlow
7 |
8 | /**
9 | * Flow
10 | */
11 |
12 | final class TasksFlow: Flow {
13 | var root: Presentable {
14 | return self.rootViewController
15 | }
16 |
17 | private let rootViewController = UINavigationController()
18 | private let services: AppServicesProvider
19 |
20 | init(withServices services: AppServicesProvider) {
21 | self.services = services
22 | }
23 |
24 | deinit {
25 | log.info("🗑 \(type(of: self))")
26 | }
27 |
28 | func navigate(to step: Step) -> FlowContributors {
29 | guard let step = step as? Steps else { return .none }
30 | switch step {
31 | case .tasksIsRequired:
32 | return navigateToTasksScreen()
33 | default:
34 | return .none
35 | }
36 | }
37 |
38 | private func navigateToTasksScreen() -> FlowContributors {
39 | let reactor = TasksListReactor(provider: self.services)
40 | let viewController = TasksListController(reactor: reactor)
41 | viewController.title = L10n.tasksTitle
42 | self.rootViewController.pushViewController(viewController, animated: true)
43 | return .one(flowContributor: .contribute(withNextPresentable: viewController, withNextStepper: OneStepper(withSingleStep: Steps.tasksIsRequired)))
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/models/TasksModel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Tasks
3 | */
4 |
5 | struct Tasks {
6 | var id: String?
7 | var title: String
8 | var description: String?
9 |
10 | init(title: String = "", description: String? = "") {
11 | self.title = title
12 | self.description = description
13 | }
14 | }
15 |
16 | extension Tasks: Hashable, Codable {
17 | enum TasksCodingKeys: String, CodingKey {
18 | case id
19 | case title
20 | case description
21 | }
22 |
23 | init(from decoder: Decoder) throws {
24 | let container = try decoder.container(keyedBy: TasksCodingKeys.self)
25 |
26 | id = try container.decodeIfPresent(String.self, forKey: .id)
27 | title = try container.decode(String.self, forKey: .title)
28 | description? = try container.decode(String.self, forKey: .description)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/models/TasksResponses.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Tasks Responses
3 | */
4 |
5 | struct TasksResponse {
6 | var data: [Tasks]
7 | }
8 | extension TasksResponse: Codable {
9 | enum TasksResponseCodingKeys: String, CodingKey {
10 | case data
11 | }
12 | }
13 |
14 | /**
15 | * Model Task Responses
16 | */
17 |
18 | struct TaskResponse {
19 | var data: Tasks
20 | }
21 | extension TaskResponse: Codable {
22 | enum TaskResponseCodingKeys: String, CodingKey {
23 | case data
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/reactors/TasksCellReactor.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import ReactorKit
6 |
7 | /**
8 | * Reactor
9 | */
10 |
11 | final class TasksCellReactor: Reactor {
12 |
13 | // MARK: Constants
14 |
15 | // user actions
16 | typealias Action = NoAction
17 |
18 | // MARK: Properties
19 |
20 | let initialState: Tasks
21 |
22 | // MARK: Initialization
23 |
24 | init(task: Tasks) {
25 | self.initialState = task
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/services/TasksService.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxSwift
7 |
8 | /**
9 | * Service
10 | */
11 |
12 | protocol TasksServiceType {
13 | var tasks: Observable<[Tasks]?> { get }
14 |
15 | func list() -> Observable>
16 | func create(_ task: Tasks) -> Observable>
17 | func update(_ task: Tasks) -> Observable>
18 | func delete(_ task: Tasks) -> Observable>
19 | }
20 |
21 | final class TasksService: CoreService, TasksServiceType {
22 | fileprivate let networking = Networking(plugins: [CookiePlugin()])
23 |
24 | // temporary array
25 | var defaultTasks: [Tasks] = [Tasks()]
26 |
27 | fileprivate let tasksSubject = ReplaySubject<[Tasks]?>.create(bufferSize: 1)
28 | lazy var tasks: Observable<[Tasks]?> = self.tasksSubject.asObservable()
29 | .startWith(nil)
30 | .share(replay: 1)
31 |
32 | func list() -> Observable> {
33 | log.verbose("🔌 service : get")
34 | return self.networking
35 | .request(.list)
36 | .map(TasksResponse.self)
37 | .map { response in
38 | self.defaultTasks = response.data
39 | return response
40 | }
41 | .asObservable()
42 | .map(MyResult.success)
43 | .catch { err in .just(.error(getError(err)))}
44 | }
45 |
46 | func create(_ task: Tasks) -> Observable> {
47 | log.verbose("🔌 service : create")
48 | return self.networking
49 | .request(.create(task))
50 | .map(TaskResponse.self)
51 | .map { response in
52 | self.defaultTasks.insert(response.data, at: 0)
53 | self.tasksSubject.onNext(self.defaultTasks)
54 | return response
55 | }
56 | .asObservable()
57 | .map(MyResult.success)
58 | .catch { err in .just(.error(getError(err)))}
59 | }
60 |
61 | func update(_ task: Tasks) -> Observable> {
62 | log.verbose("🔌 service : update")
63 | return self.networking
64 | .request(.update(task))
65 | .map(TaskResponse.self)
66 | .map { response in
67 | if let index = self.defaultTasks.firstIndex(where: { $0.id == response.data.id }) {
68 | self.defaultTasks[index] = response.data
69 | }
70 | self.tasksSubject.onNext(self.defaultTasks)
71 | return response
72 | }
73 | .asObservable()
74 | .map(MyResult.success)
75 | .catch { err in .just(.error(getError(err)))}
76 | }
77 |
78 | func delete(_ task: Tasks) -> Observable> {
79 | log.verbose("🔌 service : delete")
80 | return self.networking
81 | .request(.delete(task))
82 | .map(DeleteResponse.self)
83 | .map { response in
84 | if let index = self.defaultTasks.firstIndex(where: { $0.id == response.data.id }) {
85 | self.defaultTasks.remove(at: index)
86 | }
87 | self.tasksSubject.onNext(self.defaultTasks)
88 | return response
89 | }
90 | .asObservable()
91 | .map(MyResult.success)
92 | .catch { err in .just(.error(getError(err)))}
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/services/api/TasksApi.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Moya
7 |
8 | /**
9 | * Api
10 | */
11 |
12 | enum TasksApi {
13 | case list
14 | case create(_ task: Tasks)
15 | case get(_ task: Tasks)
16 | case update(_ task: Tasks)
17 | case delete(_ task: Tasks)
18 |
19 | }
20 |
21 | extension TasksApi: TargetType {
22 |
23 | public var baseURL: URL {
24 | return getUrl(_protocol: config["api"]["protocol"].string ?? "http",
25 | _host: config["api"]["host"].string ?? "localhost",
26 | _port: config["api"]["port"].string ?? "3000",
27 | _path: config["api"]["endPoints"]["basePath"].string ?? "api")
28 | }
29 |
30 | var path: String {
31 | let apiPathTasks = config["api"]["endPoints"]["tasks"].string ?? "tasks"
32 |
33 | switch self {
34 | case .list, .create:
35 | return "/" + apiPathTasks
36 | case .get(let task), .update(let task), .delete(let task):
37 | return "/" + apiPathTasks + "/" + (task.id ?? "")
38 | }
39 | }
40 |
41 | var method: Moya.Method {
42 | switch self {
43 | case .list:
44 | return .get
45 | case .create:
46 | return .post
47 | case .get:
48 | return .get
49 | case .update:
50 | return .put
51 | case .delete:
52 | return .delete
53 | }
54 | }
55 |
56 | var sampleData: Data {
57 | switch self {
58 | case .list: return stubbed("list")
59 | case .create: return stubbed("create")
60 | case .get: return stubbed("get")
61 | case .update: return stubbed("update")
62 | case .delete: return stubbed("delete")
63 | }
64 | }
65 |
66 | var task: Task {
67 | switch self {
68 | case .list, .get, .delete:
69 | return .requestPlain
70 |
71 | case .create(let task), .update(let task):
72 | return .requestJSONEncodable(task)
73 | // return .requestParameters(parameters: ["title": task.title, "description": task.description ?? ""], encoding: JSONEncoding.default)
74 | }
75 | }
76 |
77 | var headers: [String: String]? {
78 | return ["Content-Type": "application/json"]
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/services/api/stubbed/create.json:
--------------------------------------------------------------------------------
1 | {"type":"success","message":"task deleted","data":{"title":"title1","description":"do something about something else","user":"5cdbd2c554b9e1f85c922603","id":"5cdbd2c654b9e1f85c922605"}}
2 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/services/api/stubbed/delete.json:
--------------------------------------------------------------------------------
1 | {"type":"success","message":"task deleted","data":{"id":"5cdbd2c654b9e1f85c922605", "deletedCount": 1}}
2 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/services/api/stubbed/get.json:
--------------------------------------------------------------------------------
1 | {"type":"success","message":"task get","data":{"title":"title1","description":"do something about something else","user":"5cdbd2c554b9e1f85c922603","id":"5cdbd2c654b9e1f85c922605"}}
2 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/services/api/stubbed/list.json:
--------------------------------------------------------------------------------
1 | {"type":"success","message":"task list","data":[{"title":"title1","description":"do something about something else","user":"5cdbd2c554b9e1f85c922603","id":"5cdbd2c654b9e1f85c922605"},{"title":"title2","description":"do something about something else","user":"5cdbd2c654b9e1f85c922604","id":"5cdbd2c654b9e1f85c922606"}]}
2 |
--------------------------------------------------------------------------------
/waosSwift/modules/tasks/services/api/stubbed/update.json:
--------------------------------------------------------------------------------
1 | {"type":"success","message":"task updated","data":{"title":"title1","description":"do something about something else","user":"5cdbd2c554b9e1f85c922603","id":"5cdbd2c654b9e1f85c922605"}}
2 |
--------------------------------------------------------------------------------
/waosSwift/modules/users/flows/UserFlow.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import RxFlow
7 |
8 | /**
9 | * Flow
10 | */
11 |
12 | final class UserFlow: Flow {
13 | var root: Presentable {
14 | return self.rootViewController
15 | }
16 |
17 | private let rootViewController = UINavigationController()
18 | private let services: AppServicesProvider
19 |
20 | init(withServices services: AppServicesProvider) {
21 | self.services = services
22 | }
23 |
24 | deinit {
25 | log.info("🗑 \(type(of: self))")
26 | }
27 |
28 | func navigate(to step: Step) -> FlowContributors {
29 | guard let step = step as? Steps else { return .none }
30 | switch step {
31 | case .userIsRequired:
32 | return navigateToUserScreen()
33 | default:
34 | return .none
35 | }
36 | }
37 |
38 | private func navigateToUserScreen() -> FlowContributors {
39 | let reactor = UserReactor(provider: self.services)
40 | let viewController = UserController(reactor: reactor)
41 | viewController.title = L10n.userTitle
42 | self.rootViewController.pushViewController(viewController, animated: true)
43 | return .one(flowContributor: .contribute(withNextPresentable: viewController, withNextStepper: OneStepper(withSingleStep: Steps.userIsRequired)))
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/waosSwift/modules/users/models/ComplementaryModel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Complementary
3 | */
4 |
5 | struct Complementary: Equatable {
6 | var iosDevices: [Devices]?
7 | var socialNetworks: SocialNetworks?
8 |
9 | init(iosDevices: [Devices]? = nil, socialNetworks: SocialNetworks? = nil) {
10 | self.iosDevices = iosDevices
11 | self.socialNetworks = socialNetworks
12 | }
13 | }
14 |
15 | extension Complementary: Codable, Hashable {
16 | enum ComplementaryCodingKeys: String, CodingKey {
17 | case iosDevices
18 | case socialNetworks
19 | }
20 |
21 | init(from decoder: Decoder) throws {
22 | let container = try decoder.container(keyedBy: ComplementaryCodingKeys.self)
23 |
24 | iosDevices = try container.decodeIfPresent([Devices].self, forKey: .iosDevices)
25 | socialNetworks = try container.decodeIfPresent(SocialNetworks.self, forKey: .socialNetworks)
26 | }
27 | }
28 |
29 | /**
30 | * Model SocialNetworks
31 | */
32 |
33 | struct SocialNetworks: Equatable {
34 | var instagram: String?
35 | var twitter: String?
36 | var facebook: String?
37 |
38 | init(instagram: String? = nil, twitter: String? = nil, facebook: String? = nil) {
39 | self.instagram = instagram
40 | self.twitter = twitter
41 | self.facebook = facebook
42 | }
43 | }
44 |
45 | extension SocialNetworks: Codable, Hashable {
46 | enum SocialNetworksCodingKeys: String, CodingKey {
47 | case instagram
48 | case twitter
49 | case facebook
50 | }
51 |
52 | init(from decoder: Decoder) throws {
53 | let container = try decoder.container(keyedBy: SocialNetworksCodingKeys.self)
54 |
55 | instagram = try container.decodeIfPresent(String.self, forKey: .instagram)
56 | twitter = try container.decodeIfPresent(String.self, forKey: .twitter)
57 | facebook = try container.decodeIfPresent(String.self, forKey: .facebook)
58 | }
59 | }
60 |
61 | /**
62 | * Model Devices
63 | */
64 |
65 | struct Devices: Equatable {
66 | var token: String?
67 | var swift: String?
68 |
69 | init(token: String? = nil, swift: String? = nil) {
70 | self.token = token
71 | self.swift = swift
72 | }
73 | }
74 |
75 | extension Devices: Codable, Hashable {
76 | enum DevicesCodingKeys: String, CodingKey {
77 | case token
78 | case swift
79 | }
80 |
81 | init(from decoder: Decoder) throws {
82 | let container = try decoder.container(keyedBy: DevicesCodingKeys.self)
83 |
84 | token = try container.decodeIfPresent(String.self, forKey: .token)
85 | swift = try container.decodeIfPresent(String.self, forKey: .swift)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/waosSwift/modules/users/models/UserPolicyModel.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Model Alerts
3 | */
4 |
5 | struct UsersPolicy {
6 | var preference: Bool
7 |
8 | init(
9 | preference: Bool = false
10 | ) {
11 | self.preference = preference
12 | }
13 | }
14 |
15 | extension UsersPolicy: Codable, Hashable {
16 | enum UsersPolicyCodingKeys: String, CodingKey {
17 | case preference
18 | }
19 |
20 | init(from decoder: Decoder) throws {
21 | let container = try decoder.container(keyedBy: UsersPolicyCodingKeys.self)
22 |
23 | preference = try container.decode(Bool.self, forKey: .preference)
24 | }
25 |
26 | func encode(to encoder: Encoder) throws {
27 | var container = encoder.container(keyedBy: UsersPolicyCodingKeys.self)
28 |
29 | try container.encode(preference, forKey: .preference)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/waosSwift/modules/users/reactors/UserMoreReactor.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import ReactorKit
6 |
7 | /**
8 | * Reactor
9 | */
10 |
11 | final class UserMoreReactor: Reactor {
12 |
13 | // MARK: Constants
14 |
15 | // user actions
16 | enum Action {
17 | }
18 |
19 | // state changes
20 | enum Mutation {
21 | // inputs
22 | case dismiss
23 | case success(String)
24 | case error(CustomError)
25 | }
26 |
27 | // the current view state
28 | struct State {
29 | var isDismissed: Bool
30 | var errors: [DisplayError]
31 | var error: DisplayError?
32 |
33 | init() {
34 | self.isDismissed = false
35 | self.errors = []
36 | }
37 | }
38 |
39 | // MARK: Properties
40 |
41 | let provider: AppServicesProviderType
42 | let initialState: State
43 |
44 | // MARK: Initialization
45 |
46 | init(provider: AppServicesProviderType) {
47 | self.provider = provider
48 | self.initialState = State()
49 | }
50 |
51 | // MARK: Action -> Mutation (mutate() receives an Action and generates an Observable)
52 |
53 | // func mutate(action: Action) -> Observable {
54 | // switch action {
55 | // }
56 | // }
57 |
58 | // MARK: Mutation -> State (reduce() generates a new State from a previous State and a Mutation)
59 |
60 | func reduce(state: State, mutation: Mutation) -> State {
61 | var state = state
62 | switch mutation {
63 | // dissmiss
64 | case .dismiss:
65 | log.verbose("♻️ Mutation -> State : dismiss")
66 | state.isDismissed = true
67 | state.errors = []
68 | // success
69 | case let .success(success):
70 | log.verbose("♻️ Mutation -> State : succes \(success)")
71 | state.error = nil
72 | state.errors = purgeErrors(errors: state.errors, specificTitles: [success])
73 | // error
74 | case let .error(error):
75 | log.verbose("♻️ Mutation -> State : error \(error)")
76 | let _error: DisplayError = getDisplayError(error, self.provider.preferencesService.isLogged)
77 | self.provider.preferencesService.isLogged = _error.code == 401 ? false : true
78 | state.error = _error
79 | }
80 | return state
81 | }
82 |
83 | func pageReactor(name: String) -> HomePageReactor {
84 | return HomePageReactor(provider: self.provider, api: .page(name), style: .classic, displayLinks: true)
85 | }
86 |
87 | func changelogReactor() -> HomePageReactor {
88 | return HomePageReactor(provider: self.provider, api: .changelogs, style: .air, displayLinks: false)
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/waosSwift/modules/users/reactors/UserPreferenceReactor.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import ReactorKit
6 |
7 | /**
8 | * Reactor
9 | */
10 |
11 | final class UserPreferenceReactor: Reactor {
12 |
13 | // MARK: Constants
14 |
15 | // user actions
16 | enum Action {
17 | // inputs
18 | case updateBackground(Bool)
19 | // work
20 | case done
21 | }
22 |
23 | // state changes
24 | enum Mutation {
25 | // inputs
26 | case updateBackground(Bool)
27 | // work
28 | case dismiss
29 | // default
30 | case success(String)
31 | case error(CustomError)
32 | }
33 |
34 | // the current view state
35 | struct State {
36 | var user: User
37 | var policy: UsersPolicy
38 | var background: Bool
39 | // work
40 | var isDismissed: Bool
41 | // default
42 | var errors: [DisplayError]
43 | var error: DisplayError?
44 |
45 | init(background: Bool, user: User, policy: UsersPolicy) {
46 | self.user = user
47 | self.policy = policy
48 | self.background = background
49 | // work
50 | self.isDismissed = false
51 | // default
52 | self.errors = []
53 | }
54 | }
55 |
56 | // MARK: Properties
57 |
58 | let provider: AppServicesProviderType
59 | let initialState: State
60 |
61 | // MARK: Initialization
62 |
63 | init(provider: AppServicesProviderType, user: User, policy: UsersPolicy) {
64 | self.provider = provider
65 | self.initialState = State(background: self.provider.preferencesService.isBackground, user: user, policy: policy)
66 | }
67 |
68 | // MARK: Action -> Mutation (mutate() receives an Action and generates an Observable)
69 |
70 | func mutate(action: Action) -> Observable {
71 | switch action {
72 | // inputs
73 | case let .updateBackground(background):
74 | self.provider.preferencesService.isBackground = background
75 | return .just(.updateBackground(background))
76 | // done
77 | case .done:
78 | return self.provider.userService
79 | .update(self.currentState.user)
80 | .map { result in
81 | switch result {
82 | case .success: return .dismiss
83 | case let .error(err): return .error(err)
84 | }
85 | }
86 | }
87 | }
88 |
89 | // MARK: Mutation -> State (reduce() generates a new State from a previous State and a Mutation)
90 |
91 | func reduce(state: State, mutation: Mutation) -> State {
92 | var state = state
93 | switch mutation {
94 | // inputs
95 | case let .updateBackground(background):
96 | state.background = background
97 | // dissmiss
98 | case .dismiss:
99 | log.verbose("♻️ Mutation -> State : dismiss")
100 | state.isDismissed = true
101 | state.errors = []
102 | // success
103 | case let .success(success):
104 | log.verbose("♻️ Mutation -> State : succes \(success)")
105 | state.error = nil
106 | state.errors = purgeErrors(errors: state.errors, specificTitles: [success])
107 | // error
108 | case let .error(error):
109 | log.verbose("♻️ Mutation -> State : error \(error)")
110 | let _error: DisplayError = getDisplayError(error, self.provider.preferencesService.isLogged)
111 | self.provider.preferencesService.isLogged = _error.code == 401 ? false : true
112 | state.error = _error
113 | }
114 | return state
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/waosSwift/modules/users/services/api/UserApi.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies
3 | */
4 |
5 | import UIKit
6 | import Moya
7 |
8 | /**
9 | * Api
10 | */
11 |
12 | enum UserApi {
13 | case me
14 | case update(_ user: User)
15 | case terms
16 | case delete
17 | case updateAvatar(file: Data, partName: String, fileName: String, mimeType: String)
18 | case deleteAvatar
19 | case data
20 |
21 | }
22 |
23 | extension UserApi: TargetType {
24 |
25 | public var baseURL: URL {
26 | return getUrl(_protocol: config["api"]["protocol"].string ?? "http",
27 | _host: config["api"]["host"].string ?? "localhost",
28 | _port: config["api"]["port"].string ?? "3000",
29 | _path: config["api"]["endPoints"]["basePath"].string ?? "api")
30 | }
31 |
32 | var path: String {
33 | let apiPathUser = config["api"]["endPoints"]["users"].string ?? "users"
34 |
35 | switch self {
36 | case .me :
37 | return "/" + apiPathUser + "/me"
38 | case .update :
39 | return "/" + apiPathUser
40 | case .terms :
41 | return "/" + apiPathUser + "/terms"
42 | case .delete :
43 | return "/" + apiPathUser + "/data"
44 | case .updateAvatar :
45 | return "/" + apiPathUser + "/avatar"
46 | case .deleteAvatar :
47 | return "/" + apiPathUser + "/avatar"
48 | case .data :
49 | return "/" + apiPathUser + "/data/mail"
50 | }
51 | }
52 |
53 | var method: Moya.Method {
54 | switch self {
55 | case .me:
56 | return .get
57 | case .update:
58 | return .put
59 | case .terms:
60 | return .get
61 | case .delete:
62 | return .delete
63 | case .updateAvatar:
64 | return .post
65 | case .deleteAvatar:
66 | return .delete
67 | case .data:
68 | return .get
69 | }
70 | }
71 |
72 | var sampleData: Data {
73 | switch self {
74 | case .me: return stubbed("me")
75 | case .update: return stubbed("update")
76 | case .terms: return stubbed("terms")
77 | case .delete: return stubbed("delete")
78 | case .updateAvatar: return stubbed("avatar")
79 | case .deleteAvatar: return stubbed("avatar")
80 | case .data: return stubbed("data")
81 | }
82 | }
83 |
84 | var task: Task {
85 | switch self {
86 | case .me, .terms, .delete, .deleteAvatar, .data:
87 | return .requestPlain
88 | case .update(let user):
89 | return .requestJSONEncodable(user)
90 | case .updateAvatar(let data, let partName, let fileName, let mimeType):
91 | let gifData = MultipartFormData(provider: .data(data), name: partName, fileName: fileName, mimeType: mimeType)
92 | return .uploadMultipart([gifData])
93 | }
94 | }
95 |
96 | var headers: [String: String]? {
97 | return ["Content-Type": "application/json"]
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/waosSwift/modules/users/services/api/stubbed/me.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "success",
3 | "message": "user get",
4 | "data": {
5 | "id": "5ce3eb6236bb3afbb77dcaae",
6 | "provider": "local",
7 | "username": "seeduser",
8 | "roles": [
9 | "user"
10 | ],
11 | "email": "user@localhost.com",
12 | "lastName": "Local",
13 | "firstName": "User"
14 | "bio": "bio"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/waosSwift/waosSwift.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 | com.apple.developer.applesignin
8 |
9 | Default
10 |
11 | com.apple.developer.associated-domains
12 |
13 | webcredentials:vue.weareopensource.me
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/waosSwift/waosSwiftRelease.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 | com.apple.developer.applesignin
8 |
9 | Default
10 |
11 | com.apple.developer.associated-domains
12 |
13 | webcredentials:vue.weareopensource.me
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/waosSwift/waosSwiftdevelopment.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 | com.apple.developer.applesignin
8 |
9 | Default
10 |
11 | com.apple.developer.associated-domains
12 |
13 | webcredentials:vue.weareopensource.me
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/waosSwiftTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/waosSwiftTests/waosSwiftTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // waosSwiftTests.swift
3 | // waosSwiftTests
4 | //
5 | // Created by pierre brisorgueil on 21/02/2019.
6 | // Copyright © 2019 WeAreOpenSource. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import waosSwift
11 |
12 | class WaosSwiftTests: XCTestCase {
13 |
14 | override func setUp() {
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | }
21 |
22 | func testExample() {
23 | // This is an example of a functional test case.
24 | // Use XCTAssert and related functions to verify your tests produce the correct results.
25 | }
26 |
27 | func testPerformanceExample() {
28 | // This is an example of a performance test case.
29 | self.measure {
30 | // Put the code you want to measure the time of here.
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/waosSwiftUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/waosSwiftUITests/waosSwiftUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // waosSwiftUITests.swift
3 | // waosSwiftUITests
4 | //
5 | // Created by pierre brisorgueil on 21/02/2019.
6 | // Copyright © 2019 WeAreOpenSource. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class WaosSwiftUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 |
16 | // In UI tests it is usually best to stop immediately when a failure occurs.
17 | continueAfterFailure = false
18 |
19 | // UI tests must launch the application that they test. Doing this in setup will make sure it
20 | // happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation -
24 | // required for your tests before they run. The setUp method is a good place to do this.
25 | }
26 |
27 | override func tearDown() {
28 | // Put teardown code here. This method is called after the invocation of each test method in the class.
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
| | | | | | | | | | | |