├── 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 | --------------------------------------------------------------------------------