├── SwiftHub
├── Networking
│ ├── Rest
│ │ ├── Stubbed Responses
│ │ │ ├── EmptyObject.json
│ │ │ ├── Events.json
│ │ │ ├── EmptyArray.json
│ │ │ ├── Notifications.json
│ │ │ ├── EventsOrganization.json
│ │ │ ├── EventsRepository.json
│ │ │ ├── EventsUserReceived.json
│ │ │ ├── RepositoryBranches.json
│ │ │ ├── RepositoryCommits.json
│ │ │ ├── RepositoryIssues.json
│ │ │ ├── RepositoryReleases.json
│ │ │ ├── EventsUserPerformed.json
│ │ │ ├── NotificationsRepository.json
│ │ │ ├── RepositoryIssueComments.json
│ │ │ ├── RepositoryPullRequests.json
│ │ │ ├── RepositoryPullRequestComments.json
│ │ │ ├── RepositoryNumberOfLines.json
│ │ │ ├── Organization.json
│ │ │ ├── User.json
│ │ │ └── Profile.json
│ │ └── ErrorResponse.swift
│ └── GraphQL
│ │ └── Queries
│ │ └── Search.graphql
├── Resources
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── 76 - iPad.png
│ │ │ ├── 76 - iPad@2x.png
│ │ │ ├── 176 - iPad Pro.png
│ │ │ ├── 29 - Settings.png
│ │ │ ├── 40 - Spotlight.png
│ │ │ ├── 60 - iPhone@2x.png
│ │ │ ├── 60 - iPhone@3x.png
│ │ │ ├── 1024 - App Store.png
│ │ │ ├── 20 - Notification.png
│ │ │ ├── 29 - Settings@2x.png
│ │ │ ├── 29 - Settings@3x.png
│ │ │ ├── 40 - Spotlight@2x.png
│ │ │ ├── 40 - Spotlight@3x.png
│ │ │ ├── 29 - Settings@2x-1.png
│ │ │ ├── 40 - Spotlight@2x-1.png
│ │ │ ├── 20 - Notification@2x-1.png
│ │ │ ├── 20 - Notification@2x.png
│ │ │ └── 20 - Notification@3x.png
│ │ ├── launch_image.imageset
│ │ │ ├── launch_image.pdf
│ │ │ └── Contents.json
│ │ └── image_no_result.imageset
│ │ │ ├── image_no_result.pdf
│ │ │ └── Contents.json
│ ├── Icons.xcassets
│ │ ├── Contents.json
│ │ ├── icon_cell_dir.imageset
│ │ │ ├── icon_cell_dir.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_cloc.imageset
│ │ │ ├── icon_cell_cloc.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_file.imageset
│ │ │ ├── icon_cell_file.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_link.imageset
│ │ │ ├── icon_cell_link.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_size.imageset
│ │ │ ├── icon_cell_size.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_star.imageset
│ │ │ ├── icon_cell_star.pdf
│ │ │ └── Contents.json
│ │ ├── icon_button_star.imageset
│ │ │ ├── icon_button_star.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_check.imageset
│ │ │ ├── icon_cell_check.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_events.imageset
│ │ │ ├── icon_cell_events.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_frown.imageset
│ │ │ ├── icon_cell_frown.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_issues.imageset
│ │ │ ├── icon_cell_issues.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_logout.imageset
│ │ │ ├── icon_cell_logout.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_readme.imageset
│ │ │ ├── icon_cell_readme.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_remove.imageset
│ │ │ ├── icon_cell_remove.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_smile.imageset
│ │ │ ├── icon_cell_smile.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_source.imageset
│ │ │ ├── icon_cell_source.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_theme.imageset
│ │ │ ├── icon_cell_theme.pdf
│ │ │ └── Contents.json
│ │ ├── icon_tabbar_news.imageset
│ │ │ ├── icon_tabbar_news.pdf
│ │ │ └── Contents.json
│ │ ├── icon_toast_error.imageset
│ │ │ ├── icon_toast_error.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_company.imageset
│ │ │ ├── icon_cell_company.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_created.imageset
│ │ │ ├── icon_cell_created.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_updated.imageset
│ │ │ ├── icon_cell_updated.pdf
│ │ │ └── Contents.json
│ │ ├── icon_tabbar_login.imageset
│ │ │ ├── icon_tabbar_login.pdf
│ │ │ └── Contents.json
│ │ ├── icon_button_github.imageset
│ │ │ ├── icon_button_github.pdf
│ │ │ └── Contents.json
│ │ ├── icon_button_unstar.imageset
│ │ │ ├── icon_button_unstar.pdf
│ │ │ └── Contents.json
│ │ ├── icon_button_user_x.imageset
│ │ │ ├── icon_button_user_x.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_git_fork.imageset
│ │ │ ├── icon_cell_git_fork.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_language.imageset
│ │ │ ├── icon_cell_language.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_releases.imageset
│ │ │ ├── icon_cell_releases.pdf
│ │ │ └── Contents.json
│ │ ├── icon_tabbar_search.imageset
│ │ │ ├── icon_tabbar_search.pdf
│ │ │ └── Contents.json
│ │ ├── icon_toast_success.imageset
│ │ │ ├── icon_toast_success.pdf
│ │ │ └── Contents.json
│ │ ├── icon_toast_warning.imageset
│ │ │ ├── icon_toast_warning.pdf
│ │ │ └── Contents.json
│ │ ├── icon_whatsnew_cloc.imageset
│ │ │ ├── icon_whatsnew_cloc.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_tag.imageset
│ │ │ ├── icon_cell_badge_tag.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_git_merge.imageset
│ │ │ ├── icon_cell_git_merge.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_submodule.imageset
│ │ │ ├── icon_cell_submodule.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_whats_new.imageset
│ │ │ ├── icon_cell_whats_new.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_web.imageset
│ │ │ ├── icon_navigation_web.pdf
│ │ │ └── Contents.json
│ │ ├── icon_tabbar_profile.imageset
│ │ │ ├── icon_tabbar_profile.pdf
│ │ │ └── Contents.json
│ │ ├── icon_whatsnew_theme.imageset
│ │ │ ├── icon_whatsnew_theme.pdf
│ │ │ └── Contents.json
│ │ ├── icon_button_user_plus.imageset
│ │ │ ├── icon_button_user_plus.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_fork.imageset
│ │ │ ├── icon_cell_badge_fork.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_issue.imageset
│ │ │ ├── icon_cell_badge_issue.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_push.imageset
│ │ │ ├── icon_cell_badge_push.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_star.imageset
│ │ │ ├── icon_cell_badge_star.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_user.imageset
│ │ │ ├── icon_cell_badge_user.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_disclosure.imageset
│ │ │ ├── icon_cell_disclosure.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_git_branch.imageset
│ │ │ ├── icon_cell_git_branch.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_git_commit.imageset
│ │ │ ├── icon_cell_git_commit.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_night_mode.imageset
│ │ │ ├── icon_cell_night_mode.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_back.imageset
│ │ │ ├── icon_navigation_back.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_close.imageset
│ │ │ ├── icon_navigation_close.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_stop.imageset
│ │ │ ├── icon_navigation_stop.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_theme.imageset
│ │ │ ├── icon_navigation_theme.pdf
│ │ │ └── Contents.json
│ │ ├── icon_tabbar_activity.imageset
│ │ │ ├── icon_tabbar_activity.pdf
│ │ │ └── Contents.json
│ │ ├── icon_tabbar_settings.imageset
│ │ │ ├── icon_tabbar_settings.pdf
│ │ │ └── Contents.json
│ │ ├── icon_whatsnew_github.imageset
│ │ │ ├── icon_whatsnew_github.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_branch.imageset
│ │ │ ├── icon_cell_badge_branch.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_commit.imageset
│ │ │ ├── icon_cell_badge_commit.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_search.imageset
│ │ │ ├── icon_cell_badge_search.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_git_language.imageset
│ │ │ ├── icon_cell_git_language.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_github.imageset
│ │ │ ├── icon_navigation_github.pdf
│ │ │ └── Contents.json
│ │ ├── icon_whatsnew_trending.imageset
│ │ │ ├── icon_whatsnew_trending.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_comment.imageset
│ │ │ ├── icon_cell_badge_comment.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_stars_history.imageset
│ │ │ ├── icon_cell_stars_history.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_forward.imageset
│ │ │ ├── icon_navigation_forward.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_history.imageset
│ │ │ ├── icon_navigation_history.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_refresh.imageset
│ │ │ ├── icon_navigation_refresh.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_trending.imageset
│ │ │ ├── icon_cell_badge_trending.pdf
│ │ │ └── Contents.json
│ │ ├── icon_navigation_language.imageset
│ │ │ ├── icon_navigation_language.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_acknowledgements.imageset
│ │ │ ├── icon_cell_acknowledgements.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_repository.imageset
│ │ │ ├── icon_cell_badge_repository.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_contact_no_image.imageset
│ │ │ ├── icon_cell_contact_no_image.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_git_pull_request.imageset
│ │ │ ├── icon_cell_git_pull_request.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_profile_summary.imageset
│ │ │ ├── icon_cell_profile_summary.pdf
│ │ │ └── Contents.json
│ │ ├── icon_cell_badge_collaborator.imageset
│ │ │ ├── icon_cell_badge_collaborator.pdf
│ │ │ └── Contents.json
│ │ └── icon_cell_badge_pull_request.imageset
│ │ │ ├── icon_cell_badge_pull_request.pdf
│ │ │ └── Contents.json
│ └── GoogleService-Info.plist
├── Common
│ ├── ScrollView.swift
│ ├── BarButtonItem.swift
│ ├── Table View Cells
│ │ ├── TableViewCellViewModel.swift
│ │ └── DefaultTableViewCellViewModel.swift
│ ├── CollectionViewCell.swift
│ ├── PickerView.swift
│ ├── Switch.swift
│ ├── StackView.swift
│ ├── Toolbar.swift
│ ├── ImageView.swift
│ ├── TableView.swift
│ ├── SplitViewController.swift
│ ├── Button.swift
│ ├── CollectionViewController.swift
│ ├── TextField.swift
│ ├── NavigationController.swift
│ ├── CollectionView.swift
│ ├── View.swift
│ └── ViewModelType.swift
├── Modules
│ ├── Contacts
│ │ ├── ContactCell.swift
│ │ ├── ContactCellViewModel.swift
│ │ └── ContactCell.xib
│ ├── Search
│ │ ├── TrendingUserCell.swift
│ │ ├── TrendingRepositoryCell.swift
│ │ ├── TrendingUserCellViewModel.swift
│ │ ├── SearchSection.swift
│ │ └── TrendingUserCell.xib
│ ├── Branches
│ │ ├── BranchCell.swift
│ │ ├── BranchCellViewModel.swift
│ │ ├── BranchesViewController.swift
│ │ └── BranchCell.xib
│ ├── Repository Details
│ │ ├── LanguagesCellViewModel.swift
│ │ ├── RepositoryDetailCellViewModel.swift
│ │ ├── RepositoryDetailCell.swift
│ │ └── LanguageView.swift
│ ├── Contents
│ │ ├── ContentCell.swift
│ │ ├── ContentCellViewModel.swift
│ │ └── ContentCell.xib
│ ├── Languages
│ │ ├── RepoLanguageCellViewModel.swift
│ │ ├── RepoLanguageCell.swift
│ │ └── LanguagesSection.swift
│ ├── Theme
│ │ ├── ThemeCellViewModel.swift
│ │ ├── ThemeCell.swift
│ │ ├── ThemeViewModel.swift
│ │ ├── ThemeViewController.swift
│ │ └── ThemeCell.xib
│ ├── Settings
│ │ └── Cells
│ │ │ ├── SettingCellViewModel.swift
│ │ │ ├── SettingCell.swift
│ │ │ ├── SettingSwitchCellViewModel.swift
│ │ │ ├── SettingSwitchCell.swift
│ │ │ └── SettingCell.xib
│ ├── User Details
│ │ ├── UserDetailCellViewModel.swift
│ │ ├── UserDetailCell.swift
│ │ ├── ContributionsCellViewModel.swift
│ │ └── UserSection.swift
│ ├── Settings Language
│ │ ├── LanguageCell.swift
│ │ ├── LanguageCellViewModel.swift
│ │ └── LanguageCell.xib
│ ├── Commits
│ │ ├── CommitCell.swift
│ │ ├── CommitCellViewModel.swift
│ │ └── CommitCell.xib
│ ├── Main
│ │ └── InitialSplitViewController.swift
│ ├── Pull Requests
│ │ └── PullRequestCell.swift
│ ├── Releases
│ │ ├── ReleaseCell.swift
│ │ ├── ReleaseCellViewModel.swift
│ │ └── ReleaseCell.xib
│ ├── Issues
│ │ └── IssueCell.swift
│ ├── Events
│ │ ├── EventCell.swift
│ │ └── EventCell.xib
│ ├── Notifications
│ │ ├── NotificationCell.swift
│ │ └── NotificationCellViewModel.swift
│ ├── Issue Details
│ │ ├── IssueCommentsViewController.swift
│ │ ├── IssueCommentsViewModel.swift
│ │ └── IssueViewModel.swift
│ ├── Pull Request Details
│ │ ├── PullRequestCommentsViewController.swift
│ │ ├── PullRequestCommentsViewModel.swift
│ │ └── PullRequestViewModel.swift
│ ├── Users
│ │ ├── UserCell.swift
│ │ └── UserCell.xib
│ ├── Repositories
│ │ ├── RepositoryCell.swift
│ │ └── RepositoryCell.xib
│ └── Lines Count
│ │ └── LinesCountViewModel.swift
├── Models
│ ├── State.swift
│ ├── SectionType.swift
│ ├── Committer.swift
│ ├── License.swift
│ ├── Branch.swift
│ ├── ISO8601DateTransform.swift
│ ├── Contact.swift
│ ├── Comment.swift
│ ├── Milestone.swift
│ └── Notification.swift
├── Extensions
│ ├── RxSwift
│ │ ├── KafkaRefresh+Rx.swift
│ │ └── Observable+Logging.swift
│ ├── UIImage
│ │ └── UIImage+SwiftHub.swift
│ ├── UIFont
│ │ └── UIFont+SwiftHub.swift
│ ├── Foundation
│ │ └── Foundation+SwiftHub.swift
│ ├── UIColor
│ │ └── UIColor+SwiftHub.swift
│ └── UIView
│ │ └── UIView+SwiftHub.swift
├── Managers
│ ├── LogManager.swift
│ ├── Reachability.swift
│ └── AuthManager.swift
└── Third Party
│ └── RxErrorTracker
│ └── ErrorTracker.swift
├── Sketch
└── SwiftHub.sketch
├── iThoughtsX
├── SwiftHub.itmz
├── SwiftHub.png
└── SwiftHub_full.pdf
├── fastlane
├── screenshots
│ ├── background.jpg
│ ├── en-US
│ │ ├── keyword.strings
│ │ └── title.strings
│ ├── ru
│ │ ├── keyword.strings
│ │ └── title.strings
│ ├── zh-Hans
│ │ ├── keyword.strings
│ │ └── title.strings
│ └── framefile.json
├── Appfile
└── Snapfile
├── screenshots
├── 03_settings_screen.png
├── 05_search_user_screen.png
├── 06_user_details_screen.png
├── 01_search_repository_screen.png
├── 02_repository_details_screen.png
└── 04_trending_repository_screen.png
├── SwiftHub.xcodeproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── Gemfile
├── .jazzy.yaml
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── SwiftHubTests
├── SwiftHubTests.swift
└── Info.plist
├── SwiftHubUITests
└── Info.plist
├── LICENSE
└── Postman
└── Github.postman_environment.json
/SwiftHub/Networking/Rest/Stubbed Responses/EmptyObject.json:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/Events.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/EmptyArray.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/Notifications.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/EventsOrganization.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/EventsRepository.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/EventsUserReceived.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryBranches.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryCommits.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryIssues.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryReleases.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/EventsUserPerformed.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/NotificationsRepository.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryIssueComments.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryPullRequests.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryPullRequestComments.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/Sketch/SwiftHub.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/Sketch/SwiftHub.sketch
--------------------------------------------------------------------------------
/iThoughtsX/SwiftHub.itmz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/iThoughtsX/SwiftHub.itmz
--------------------------------------------------------------------------------
/iThoughtsX/SwiftHub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/iThoughtsX/SwiftHub.png
--------------------------------------------------------------------------------
/iThoughtsX/SwiftHub_full.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/iThoughtsX/SwiftHub_full.pdf
--------------------------------------------------------------------------------
/fastlane/screenshots/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/fastlane/screenshots/background.jpg
--------------------------------------------------------------------------------
/screenshots/03_settings_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/screenshots/03_settings_screen.png
--------------------------------------------------------------------------------
/screenshots/05_search_user_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/screenshots/05_search_user_screen.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/screenshots/06_user_details_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/screenshots/06_user_details_screen.png
--------------------------------------------------------------------------------
/screenshots/01_search_repository_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/screenshots/01_search_repository_screen.png
--------------------------------------------------------------------------------
/screenshots/02_repository_details_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/screenshots/02_repository_details_screen.png
--------------------------------------------------------------------------------
/screenshots/04_trending_repository_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/screenshots/04_trending_repository_screen.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/keyword.strings:
--------------------------------------------------------------------------------
1 | "01_search_repository_screen" = "SEARCH";
2 | "02_repository_details_screen" = "REPOSITORY";
3 | "03_settings_screen" = "SETTINGS";
--------------------------------------------------------------------------------
/fastlane/screenshots/ru/keyword.strings:
--------------------------------------------------------------------------------
1 | "01_search_repository_screen" = "ПОИСК";
2 | "02_repository_details_screen" = "РЕПОЗИТОРИИ";
3 | "03_settings_screen" = "НАСТРОЙКИ";
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/76 - iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/76 - iPad.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/76 - iPad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/76 - iPad@2x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/176 - iPad Pro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/176 - iPad Pro.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/60 - iPhone@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/60 - iPhone@2x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/60 - iPhone@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/60 - iPhone@3x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/1024 - App Store.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/1024 - App Store.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings@2x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings@3x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight@2x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight@3x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/launch_image.imageset/launch_image.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/launch_image.imageset/launch_image.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_dir.imageset/icon_cell_dir.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_dir.imageset/icon_cell_dir.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/29 - Settings@2x-1.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/40 - Spotlight@2x-1.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_cloc.imageset/icon_cell_cloc.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_cloc.imageset/icon_cell_cloc.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_file.imageset/icon_cell_file.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_file.imageset/icon_cell_file.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_link.imageset/icon_cell_link.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_link.imageset/icon_cell_link.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_size.imageset/icon_cell_size.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_size.imageset/icon_cell_size.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_star.imageset/icon_cell_star.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_star.imageset/icon_cell_star.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification@2x-1.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification@2x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/AppIcon.appiconset/20 - Notification@3x.png
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/image_no_result.imageset/image_no_result.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Assets.xcassets/image_no_result.imageset/image_no_result.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_star.imageset/icon_button_star.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_button_star.imageset/icon_button_star.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_check.imageset/icon_cell_check.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_check.imageset/icon_cell_check.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_events.imageset/icon_cell_events.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_events.imageset/icon_cell_events.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_frown.imageset/icon_cell_frown.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_frown.imageset/icon_cell_frown.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_issues.imageset/icon_cell_issues.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_issues.imageset/icon_cell_issues.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_logout.imageset/icon_cell_logout.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_logout.imageset/icon_cell_logout.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_readme.imageset/icon_cell_readme.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_readme.imageset/icon_cell_readme.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_remove.imageset/icon_cell_remove.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_remove.imageset/icon_cell_remove.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_smile.imageset/icon_cell_smile.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_smile.imageset/icon_cell_smile.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_source.imageset/icon_cell_source.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_source.imageset/icon_cell_source.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_theme.imageset/icon_cell_theme.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_theme.imageset/icon_cell_theme.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_news.imageset/icon_tabbar_news.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_tabbar_news.imageset/icon_tabbar_news.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_toast_error.imageset/icon_toast_error.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_toast_error.imageset/icon_toast_error.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_company.imageset/icon_cell_company.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_company.imageset/icon_cell_company.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_created.imageset/icon_cell_created.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_created.imageset/icon_cell_created.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_updated.imageset/icon_cell_updated.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_updated.imageset/icon_cell_updated.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_login.imageset/icon_tabbar_login.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_tabbar_login.imageset/icon_tabbar_login.pdf
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/title.strings:
--------------------------------------------------------------------------------
1 | "01_search_repository_screen" = "Explore Trending Repositories";
2 | "02_repository_details_screen" = "View Repository Details";
3 | "03_settings_screen" = "Customize App Theme";
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_github.imageset/icon_button_github.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_button_github.imageset/icon_button_github.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_unstar.imageset/icon_button_unstar.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_button_unstar.imageset/icon_button_unstar.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_user_x.imageset/icon_button_user_x.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_button_user_x.imageset/icon_button_user_x.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_fork.imageset/icon_cell_git_fork.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_git_fork.imageset/icon_cell_git_fork.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_language.imageset/icon_cell_language.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_language.imageset/icon_cell_language.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_releases.imageset/icon_cell_releases.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_releases.imageset/icon_cell_releases.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_search.imageset/icon_tabbar_search.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_tabbar_search.imageset/icon_tabbar_search.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_toast_success.imageset/icon_toast_success.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_toast_success.imageset/icon_toast_success.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_toast_warning.imageset/icon_toast_warning.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_toast_warning.imageset/icon_toast_warning.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_cloc.imageset/icon_whatsnew_cloc.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_cloc.imageset/icon_whatsnew_cloc.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_tag.imageset/icon_cell_badge_tag.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_tag.imageset/icon_cell_badge_tag.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_merge.imageset/icon_cell_git_merge.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_git_merge.imageset/icon_cell_git_merge.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_submodule.imageset/icon_cell_submodule.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_submodule.imageset/icon_cell_submodule.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_whats_new.imageset/icon_cell_whats_new.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_whats_new.imageset/icon_cell_whats_new.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_web.imageset/icon_navigation_web.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_web.imageset/icon_navigation_web.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_profile.imageset/icon_tabbar_profile.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_tabbar_profile.imageset/icon_tabbar_profile.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_theme.imageset/icon_whatsnew_theme.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_theme.imageset/icon_whatsnew_theme.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_user_plus.imageset/icon_button_user_plus.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_button_user_plus.imageset/icon_button_user_plus.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_fork.imageset/icon_cell_badge_fork.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_fork.imageset/icon_cell_badge_fork.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_issue.imageset/icon_cell_badge_issue.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_issue.imageset/icon_cell_badge_issue.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_push.imageset/icon_cell_badge_push.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_push.imageset/icon_cell_badge_push.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_star.imageset/icon_cell_badge_star.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_star.imageset/icon_cell_badge_star.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_user.imageset/icon_cell_badge_user.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_user.imageset/icon_cell_badge_user.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_disclosure.imageset/icon_cell_disclosure.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_disclosure.imageset/icon_cell_disclosure.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_branch.imageset/icon_cell_git_branch.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_git_branch.imageset/icon_cell_git_branch.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_commit.imageset/icon_cell_git_commit.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_git_commit.imageset/icon_cell_git_commit.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_night_mode.imageset/icon_cell_night_mode.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_night_mode.imageset/icon_cell_night_mode.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_back.imageset/icon_navigation_back.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_back.imageset/icon_navigation_back.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_close.imageset/icon_navigation_close.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_close.imageset/icon_navigation_close.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_stop.imageset/icon_navigation_stop.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_stop.imageset/icon_navigation_stop.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_theme.imageset/icon_navigation_theme.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_theme.imageset/icon_navigation_theme.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_activity.imageset/icon_tabbar_activity.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_tabbar_activity.imageset/icon_tabbar_activity.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_settings.imageset/icon_tabbar_settings.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_tabbar_settings.imageset/icon_tabbar_settings.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_github.imageset/icon_whatsnew_github.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_github.imageset/icon_whatsnew_github.pdf
--------------------------------------------------------------------------------
/fastlane/screenshots/ru/title.strings:
--------------------------------------------------------------------------------
1 | "01_search_repository_screen" = "Исследуйте Трендовые Репозитории";
2 | "02_repository_details_screen" = "Посмотреть Детали Репозитории";
3 | "03_settings_screen" = "Настроить Тему Приложения";
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_branch.imageset/icon_cell_badge_branch.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_branch.imageset/icon_cell_badge_branch.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_commit.imageset/icon_cell_badge_commit.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_commit.imageset/icon_cell_badge_commit.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_search.imageset/icon_cell_badge_search.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_search.imageset/icon_cell_badge_search.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_language.imageset/icon_cell_git_language.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_git_language.imageset/icon_cell_git_language.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_github.imageset/icon_navigation_github.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_github.imageset/icon_navigation_github.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_trending.imageset/icon_whatsnew_trending.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_trending.imageset/icon_whatsnew_trending.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_comment.imageset/icon_cell_badge_comment.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_comment.imageset/icon_cell_badge_comment.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_stars_history.imageset/icon_cell_stars_history.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_stars_history.imageset/icon_cell_stars_history.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_forward.imageset/icon_navigation_forward.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_forward.imageset/icon_navigation_forward.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_history.imageset/icon_navigation_history.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_history.imageset/icon_navigation_history.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_refresh.imageset/icon_navigation_refresh.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_refresh.imageset/icon_navigation_refresh.pdf
--------------------------------------------------------------------------------
/SwiftHub.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_trending.imageset/icon_cell_badge_trending.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_trending.imageset/icon_cell_badge_trending.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_language.imageset/icon_navigation_language.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_navigation_language.imageset/icon_navigation_language.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_acknowledgements.imageset/icon_cell_acknowledgements.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_acknowledgements.imageset/icon_cell_acknowledgements.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_repository.imageset/icon_cell_badge_repository.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_repository.imageset/icon_cell_badge_repository.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_contact_no_image.imageset/icon_cell_contact_no_image.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_contact_no_image.imageset/icon_cell_contact_no_image.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_pull_request.imageset/icon_cell_git_pull_request.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_git_pull_request.imageset/icon_cell_git_pull_request.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_profile_summary.imageset/icon_cell_profile_summary.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_profile_summary.imageset/icon_cell_profile_summary.pdf
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source "https://rubygems.org"
3 |
4 | gem 'fastlane' # https://github.com/fastlane/fastlane
5 |
6 | gem 'cocoapods' # https://github.com/CocoaPods/CocoaPods
7 |
8 | #gem 'jazzy' # https://github.com/realm/jazzy
9 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_collaborator.imageset/icon_cell_badge_collaborator.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_collaborator.imageset/icon_cell_badge_collaborator.pdf
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_pull_request.imageset/icon_cell_badge_pull_request.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khoren93/SwiftHub/HEAD/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_pull_request.imageset/icon_cell_badge_pull_request.pdf
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | app_identifier("com.public.SwiftHub") # The bundle identifier of your app
2 | apple_id("xoren93@gmail.com") # Your Apple email address
3 |
4 |
5 | # For more information about the Appfile, see:
6 | # https://docs.fastlane.tools/advanced/#appfile
7 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/launch_image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "launch_image.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_dir.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_dir.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Assets.xcassets/image_no_result.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "image_no_result.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_check.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_file.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_file.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_frown.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_frown.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_link.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_link.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_size.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_size.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_smile.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_smile.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_star.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_star.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_theme.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_theme.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Common/ScrollView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScrollView.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ScrollView: UIScrollView {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_github.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_button_github.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_star.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_button_star.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_unstar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_button_unstar.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_user_x.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_button_user_x.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_cloc.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_cell_cloc.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_company.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_company.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_created.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_created.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_events.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_events.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_fork.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_git_fork.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_issues.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_issues.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_language.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_language.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_logout.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_logout.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_readme.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_readme.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_releases.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_releases.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_remove.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_remove.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_source.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_source.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_updated.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_updated.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_login.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_tabbar_login.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_news.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_tabbar_news.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_search.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_tabbar_search.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_toast_error.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_toast_error.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_toast_success.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_toast_success.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_toast_warning.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_toast_warning.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_fork.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_fork.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_push.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_push.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_star.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_star.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_tag.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_tag.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_user.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_user.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_disclosure.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_disclosure.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_branch.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_git_branch.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_commit.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_git_commit.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_merge.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_git_merge.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_night_mode.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_night_mode.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_submodule.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_submodule.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_whats_new.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_whats_new.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_back.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_stop.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_stop.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_web.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_web.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_activity.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_tabbar_activity.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_profile.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_tabbar_profile.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_tabbar_settings.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_tabbar_settings.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_github.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_whatsnew_github.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Common/BarButtonItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarButtonItem.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class BarButtonItem: UIBarButtonItem {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_button_user_plus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_button_user_plus.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_branch.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_branch.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_comment.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_comment.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_commit.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_commit.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_issue.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_issue.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_search.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_search.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_language.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_git_language.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_stars_history.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_stars_history.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_close.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_forward.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_forward.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_github.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_github.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_history.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_history.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_refresh.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_refresh.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_theme.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_theme.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_cloc.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_whatsnew_cloc.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_theme.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_whatsnew_theme.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/fastlane/screenshots/zh-Hans/keyword.strings:
--------------------------------------------------------------------------------
1 | //"01_search_repository_screen" = "搜索";
2 | //"02_repository_details_screen" = "处置库";
3 | //"03_settings_screen" = "设置";
4 | "01_search_repository_screen" = "SEARCH";
5 | "02_repository_details_screen" = "REPOSITORY";
6 | "03_settings_screen" = "SETTINGS";
7 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_trending.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_trending.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_profile_summary.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_profile_summary.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_navigation_language.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_navigation_language.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_whatsnew_trending.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_whatsnew_trending.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Contacts/ContactCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContactCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/15/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ContactCell: DefaultTableViewCell {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_acknowledgements.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_acknowledgements.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_collaborator.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_collaborator.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_pull_request.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_pull_request.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_badge_repository.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_badge_repository.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_contact_no_image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_contact_no_image.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Resources/Icons.xcassets/icon_cell_git_pull_request.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_cell_git_pull_request.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftHub/Modules/Search/TrendingUserCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TrendingUserCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 12/18/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TrendingUserCell: DefaultTableViewCell {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/SwiftHub/Models/State.swift:
--------------------------------------------------------------------------------
1 | //
2 | // State.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/20/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum State: String {
12 | case open
13 | case closed
14 | case all
15 | }
16 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Search/TrendingRepositoryCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TrendingRepositoryCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 12/18/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TrendingRepositoryCell: DefaultTableViewCell {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/fastlane/screenshots/zh-Hans/title.strings:
--------------------------------------------------------------------------------
1 | //"01_search_repository_screen" = "探索趋势存储库";
2 | //"02_repository_details_screen" = "查看存储库详细信息";
3 | //"03_settings_screen" = "自定义应用主题";
4 | "01_search_repository_screen" = "Explore Trending Repositories";
5 | "02_repository_details_screen" = "View Repository Details";
6 | "03_settings_screen" = "Customize App Theme";
7 |
--------------------------------------------------------------------------------
/.jazzy.yaml:
--------------------------------------------------------------------------------
1 | clean: true
2 | sdk: iphone
3 | #swift_version: 4.2.1
4 | author: Khoren Markosyan
5 | github_url: https://github.com/khoren93/SwiftHub
6 | module: SwiftHub
7 | module_version: 1.5.0
8 | copyright: "2017-present. See LICENSE for more details."
9 | xcodebuild_arguments: [clean,build,-project,SwiftHub.xcodeproj,-scheme,SwiftHub]
10 | min_acl: internal
11 |
--------------------------------------------------------------------------------
/SwiftHub/Common/Table View Cells/TableViewCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/12/20.
6 | // Copyright © 2020 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class TableViewCellViewModel: NSObject {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Branches/BranchCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BranchCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 4/6/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class BranchCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | leftImageView.contentMode = .center
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SwiftHub/Common/CollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionViewCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class CollectionViewCell: UICollectionViewCell {
12 |
13 | func makeUI() {
14 | self.layer.masksToBounds = true
15 | updateUI()
16 | }
17 |
18 | func updateUI() {
19 | setNeedsDisplay()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Repository Details/LanguagesCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LanguagesCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 7/26/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class LanguagesCellViewModel: NSObject {
14 |
15 | let languages: Languages?
16 |
17 | init(languages: Languages) {
18 | self.languages = languages
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/SwiftHub/Models/SectionType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SectionType.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 7/8/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxDataSources
11 |
12 | struct SectionType {
13 | var header: String
14 | var items: [T]
15 | }
16 |
17 | extension SectionType: SectionModelType {
18 | typealias Item = T
19 |
20 | init(original: SectionType, items: [T]) {
21 | self = original
22 | self.items = items
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Contents/ContentCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/6/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ContentCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | leftImageView.contentMode = .center
16 | leftImageView.layerCornerRadius = 0
17 | leftImageView.snp.remakeConstraints { (make) in
18 | make.size.equalTo(30)
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Languages/RepoLanguageCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoLanguageCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 12/18/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class RepoLanguageCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let language: Language
16 |
17 | init(with language: Language) {
18 | self.language = language
19 | super.init()
20 | title.accept(language.displayName())
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SwiftHub/Models/Committer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Committer.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct Committer: Mappable {
13 |
14 | var name: String?
15 | var email: String?
16 | var date: Date?
17 |
18 | init?(map: Map) {}
19 | init() {}
20 |
21 | mutating func mapping(map: Map) {
22 | name <- map["name"]
23 | email <- map["email"]
24 | date <- (map["date"], ISO8601DateTransform())
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Branches/BranchCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BranchCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 4/6/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class BranchCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let branch: Branch
16 |
17 | init(with branch: Branch) {
18 | self.branch = branch
19 | super.init()
20 | title.accept(branch.name)
21 | image.accept(R.image.icon_cell_git_branch()?.template)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SwiftHub/Common/PickerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PickerView.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 12/26/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PickerView: UIPickerView {
12 |
13 | init () {
14 | super.init(frame: CGRect())
15 | }
16 |
17 | override init(frame: CGRect) {
18 | super.init(frame: frame)
19 | makeUI()
20 | }
21 |
22 | required init?(coder aDecoder: NSCoder) {
23 | super.init(coder: aDecoder)
24 | makeUI()
25 | }
26 |
27 | func makeUI() {
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Theme/ThemeCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThemeCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 9/15/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class ThemeCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let imageColor = BehaviorRelay(value: nil)
16 |
17 | let theme: ColorTheme
18 |
19 | init(with theme: ColorTheme) {
20 | self.theme = theme
21 | super.init()
22 | title.accept(theme.title)
23 | imageColor.accept(theme.color)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings/Cells/SettingCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 7/8/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class SettingCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | init(with title: String, detail: String?, image: UIImage?, hidesDisclosure: Bool) {
16 | super.init()
17 | self.title.accept(title)
18 | self.secondDetail.accept(detail)
19 | self.image.accept(image)
20 | self.hidesDisclosure.accept(hidesDisclosure)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/User Details/UserDetailCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDetailCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 10/13/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class UserDetailCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | init(with title: String, detail: String, image: UIImage?, hidesDisclosure: Bool) {
16 | super.init()
17 | self.title.accept(title)
18 | self.secondDetail.accept(detail)
19 | self.image.accept(image)
20 | self.hidesDisclosure.accept(hidesDisclosure)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SwiftHub/Common/Switch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Switch.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 7/23/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class Switch: UISwitch {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | makeUI()
16 | }
17 |
18 | required public init?(coder aDecoder: NSCoder) {
19 | super.init(coder: aDecoder)
20 | makeUI()
21 | }
22 |
23 | func makeUI() {
24 | self.theme.tintColor = themeService.attribute { $0.secondary }
25 | self.theme.onTintColor = themeService.attribute { $0.secondary }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/SwiftHub/Extensions/RxSwift/KafkaRefresh+Rx.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KafkaRefresh+Rx.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 7/24/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxCocoa
11 | import RxSwift
12 | import KafkaRefresh
13 |
14 | extension Reactive where Base: KafkaRefreshControl {
15 |
16 | public var isAnimating: Binder {
17 | return Binder(self.base) { refreshControl, active in
18 | if active {
19 | // refreshControl.beginRefreshing()
20 | } else {
21 | refreshControl.endRefreshing()
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | 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 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Repository Details/RepositoryDetailCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepositoryDetailCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/5/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class RepositoryDetailCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | init(with title: String, detail: String, image: UIImage?, hidesDisclosure: Bool) {
16 | super.init()
17 | self.title.accept(title)
18 | self.secondDetail.accept(detail)
19 | self.image.accept(image)
20 | self.hidesDisclosure.accept(hidesDisclosure)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings Language/LanguageCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LanguageCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 3/25/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LanguageCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | leftImageView.isHidden = true
16 | }
17 |
18 | override func setSelected(_ selected: Bool, animated: Bool) {
19 | super.setSelected(selected, animated: animated)
20 |
21 | // Configure the view for the selected state
22 | rightImageView.image = selected ? R.image.icon_cell_check()?.template : nil
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Commits/CommitCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommitCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 |
12 | class CommitCell: DefaultTableViewCell {
13 |
14 | override func bind(to viewModel: TableViewCellViewModel) {
15 | super.bind(to: viewModel)
16 | guard let viewModel = viewModel as? CommitCellViewModel else { return }
17 | cellDisposeBag = DisposeBag()
18 |
19 | leftImageView.rx.tap().map { _ in viewModel.commit.committer }.filterNil()
20 | .bind(to: viewModel.userSelected).disposed(by: cellDisposeBag)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Languages/RepoLanguageCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoLanguageCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 12/18/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class RepoLanguageCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | leftImageView.isHidden = true
16 | }
17 |
18 | override func setSelected(_ selected: Bool, animated: Bool) {
19 | super.setSelected(selected, animated: animated)
20 |
21 | // Configure the view for the selected state
22 | rightImageView.image = selected ? R.image.icon_cell_check()?.template : nil
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Theme/ThemeCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThemeCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 9/15/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ThemeCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | rightImageView.isHidden = true
16 | }
17 |
18 | override func bind(to viewModel: TableViewCellViewModel) {
19 | super.bind(to: viewModel)
20 | guard let viewModel = viewModel as? ThemeCellViewModel else { return }
21 |
22 | viewModel.imageColor.asDriver().drive(leftImageView.rx.backgroundColor).disposed(by: rx.disposeBag)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Main/InitialSplitViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InitialSplitViewController.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 7/23/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class InitialSplitViewController: TableViewController {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 |
16 | if #available(iOS 11.0, *) {
17 | navigationController?.navigationBar.prefersLargeTitles = false
18 | }
19 |
20 | emptyDataSetTitle = R.string.localizable.initialNoResults.key.localized()
21 | tableView.headRefreshControl = nil
22 | tableView.footRefreshControl = nil
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Pull Requests/PullRequestCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PullRequestCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 |
12 | class PullRequestCell: DefaultTableViewCell {
13 |
14 | override func bind(to viewModel: TableViewCellViewModel) {
15 | super.bind(to: viewModel)
16 | guard let viewModel = viewModel as? PullRequestCellViewModel else { return }
17 | cellDisposeBag = DisposeBag()
18 |
19 | leftImageView.rx.tap().map { _ in viewModel.pullRequest.user }.filterNil()
20 | .bind(to: viewModel.userSelected).disposed(by: cellDisposeBag)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SwiftHubTests/SwiftHubTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftHubTests.swift
3 | // SwiftHubTests
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftHub
11 |
12 | class SwiftHubTests: XCTestCase {
13 |
14 | func testExample() {
15 | // This is an example of a functional test case.
16 | // Use XCTAssert and related functions to verify your tests produce the correct results.
17 | }
18 |
19 | func testPerformanceExample() {
20 | // This is an example of a performance test case.
21 | self.measure {
22 | // Put the code you want to measure the time of here.
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SwiftHub/Common/StackView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StackView.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 6/26/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class StackView: UIStackView {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | makeUI()
16 | }
17 |
18 | required init(coder aDecoder: NSCoder) {
19 | super.init(coder: aDecoder)
20 | makeUI()
21 | }
22 |
23 | func makeUI() {
24 | spacing = inset
25 | axis = .vertical
26 | // self.distribution = .fill
27 |
28 | updateUI()
29 | }
30 |
31 | func updateUI() {
32 | setNeedsDisplay()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/User Details/UserDetailCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDetailCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 10/13/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class UserDetailCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | leftImageView.contentMode = .center
16 | leftImageView.layerCornerRadius = 0
17 | leftImageView.snp.updateConstraints { (make) in
18 | make.size.equalTo(30)
19 | }
20 | detailLabel.isHidden = true
21 | secondDetailLabel.textAlignment = .right
22 | textsStackView.axis = .horizontal
23 | textsStackView.distribution = .fillEqually
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Releases/ReleaseCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReleaseCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 4/12/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ReleaseCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | secondDetailLabel.numberOfLines = 0
16 | }
17 |
18 | override func bind(to viewModel: TableViewCellViewModel) {
19 | super.bind(to: viewModel)
20 | guard let viewModel = viewModel as? ReleaseCellViewModel else { return }
21 |
22 | leftImageView.rx.tap().map { _ in viewModel.release.author }.filterNil()
23 | .bind(to: viewModel.userSelected).disposed(by: cellDisposeBag)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Contacts/ContactCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContactCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/15/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class ContactCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let contact: Contact
16 |
17 | init(with contact: Contact) {
18 | self.contact = contact
19 | super.init()
20 | title.accept(contact.name)
21 | let info = contact.phones + contact.emails
22 | detail.accept(info.joined(separator: ", "))
23 | image.accept(UIImage(data: contact.imageData ?? Data()) ?? R.image.icon_cell_contact_no_image()?.template)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SwiftHubTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
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.10.1
19 | CFBundleVersion
20 | 32
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwiftHubUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
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.10.1
19 | CFBundleVersion
20 | 32
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwiftHub/Models/License.swift:
--------------------------------------------------------------------------------
1 | //
2 | // License.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 6/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 | // Model file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
9 |
10 | import Foundation
11 | import ObjectMapper
12 |
13 | struct License: Mappable {
14 |
15 | var key: String?
16 | var name: String?
17 | var nodeId: String?
18 | var spdxId: AnyObject?
19 | var url: AnyObject?
20 |
21 | init?(map: Map) {}
22 | init() {}
23 |
24 | mutating func mapping(map: Map) {
25 | key <- map["key"]
26 | name <- map["name"]
27 | nodeId <- map["node_id"]
28 | spdxId <- map["spdx_id"]
29 | url <- map["url"]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/fastlane/screenshots/framefile.json:
--------------------------------------------------------------------------------
1 | {
2 | "device_frame_version": "latest",
3 | "default": {
4 | "title": {
5 | "color": "#545454"
6 | },
7 | "background": "./background.jpg",
8 | "padding": 30,
9 | "show_complete_frame": false,
10 | "stack_title" : true,
11 | "title_below_image": false,
12 | "frame": "BLACK"
13 | },
14 |
15 | "data": [
16 | {
17 | "filter": "01_search_repository_screen",
18 | "keyword": {
19 | "color": "#BF382A"
20 | }
21 | },
22 | {
23 | "filter": "02_repository_details_screen",
24 | "keyword": {
25 | "color": "#26AD5E"
26 | }
27 | },
28 | {
29 | "filter": "03_settings_screen",
30 | "keyword": {
31 | "color": "#394C82"
32 | }
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/User Details/ContributionsCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContributionsCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/12/20.
6 | // Copyright © 2020 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class ContributionsCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let contributionCalendar = BehaviorRelay(value: nil)
16 |
17 | init(with title: String, detail: String, image: UIImage?, contributionCalendar: ContributionCalendar?) {
18 | super.init()
19 | self.title.accept(title)
20 | self.secondDetail.accept(detail)
21 | self.image.accept(image)
22 | self.contributionCalendar.accept(contributionCalendar)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings/Cells/SettingCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 7/8/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SettingCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | leftImageView.contentMode = .center
16 | leftImageView.layerCornerRadius = 0
17 | leftImageView.snp.updateConstraints { (make) in
18 | make.size.equalTo(30)
19 | }
20 | detailLabel.isHidden = true
21 | attributedDetailLabel.isHidden = true
22 | secondDetailLabel.textAlignment = .right
23 | textsStackView.axis = .horizontal
24 | textsStackView.distribution = .fillEqually
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Issues/IssueCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IssueCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/20/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 |
12 | class IssueCell: DefaultTableViewCell {
13 |
14 | override func makeUI() {
15 | super.makeUI()
16 | titleLabel.numberOfLines = 2
17 | }
18 |
19 | override func bind(to viewModel: TableViewCellViewModel) {
20 | super.bind(to: viewModel)
21 | guard let viewModel = viewModel as? IssueCellViewModel else { return }
22 | cellDisposeBag = DisposeBag()
23 |
24 | leftImageView.rx.tap().map { _ in viewModel.issue.user }.filterNil()
25 | .bind(to: viewModel.userSelected).disposed(by: cellDisposeBag)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/SwiftHub/Models/Branch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Branch.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/20/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 | // Model file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
9 |
10 | import Foundation
11 | import ObjectMapper
12 |
13 | struct Branch: Mappable {
14 |
15 | // var links: Link?
16 | var commit: Commit?
17 | var name: String?
18 | var protectedField: Bool?
19 | var protectionUrl: String?
20 |
21 | init?(map: Map) {}
22 | init() {}
23 |
24 | mutating func mapping(map: Map) {
25 | // links <- map["_links"]
26 | commit <- map["commit"]
27 | name <- map["name"]
28 | protectedField <- map["protected"]
29 | protectionUrl <- map["protection_url"]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SwiftHub/Models/ISO8601DateTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ISO8601DateTransform.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 9/6/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | open class ISO8601DateTransform: TransformType {
13 | public typealias Object = Date
14 | public typealias JSON = String
15 |
16 | public init() {}
17 |
18 | open func transformFromJSON(_ value: Any?) -> Date? {
19 | if let dateString = value as? String {
20 | return dateString.toISODate()?.date
21 | }
22 | return nil
23 | }
24 |
25 | open func transformToJSON(_ value: Date?) -> String? {
26 | if let date = value {
27 | return date.toISO()
28 | }
29 | return nil
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Repository Details/RepositoryDetailCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepositoryDetailCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/5/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class RepositoryDetailCell: DefaultTableViewCell {
12 |
13 | override func makeUI() {
14 | super.makeUI()
15 | leftImageView.contentMode = .center
16 | leftImageView.layerCornerRadius = 0
17 | leftImageView.snp.updateConstraints { (make) in
18 | make.size.equalTo(30)
19 | }
20 | detailLabel.isHidden = true
21 | attributedDetailLabel.isHidden = true
22 | secondDetailLabel.textAlignment = .right
23 | textsStackView.axis = .horizontal
24 | textsStackView.distribution = .fillEqually
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/RepositoryNumberOfLines.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "language": "JSON",
4 | "files": "126",
5 | "lines": "63741",
6 | "blanks": "1",
7 | "comments": "0",
8 | "linesOfCode": "63740"
9 | },
10 | {
11 | "language": "Swift",
12 | "files": "185",
13 | "lines": "15984",
14 | "blanks": "2537",
15 | "comments": "1564",
16 | "linesOfCode": "11883"
17 | },
18 | {
19 | "language": "Markdown",
20 | "files": "4",
21 | "lines": "457",
22 | "blanks": "116",
23 | "comments": "0",
24 | "linesOfCode": "341"
25 | },
26 | {
27 | "language": "Total",
28 | "files": "315",
29 | "lines": "80182",
30 | "blanks": "2654",
31 | "comments": "1564",
32 | "linesOfCode": "75964"
33 | }
34 | ]
35 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Events/EventCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 9/6/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 |
12 | class EventCell: DefaultTableViewCell {
13 |
14 | override func makeUI() {
15 | super.makeUI()
16 | titleLabel.numberOfLines = 2
17 | secondDetailLabel.numberOfLines = 0
18 | }
19 |
20 | override func bind(to viewModel: TableViewCellViewModel) {
21 | super.bind(to: viewModel)
22 | guard let viewModel = viewModel as? EventCellViewModel else { return }
23 | cellDisposeBag = DisposeBag()
24 |
25 | leftImageView.rx.tap().map { _ in viewModel.event.actor }.filterNil()
26 | .bind(to: viewModel.userSelected).disposed(by: cellDisposeBag)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings Language/LanguageCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LanguageCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 3/25/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class LanguageCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let language: String
16 |
17 | init(with language: String) {
18 | self.language = language
19 | super.init()
20 | title.accept(displayName(forLanguage: language))
21 | }
22 | }
23 |
24 | func displayName(forLanguage language: String) -> String {
25 | let local = Locale(identifier: language)
26 | if let displayName = local.localizedString(forIdentifier: language) {
27 | return displayName.capitalized(with: local)
28 | }
29 | return String()
30 | }
31 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Notifications/NotificationCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 9/19/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 |
12 | class NotificationCell: DefaultTableViewCell {
13 |
14 | override func makeUI() {
15 | super.makeUI()
16 | titleLabel.numberOfLines = 2
17 | }
18 |
19 | override func bind(to viewModel: TableViewCellViewModel) {
20 | super.bind(to: viewModel)
21 | guard let viewModel = viewModel as? NotificationCellViewModel else { return }
22 | cellDisposeBag = DisposeBag()
23 |
24 | leftImageView.rx.tap().map { _ in viewModel.notification.repository?.owner }.filterNil()
25 | .bind(to: viewModel.userSelected).disposed(by: cellDisposeBag)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings/Cells/SettingSwitchCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingSwitchCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 7/23/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class SettingSwitchCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let isEnabled = BehaviorRelay(value: false)
16 |
17 | let switchChanged = PublishSubject()
18 |
19 | init(with title: String, detail: String?, image: UIImage?, hidesDisclosure: Bool, isEnabled: Bool) {
20 | super.init()
21 | self.title.accept(title)
22 | self.secondDetail.accept(detail)
23 | self.image.accept(image)
24 | self.hidesDisclosure.accept(hidesDisclosure)
25 | self.isEnabled.accept(isEnabled)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/SwiftHub/Common/Table View Cells/DefaultTableViewCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DefaultTableViewCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 6/23/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class DefaultTableViewCellViewModel: TableViewCellViewModel {
14 | let title = BehaviorRelay(value: nil)
15 | let detail = BehaviorRelay(value: nil)
16 | let secondDetail = BehaviorRelay(value: nil)
17 | let attributedDetail = BehaviorRelay(value: nil)
18 | let image = BehaviorRelay(value: nil)
19 | let imageUrl = BehaviorRelay(value: nil)
20 | let badge = BehaviorRelay(value: nil)
21 | let badgeColor = BehaviorRelay(value: nil)
22 | let hidesDisclosure = BehaviorRelay(value: false)
23 | }
24 |
--------------------------------------------------------------------------------
/SwiftHub/Common/Toolbar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Toolbar.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 2/9/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class Toolbar: UIToolbar {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | makeUI()
16 | }
17 |
18 | required public init?(coder aDecoder: NSCoder) {
19 | super.init(coder: aDecoder)
20 | makeUI()
21 | }
22 |
23 | func makeUI() {
24 | isTranslucent = false
25 |
26 | theme.barStyle = themeService.attribute { $0.barStyle }
27 | theme.barTintColor = themeService.attribute { $0.primaryDark }
28 | theme.tintColor = themeService.attribute { $0.secondary }
29 |
30 | snp.makeConstraints { (make) in
31 | make.height.equalTo(Configs.BaseDimensions.tableRowHeight)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Releases/ReleaseCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReleaseCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 4/12/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class ReleaseCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let release: Release
16 |
17 | let userSelected = PublishSubject()
18 |
19 | init(with release: Release) {
20 | self.release = release
21 | super.init()
22 | title.accept("\(release.tagName ?? "") - \(release.name ?? "")")
23 | detail.accept(release.publishedAt?.toRelative(since: nil))
24 | secondDetail.accept(release.body)
25 | imageUrl.accept(release.author?.avatarUrl)
26 | badge.accept(R.image.icon_cell_badge_tag()?.template)
27 | badgeColor.accept(UIColor.Material.green)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/fastlane/Snapfile:
--------------------------------------------------------------------------------
1 | # Uncomment the lines below you want to change by removing the # in the beginning
2 |
3 | # A list of devices you want to take the screenshots from
4 | devices([
5 | "iPhone 8 Plus",
6 | "iPhone 13 Pro Max",
7 | "iPad Pro (12.9-inch) (5th generation)"
8 | ])
9 |
10 | languages([
11 | "en-US",
12 | "zh-Hans",
13 | "ru"
14 | ])
15 |
16 | # The name of the scheme which contains the UI Tests
17 | scheme("SwiftHubUITests")
18 |
19 | # Where should the resulting screenshots be stored?
20 | # output_directory("./screenshots")
21 |
22 | # remove the '#' to clear all previously generated screenshots before creating new ones
23 | clear_previous_screenshots(true)
24 |
25 | # Arguments to pass to the app on launch. See https://docs.fastlane.tools/actions/snapshot/#launch-arguments
26 | # launch_arguments(["-favColor red"])
27 |
28 | # For more information about all available options run
29 | # fastlane action snapshot
30 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Commits/CommitCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommitCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class CommitCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let commit: Commit
16 |
17 | let userSelected = PublishSubject()
18 |
19 | init(with commit: Commit) {
20 | self.commit = commit
21 | super.init()
22 | title.accept(commit.commit?.message)
23 | detail.accept(commit.commit?.committer?.date?.toRelative(since: nil))
24 | secondDetail.accept(commit.sha?.slicing(from: 0, length: 7))
25 | imageUrl.accept(commit.committer?.avatarUrl)
26 | badge.accept(R.image.icon_cell_badge_commit()?.template)
27 | badgeColor.accept(UIColor.Material.green)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/SwiftHub/Managers/LogManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LogManager.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CocoaLumberjack
11 | import RxSwift
12 |
13 | public func logDebug(_ message: @autoclosure () -> String) {
14 | DDLogDebug(message())
15 | }
16 |
17 | public func logError(_ message: @autoclosure () -> String) {
18 | DDLogError(message())
19 | }
20 |
21 | public func logInfo(_ message: @autoclosure () -> String) {
22 | DDLogInfo(message())
23 | }
24 |
25 | public func logVerbose(_ message: @autoclosure () -> String) {
26 | DDLogVerbose(message())
27 | }
28 |
29 | public func logWarn(_ message: @autoclosure () -> String) {
30 | DDLogWarn(message())
31 | }
32 |
33 | public func logResourcesCount() {
34 | #if DEBUG
35 | logDebug("RxSwift resources count: \(RxSwift.Resources.total)")
36 | #endif
37 | }
38 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Search/TrendingUserCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TrendingUserCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 12/18/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class TrendingUserCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let user: TrendingUser
16 |
17 | init(with user: TrendingUser) {
18 | self.user = user
19 | super.init()
20 | title.accept("\(user.username ?? "") (\(user.name ?? ""))")
21 | detail.accept(user.repo?.fullname)
22 | imageUrl.accept(user.avatar)
23 | badge.accept(R.image.icon_cell_badge_user()?.template)
24 | badgeColor.accept(UIColor.Material.green900)
25 | }
26 | }
27 |
28 | extension TrendingUserCellViewModel {
29 | static func == (lhs: TrendingUserCellViewModel, rhs: TrendingUserCellViewModel) -> Bool {
30 | return lhs.user == rhs.user
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | 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 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/SwiftHub/Extensions/UIImage/UIImage+SwiftHub.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+SwiftHub.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 |
12 | extension UIImage {
13 | func filled(withColor color: UIColor) -> UIImage {
14 | UIGraphicsBeginImageContextWithOptions(size, false, scale)
15 | color.setFill()
16 | guard let context = UIGraphicsGetCurrentContext() else { return self }
17 |
18 | context.translateBy(x: 0, y: size.height)
19 | context.scaleBy(x: 1.0, y: -1.0)
20 | context.setBlendMode(CGBlendMode.normal)
21 |
22 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
23 | guard let mask = cgImage else { return self }
24 | context.clip(to: rect, mask: mask)
25 | context.fill(rect)
26 |
27 | let newImage = UIGraphicsGetImageFromCurrentImageContext()!
28 | UIGraphicsEndImageContext()
29 | return newImage
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SwiftHub/Models/Contact.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Contact.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/15/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 | import Contacts
12 |
13 | struct Contact: Mappable {
14 |
15 | var id: String?
16 | var name: String?
17 | var phones: [String] = []
18 | var emails: [String] = []
19 |
20 | var imageData: Data?
21 |
22 | init?(map: Map) {}
23 | init() {}
24 |
25 | init(with contact: CNContact) {
26 | id = contact.identifier
27 | name = [contact.givenName, contact.familyName].joined(separator: " ")
28 | phones = contact.phoneNumbers.map { $0.value.stringValue }
29 | emails = contact.emailAddresses.map { $0.value as String }
30 | imageData = contact.thumbnailImageData
31 | }
32 |
33 | mutating func mapping(map: Map) {
34 | id <- map["id"]
35 | phones <- map["phones"]
36 | // emails <- map["emails"]
37 | name <- map["name"]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Contents/ContentCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/6/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class ContentCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let content: Content
16 |
17 | init(with content: Content) {
18 | self.content = content
19 | super.init()
20 | title.accept(content.name)
21 | detail.accept(content.type == .file ? content.size?.sizeFromByte() : nil)
22 | image.accept(content.type.image()?.template)
23 | }
24 | }
25 |
26 | extension ContentType {
27 | func image() -> UIImage? {
28 | switch self {
29 | case .file: return R.image.icon_cell_file()
30 | case .dir: return R.image.icon_cell_dir()
31 | case .submodule: return R.image.icon_cell_submodule()
32 | case .symlink: return R.image.icon_cell_submodule()
33 | case .unknown: return nil
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/SwiftHub/Common/ImageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageView.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ImageView: UIImageView {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | makeUI()
16 | }
17 |
18 | override init(image: UIImage?) {
19 | super.init(image: image)
20 | makeUI()
21 | }
22 |
23 | override init(image: UIImage?, highlightedImage: UIImage?) {
24 | super.init(image: image, highlightedImage: highlightedImage)
25 | makeUI()
26 | }
27 |
28 | required public init?(coder aDecoder: NSCoder) {
29 | super.init(coder: aDecoder)
30 | makeUI()
31 | }
32 |
33 | func makeUI() {
34 | tintColor = .primary()
35 | layer.masksToBounds = true
36 | contentMode = .center
37 |
38 | hero.modifiers = [.arc]
39 |
40 | updateUI()
41 | }
42 |
43 | func updateUI() {
44 | setNeedsDisplay()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Languages/LanguagesSection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LanguagesSection.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 12/18/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxDataSources
11 |
12 | enum LanguageSection {
13 | case languages(title: String, items: [LanguageSectionItem])
14 | }
15 |
16 | enum LanguageSectionItem {
17 | case languageItem(cellViewModel: RepoLanguageCellViewModel)
18 | }
19 |
20 | extension LanguageSection: SectionModelType {
21 | typealias Item = LanguageSectionItem
22 |
23 | var title: String {
24 | switch self {
25 | case .languages(let title, _): return title
26 | }
27 | }
28 |
29 | var items: [LanguageSectionItem] {
30 | switch self {
31 | case .languages(_, let items): return items.map {$0}
32 | }
33 | }
34 |
35 | init(original: LanguageSection, items: [Item]) {
36 | switch original {
37 | case .languages(let title, let items): self = .languages(title: title, items: items)
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Khoren Markosyan
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 |
--------------------------------------------------------------------------------
/SwiftHub/Common/TableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableView.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TableView: UITableView {
12 |
13 | init () {
14 | super.init(frame: CGRect(), style: .grouped)
15 | }
16 |
17 | override init(frame: CGRect, style: UITableView.Style) {
18 | super.init(frame: frame, style: style)
19 | makeUI()
20 | }
21 |
22 | required init?(coder aDecoder: NSCoder) {
23 | super.init(coder: aDecoder)
24 | makeUI()
25 | }
26 |
27 | func makeUI() {
28 | rowHeight = UITableView.automaticDimension
29 | estimatedRowHeight = 50
30 | sectionHeaderHeight = 40
31 | backgroundColor = .clear
32 | cellLayoutMarginsFollowReadableWidth = false
33 | keyboardDismissMode = .onDrag
34 | separatorColor = .clear
35 | separatorInset = UIEdgeInsets(top: 0, left: inset, bottom: 0, right: 0)
36 | tableHeaderView = View(height: 1)
37 | tableFooterView = UIView()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/SwiftHub/Common/SplitViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SplitViewController.swift
3 | // CakeBuilderBakery
4 | //
5 | // Created by Khoren Markosyan on 3/13/17.
6 | // Copyright © 2017 GAVR. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SplitViewController: UISplitViewController {
12 |
13 | override var preferredStatusBarStyle: UIStatusBarStyle {
14 | return globalStatusBarStyle.value
15 | }
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | // Do any additional setup after loading the view.
21 | delegate = self
22 | preferredDisplayMode = .allVisible
23 |
24 | globalStatusBarStyle.mapToVoid().subscribe(onNext: { [weak self] () in
25 | self?.setNeedsStatusBarAppearanceUpdate()
26 | }).disposed(by: rx.disposeBag)
27 | }
28 | }
29 |
30 | extension SplitViewController: UISplitViewControllerDelegate {
31 |
32 | func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
33 | return true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Notifications/NotificationCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationCellViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 9/19/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 |
13 | class NotificationCellViewModel: DefaultTableViewCellViewModel {
14 |
15 | let notification: Notification
16 |
17 | let userSelected = PublishSubject()
18 |
19 | init(with notification: Notification) {
20 | self.notification = notification
21 | super.init()
22 | let actionText = notification.subject?.title ?? ""
23 | let repoName = notification.repository?.fullname ?? ""
24 | title.accept([repoName, actionText].joined(separator: "\n"))
25 | detail.accept(notification.updatedAt?.toRelative(since: nil))
26 | imageUrl.accept(notification.repository?.owner?.avatarUrl)
27 | }
28 | }
29 |
30 | extension NotificationCellViewModel {
31 | static func == (lhs: NotificationCellViewModel, rhs: NotificationCellViewModel) -> Bool {
32 | return lhs.notification == rhs.notification
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SwiftHub/Extensions/UIFont/UIFont+SwiftHub.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIFont+SwiftHub.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 |
12 | // MARK: SwiftHub Fonts
13 |
14 | extension UIFont {
15 |
16 | static func navigationTitleFont() -> UIFont {
17 | return UIFont.systemFont(ofSize: 17.0)
18 | }
19 |
20 | static func titleFont() -> UIFont {
21 | return UIFont.systemFont(ofSize: 17.0)
22 | }
23 |
24 | static func descriptionFont() -> UIFont {
25 | return UIFont.systemFont(ofSize: 14.0)
26 | }
27 | }
28 |
29 | // MARK: All Fonts
30 |
31 | extension UIFont {
32 |
33 | static func allSystemFontsNames() -> [String] {
34 | var fontsNames = [String]()
35 | let fontFamilies = UIFont.familyNames
36 | for fontFamily in fontFamilies {
37 | let fontsForFamily = UIFont.fontNames(forFamilyName: fontFamily)
38 | for fontName in fontsForFamily {
39 | fontsNames.append(fontName)
40 | }
41 | }
42 | return fontsNames
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/ErrorResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ErrorResponse.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 1/28/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct ErrorResponse: Mappable {
13 | var message: String?
14 | var errors: [ErrorModel] = []
15 | var documentationUrl: String?
16 |
17 | init?(map: Map) {}
18 | init() {}
19 |
20 | mutating func mapping(map: Map) {
21 | message <- map["message"]
22 | errors <- map["errors"]
23 | documentationUrl <- map["documentation_url"]
24 | }
25 |
26 | func detail() -> String {
27 | return errors.map { $0.message ?? "" }
28 | .joined(separator: "\n")
29 | }
30 | }
31 |
32 | struct ErrorModel: Mappable {
33 | var code: String?
34 | var message: String?
35 | var field: String?
36 | var resource: String?
37 |
38 | init?(map: Map) {}
39 | init() {}
40 |
41 | mutating func mapping(map: Map) {
42 | code <- map["code"]
43 | message <- map["message"]
44 | field <- map["field"]
45 | resource <- map["resource"]
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/SwiftHub/Third Party/RxErrorTracker/ErrorTracker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by sergdort on 03/02/2017.
3 | // Copyright (c) 2017 sergdort. All rights reserved.
4 | //
5 |
6 | import Foundation
7 | import RxSwift
8 | import RxCocoa
9 |
10 | final class ErrorTracker: SharedSequenceConvertibleType {
11 | typealias SharingStrategy = DriverSharingStrategy
12 | private let _subject = PublishSubject()
13 |
14 | func trackError(from source: O) -> Observable {
15 | return source.asObservable().do(onError: onError)
16 | }
17 |
18 | func asSharedSequence() -> SharedSequence {
19 | return _subject.asObservable().asDriverOnErrorJustComplete()
20 | }
21 |
22 | func asObservable() -> Observable {
23 | return _subject.asObservable()
24 | }
25 |
26 | private func onError(_ error: Error) {
27 | _subject.onNext(error)
28 | }
29 |
30 | deinit {
31 | _subject.onCompleted()
32 | }
33 | }
34 |
35 | extension ObservableConvertibleType {
36 | func trackError(_ errorTracker: ErrorTracker) -> Observable {
37 | return errorTracker.trackError(from: self)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/Organization.json:
--------------------------------------------------------------------------------
1 | {
2 | "login": "realm",
3 | "id": 7575099,
4 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NzUwOTk=",
5 | "url": "https://api.github.com/orgs/realm",
6 | "repos_url": "https://api.github.com/orgs/realm/repos",
7 | "events_url": "https://api.github.com/orgs/realm/events",
8 | "hooks_url": "https://api.github.com/orgs/realm/hooks",
9 | "issues_url": "https://api.github.com/orgs/realm/issues",
10 | "members_url": "https://api.github.com/orgs/realm/members{/member}",
11 | "public_members_url": "https://api.github.com/orgs/realm/public_members{/member}",
12 | "avatar_url": "https://avatars0.githubusercontent.com/u/7575099?v=4",
13 | "description": "",
14 | "name": "Realm",
15 | "company": null,
16 | "blog": "https://realm.io",
17 | "location": null,
18 | "email": "help@realm.io",
19 | "has_organization_projects": true,
20 | "has_repository_projects": true,
21 | "public_repos": 61,
22 | "public_gists": 0,
23 | "followers": 0,
24 | "following": 0,
25 | "html_url": "https://github.com/realm",
26 | "created_at": "2014-05-13T23:55:11Z",
27 | "updated_at": "2017-09-14T10:00:21Z",
28 | "type": "Organization"
29 | }
30 |
--------------------------------------------------------------------------------
/SwiftHub/Managers/Reachability.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Reachability.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import Alamofire
12 |
13 | // An observable that completes when the app gets online (possibly completes immediately).
14 | func connectedToInternet() -> Observable {
15 | return ReachabilityManager.shared.reach
16 | }
17 |
18 | private class ReachabilityManager: NSObject {
19 |
20 | static let shared = ReachabilityManager()
21 |
22 | let reachSubject = ReplaySubject.create(bufferSize: 1)
23 | var reach: Observable {
24 | return reachSubject.asObservable()
25 | }
26 |
27 | override init() {
28 | super.init()
29 |
30 | NetworkReachabilityManager.default?.startListening(onUpdatePerforming: { (status) in
31 | switch status {
32 | case .notReachable:
33 | self.reachSubject.onNext(false)
34 | case .reachable:
35 | self.reachSubject.onNext(true)
36 | case .unknown:
37 | self.reachSubject.onNext(false)
38 | }
39 | })
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings/Cells/SettingSwitchCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingSwitchCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 7/23/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SettingSwitchCell: DefaultTableViewCell {
12 |
13 | lazy var switchView: Switch = {
14 | let view = Switch()
15 | return view
16 | }()
17 |
18 | override func makeUI() {
19 | super.makeUI()
20 | leftImageView.contentMode = .center
21 | leftImageView.layerCornerRadius = 0
22 | leftImageView.snp.updateConstraints { (make) in
23 | make.size.equalTo(30)
24 | }
25 | stackView.insertArrangedSubview(switchView, at: 2)
26 | leftImageView.theme.tintColor = themeService.attribute { $0.secondary }
27 | }
28 |
29 | override func bind(to viewModel: TableViewCellViewModel) {
30 | super.bind(to: viewModel)
31 | guard let viewModel = viewModel as? SettingSwitchCellViewModel else { return }
32 |
33 | viewModel.isEnabled.asDriver().drive(switchView.rx.isOn).disposed(by: rx.disposeBag)
34 | switchView.rx.isOn.bind(to: viewModel.switchChanged).disposed(by: rx.disposeBag)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Issue Details/IssueCommentsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IssueCommentsViewController.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/7/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 | import RxCocoa
12 | import MessageKit
13 |
14 | class IssueCommentsViewController: ChatViewController {
15 |
16 | var viewModel: IssueCommentsViewModel!
17 |
18 | override func bindViewModel() {
19 | super.bindViewModel()
20 |
21 | let refresh = Observable.of(Observable.just(()), themeService.typeStream.mapToVoid()).merge()
22 | let input = IssueCommentsViewModel.Input(headerRefresh: refresh,
23 | sendSelected: sendPressed)
24 | let output = viewModel.transform(input: input)
25 |
26 | output.items.subscribe(onNext: { [weak self] (comments) in
27 | self?.messages = comments
28 | }).disposed(by: rx.disposeBag)
29 |
30 | viewModel.error.asDriver().drive(onNext: { [weak self] (error) in
31 | self?.showAlert(title: R.string.localizable.commonError.key.localized(), message: error.localizedDescription)
32 | }).disposed(by: rx.disposeBag)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SwiftHub/Extensions/Foundation/Foundation+SwiftHub.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Foundation+SwiftHub.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/6/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Int {
12 |
13 | func sizeFromKB() -> String {
14 | return (self*1024).sizeFromByte()
15 | }
16 |
17 | func sizeFromByte() -> String {
18 | return ByteCountFormatter.string(fromByteCount: Int64(self), countStyle: .file)
19 | }
20 |
21 | func kFormatted() -> String {
22 | let sign = ((self < 0) ? "-" : "" )
23 | if self < 1000 {
24 | return "\(sign)\(self)"
25 | }
26 | let num = fabs(self.double)
27 | let exp: Int = Int(log10(num) / 3.0 )
28 | let units: [String] = ["K", "M", "G", "T", "P", "E"]
29 | let roundedNum: Double = round(10 * num / pow(1000.0, Double(exp))) / 10
30 | return "\(sign)\(roundedNum)\(units[exp-1])"
31 | }
32 | }
33 |
34 | extension StaticString {
35 |
36 | func localized() -> String {
37 | return description.localized()
38 | }
39 |
40 | func localizedFormat(_ arguments: CVarArg...) -> String {
41 | return description.localizedFormat(arguments)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Pull Request Details/PullRequestCommentsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PullRequestCommentsViewController.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/12/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 | import RxCocoa
12 | import MessageKit
13 |
14 | class PullRequestCommentsViewController: ChatViewController {
15 |
16 | var viewModel: PullRequestCommentsViewModel!
17 |
18 | override func bindViewModel() {
19 | super.bindViewModel()
20 |
21 | let refresh = Observable.of(Observable.just(()), themeService.typeStream.mapToVoid()).merge()
22 | let input = PullRequestCommentsViewModel.Input(headerRefresh: refresh,
23 | sendSelected: sendPressed)
24 | let output = viewModel.transform(input: input)
25 |
26 | output.items.subscribe(onNext: { [weak self] (comments) in
27 | self?.messages = comments
28 | }).disposed(by: rx.disposeBag)
29 |
30 | viewModel.error.asDriver().drive(onNext: { [weak self] (error) in
31 | self?.showAlert(title: R.string.localizable.commonError.key.localized(), message: error.localizedDescription)
32 | }).disposed(by: rx.disposeBag)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Repository Details/LanguageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LanguageView.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 7/26/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LanguageView: StackView {
12 |
13 | private lazy var titleLabel: UILabel = {
14 | let view = Label()
15 | view.font = view.font.withSize(12)
16 | view.textColor = UIColor.text()
17 | return view
18 | }()
19 |
20 | private lazy var colorView: UIView = {
21 | let view = UIView()
22 | view.layer.cornerRadius = 3
23 | view.layer.masksToBounds = true
24 | view.snp.makeConstraints({ (make) in
25 | make.size.equalTo(15)
26 | })
27 | return view
28 | }()
29 |
30 | init(language: RepoLanguage) {
31 | super.init(frame: .zero)
32 | axis = .horizontal
33 | spacing = 6
34 |
35 | addArrangedSubview(colorView)
36 | colorView.backgroundColor = UIColor(hexString: language.color ?? "") ?? .lightGray
37 |
38 | addArrangedSubview(titleLabel)
39 | titleLabel.text = language.name
40 | }
41 |
42 | required init(coder: NSCoder) {
43 | fatalError("init(coder:) has not been implemented")
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Postman/Github.postman_environment.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "e2cbd0cb-aa2a-4679-8ea7-490e45b00e51",
3 | "name": "Github",
4 | "values": [
5 | {
6 | "key": "graphql_base_url",
7 | "value": "https://api.github.com/graphql",
8 | "enabled": true
9 | },
10 | {
11 | "key": "base_url",
12 | "value": "https://api.github.com",
13 | "enabled": true
14 | },
15 | {
16 | "key": "trending_base_url",
17 | "value": "https://github-trending-api.now.sh",
18 | "enabled": true
19 | },
20 | {
21 | "key": "codetabs_base_url",
22 | "value": "https://api.codetabs.com/v1",
23 | "enabled": true
24 | },
25 | {
26 | "key": "org",
27 | "value": "apple",
28 | "enabled": true
29 | },
30 | {
31 | "key": "owner",
32 | "value": "khoren93",
33 | "enabled": true
34 | },
35 | {
36 | "key": "repo",
37 | "value": "SwiftHub",
38 | "enabled": true
39 | },
40 | {
41 | "key": "username",
42 | "value": "khoren93",
43 | "enabled": true
44 | },
45 | {
46 | "key": "per_page",
47 | "value": "10",
48 | "enabled": true
49 | },
50 | {
51 | "key": "access_token",
52 | "value": "",
53 | "enabled": true
54 | }
55 | ],
56 | "_postman_variable_scope": "environment",
57 | "_postman_exported_at": "2020-05-03T17:28:25.382Z",
58 | "_postman_exported_using": "Postman/7.23.0"
59 | }
--------------------------------------------------------------------------------
/SwiftHub/Common/Button.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Button.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class Button: UIButton {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | makeUI()
16 | }
17 |
18 | required public init?(coder aDecoder: NSCoder) {
19 | super.init(coder: aDecoder)
20 | makeUI()
21 | }
22 |
23 | func makeUI() {
24 | theme.backgroundImage(from: themeService.attribute { $0.secondary }, for: .normal)
25 | theme.backgroundImage(from: themeService.attribute { $0.secondary.withAlphaComponent(0.9) }, for: .selected)
26 | theme.backgroundImage(from: themeService.attribute { $0.secondary.withAlphaComponent(0.6) }, for: .disabled)
27 |
28 | layer.masksToBounds = true
29 | titleLabel?.lineBreakMode = .byWordWrapping
30 | layerCornerRadius = Configs.BaseDimensions.cornerRadius
31 | // font = font?.withSize(14)
32 |
33 | snp.makeConstraints { (make) in
34 | make.height.equalTo(Configs.BaseDimensions.buttonHeight)
35 | }
36 |
37 | updateUI()
38 | }
39 |
40 | func updateUI() {
41 | setNeedsDisplay()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/SwiftHub/Common/CollectionViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionViewController.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class CollectionViewController: ViewController {
12 |
13 | lazy var collectionView: CollectionView = {
14 | let view = CollectionView()
15 | view.emptyDataSetSource = self
16 | view.emptyDataSetDelegate = self
17 | return view
18 | }()
19 |
20 | var clearsSelectionOnViewWillAppear = true
21 |
22 | override func viewWillAppear(_ animated: Bool) {
23 | super.viewWillAppear(animated)
24 |
25 | if clearsSelectionOnViewWillAppear == true {
26 | deselectSelectedItems()
27 | }
28 | }
29 |
30 | override func makeUI() {
31 | super.makeUI()
32 |
33 | stackView.spacing = 0
34 | stackView.insertArrangedSubview(collectionView, at: 0)
35 | }
36 | }
37 |
38 | extension CollectionViewController {
39 |
40 | func deselectSelectedItems() {
41 | if let selectedIndexPaths = collectionView.indexPathsForSelectedItems {
42 | selectedIndexPaths.forEach({ (indexPath) in
43 | collectionView.deselectItem(at: indexPath, animated: false)
44 | })
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/SwiftHub/Common/TextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextField.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TextField: UITextField {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | makeUI()
16 | }
17 |
18 | required public init?(coder aDecoder: NSCoder) {
19 | super.init(coder: aDecoder)
20 | makeUI()
21 | }
22 |
23 | override var placeholder: String? {
24 | didSet {
25 | themeService.switch(themeService.type)
26 | }
27 | }
28 |
29 | func makeUI() {
30 | theme.textColor = themeService.attribute { $0.text }
31 | theme.tintColor = themeService.attribute { $0.secondary }
32 | theme.placeholderColor = themeService.attribute { $0.textGray }
33 | theme.borderColor = themeService.attribute { $0.text }
34 | theme.keyboardAppearance = themeService.attribute { $0.keyboardAppearance }
35 |
36 | layer.masksToBounds = true
37 | layerBorderWidth = Configs.BaseDimensions.borderWidth
38 | layerCornerRadius = Configs.BaseDimensions.cornerRadius
39 |
40 | snp.makeConstraints { (make) in
41 | make.height.equalTo(Configs.BaseDimensions.textFieldHeight)
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/SwiftHub/Extensions/UIColor/UIColor+SwiftHub.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+SwiftHub.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: Colors
12 |
13 | extension UIColor {
14 |
15 | static func primary() -> UIColor {
16 | return themeService.type.associatedObject.primary
17 | }
18 |
19 | static func primaryDark() -> UIColor {
20 | return themeService.type.associatedObject.primaryDark
21 | }
22 |
23 | static func secondary() -> UIColor {
24 | return themeService.type.associatedObject.secondary
25 | }
26 |
27 | static func secondaryDark() -> UIColor {
28 | return themeService.type.associatedObject.secondaryDark
29 | }
30 |
31 | static func separator() -> UIColor {
32 | return themeService.type.associatedObject.separator
33 | }
34 |
35 | static func text() -> UIColor {
36 | return themeService.type.associatedObject.text
37 | }
38 | }
39 |
40 | extension UIColor {
41 |
42 | var brightnessAdjustedColor: UIColor {
43 | var components = self.cgColor.components
44 | let alpha = components?.last
45 | components?.removeLast()
46 | let color = CGFloat(1-(components?.max())! >= 0.5 ? 1.0 : 0.0)
47 | return UIColor(red: color, green: color, blue: color, alpha: alpha!)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Theme/ThemeViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThemeViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 9/15/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxCocoa
11 | import RxSwift
12 | import RxDataSources
13 |
14 | class ThemeViewModel: ViewModel, ViewModelType {
15 |
16 | struct Input {
17 | let refresh: Observable
18 | let selection: Driver
19 | }
20 |
21 | struct Output {
22 | let items: Driver<[ThemeCellViewModel]>
23 | let selected: Driver
24 | }
25 |
26 | func transform(input: Input) -> Output {
27 |
28 | let elements = input.refresh
29 | .map { ColorTheme.allValues }
30 | .map { $0.map { ThemeCellViewModel(with: $0) } }
31 | .asDriver(onErrorJustReturn: [])
32 |
33 | let selected = input.selection
34 |
35 | selected.drive(onNext: { (cellViewModel) in
36 | let color = cellViewModel.theme
37 | let theme = ThemeType.currentTheme().withColor(color: color)
38 | themeService.switch(theme)
39 | analytics.log(.appTheme(color: color.title))
40 | analytics.set(.colorTheme(value: color.title))
41 | }).disposed(by: rx.disposeBag)
42 |
43 | return Output(items: elements,
44 | selected: selected)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/SwiftHub/Extensions/RxSwift/Observable+Logging.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Observable+Logging.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 |
12 | extension Observable {
13 | func logError(prefix: String = "Error: ") -> Observable {
14 | return self.do(onNext: nil,
15 | onError: { (error) in
16 | print("\(prefix)\(error)")
17 | },
18 | onCompleted: nil,
19 | onSubscribe: nil,
20 | onDispose: nil)
21 |
22 | }
23 |
24 | func logServerError(message: String) -> Observable {
25 | return self.do(onNext: nil,
26 | onError: { (error) in
27 | print("\(message)")
28 | print("Error: \(error.localizedDescription). \n")
29 | },
30 | onCompleted: nil,
31 | onSubscribe: nil,
32 | onDispose: nil)
33 | }
34 |
35 | func logNext() -> Observable {
36 | return self.do(onNext: { (element) in
37 | print("\(element)")
38 | },
39 | onError: nil,
40 | onCompleted: nil,
41 | onSubscribe: nil,
42 | onDispose: nil)
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/SwiftHub/Models/Comment.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Comment.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 11/22/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 | // Model file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
9 |
10 | import Foundation
11 | import ObjectMapper
12 | import MessageKit
13 |
14 | struct Comment: Mappable, MessageType {
15 |
16 | var authorAssociation: String?
17 | var body: String?
18 | var createdAt: Date?
19 | var htmlUrl: String?
20 | var id: Int?
21 | var issueUrl: String?
22 | var nodeId: String?
23 | var updatedAt: Date?
24 | var url: String?
25 | var user: User?
26 |
27 | // MessageType
28 | var sender: SenderType { return user ?? User() }
29 | var messageId: String { return id?.string ?? "" }
30 | var sentDate: Date { return createdAt ?? Date() }
31 | var kind: MessageKind { return .text(body ?? "") }
32 |
33 | init?(map: Map) {}
34 | init() {}
35 |
36 | mutating func mapping(map: Map) {
37 | authorAssociation <- map["author_association"]
38 | body <- map["body"]
39 | createdAt <- (map["created_at"], ISO8601DateTransform())
40 | htmlUrl <- map["html_url"]
41 | id <- map["id"]
42 | issueUrl <- map["issue_url"]
43 | nodeId <- map["node_id"]
44 | updatedAt <- (map["updated_at"], ISO8601DateTransform())
45 | url <- map["url"]
46 | user <- map["user"]
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/User.json:
--------------------------------------------------------------------------------
1 | {
2 | "login": "khoren93",
3 | "id": 11523360,
4 | "node_id": "MDQ6VXNlcjExNTIzMzYw",
5 | "avatar_url": "https://avatars2.githubusercontent.com/u/11523360?v=4",
6 | "gravatar_id": "",
7 | "url": "https://api.github.com/users/khoren93",
8 | "html_url": "https://github.com/khoren93",
9 | "followers_url": "https://api.github.com/users/khoren93/followers",
10 | "following_url": "https://api.github.com/users/khoren93/following{/other_user}",
11 | "gists_url": "https://api.github.com/users/khoren93/gists{/gist_id}",
12 | "starred_url": "https://api.github.com/users/khoren93/starred{/owner}{/repo}",
13 | "subscriptions_url": "https://api.github.com/users/khoren93/subscriptions",
14 | "organizations_url": "https://api.github.com/users/khoren93/orgs",
15 | "repos_url": "https://api.github.com/users/khoren93/repos",
16 | "events_url": "https://api.github.com/users/khoren93/events{/privacy}",
17 | "received_events_url": "https://api.github.com/users/khoren93/received_events",
18 | "type": "User",
19 | "site_admin": false,
20 | "name": "Khoren Markosyan",
21 | "company": null,
22 | "blog": "",
23 | "location": null,
24 | "email": null,
25 | "hireable": true,
26 | "bio": null,
27 | "public_repos": 17,
28 | "public_gists": 0,
29 | "followers": 11,
30 | "following": 29,
31 | "created_at": "2015-03-17T15:14:24Z",
32 | "updated_at": "2018-07-03T09:35:54Z"
33 | }
34 |
--------------------------------------------------------------------------------
/SwiftHub/Common/NavigationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationController.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class NavigationController: UINavigationController {
12 |
13 | override var preferredStatusBarStyle: UIStatusBarStyle {
14 | return globalStatusBarStyle.value
15 | }
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | // Do any additional setup after loading the view.
21 | interactivePopGestureRecognizer?.delegate = nil // Enable default iOS back swipe gesture
22 |
23 | if #available(iOS 13.0, *) {
24 | hero.isEnabled = false
25 | } else {
26 | hero.isEnabled = true
27 | }
28 | hero.modalAnimationType = .autoReverse(presenting: .fade)
29 | hero.navigationAnimationType = .autoReverse(presenting: .slide(direction: .left))
30 |
31 | // navigationBar.isTranslucent = false
32 | navigationBar.backIndicatorImage = R.image.icon_navigation_back()
33 | navigationBar.backIndicatorTransitionMaskImage = R.image.icon_navigation_back()
34 |
35 | navigationBar.theme.tintColor = themeService.attribute { $0.secondary }
36 | // navigationBar.theme.barTintColor = themeService.attribute { $0.primaryDark }
37 | navigationBar.theme.titleTextAttributes = themeService.attribute { [NSAttributedString.Key.foregroundColor: $0.text] }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/SwiftHub/Resources/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AD_UNIT_ID_FOR_BANNER_TEST
6 | ca-app-pub-3940256099942544/2934735716
7 | AD_UNIT_ID_FOR_INTERSTITIAL_TEST
8 | ca-app-pub-3940256099942544/4411468910
9 | CLIENT_ID
10 | 296465096839-b8qrqcd5ti9gdvpg8as3qgm8g5lj8nsi.apps.googleusercontent.com
11 | REVERSED_CLIENT_ID
12 | com.googleusercontent.apps.296465096839-b8qrqcd5ti9gdvpg8as3qgm8g5lj8nsi
13 | API_KEY
14 | AIzaSyAAMzsV1IL1Cr683cboMdv4ivILecmTBAw
15 | GCM_SENDER_ID
16 | 296465096839
17 | PLIST_VERSION
18 | 1
19 | BUNDLE_ID
20 | com.public.SwiftHub
21 | PROJECT_ID
22 | swifthub-39db2
23 | STORAGE_BUCKET
24 | swifthub-39db2.appspot.com
25 | IS_ADS_ENABLED
26 |
27 | IS_ANALYTICS_ENABLED
28 |
29 | IS_APPINVITE_ENABLED
30 |
31 | IS_GCM_ENABLED
32 |
33 | IS_SIGNIN_ENABLED
34 |
35 | GOOGLE_APP_ID
36 | 1:296465096839:ios:fee5cc7e47b530f1
37 | DATABASE_URL
38 | https://swifthub-39db2.firebaseio.com
39 |
40 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Users/UserCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 6/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class UserCell: DefaultTableViewCell {
12 |
13 | lazy var followButton: Button = {
14 | let view = Button()
15 | view.layerBorderColor = .white
16 | view.layerBorderWidth = Configs.BaseDimensions.borderWidth
17 | view.tintColor = .white
18 | view.layerCornerRadius = 17
19 | view.snp.remakeConstraints({ (make) in
20 | make.size.equalTo(34)
21 | })
22 | return view
23 | }()
24 |
25 | override func makeUI() {
26 | super.makeUI()
27 | stackView.insertArrangedSubview(followButton, at: 2)
28 | }
29 |
30 | override func bind(to viewModel: TableViewCellViewModel) {
31 | super.bind(to: viewModel)
32 | guard let viewModel = viewModel as? UserCellViewModel else { return }
33 |
34 | viewModel.hidesFollowButton.asDriver().drive(followButton.rx.isHidden).disposed(by: rx.disposeBag)
35 | viewModel.following.asDriver().map { (followed) -> UIImage? in
36 | let image = followed ? R.image.icon_button_user_x() : R.image.icon_button_user_plus()
37 | return image?.template
38 | }.drive(followButton.rx.image()).disposed(by: rx.disposeBag)
39 | viewModel.following.map { $0 ? 1.0: 0.6 }.asDriver(onErrorJustReturn: 0).drive(followButton.rx.alpha).disposed(by: rx.disposeBag)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Repositories/RepositoryCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepositoryCell.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 6/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class RepositoryCell: DefaultTableViewCell {
12 |
13 | lazy var starButton: Button = {
14 | let view = Button()
15 | view.layerBorderColor = .white
16 | view.layerBorderWidth = Configs.BaseDimensions.borderWidth
17 | view.tintColor = .white
18 | view.layerCornerRadius = 17
19 | view.snp.remakeConstraints({ (make) in
20 | make.size.equalTo(34)
21 | })
22 | return view
23 | }()
24 |
25 | override func makeUI() {
26 | super.makeUI()
27 | stackView.insertArrangedSubview(starButton, at: 2)
28 | }
29 |
30 | override func bind(to viewModel: TableViewCellViewModel) {
31 | super.bind(to: viewModel)
32 | guard let viewModel = viewModel as? RepositoryCellViewModel else { return }
33 |
34 | viewModel.hidesStarButton.asDriver().drive(starButton.rx.isHidden).disposed(by: rx.disposeBag)
35 | viewModel.starring.asDriver().map { (starred) -> UIImage? in
36 | let image = starred ? R.image.icon_button_unstar() : R.image.icon_button_star()
37 | return image?.template
38 | }.drive(starButton.rx.image()).disposed(by: rx.disposeBag)
39 | viewModel.starring.map { $0 ? 1.0: 0.6 }.asDriver(onErrorJustReturn: 0).drive(starButton.rx.alpha).disposed(by: rx.disposeBag)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Search/SearchSection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SearchSection.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 6/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxDataSources
11 |
12 | enum SearchSection {
13 | case repositories(title: String, items: [SearchSectionItem])
14 | case users(title: String, items: [SearchSectionItem])
15 | }
16 |
17 | enum SearchSectionItem {
18 | case trendingRepositoriesItem(cellViewModel: TrendingRepositoryCellViewModel)
19 | case trendingUsersItem(cellViewModel: TrendingUserCellViewModel)
20 | case repositoriesItem(cellViewModel: RepositoryCellViewModel)
21 | case usersItem(cellViewModel: UserCellViewModel)
22 | }
23 |
24 | extension SearchSection: SectionModelType {
25 | typealias Item = SearchSectionItem
26 |
27 | var title: String {
28 | switch self {
29 | case .repositories(let title, _): return title
30 | case .users(let title, _): return title
31 | }
32 | }
33 |
34 | var items: [SearchSectionItem] {
35 | switch self {
36 | case .repositories(_, let items): return items.map {$0}
37 | case .users(_, let items): return items.map {$0}
38 | }
39 | }
40 |
41 | init(original: SearchSection, items: [Item]) {
42 | switch original {
43 | case .repositories(let title, let items): self = .repositories(title: title, items: items)
44 | case .users(let title, let items): self = .users(title: title, items: items)
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Theme/ThemeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThemeViewController.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 9/15/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 | import RxCocoa
12 |
13 | private let reuseIdentifier = R.reuseIdentifier.themeCell.identifier
14 |
15 | class ThemeViewController: TableViewController {
16 |
17 | override func makeUI() {
18 | super.makeUI()
19 |
20 | navigationTitle = R.string.localizable.themeNavigationTitle.key.localized()
21 | tableView.register(R.nib.themeCell)
22 | tableView.headRefreshControl = nil
23 | tableView.footRefreshControl = nil
24 | }
25 |
26 | override func bindViewModel() {
27 | super.bindViewModel()
28 | guard let viewModel = viewModel as? ThemeViewModel else { return }
29 |
30 | let input = ThemeViewModel.Input(refresh: Observable.just(()),
31 | selection: tableView.rx.modelSelected(ThemeCellViewModel.self).asDriver())
32 | let output = viewModel.transform(input: input)
33 |
34 | output.items
35 | .drive(tableView.rx.items(cellIdentifier: reuseIdentifier, cellType: ThemeCell.self)) { tableView, viewModel, cell in
36 | cell.bind(to: viewModel)
37 | }.disposed(by: rx.disposeBag)
38 |
39 | output.selected.drive(onNext: { [weak self] (cellViewModel) in
40 | self?.navigator.dismiss(sender: self)
41 | }).disposed(by: rx.disposeBag)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/SwiftHub/Common/CollectionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionView.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class CollectionView: UICollectionView {
12 |
13 | init() {
14 | super.init(frame: CGRect(), collectionViewLayout: UICollectionViewFlowLayout())
15 | makeUI()
16 | }
17 |
18 | override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
19 | super.init(frame: frame, collectionViewLayout: layout)
20 | makeUI()
21 | }
22 |
23 | required init?(coder aDecoder: NSCoder) {
24 | super.init(coder: aDecoder)
25 | makeUI()
26 | }
27 |
28 | func makeUI() {
29 | self.layer.masksToBounds = true
30 | self.backgroundColor = .clear
31 | updateUI()
32 | }
33 |
34 | func updateUI() {
35 | setNeedsDisplay()
36 | }
37 |
38 | func itemWidth(forItemsPerRow itemsPerRow: Int, withInset inset: CGFloat = 0) -> CGFloat {
39 | let collectionWidth = Int(frame.size.width)
40 | if collectionWidth == 0 {
41 | return 0
42 | }
43 | return CGFloat(Int((collectionWidth - (itemsPerRow + 1) * Int(inset)) / itemsPerRow))
44 | }
45 |
46 | func setItemSize(_ size: CGSize) {
47 | if size.width == 0 || size.height == 0 {
48 | return
49 | }
50 | let layout = (self.collectionViewLayout as? UICollectionViewFlowLayout)!
51 | layout.itemSize = size
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/SwiftHub/Common/View.swift:
--------------------------------------------------------------------------------
1 | //
2 | // View.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class View: UIView {
12 |
13 | convenience init(width: CGFloat) {
14 | self.init(frame: CGRect(x: 0, y: 0, width: width, height: 0))
15 | snp.makeConstraints { (make) in
16 | make.width.equalTo(width)
17 | }
18 | }
19 |
20 | convenience init(height: CGFloat) {
21 | self.init(frame: CGRect(x: 0, y: 0, width: 0, height: height))
22 | snp.makeConstraints { (make) in
23 | make.height.equalTo(height)
24 | }
25 | }
26 |
27 | override init(frame: CGRect) {
28 | super.init(frame: frame)
29 | makeUI()
30 | }
31 |
32 | required public init?(coder aDecoder: NSCoder) {
33 | super.init(coder: aDecoder)
34 | makeUI()
35 | }
36 |
37 | func makeUI() {
38 | self.layer.masksToBounds = true
39 | updateUI()
40 | }
41 |
42 | func updateUI() {
43 | setNeedsDisplay()
44 | }
45 |
46 | func getCenter() -> CGPoint {
47 | return convert(center, from: superview)
48 | }
49 | }
50 |
51 | extension UIView {
52 |
53 | var inset: CGFloat {
54 | return Configs.BaseDimensions.inset
55 | }
56 |
57 | open func setPriority(_ priority: UILayoutPriority, for axis: NSLayoutConstraint.Axis) {
58 | self.setContentHuggingPriority(priority, for: axis)
59 | self.setContentCompressionResistancePriority(priority, for: axis)
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Lines Count/LinesCountViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LinesCountViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 4/16/20.
6 | // Copyright © 2020 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxCocoa
11 | import RxSwift
12 |
13 | class LinesCountViewModel: ViewModel, ViewModelType {
14 |
15 | struct Input {
16 | let refresh: Observable
17 | }
18 |
19 | struct Output {
20 | let items: Driver<[LanguageLines]>
21 | }
22 |
23 | let repository: BehaviorRelay
24 |
25 | init(repository: Repository, provider: SwiftHubAPI) {
26 | self.repository = BehaviorRelay(value: repository)
27 | super.init(provider: provider)
28 | if let fullname = repository.fullname {
29 | analytics.log(.linesCount(fullname: fullname))
30 | }
31 | }
32 |
33 | func transform(input: Input) -> Output {
34 |
35 | let elements = input.refresh.flatMapLatest { () -> Observable<[LanguageLines]> in
36 | let fullname = self.repository.value.fullname ?? ""
37 | return self.provider.numberOfLines(fullname: fullname)
38 | .trackActivity(self.loading)
39 | .trackError(self.error)
40 | }.asDriver(onErrorJustReturn: [])
41 |
42 | return Output(items: elements)
43 | }
44 |
45 | func color(for language: String) -> String? {
46 | guard let language = repository.value.languages?.languages.filter({ $0.name == language }).first else {
47 | return nil
48 | }
49 | return language.color
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Issue Details/IssueCommentsViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IssueCommentsViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/7/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxCocoa
11 | import RxSwift
12 | import MessageKit
13 |
14 | class IssueCommentsViewModel: ViewModel, ViewModelType {
15 |
16 | struct Input {
17 | let headerRefresh: Observable
18 | let sendSelected: Observable
19 | }
20 |
21 | struct Output {
22 | let items: Observable<[Comment]>
23 | }
24 |
25 | let repository: BehaviorRelay
26 | let issue: BehaviorRelay
27 |
28 | init(repository: Repository, issue: Issue, provider: SwiftHubAPI) {
29 | self.repository = BehaviorRelay(value: repository)
30 | self.issue = BehaviorRelay(value: issue)
31 | super.init(provider: provider)
32 | }
33 |
34 | func transform(input: Input) -> Output {
35 |
36 | let comments = input.headerRefresh.flatMapLatest { () -> Observable<[Comment]> in
37 | let fullname = self.repository.value.fullname ?? ""
38 | let issueNumber = self.issue.value.number ?? 0
39 | return self.provider.issueComments(fullname: fullname, number: issueNumber, page: self.page)
40 | .trackActivity(self.loading)
41 | .trackError(self.error)
42 | }
43 |
44 | input.sendSelected.subscribe(onNext: { (text) in
45 | logDebug(text)
46 | }).disposed(by: rx.disposeBag)
47 |
48 | return Output(items: comments)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/GraphQL/Queries/Search.graphql:
--------------------------------------------------------------------------------
1 | query SearchRepositories($query: String!, $before: String) {
2 | search(first: 20, query: $query, type: REPOSITORY, before: $before) {
3 | repositoryCount
4 | pageInfo {
5 | endCursor
6 | hasNextPage
7 | }
8 | nodes {
9 | ... on Repository {
10 | name
11 | nameWithOwner
12 | description
13 | owner {
14 | avatarUrl
15 | ... on Organization {
16 | description
17 | }
18 | }
19 | updatedAt
20 | viewerHasStarred
21 | primaryLanguage {
22 | name
23 | color
24 | }
25 | stargazers {
26 | totalCount
27 | }
28 | }
29 | }
30 | }
31 | }
32 |
33 | query SearchUsers($query: String!, $before: String) {
34 | search(first: 20, query: $query, type: USER, before: $before) {
35 | nodes {
36 | ... on User {
37 | name
38 | login
39 | avatarUrl
40 | viewerCanFollow
41 | viewerIsFollowing
42 | followers {
43 | totalCount
44 | }
45 | repositories {
46 | totalCount
47 | }
48 | }
49 | }
50 | pageInfo {
51 | endCursor
52 | hasNextPage
53 | }
54 | userCount
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/User Details/UserSection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserSection.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 10/13/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxDataSources
11 |
12 | enum UserSection {
13 | case user(title: String, items: [UserSectionItem])
14 | }
15 |
16 | enum UserSectionItem {
17 | case contributionsItem(viewModel: ContributionsCellViewModel)
18 | case createdItem(viewModel: UserDetailCellViewModel)
19 | case updatedItem(viewModel: UserDetailCellViewModel)
20 | case starsItem(viewModel: UserDetailCellViewModel)
21 | case watchingItem(viewModel: UserDetailCellViewModel)
22 | case eventsItem(viewModel: UserDetailCellViewModel)
23 | case companyItem(viewModel: UserDetailCellViewModel)
24 | case blogItem(viewModel: UserDetailCellViewModel)
25 | case profileSummaryItem(viewModel: UserDetailCellViewModel)
26 |
27 | case repositoryItem(viewModel: RepositoryCellViewModel)
28 | case organizationItem(viewModel: UserCellViewModel)
29 | }
30 |
31 | extension UserSection: SectionModelType {
32 | typealias Item = UserSectionItem
33 |
34 | var title: String {
35 | switch self {
36 | case .user(let title, _): return title
37 | }
38 | }
39 |
40 | var items: [UserSectionItem] {
41 | switch self {
42 | case .user(_, let items): return items.map {$0}
43 | }
44 | }
45 |
46 | init(original: UserSection, items: [Item]) {
47 | switch original {
48 | case .user(let title, let items): self = .user(title: title, items: items)
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/SwiftHub/Models/Milestone.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Milestone.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 11/20/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 | // Model file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
9 |
10 | import Foundation
11 | import ObjectMapper
12 |
13 | struct Milestone: Mappable {
14 |
15 | var closedAt: Date?
16 | var closedIssues: Int?
17 | var createdAt: Date?
18 | var creator: User?
19 | var descriptionField: String?
20 | var dueOn: Date?
21 | var htmlUrl: String?
22 | var id: Int?
23 | var labelsUrl: String?
24 | var nodeId: String?
25 | var number: Int?
26 | var openIssues: Int?
27 | var state: State = .open
28 | var title: String?
29 | var updatedAt: Date?
30 | var url: String?
31 |
32 | init?(map: Map) {}
33 | init() {}
34 |
35 | mutating func mapping(map: Map) {
36 | closedAt <- (map["closed_at"], ISO8601DateTransform())
37 | closedIssues <- map["closed_issues"]
38 | createdAt <- (map["created_at"], ISO8601DateTransform())
39 | creator <- map["creator"]
40 | descriptionField <- map["description"]
41 | dueOn <- (map["due_on"], ISO8601DateTransform())
42 | htmlUrl <- map["html_url"]
43 | id <- map["id"]
44 | labelsUrl <- map["labels_url"]
45 | nodeId <- map["node_id"]
46 | number <- map["number"]
47 | openIssues <- map["open_issues"]
48 | state <- map["state"]
49 | title <- map["title"]
50 | updatedAt <- (map["updated_at"], ISO8601DateTransform())
51 | url <- map["url"]
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Pull Request Details/PullRequestCommentsViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PullRequestCommentsViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/12/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxCocoa
11 | import RxSwift
12 | import MessageKit
13 |
14 | class PullRequestCommentsViewModel: ViewModel, ViewModelType {
15 |
16 | struct Input {
17 | let headerRefresh: Observable
18 | let sendSelected: Observable
19 | }
20 |
21 | struct Output {
22 | let items: Observable<[Comment]>
23 | }
24 |
25 | let repository: BehaviorRelay
26 | let pullRequest: BehaviorRelay
27 |
28 | init(repository: Repository, pullRequest: PullRequest, provider: SwiftHubAPI) {
29 | self.repository = BehaviorRelay(value: repository)
30 | self.pullRequest = BehaviorRelay(value: pullRequest)
31 | super.init(provider: provider)
32 | }
33 |
34 | func transform(input: Input) -> Output {
35 |
36 | let comments = input.headerRefresh.flatMapLatest { () -> Observable<[Comment]> in
37 | let fullname = self.repository.value.fullname ?? ""
38 | let issueNumber = self.pullRequest.value.number ?? 0
39 | return self.provider.issueComments(fullname: fullname, number: issueNumber, page: self.page)
40 | .trackActivity(self.loading)
41 | .trackError(self.error)
42 | }
43 |
44 | input.sendSelected.subscribe(onNext: { (text) in
45 | logDebug(text)
46 | }).disposed(by: rx.disposeBag)
47 |
48 | return Output(items: comments)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/SwiftHub/Managers/AuthManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthManager.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 9/1/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import KeychainAccess
11 | import ObjectMapper
12 | import RxSwift
13 | import RxCocoa
14 |
15 | let loggedIn = BehaviorRelay(value: false)
16 |
17 | class AuthManager {
18 |
19 | /// The default singleton instance.
20 | static let shared = AuthManager()
21 |
22 | // MARK: - Properties
23 | fileprivate let tokenKey = "TokenKey"
24 | fileprivate let keychain = Keychain(service: Configs.App.bundleIdentifier)
25 |
26 | let tokenChanged = PublishSubject()
27 |
28 | init() {
29 | loggedIn.accept(hasValidToken)
30 | }
31 |
32 | var token: Token? {
33 | get {
34 | guard let jsonString = keychain[tokenKey] else { return nil }
35 | return Mapper().map(JSONString: jsonString)
36 | }
37 | set {
38 | if let token = newValue, let jsonString = token.toJSONString() {
39 | keychain[tokenKey] = jsonString
40 | } else {
41 | keychain[tokenKey] = nil
42 | }
43 | tokenChanged.onNext(newValue)
44 | loggedIn.accept(hasValidToken)
45 | }
46 | }
47 |
48 | var hasValidToken: Bool {
49 | return token?.isValid == true
50 | }
51 |
52 | class func setToken(token: Token) {
53 | AuthManager.shared.token = token
54 | }
55 |
56 | class func removeToken() {
57 | AuthManager.shared.token = nil
58 | }
59 |
60 | class func tokenValidated() {
61 | AuthManager.shared.token?.isValid = true
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/SwiftHub/Models/Notification.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Notification.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 9/19/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 | // Model file Generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
9 |
10 | import Foundation
11 | import ObjectMapper
12 |
13 | struct Notification: Mappable {
14 |
15 | var id: String?
16 | var lastReadAt: Date?
17 | var reason: String?
18 | var repository: Repository?
19 | var subject: Subject?
20 | var subscriptionUrl: String?
21 | var unread: Bool?
22 | var updatedAt: Date?
23 | var url: String?
24 |
25 | init?(map: Map) {}
26 | init() {}
27 |
28 | mutating func mapping(map: Map) {
29 | id <- map["id"]
30 | lastReadAt <- (map["last_read_at"], ISO8601DateTransform())
31 | reason <- map["reason"]
32 | repository <- map["repository"]
33 | subject <- map["subject"]
34 | subscriptionUrl <- map["subscription_url"]
35 | unread <- map["unread"]
36 | updatedAt <- (map["updated_at"], ISO8601DateTransform())
37 | url <- map["url"]
38 | }
39 | }
40 |
41 | extension Notification: Equatable {
42 | static func == (lhs: Notification, rhs: Notification) -> Bool {
43 | return lhs.id == rhs.id
44 | }
45 | }
46 |
47 | struct Subject: Mappable {
48 |
49 | var latestCommentUrl: String?
50 | var title: String?
51 | var type: String?
52 | var url: String?
53 |
54 | init?(map: Map) {}
55 | init() {}
56 |
57 | mutating func mapping(map: Map) {
58 | latestCommentUrl <- map["latest_comment_url"]
59 | title <- map["title"]
60 | type <- map["type"]
61 | url <- map["url"]
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Issue Details/IssueViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IssueViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/5/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxCocoa
11 | import RxSwift
12 | import MessageKit
13 |
14 | class IssueViewModel: ViewModel, ViewModelType {
15 |
16 | struct Input {
17 | let headerRefresh: Observable
18 | let userSelected: Observable
19 | let mentionSelected: Observable
20 | }
21 |
22 | struct Output {
23 | let userSelected: Observable
24 | }
25 |
26 | let repository: BehaviorRelay
27 | let issue: BehaviorRelay
28 |
29 | init(repository: Repository, issue: Issue, provider: SwiftHubAPI) {
30 | self.repository = BehaviorRelay(value: repository)
31 | self.issue = BehaviorRelay(value: issue)
32 | super.init(provider: provider)
33 | }
34 |
35 | func transform(input: Input) -> Output {
36 | let userSelected = Observable.of(input.userSelected, input.mentionSelected.map({ (mention) -> User in
37 | var user = User()
38 | user.login = mention.removingPrefix("@")
39 | return user
40 | }) ).merge()
41 | .map { (user) -> UserViewModel in
42 | let viewModel = UserViewModel(user: user, provider: self.provider)
43 | return viewModel
44 | }
45 |
46 | return Output(userSelected: userSelected)
47 | }
48 |
49 | func issueCommentsViewModel() -> IssueCommentsViewModel {
50 | let viewModel = IssueCommentsViewModel(repository: repository.value, issue: issue.value, provider: provider)
51 | return viewModel
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Branches/BranchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BranchesViewController.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 4/6/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 | import RxCocoa
12 | import RxDataSources
13 |
14 | private let reuseIdentifier = R.reuseIdentifier.branchCell.identifier
15 |
16 | class BranchesViewController: TableViewController {
17 |
18 | override func makeUI() {
19 | super.makeUI()
20 |
21 | tableView.register(R.nib.branchCell)
22 | }
23 |
24 | override func bindViewModel() {
25 | super.bindViewModel()
26 | guard let viewModel = viewModel as? BranchesViewModel else { return }
27 |
28 | let refresh = Observable.of(Observable.just(()), headerRefreshTrigger).merge()
29 | let input = BranchesViewModel.Input(headerRefresh: refresh,
30 | footerRefresh: footerRefreshTrigger,
31 | selection: tableView.rx.modelSelected(BranchCellViewModel.self).asDriver())
32 | let output = viewModel.transform(input: input)
33 |
34 | output.navigationTitle.drive(onNext: { [weak self] (title) in
35 | self?.navigationTitle = title
36 | }).disposed(by: rx.disposeBag)
37 |
38 | output.items.asDriver(onErrorJustReturn: [])
39 | .drive(tableView.rx.items(cellIdentifier: reuseIdentifier, cellType: BranchCell.self)) { tableView, viewModel, cell in
40 | cell.bind(to: viewModel)
41 | }.disposed(by: rx.disposeBag)
42 |
43 | viewModel.branchSelected.subscribe(onNext: { [weak self] (branch) in
44 | self?.navigator.pop(sender: self)
45 | }).disposed(by: rx.disposeBag)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/SwiftHub/Common/ViewModelType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewModelType.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 6/30/18.
6 | // Copyright © 2018 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 | import RxCocoa
12 | import ObjectMapper
13 |
14 | protocol ViewModelType {
15 | associatedtype Input
16 | associatedtype Output
17 |
18 | func transform(input: Input) -> Output
19 | }
20 |
21 | class ViewModel: NSObject {
22 |
23 | let provider: SwiftHubAPI
24 |
25 | var page = 1
26 |
27 | let loading = ActivityIndicator()
28 | let headerLoading = ActivityIndicator()
29 | let footerLoading = ActivityIndicator()
30 |
31 | let error = ErrorTracker()
32 | let serverError = PublishSubject()
33 | let parsedError = PublishSubject()
34 |
35 | init(provider: SwiftHubAPI) {
36 | self.provider = provider
37 | super.init()
38 |
39 | serverError.asObservable().map { (error) -> ApiError? in
40 | do {
41 | let errorResponse = error as? MoyaError
42 | if let body = try errorResponse?.response?.mapJSON() as? [String: Any],
43 | let errorResponse = Mapper().map(JSON: body) {
44 | return ApiError.serverError(response: errorResponse)
45 | }
46 | } catch {
47 | print(error)
48 | }
49 | return nil
50 | }.filterNil().bind(to: parsedError).disposed(by: rx.disposeBag)
51 |
52 | parsedError.subscribe(onNext: { (error) in
53 | logError("\(error)")
54 | }).disposed(by: rx.disposeBag)
55 | }
56 |
57 | deinit {
58 | logDebug("\(type(of: self)): Deinited")
59 | logResourcesCount()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/SwiftHub/Networking/Rest/Stubbed Responses/Profile.json:
--------------------------------------------------------------------------------
1 | {
2 | "login": "khoren93",
3 | "id": 11523360,
4 | "node_id": "MDQ6VXNlcjExNTIzMzYw",
5 | "avatar_url": "https://avatars2.githubusercontent.com/u/11523360?v=4",
6 | "gravatar_id": "",
7 | "url": "https://api.github.com/users/khoren93",
8 | "html_url": "https://github.com/khoren93",
9 | "followers_url": "https://api.github.com/users/khoren93/followers",
10 | "following_url": "https://api.github.com/users/khoren93/following{/other_user}",
11 | "gists_url": "https://api.github.com/users/khoren93/gists{/gist_id}",
12 | "starred_url": "https://api.github.com/users/khoren93/starred{/owner}{/repo}",
13 | "subscriptions_url": "https://api.github.com/users/khoren93/subscriptions",
14 | "organizations_url": "https://api.github.com/users/khoren93/orgs",
15 | "repos_url": "https://api.github.com/users/khoren93/repos",
16 | "events_url": "https://api.github.com/users/khoren93/events{/privacy}",
17 | "received_events_url": "https://api.github.com/users/khoren93/received_events",
18 | "type": "User",
19 | "site_admin": false,
20 | "name": "Khoren Markosyan",
21 | "company": null,
22 | "blog": "",
23 | "location": null,
24 | "email": null,
25 | "hireable": true,
26 | "bio": null,
27 | "public_repos": 18,
28 | "public_gists": 0,
29 | "followers": 11,
30 | "following": 30,
31 | "created_at": "2015-03-17T15:14:24Z",
32 | "updated_at": "2018-08-28T14:35:59Z",
33 | "private_gists": 0,
34 | "total_private_repos": 0,
35 | "owned_private_repos": 0,
36 | "disk_usage": 1018,
37 | "collaborators": 0,
38 | "two_factor_authentication": false,
39 | "plan": {
40 | "name": "free",
41 | "space": 976562499,
42 | "collaborators": 0,
43 | "private_repos": 0
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Users/UserCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Events/EventCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Pull Request Details/PullRequestViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PullRequestViewModel.swift
3 | // SwiftHub
4 | //
5 | // Created by Sygnoos9 on 5/12/19.
6 | // Copyright © 2019 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxCocoa
11 | import RxSwift
12 | import MessageKit
13 |
14 | class PullRequestViewModel: ViewModel, ViewModelType {
15 |
16 | struct Input {
17 | let headerRefresh: Observable
18 | let userSelected: Observable
19 | let mentionSelected: Observable
20 | }
21 |
22 | struct Output {
23 | let userSelected: Observable
24 | }
25 |
26 | let repository: BehaviorRelay
27 | let pullRequest: BehaviorRelay
28 |
29 | init(repository: Repository, pullRequest: PullRequest, provider: SwiftHubAPI) {
30 | self.repository = BehaviorRelay(value: repository)
31 | self.pullRequest = BehaviorRelay(value: pullRequest)
32 | super.init(provider: provider)
33 | }
34 |
35 | func transform(input: Input) -> Output {
36 | let userSelected = Observable.of(input.userSelected, input.mentionSelected.map({ (mention) -> User in
37 | var user = User()
38 | user.login = mention.removingPrefix("@")
39 | return user
40 | }) ).merge()
41 | .map { (user) -> UserViewModel in
42 | let viewModel = UserViewModel(user: user, provider: self.provider)
43 | return viewModel
44 | }
45 |
46 | return Output(userSelected: userSelected)
47 | }
48 |
49 | func pullRequestCommentsViewModel() -> PullRequestCommentsViewModel {
50 | let viewModel = PullRequestCommentsViewModel(repository: repository.value, pullRequest: pullRequest.value, provider: provider)
51 | return viewModel
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Theme/ThemeCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Branches/BranchCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Commits/CommitCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Contacts/ContactCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Contents/ContentCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Releases/ReleaseCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings/Cells/SettingCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Extensions/UIView/UIView+SwiftHub.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+SwiftHub.swift
3 | // SwiftHub
4 | //
5 | // Created by Khoren Markosyan on 1/4/17.
6 | // Copyright © 2017 Khoren Markosyan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 |
12 | extension UIView {
13 |
14 | func makeRoundedCorners(_ radius: CGFloat) {
15 | layer.cornerRadius = radius
16 | layer.masksToBounds = true
17 | }
18 |
19 | func makeRoundedCorners() {
20 | makeRoundedCorners(bounds.size.width / 2)
21 | }
22 |
23 | func renderAsImage() -> UIImage? {
24 | var image: UIImage?
25 | if #available(iOS 10.0, *) {
26 | let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
27 | image = renderer.image { ctx in
28 | self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
29 | }
30 | } else {
31 | // Fallback on earlier versions
32 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0)
33 | self.layer.render(in: UIGraphicsGetCurrentContext()!)
34 | image = UIGraphicsGetImageFromCurrentImageContext()
35 | UIGraphicsEndImageContext()
36 | }
37 | return image
38 | }
39 |
40 | func blur(style: UIBlurEffect.Style) {
41 | unBlur()
42 | let blurEffect = UIBlurEffect(style: style)
43 | let blurEffectView = UIVisualEffectView(effect: blurEffect)
44 | insertSubview(blurEffectView, at: 0)
45 | blurEffectView.snp.makeConstraints({ (make) in
46 | make.edges.equalToSuperview()
47 | })
48 | }
49 |
50 | func unBlur() {
51 | subviews.filter { (view) -> Bool in
52 | view as? UIVisualEffectView != nil
53 | }.forEach { (view) in
54 | view.removeFromSuperview()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Repositories/RepositoryCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Settings Language/LanguageCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SwiftHub/Modules/Search/TrendingUserCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------