├── .vscode
├── settings.json
└── launch.json
├── screenshot
├── Feeds.png
├── Home.png
├── Repo.png
├── Stars.png
├── User.png
├── Pamphlet.png
├── RepoDir.png
├── RssAtom.png
├── RssFeeds.png
├── UserInfo.png
├── appstyle.png
├── EditIssue.png
├── IssueDetail.png
├── RepoBranch.png
├── RepoIssues.png
├── IssueComments.png
├── SearchHistory.png
├── SearchResults.png
├── UserInteract.png
├── LocalDeveloper.png
├── PamphletResource.png
├── RepoBranchCreate.png
├── GithubTrendingRepo.png
└── GithubTrendingDeveloper.png
├── DJGithub
├── Assets.xcassets
│ ├── Contents.json
│ ├── Pixel
│ │ ├── Contents.json
│ │ ├── p1.imageset
│ │ │ ├── p1-1.png
│ │ │ ├── p1.png
│ │ │ └── Contents.json
│ │ ├── p10.imageset
│ │ │ ├── p10.png
│ │ │ ├── p10-1.png
│ │ │ └── Contents.json
│ │ ├── p11.imageset
│ │ │ ├── p11.png
│ │ │ ├── p11-1.png
│ │ │ └── Contents.json
│ │ ├── p12.imageset
│ │ │ ├── p12.png
│ │ │ ├── p12-1.png
│ │ │ └── Contents.json
│ │ ├── p13.imageset
│ │ │ ├── p13.png
│ │ │ ├── p13-1.png
│ │ │ └── Contents.json
│ │ ├── p14.imageset
│ │ │ ├── p14.png
│ │ │ ├── p14-1.png
│ │ │ └── Contents.json
│ │ ├── p15.imageset
│ │ │ ├── p15.png
│ │ │ ├── p15-1.png
│ │ │ └── Contents.json
│ │ ├── p16.imageset
│ │ │ ├── p16.png
│ │ │ ├── p16-1.png
│ │ │ └── Contents.json
│ │ ├── p17.imageset
│ │ │ ├── p17.png
│ │ │ ├── p17-1.png
│ │ │ └── Contents.json
│ │ ├── p18.imageset
│ │ │ ├── p18.png
│ │ │ ├── p18-1.png
│ │ │ └── Contents.json
│ │ ├── p19.imageset
│ │ │ ├── p19.png
│ │ │ ├── p19-1.png
│ │ │ └── Contents.json
│ │ ├── p2.imageset
│ │ │ ├── p2-1.png
│ │ │ ├── p2.png
│ │ │ └── Contents.json
│ │ ├── p20.imageset
│ │ │ ├── p20.png
│ │ │ ├── p20-1.png
│ │ │ └── Contents.json
│ │ ├── p21.imageset
│ │ │ ├── p21.png
│ │ │ ├── p21-1.png
│ │ │ └── Contents.json
│ │ ├── p22.imageset
│ │ │ ├── p22.png
│ │ │ ├── p22-1.png
│ │ │ └── Contents.json
│ │ ├── p23.imageset
│ │ │ ├── p23.png
│ │ │ ├── p23-1.png
│ │ │ └── Contents.json
│ │ ├── p24.imageset
│ │ │ ├── p24.png
│ │ │ ├── p24-1.png
│ │ │ └── Contents.json
│ │ ├── p25.imageset
│ │ │ ├── p25.png
│ │ │ ├── p25-1.png
│ │ │ └── Contents.json
│ │ ├── p26.imageset
│ │ │ ├── p26.png
│ │ │ ├── p26-1.png
│ │ │ └── Contents.json
│ │ ├── p27.imageset
│ │ │ ├── p27.png
│ │ │ ├── p27-1.png
│ │ │ └── Contents.json
│ │ ├── p28.imageset
│ │ │ ├── p28.png
│ │ │ ├── p28-1.png
│ │ │ └── Contents.json
│ │ ├── p29.imageset
│ │ │ ├── p29.png
│ │ │ ├── p29-1.png
│ │ │ └── Contents.json
│ │ ├── p3.imageset
│ │ │ ├── p3-1.png
│ │ │ ├── p3.png
│ │ │ └── Contents.json
│ │ ├── p30.imageset
│ │ │ ├── p30.png
│ │ │ ├── p30-1.png
│ │ │ └── Contents.json
│ │ ├── p4.imageset
│ │ │ ├── p4-1.png
│ │ │ ├── p4.png
│ │ │ └── Contents.json
│ │ ├── p5.imageset
│ │ │ ├── p5-1.png
│ │ │ ├── p5.png
│ │ │ └── Contents.json
│ │ ├── p6.imageset
│ │ │ ├── p6-1.png
│ │ │ ├── p6.png
│ │ │ └── Contents.json
│ │ ├── p7.imageset
│ │ │ ├── p7-1.png
│ │ │ ├── p7.png
│ │ │ └── Contents.json
│ │ ├── p8.imageset
│ │ │ ├── p8-1.png
│ │ │ ├── p8.png
│ │ │ └── Contents.json
│ │ └── p9.imageset
│ │ │ ├── p9-1.png
│ │ │ ├── p9.png
│ │ │ └── Contents.json
│ ├── rss.imageset
│ │ ├── rss.png
│ │ └── Contents.json
│ ├── book.imageset
│ │ ├── book.png
│ │ └── Contents.json
│ ├── plus.imageset
│ │ ├── plus.png
│ │ ├── plus 1.png
│ │ ├── plus 2.png
│ │ └── Contents.json
│ ├── star.imageset
│ │ ├── star.png
│ │ └── Contents.json
│ ├── user.imageset
│ │ ├── user.png
│ │ └── Contents.json
│ ├── arrow.imageset
│ │ ├── arrow.png
│ │ └── Contents.json
│ ├── check.imageset
│ │ ├── check.png
│ │ └── Contents.json
│ ├── close.imageset
│ │ ├── close.png
│ │ └── Contents.json
│ ├── coding.imageset
│ │ ├── coding.png
│ │ └── Contents.json
│ ├── email.imageset
│ │ ├── email.png
│ │ └── Contents.json
│ ├── group.imageset
│ │ ├── group.png
│ │ └── Contents.json
│ ├── issue.imageset
│ │ ├── issue.png
│ │ └── Contents.json
│ ├── link.imageset
│ │ ├── attach-1.png
│ │ ├── attach.png
│ │ └── Contents.json
│ ├── people.imageset
│ │ ├── people.png
│ │ └── Contents.json
│ ├── person.imageset
│ │ ├── person.png
│ │ └── Contents.json
│ ├── reload.imageset
│ │ ├── reload.png
│ │ └── Contents.json
│ ├── search.imageset
│ │ ├── search.png
│ │ └── Contents.json
│ ├── stared.imageset
│ │ ├── stared.png
│ │ └── Contents.json
│ ├── weibo.imageset
│ │ ├── weibo.png
│ │ └── Contents.json
│ ├── find.imageset
│ │ ├── search (1).png
│ │ └── Contents.json
│ ├── message.imageset
│ │ ├── message.png
│ │ └── Contents.json
│ ├── setting.imageset
│ │ ├── setting.png
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── icon-29.png
│ │ ├── icon-40.png
│ │ ├── icon-76.png
│ │ ├── icon-1024.png
│ │ ├── icon-20@2x.png
│ │ ├── icon-20@3x.png
│ │ ├── icon-29@2x.png
│ │ ├── icon-29@3x.png
│ │ ├── icon-40@2x.png
│ │ ├── icon-40@3x.png
│ │ ├── icon-60@2x.png
│ │ ├── icon-60@3x.png
│ │ ├── icon-76@2x.png
│ │ ├── icon-20-ipad.png
│ │ ├── icon-29-ipad.png
│ │ ├── icon-83.5@2x.png
│ │ ├── icon-20@2x-ipad.png
│ │ └── icon-29@2x-ipad.png
│ ├── arrow-24.imageset
│ │ ├── arrow-24.png
│ │ └── Contents.json
│ ├── document.imageset
│ │ ├── document.png
│ │ └── Contents.json
│ ├── github.imageset
│ │ ├── github (1).png
│ │ └── Contents.json
│ ├── location.imageset
│ │ ├── location.png
│ │ └── Contents.json
│ ├── rss-feed.imageset
│ │ ├── rss-feed.png
│ │ └── Contents.json
│ ├── directory.imageset
│ │ ├── directory.png
│ │ └── Contents.json
│ ├── git-merge.imageset
│ │ ├── git-merge.png
│ │ └── Contents.json
│ ├── git-branch.imageset
│ │ ├── git-branch.png
│ │ └── Contents.json
│ ├── icons-erase.imageset
│ │ ├── icons-erase.png
│ │ └── Contents.json
│ ├── repo_reload.imageset
│ │ ├── repo_reload.png
│ │ └── Contents.json
│ ├── search_sort.imageset
│ │ ├── search_sort.png
│ │ └── Contents.json
│ ├── pull-request.imageset
│ │ ├── pull-request.png
│ │ └── Contents.json
│ ├── triangle.imageset
│ │ ├── xiaoshanjiao@2x.png
│ │ ├── xiaoshanjiao@3x.png
│ │ └── Contents.json
│ └── AccentColor.colorset
│ │ └── Contents.json
├── Pamphlet
│ ├── Extension
│ │ └── Array+Ext.swift
│ ├── ViewController
│ │ └── PamphletContentViewController.swift
│ ├── Model
│ │ ├── PamphletResourceModel.swift
│ │ └── PamphletSimpleModel.swift
│ ├── Utils
│ │ └── URLRouterModel.swift
│ ├── Resources
│ │ ├── PamphletSectionContentResource.json
│ │ ├── Data
│ │ │ ├── 新鲜事
│ │ │ │ ├── D-周报.json
│ │ │ │ └── D-播客.json
│ │ │ └── Swift
│ │ │ │ ├── D-Swift 官方.json
│ │ │ │ ├── D-SwiftUI.json
│ │ │ │ └── D-Swift 技术.json
│ │ └── lib-Concurrency.json
│ └── View
│ │ ├── PamphletResourceCell.swift
│ │ └── PamphletSimpleCell.swift
├── DJFoundation
│ ├── Protocol
│ │ ├── DJCodable.swift
│ │ ├── URLConvertible.swift
│ │ └── DefaultValue.swift
│ ├── Common
│ │ └── Error.swift
│ └── Utils
│ │ ├── Utils.swift
│ │ └── DJParser.swift
├── Github
│ ├── Model
│ │ ├── Readme.swift
│ │ ├── Config.swift
│ │ ├── RepoPullFile.swift
│ │ ├── RepoBranch.swift
│ │ ├── StatusModel.swift
│ │ ├── SearchList.swift
│ │ ├── LocalRepo.swift
│ │ ├── Organization.swift
│ │ ├── IssueDetail.swift
│ │ ├── NextPageModel.swift
│ │ ├── RepoContent.swift
│ │ ├── SqlCountModel.swift
│ │ ├── RepoPull.swift
│ │ ├── Language.swift
│ │ ├── RepoBranchCommit.swift
│ │ ├── Issue.swift
│ │ ├── UserViewer.swift
│ │ └── Repo.swift
│ ├── Utils
│ │ ├── UnChecked.swift
│ │ ├── Parse
│ │ │ ├── Parser.swift
│ │ │ ├── DJJSONParser.swift
│ │ │ ├── RegularParser.swift
│ │ │ └── DateParser.swift
│ │ ├── NotificationKeys.swift
│ │ ├── Color.swift
│ │ ├── GithubTrending
│ │ │ ├── GithubTrendingDeveloper.swift
│ │ │ ├── GithubTrendingRepo.swift
│ │ │ └── GithubTrendingItemsManager.swift
│ │ ├── DJObserverable.swift
│ │ ├── ImageCoder.swift
│ │ ├── LanguageManager.swift
│ │ └── ConfigManager.swift
│ ├── AppStyle
│ │ ├── AppStyle.swift
│ │ └── AppStyleUtility.swift
│ ├── Extension
│ │ ├── Base.swift
│ │ ├── Bundle+Ext.swift
│ │ ├── Int+Ext.swift
│ │ ├── Bool+Ext.swift
│ │ ├── String+File.swift
│ │ ├── UIView+Ext.swift
│ │ ├── UIColor+Ext.swift
│ │ ├── UIScrollView+Refresh.swift
│ │ ├── URL+Ext.swift
│ │ ├── Result.swift
│ │ ├── UIViewController+Share.swift
│ │ ├── UIApplication+Ext.swift
│ │ ├── Color+Ext.swift
│ │ ├── Default+Ext.swift
│ │ ├── UIImage+Ext.swift
│ │ ├── UIView+Loading.swift
│ │ ├── JSONSerialization+Ext.swift
│ │ └── String+Ext.swift
│ ├── ViewController
│ │ ├── Developer
│ │ │ ├── LocalDataViewController.swift
│ │ │ ├── LocalDataManager.swift
│ │ │ └── View
│ │ │ │ ├── LocalDeveloperSectionHeaderView.swift
│ │ │ │ └── LocalRepoCell.swift
│ │ ├── GithubTrending
│ │ │ ├── GithubTrendingRepoViewController.swift
│ │ │ ├── Model
│ │ │ │ └── GithubTrendingType.swift
│ │ │ ├── LoaderView.swift
│ │ │ ├── GithubTrendingReposRepresentation.swift
│ │ │ ├── GithubTrendingManager.swift
│ │ │ └── GithubTrendingViewController.swift
│ │ ├── Home
│ │ │ ├── DevelopersTrendingView.swift
│ │ │ ├── HomeHorizontalItemsView.swift
│ │ │ ├── GithubTrendingItemView.swift
│ │ │ ├── RssFeedItem.swift
│ │ │ ├── ReposTrendingView.swift
│ │ │ └── ViewModel
│ │ │ │ └── HomeViewModel.swift
│ │ ├── Authorization
│ │ │ └── AuthorizationViewManager.swift
│ │ ├── User
│ │ │ ├── ViewModel
│ │ │ │ ├── Setting.swift
│ │ │ │ ├── SettingType.swift
│ │ │ │ └── UserViewModel.swift
│ │ │ ├── Views
│ │ │ │ ├── UserContrbutionItemCell.swift
│ │ │ │ ├── UserContributionCell.swift
│ │ │ │ ├── UserInfoCell.swift
│ │ │ │ └── UserCell.swift
│ │ │ ├── SettingViewController.swift
│ │ │ └── SettingView.swift
│ │ ├── Repo
│ │ │ └── Views
│ │ │ │ ├── RepoBranchCommitCell.swift
│ │ │ │ ├── RepoHeaderView.swift
│ │ │ │ ├── RepoListView.swift
│ │ │ │ ├── RepoFooterView.swift
│ │ │ │ └── RepoBranchCommitFileCell.swift
│ │ ├── Feed
│ │ │ ├── Views
│ │ │ │ └── RssFeedsItemView.swift
│ │ │ └── ViewModel
│ │ │ │ └── FeedViewModel.swift
│ │ └── Search
│ │ │ └── Views
│ │ │ └── SearchWordHeaderView.swift
│ ├── Store
│ │ ├── LocalRepoManager.swift
│ │ ├── FeedManager.swift
│ │ ├── LocalUserManager.swift
│ │ └── SearchWordManager.swift
│ ├── Source
│ │ └── Language.xcdatamodeld
│ │ │ └── Language.xcdatamodel
│ │ │ └── contents
│ └── Widget
│ │ ├── LanguageGradientView.swift
│ │ ├── NavigationController.swift
│ │ └── AvatarImageView.swift
├── SwiftUI
│ ├── Extension
│ │ └── Image+Ext.swift
│ └── Modifier
│ │ └── ViewDidLoadModifier.swift
├── Info.plist
├── AppDelegate.swift
├── LoadingViewerViewController.swift
└── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
├── .swiftlint.yml
├── DJGithub.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── polarisdev.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcuserdata
│ ├── polarisdev.xcuserdatad
│ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── jiqinqiang.xcuserdatad
│ └── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
├── .gitignore
├── DJGithubUITests
├── DJGithubUITestsLaunchTests.swift
└── DJGithubUITests.swift
└── DJGithubTests
└── DJGithubTests.swift
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/screenshot/Feeds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/Feeds.png
--------------------------------------------------------------------------------
/screenshot/Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/Home.png
--------------------------------------------------------------------------------
/screenshot/Repo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/Repo.png
--------------------------------------------------------------------------------
/screenshot/Stars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/Stars.png
--------------------------------------------------------------------------------
/screenshot/User.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/User.png
--------------------------------------------------------------------------------
/screenshot/Pamphlet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/Pamphlet.png
--------------------------------------------------------------------------------
/screenshot/RepoDir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/RepoDir.png
--------------------------------------------------------------------------------
/screenshot/RssAtom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/RssAtom.png
--------------------------------------------------------------------------------
/screenshot/RssFeeds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/RssFeeds.png
--------------------------------------------------------------------------------
/screenshot/UserInfo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/UserInfo.png
--------------------------------------------------------------------------------
/screenshot/appstyle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/appstyle.png
--------------------------------------------------------------------------------
/screenshot/EditIssue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/EditIssue.png
--------------------------------------------------------------------------------
/screenshot/IssueDetail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/IssueDetail.png
--------------------------------------------------------------------------------
/screenshot/RepoBranch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/RepoBranch.png
--------------------------------------------------------------------------------
/screenshot/RepoIssues.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/RepoIssues.png
--------------------------------------------------------------------------------
/screenshot/IssueComments.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/IssueComments.png
--------------------------------------------------------------------------------
/screenshot/SearchHistory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/SearchHistory.png
--------------------------------------------------------------------------------
/screenshot/SearchResults.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/SearchResults.png
--------------------------------------------------------------------------------
/screenshot/UserInteract.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/UserInteract.png
--------------------------------------------------------------------------------
/screenshot/LocalDeveloper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/LocalDeveloper.png
--------------------------------------------------------------------------------
/screenshot/PamphletResource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/PamphletResource.png
--------------------------------------------------------------------------------
/screenshot/RepoBranchCreate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/RepoBranchCreate.png
--------------------------------------------------------------------------------
/screenshot/GithubTrendingRepo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/GithubTrendingRepo.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/screenshot/GithubTrendingDeveloper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/screenshot/GithubTrendingDeveloper.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/rss.imageset/rss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/rss.imageset/rss.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/book.imageset/book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/book.imageset/book.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/plus.imageset/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/plus.imageset/plus.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/star.imageset/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/star.imageset/star.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/user.imageset/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/user.imageset/user.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p1.imageset/p1-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p1.imageset/p1-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p1.imageset/p1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p1.imageset/p1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p10.imageset/p10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p10.imageset/p10.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p11.imageset/p11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p11.imageset/p11.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p12.imageset/p12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p12.imageset/p12.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p13.imageset/p13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p13.imageset/p13.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p14.imageset/p14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p14.imageset/p14.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p15.imageset/p15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p15.imageset/p15.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p16.imageset/p16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p16.imageset/p16.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p17.imageset/p17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p17.imageset/p17.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p18.imageset/p18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p18.imageset/p18.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p19.imageset/p19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p19.imageset/p19.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p2.imageset/p2-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p2.imageset/p2-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p2.imageset/p2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p2.imageset/p2.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p20.imageset/p20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p20.imageset/p20.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p21.imageset/p21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p21.imageset/p21.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p22.imageset/p22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p22.imageset/p22.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p23.imageset/p23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p23.imageset/p23.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p24.imageset/p24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p24.imageset/p24.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p25.imageset/p25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p25.imageset/p25.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p26.imageset/p26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p26.imageset/p26.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p27.imageset/p27.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p27.imageset/p27.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p28.imageset/p28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p28.imageset/p28.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p29.imageset/p29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p29.imageset/p29.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p3.imageset/p3-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p3.imageset/p3-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p3.imageset/p3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p3.imageset/p3.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p30.imageset/p30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p30.imageset/p30.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p4.imageset/p4-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p4.imageset/p4-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p4.imageset/p4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p4.imageset/p4.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p5.imageset/p5-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p5.imageset/p5-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p5.imageset/p5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p5.imageset/p5.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p6.imageset/p6-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p6.imageset/p6-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p6.imageset/p6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p6.imageset/p6.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p7.imageset/p7-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p7.imageset/p7-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p7.imageset/p7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p7.imageset/p7.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p8.imageset/p8-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p8.imageset/p8-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p8.imageset/p8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p8.imageset/p8.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p9.imageset/p9-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p9.imageset/p9-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p9.imageset/p9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p9.imageset/p9.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/arrow.imageset/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/arrow.imageset/arrow.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/check.imageset/check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/check.imageset/check.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/close.imageset/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/close.imageset/close.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/coding.imageset/coding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/coding.imageset/coding.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/email.imageset/email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/email.imageset/email.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/group.imageset/group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/group.imageset/group.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/issue.imageset/issue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/issue.imageset/issue.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/link.imageset/attach-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/link.imageset/attach-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/link.imageset/attach.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/link.imageset/attach.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/people.imageset/people.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/people.imageset/people.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/person.imageset/person.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/person.imageset/person.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/plus.imageset/plus 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/plus.imageset/plus 1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/plus.imageset/plus 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/plus.imageset/plus 2.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/reload.imageset/reload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/reload.imageset/reload.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/search.imageset/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/search.imageset/search.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/stared.imageset/stared.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/stared.imageset/stared.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/weibo.imageset/weibo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/weibo.imageset/weibo.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p10.imageset/p10-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p10.imageset/p10-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p11.imageset/p11-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p11.imageset/p11-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p12.imageset/p12-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p12.imageset/p12-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p13.imageset/p13-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p13.imageset/p13-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p14.imageset/p14-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p14.imageset/p14-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p15.imageset/p15-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p15.imageset/p15-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p16.imageset/p16-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p16.imageset/p16-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p17.imageset/p17-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p17.imageset/p17-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p18.imageset/p18-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p18.imageset/p18-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p19.imageset/p19-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p19.imageset/p19-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p20.imageset/p20-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p20.imageset/p20-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p21.imageset/p21-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p21.imageset/p21-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p22.imageset/p22-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p22.imageset/p22-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p23.imageset/p23-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p23.imageset/p23-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p24.imageset/p24-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p24.imageset/p24-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p25.imageset/p25-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p25.imageset/p25-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p26.imageset/p26-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p26.imageset/p26-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p27.imageset/p27-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p27.imageset/p27-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p28.imageset/p28-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p28.imageset/p28-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p29.imageset/p29-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p29.imageset/p29-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p30.imageset/p30-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/Pixel/p30.imageset/p30-1.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/find.imageset/search (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/find.imageset/search (1).png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/message.imageset/message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/message.imageset/message.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/setting.imageset/setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/setting.imageset/setting.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-40.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-76.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/arrow-24.imageset/arrow-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/arrow-24.imageset/arrow-24.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/document.imageset/document.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/document.imageset/document.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/github.imageset/github (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/github.imageset/github (1).png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/location.imageset/location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/location.imageset/location.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/rss-feed.imageset/rss-feed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/rss-feed.imageset/rss-feed.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-1024.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/directory.imageset/directory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/directory.imageset/directory.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/git-merge.imageset/git-merge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/git-merge.imageset/git-merge.png
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 |
2 | disabled_rules: # rule identifiers to exclude from running
3 | - identifier_name
4 | - shorthand_operator
5 | - force_cast
6 | - line_length
7 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20-ipad.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29-ipad.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/git-branch.imageset/git-branch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/git-branch.imageset/git-branch.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/icons-erase.imageset/icons-erase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/icons-erase.imageset/icons-erase.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/repo_reload.imageset/repo_reload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/repo_reload.imageset/repo_reload.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/search_sort.imageset/search_sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/search_sort.imageset/search_sort.png
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Extension/Array+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/20.
6 | //
7 |
8 | import UIKit
9 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/pull-request.imageset/pull-request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/pull-request.imageset/pull-request.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/triangle.imageset/xiaoshanjiao@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/triangle.imageset/xiaoshanjiao@2x.png
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/triangle.imageset/xiaoshanjiao@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub/Assets.xcassets/triangle.imageset/xiaoshanjiao@3x.png
--------------------------------------------------------------------------------
/DJGithub.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/DJGithub/DJFoundation/Protocol/DJCodable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DJCodable.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/3.
6 | //
7 |
8 | import Foundation
9 |
10 | typealias DJCodable = Decodable & Encodable
11 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/Readme.swift:
--------------------------------------------------------------------------------
1 | //
2 | // readme.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/26.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Readme: DJCodable {
11 | var content: String?
12 | }
13 |
--------------------------------------------------------------------------------
/DJGithub.xcodeproj/xcuserdata/polarisdev.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/DJGithub.xcodeproj/project.xcworkspace/xcuserdata/polarisdev.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyljqq/DJGithub/HEAD/DJGithub.xcodeproj/project.xcworkspace/xcuserdata/polarisdev.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/UnChecked.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UnChecked.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2025/4/18.
6 | //
7 |
8 | import Foundation
9 |
10 | struct UnChecked: @unchecked Sendable {
11 | var value: T
12 | }
13 |
--------------------------------------------------------------------------------
/DJGithub/SwiftUI/Extension/Image+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Image+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/2/17.
6 | //
7 |
8 | import SwiftUI
9 |
10 | extension Image {
11 | static let placeholderImage = Image(uiImage: UIImage(named: "person")!)
12 | }
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /DJGithub/Github/config.plist
2 | .DS_Store
3 | build/
4 | DJGithub/Github/Resource/config.json
5 | DJGithub.xcodeproj/project.xcworkspace/xcuserdata/jiqinqiang.xcuserdatad/UserInterfaceState.xcuserstate
6 | DJGithub.xcodeproj/project.xcworkspace/xcuserdata/polarisdev.xcuserdatad/UserInterfaceState.xcuserstate
7 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/Parse/Parser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Parser.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/10.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol Parsable {
11 |
12 | associatedtype DataType: DJCodable
13 |
14 | func parse(with data: Data?) async throws -> DataType?
15 | }
16 |
--------------------------------------------------------------------------------
/DJGithub/Github/AppStyle/AppStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppStyle.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/30.
6 | //
7 |
8 | import UIKit
9 |
10 | enum AppStyle {
11 | case gray
12 |
13 | var color: UIColor {
14 | switch self {
15 | case .gray: return .lightGray
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/DJGithub.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/Base.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Untitled.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2025/4/18.
6 | //
7 |
8 | import Foundation
9 |
10 | @MainActor func executeOnMainThread(_ block: @escaping () -> Void) {
11 | Task {
12 | await MainActor.run {
13 | block()
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/Bundle+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bundle+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/2/1.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Bundle {
11 | var appVersion: String {
12 | return (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? ""
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Developer/LocalDataViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalDataViewController.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/7.
6 | //
7 |
8 | import UIKit
9 |
10 | class LocalDataViewController: UIViewController {
11 |
12 | override func viewDidLoad() {
13 | super.viewDidLoad()
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/Int+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Int+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/17.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Int {
11 | var toGitNum: String {
12 | if self > 1000 {
13 | return "\(String(format: "%.1f", Double(self) / 1000))k"
14 | }
15 | return "\(self)"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/Bool+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bool+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/29.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Bool {
11 |
12 | var followText: String {
13 | return self ? "UnFollow" : "Follow"
14 | }
15 |
16 | var starText: String {
17 | return self ? "UnStar" : "Star"
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/ViewController/PamphletContentViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PamphletSimpleContentViewController.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/20.
6 | //
7 |
8 | import UIKit
9 |
10 | class PamphletContentViewController: UIViewController {
11 |
12 | override func viewDidLoad() {
13 | super.viewDidLoad()
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/NotificationKeys.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationKeys.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/28.
6 | //
7 |
8 | import Foundation
9 |
10 | struct NotificationKeys {
11 | static let createPullRequestKey = NSNotification.Name("DJCreatePullRequest")
12 | static let closePullRequestKey = NSNotification.Name("DJClosePullRequestKey")
13 | }
14 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/String+File.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+File.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/4.
6 | //
7 |
8 | import Foundation
9 |
10 | extension String {
11 | var fileSuffix: String? {
12 | let arr = self.components(separatedBy: ".")
13 | guard arr.count > 1 else {
14 | return nil
15 | }
16 | return arr.last
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/Config.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Config.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/29.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Config: DJCodable {
11 | var authorization: String = ""
12 | let userName: String = ""
13 |
14 | init() {
15 |
16 | }
17 |
18 | enum CodingKeys: String, CodingKey {
19 | case authorization
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/RepoPullFile.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoPullFile.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/28.
6 | //
7 |
8 | import Foundation
9 |
10 | struct RepoPullFile: DJCodable {
11 | var filename: String
12 | var status: String
13 | var additions: Int
14 | var deletions: Int
15 | var contentsUrl: String
16 | var blobUrl: String
17 | var patch: String?
18 | }
19 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/RepoBranch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoBranch.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/27.
6 | //
7 |
8 | import Foundation
9 |
10 | struct RepoBranch: DJCodable {
11 | struct RepoBranchCommit: DJCodable {
12 | var sha: String
13 | var url: String
14 | }
15 |
16 | var name: String
17 | var protected: Bool
18 |
19 | var commit: RepoBranchCommit
20 | }
21 |
--------------------------------------------------------------------------------
/DJGithub/Github/Store/LocalRepoManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalRepoManager.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/7.
6 | //
7 |
8 | import Foundation
9 |
10 | struct LocalRepoManager {
11 |
12 | static func loadRepos(with filename: String? = nil) async -> [LocalRepoGroup] {
13 | guard let filename else { return [] }
14 | return loadBundleJSONFile(filename)
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/rss.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "rss.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/arrow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "arrow.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/book.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "book.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "close.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/email.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "email.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/group.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "group.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/issue.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "issue.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/weibo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "weibo.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/arrow-24.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "arrow-24.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/coding.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "coding.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/document.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "document.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/find.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "search (1).png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/github.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "github (1).png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/location.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "location.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/message.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "message.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/people.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "people.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/reload.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "reload.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/rss-feed.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "rss-feed.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/search.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "search.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/directory.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "directory.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/git-branch.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "git-branch.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/git-merge.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "git-merge.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/UIView+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/16.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 | static var className: String {
12 | return String(describing: self.classForCoder())
13 | }
14 | }
15 |
16 | extension UIViewController {
17 | static var className: String {
18 | return String(describing: self.classForCoder())
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/icons-erase.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icons-erase.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/pull-request.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "pull-request.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/repo_reload.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "repo_reload.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/search_sort.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "search_sort.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p1-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p1.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p2-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p2.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p3-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p3.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p4-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p4.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p5-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p5.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p6-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p6.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p7-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p7.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p8.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p8-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p8.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p9-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p9.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p10.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p10-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p10.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p11.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p11-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p11.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p12.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p12-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p12.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p13.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p13-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p13.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p14.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p14-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p14.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p15.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p15-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p15.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p16.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p16-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p16.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p17.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p17-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p17.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p18.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p18-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p18.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p19.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p19-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p19.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p20.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p20-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p20.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p21.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p21-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p21.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p22.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p22-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p22.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p23.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p23-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p23.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p24.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p24-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p24.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p25.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p25-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p25.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p26.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p26-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p26.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p27.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p27-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p27.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p28.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p28-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p28.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p29.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p29-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p29.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/Pixel/p30.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "p30-1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "p30.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/link.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "attach.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "attach-1.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/StatusModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StatusModel.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/28.
6 | //
7 |
8 | import Foundation
9 |
10 | struct StatusModel: DJCodable {
11 | var statusCode: Int
12 |
13 | var isStatus204: Bool {
14 | return statusCode == 204
15 | }
16 |
17 | var isStatus201: Bool {
18 | return statusCode == 201
19 | }
20 |
21 | var isStatus404: Bool {
22 | return statusCode == 404
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Model/PamphletResourceModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PamphletResourceModel.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/20.
6 | //
7 |
8 | import Foundation
9 |
10 | struct PamphletResourceModel: DJCodable {
11 | let title: String
12 | @Default var desc: String
13 | let url: String
14 |
15 | enum CodingKeys: String, CodingKey {
16 | case title = "t"
17 | case url = "id"
18 | case desc = "d"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/DJGithub/DJFoundation/Common/Error.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Error.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import Foundation
9 |
10 | enum DJError: Error {
11 | case invalidURL(String)
12 | case parseError(String)
13 | case requestError
14 | case statusCode(Int)
15 | case dataError
16 | case other(Error)
17 | case unknown
18 |
19 | static func map(_ error: Error) -> DJError {
20 | return (error as? DJError) ?? .other(error)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/person.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "person.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "original"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/star.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "star.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "original"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/stared.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "stared.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "original"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/user.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "user.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/setting.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "setting.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "original"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/SearchList.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SearchList.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/1.
6 | //
7 |
8 | import Foundation
9 |
10 | enum SearchType {
11 | case users
12 | case repos
13 |
14 | var title: String {
15 | switch self {
16 | case .users: return "users"
17 | case .repos: return "repos"
18 | }
19 | }
20 | }
21 |
22 | struct SearchList: DJCodable {
23 | var totalCount: Int
24 | var incompleteResults: Bool
25 | var items: [T]
26 | }
27 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/GithubTrending/GithubTrendingRepoViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrendingRepoViewController.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/19.
6 | //
7 |
8 | import UIKit
9 |
10 | class GithubTrendingRepoViewController: UIViewController {
11 |
12 | private let manager = GithubTrendingManager()
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 |
17 | setUp()
18 | }
19 |
20 | private func setUp() {
21 |
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Home/DevelopersTrendingView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DevelopersTrendingView.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/30.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct DevelopersTrendingView: View {
11 | var body: some View {
12 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
13 | }
14 | }
15 |
16 | struct DevelopersTrendingView_Previews: PreviewProvider {
17 | static var previews: some View {
18 | DevelopersTrendingView()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/UIColor+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/17.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIColor {
11 | static var randomColor: UIColor? {
12 | return randomHex.toColor
13 | }
14 |
15 | static var randomHex: String {
16 | let red = arc4random() % 256
17 | let green = arc4random() % 256
18 | let blue = arc4random() % 256
19 | return String(red, radix: 16) + String(green, radix: 16) + String(blue, radix: 16)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Utils/URLRouterModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLRouterModel.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/20.
6 | //
7 |
8 | import UIKit
9 |
10 | struct URLRouterModel {
11 | let scheme: String
12 | let host: String
13 | let path: String
14 | let type: HostVCType?
15 | let queryItems: [String: String]
16 |
17 | var transition: VCTransition = .push
18 | }
19 |
20 | extension URLRouterModel {
21 | @MainActor var vc: UIViewController? {
22 | return type?.getVC(with: queryItems)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/Color.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Color.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/16.
6 | //
7 |
8 | import Foundation
9 | import UIKit
10 |
11 | extension UIColor {
12 |
13 | static let backgroundColor = UIColorFromRGB(0xf5f5f5)
14 | static let textColor = UIColorFromRGB(0x222222)
15 | static let textReadColor = UIColorFromRGB(0x4444)
16 | static let textGrayColor = UIColorFromRGB(0x666666)
17 | static let lightBlue = UIColorFromRGB(0x6495ED)
18 | static let lightGreen = UIColorFromRGB(0x90ee90)
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "lldb",
9 | "request": "launch",
10 | "name": "Debug",
11 | "program": "${workspaceFolder}/",
12 | "args": [],
13 | "cwd": "${workspaceFolder}"
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/GithubTrending/GithubTrendingDeveloper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrendingDeveloper.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/20.
6 | //
7 |
8 | import Foundation
9 |
10 | struct GithubTrendingDeveloper: Codable {
11 |
12 | let id = UUID()
13 |
14 | let avatarImageUrl: String
15 | let name: String
16 | let login: String
17 | let repoName: String
18 | let repoDesc: String
19 |
20 | enum CodingKeys: String, CodingKey {
21 | case avatarImageUrl, name, login, repoName, repoDesc
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/triangle.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "xiaoshanjiao@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "xiaoshanjiao@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/LocalRepo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalRepo.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/7.
6 | //
7 |
8 | import Foundation
9 |
10 | struct LocalRepoGroup: DJCodable {
11 | var name: String
12 | var id: Int
13 | var repos: [LocalRepo]
14 | }
15 |
16 | struct LocalRepo: DJCodable {
17 | var id: String
18 | var des: String?
19 | var groupId: Int?
20 |
21 | var description: String {
22 | return self.des ?? "No description provided."
23 | }
24 |
25 | enum CodingKeys: String, CodingKey {
26 | case id, des
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/DJObserverable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DJObserverable.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/22.
6 | //
7 |
8 | import Foundation
9 |
10 | class DJObserverable {
11 |
12 | var value: T? {
13 | didSet {
14 | listener?(value)
15 | }
16 | }
17 |
18 | private var listener: ((T?) -> Void)?
19 |
20 | init(value: T? = nil) {
21 | self.value = value
22 | }
23 |
24 | func bind(_ listener: @escaping (T?) -> Void) {
25 | self.listener = listener
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DJGithub/Assets.xcassets/plus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "plus 1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "plus 2.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "plus.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Authorization/AuthorizationViewManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthorizationViewManager.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/28.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | class AuthorizationViewManager: NSObject {
12 |
13 | @MainActor
14 | func addAuthorizationView(_ completionHandler: ((Bool) -> Void)? = nil) -> UIViewController {
15 | let authorizationView = AuthorizationView(completionHandler: completionHandler)
16 | return UIHostingController(rootView: authorizationView)
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/GithubTrending/Model/GithubTrendingType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrendingType.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/20.
6 | //
7 |
8 | import Foundation
9 |
10 | enum GithubTrendingType {
11 | case repo(String)
12 | case developer(String)
13 | }
14 |
15 | extension GithubTrendingType {
16 |
17 | var urlString: String {
18 | switch self {
19 | case .repo(let path): return "https://github.com/trending" + path
20 | case .developer(let path): return "https://github.com/trending/developers" + path
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/UIScrollView+Refresh.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIScrollView+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIScrollView {
11 | var contentInsetTop: CGFloat {
12 | if #available(iOS 11.0, *) {
13 | return contentInset.top + adjustedContentInset.top
14 | } else {
15 | return contentInset.top
16 | }
17 | }
18 |
19 | var contentInsetBottom: CGFloat {
20 | if #available(iOS 11.0, *) {
21 | return contentInset.bottom + adjustedContentInset.bottom
22 | } else {
23 | return contentInset.bottom
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/GithubTrending/LoaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadingView.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/19.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct LoaderView: View {
11 |
12 | var tintColor: Color = .blue
13 | var scaleSize: CGFloat = 1.0
14 |
15 | var body: some View {
16 | ProgressView()
17 | .scaleEffect(scaleSize, anchor: .center)
18 | .progressViewStyle(CircularProgressViewStyle(tint: tintColor))
19 | }
20 | }
21 |
22 | struct LoaderView_Previews: PreviewProvider {
23 | static var previews: some View {
24 | LoaderView()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/URL+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URL+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/20.
6 | //
7 |
8 | import Foundation
9 |
10 | extension URL {
11 | func appending(by queryItems: [String: String]) -> URL {
12 | guard !queryItems.isEmpty, var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true) else {
13 | return self
14 | }
15 | urlComponents.queryItems = urlComponents.queryItems ?? [] + queryItems.map { URLQueryItem(name: $0, value: $1.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)) }
16 | return urlComponents.url != nil ? urlComponents.url! : self
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/Parse/DJJSONParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DJJSONParser.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/10.
6 | //
7 |
8 | import Foundation
9 |
10 | class DJJSONParser: JSONDecoder, Parsable {
11 |
12 | typealias DataType = T
13 |
14 | override init() {
15 | super.init()
16 | self.keyDecodingStrategy = .convertFromSnakeCase
17 | }
18 |
19 | func parse(with data: Data?) async throws -> T? {
20 | guard let data = data else { return nil }
21 | do {
22 | return try self.decode(T.self, from: data)
23 | } catch {
24 | throw DJError.parseError("\(error)")
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/Organization.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Organization.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/11.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Organization: DJCodable {
11 | let avatarUrl: String
12 | let createdAt: String
13 | let login: String
14 |
15 | @Default var description: String
16 | @Default var name: String
17 | @Default var email: String
18 | @Default var location: String
19 | @Default var websiteUrl: String
20 |
21 | var membersWithRole: TotalCountModel
22 | var pinnableItems: TotalCountModel
23 | var pinnedItems: PinnedRepos
24 | }
25 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Resources/PamphletSectionContentResource.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "sectionName": "新鲜事",
4 | "items": [
5 | {
6 | "title": "周报"
7 | },
8 | {
9 | "title": "播客"
10 | }
11 | ],
12 | },
13 | {
14 | "sectionName": "Swift",
15 | "items": [
16 | {
17 | "title": "Swift 官方"
18 | },
19 | {
20 | "title": "Swift 技术"
21 | },
22 | {
23 | "title": "SwiftUI"
24 | }
25 | ],
26 | },
27 | {
28 | "sectionName": "美术",
29 | "items": [
30 | {
31 | "title": "图片工具"
32 | },
33 | {
34 | "title": "美术素材"
35 | }
36 | ]
37 | }
38 | ]
39 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/GithubTrending/GithubTrendingReposRepresentation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrendingReposRepresentation.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/19.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | struct GithubTrendingReposRepresentation: UIViewControllerRepresentable {
12 |
13 | let userName: String
14 | let repoName: String
15 |
16 | func makeUIViewController(context: Context) -> some UIViewController {
17 | return RepoViewController(with: userName, repoName: repoName)
18 | }
19 |
20 | func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/ViewModel/Setting.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Setting.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2023/1/31.
6 | //
7 |
8 | import Foundation
9 |
10 | @Observable class Setting {
11 |
12 | let dataSource: [SettingSection] = [
13 | SettingSection(name: "Abillity", items: [.iCloud]),
14 | SettingSection(name: "Social", items: [.github, .email, .weibo]),
15 | SettingSection(name: "Other", items: [.version(Bundle.main.appVersion), .signUp])
16 | ]
17 |
18 | }
19 |
20 | extension Setting {
21 | struct SettingSection {
22 | let id = UUID()
23 |
24 | let name: String
25 | let items: [SettingType]
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/Views/UserContrbutionItemCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserContrbutionCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/16.
6 | //
7 |
8 | import UIKit
9 |
10 | class UserContrbutionItemCell: UICollectionViewCell {
11 | override init(frame: CGRect) {
12 | super.init(frame: frame)
13 |
14 | setUp()
15 | }
16 |
17 | func render(with item: UserContributionItem) {
18 | contentView.backgroundColor = item.color.toColor
19 | }
20 |
21 | func setUp() {
22 | contentView.backgroundColor = .white
23 | contentView.layer.cornerRadius = 2
24 | }
25 |
26 | required init?(coder: NSCoder) {
27 | super.init(coder: coder)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Resources/Data/新鲜事/D-周报.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "t":"老司机技术周报",
4 | "id":"https://github.com/SwiftOldDriver/iOS-Weekly"
5 | },
6 | {
7 | "t":"13週報",
8 | "id":"https://ethanhuang13.substack.com/"
9 | },
10 | {
11 | "t":"摸鱼周报",
12 | "id":"https://zhangferry.com/"
13 | },
14 | {
15 | "t":"iOS Dev Weekly",
16 | "id":"https://iosdevweekly.com/"
17 | },
18 | {
19 | "t":"Swift Evolution Monthly",
20 | "d":"Swift Weekly 的精神继承者",
21 | "id":"http://se-monthly.flinedev.com/"
22 | },
23 | {
24 | "t":"SwiftUI Weekly",
25 | "id":"http://weekly.swiftwithmajid.com/"
26 | }
27 | ]
28 |
--------------------------------------------------------------------------------
/DJGithub/DJFoundation/Protocol/URLConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLConvertible.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import Foundation
9 |
10 | public protocol URLRequestConvertible {
11 | func asURLRequest() -> URLRequest?
12 | }
13 |
14 | extension URLRequestConvertible {
15 | public var urlRequest: URLRequest? { return asURLRequest() }
16 | }
17 |
18 | public protocol URLConvertible {
19 | func asURL() throws -> URL
20 | }
21 |
22 | extension String: URLConvertible {
23 | public func asURL() throws -> URL {
24 | guard let url = URL(string: self) else {
25 | throw DJError.invalidURL("Error: Invalid URLString: " + self)
26 | }
27 | return url
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/DJGithub/Github/Store/FeedManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FeedManager.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/10.
6 | //
7 |
8 | import Foundation
9 |
10 | struct FeedManager {
11 | static func getFeeds() async -> Feeds? {
12 | return try? await APIClient.shared.model(with: GithubRouter.feeds)
13 | }
14 |
15 | static func fetchFeedInfo(with urlString: String) async -> FeedInfo? {
16 | return try? await APIClient.shared.data(with: urlString, decoder: DJXMLParser())
17 | }
18 |
19 | static func fetchRssInfo(with urlString: String) async -> T? {
20 | return try? await APIClient.shared.data(with: urlString, decoder: DJXMLParser()) as T?
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Home/HomeHorizontalItemsView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HomeHorizontalItemsView.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/30.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct HomeHorizontalItemsView: View {
11 |
12 | let title: String
13 | let horizontalView: ChildView
14 |
15 | var body: some View {
16 | VStack(alignment: .leading) {
17 | Text(title)
18 | .font(.headline)
19 | .fontWeight(.bold)
20 | .foregroundColor(.black)
21 | .padding(.top, 10)
22 | .padding(.leading, 16)
23 | horizontalView
24 | }
25 | .background(Color.backgroundColor)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/Result.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Result.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Result {
11 |
12 | func parse() -> T? {
13 | switch self {
14 | case .success(let d):
15 | if let d = d as? [String: Any] {
16 | if let statusCode = d["statusCode"] as? Int,
17 | ![204, 404, 201].contains(statusCode) {
18 | print("result parse error, status code:\(statusCode)")
19 | return nil
20 | }
21 | return try? DJDecoder(dict: d).decode()
22 | }
23 | case .failure(let error):
24 | print("result parse error: \(error)")
25 | break
26 | }
27 | return nil
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/UIViewController+Share.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Share.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/8.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIViewController {
11 | func share(with urlString: String) {
12 | guard let shareURL = URL(string: urlString) else { return }
13 | let sharedItems: [Any] = [shareURL]
14 | let activityVC = UIActivityViewController(activityItems: sharedItems, applicationActivities: nil)
15 | self.present(activityVC, animated: true)
16 | }
17 |
18 | var naviVc: UIViewController? {
19 | var vc: UIViewController? = self
20 | while vc?.parent != nil && !(vc?.parent is UINavigationController) {
21 | vc = vc?.parent
22 | }
23 | return vc
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/UIApplication+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIApplication.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/19.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIApplication {
11 |
12 | var keyWindow: UIWindow? {
13 | // Get connected scenes
14 | return UIApplication.shared.connectedScenes
15 | // Keep only active scenes, onscreen and visible to the user
16 | .filter { $0.activationState == .foregroundActive }
17 | // Keep only the first `UIWindowScene`
18 | .first(where: { $0 is UIWindowScene })
19 | // Get its associated windows
20 | .flatMap({ $0 as? UIWindowScene })?.windows
21 | // Finally, keep only the key window
22 | .first(where: \.isKeyWindow)
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/IssueDetail.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IssueDetail.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/5.
6 | //
7 |
8 | import Foundation
9 |
10 | struct IssueDetail: DJCodable {
11 |
12 | var id: Int
13 | var number: Int
14 | var title: String
15 | var body: String?
16 | var createdAt: String
17 | var updatedAt: String
18 | var authorAssociation: String
19 | var htmlUrl: String
20 | var reactions: IssueDetailReaction?
21 |
22 | var state: Issue.IssueState
23 |
24 | var user: UserFollowing
25 |
26 | }
27 |
28 | struct IssueDetailReaction: DJCodable {
29 | var plus: Int
30 | var minus: Int
31 | var totalCount: Int
32 |
33 | enum CodingKeys: String, CodingKey {
34 | case plus = "+1", minus = "-1", totalCount
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/DJGithub/SwiftUI/Modifier/ViewDidLoadModifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewDidLoadModifier.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2023/2/2.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ViewDidLoadModifer: ViewModifier {
11 | @State private var viewDidLoad = false
12 |
13 | var action: (() -> Void)?
14 |
15 | func body(content: Content) -> some View {
16 | content
17 | .onAppear {
18 | if !viewDidLoad {
19 | viewDidLoad = true
20 | action?()
21 | }
22 | }
23 | }
24 |
25 | }
26 |
27 | extension View {
28 | func onViewDidLoad(perform action: (() -> Void)? = nil) -> some View {
29 | self.modifier(ViewDidLoadModifer(action: action))
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/NextPageModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NextPageModel.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/27.
6 | //
7 |
8 | import Foundation
9 |
10 | struct NextPageModel {
11 |
12 | var nextIndex: Int = 0
13 | var dataSource: [Any] = []
14 | var isEnding: Bool = false
15 |
16 | init() {
17 | self.nextIndex = 0
18 | self.dataSource = []
19 | self.isEnding = false
20 | }
21 |
22 | init(nextIndex: Int, dataSource: [Any], isEnding: Bool) {
23 | self.nextIndex = nextIndex
24 | self.dataSource = dataSource
25 | self.isEnding = isEnding
26 | }
27 |
28 | mutating func update(nextIndex: Int, dataSource: [Any], isEnding: Bool) {
29 | self.nextIndex = nextIndex
30 | self.dataSource = dataSource
31 | self.isEnding = isEnding
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/DJGithub/Github/Store/LocalUserManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalUserManager.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/25.
6 | //
7 |
8 | import Foundation
9 |
10 | struct LocalUserManager {
11 |
12 | static func getUser() -> UserViewer? {
13 | return DJUserDefaults.userInfo()
14 | }
15 |
16 | static func saveUser(_ user: UserViewer?) {
17 | DJUserDefaults.save(with: user)
18 | }
19 |
20 | static func loadViewer() async -> UserViewer? {
21 | if let viewer = await UserManager.fetchUserInfo() {
22 | saveUser(viewer)
23 | return UnChecked(value: viewer).value
24 | }
25 | return nil
26 | }
27 |
28 | static func getViewerName() -> String {
29 | return DJUserDefaults.viewerName()
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/DJGithub/Github/Source/Language.xcdatamodeld/Language.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/Color+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Color+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/19.
6 | //
7 |
8 | import SwiftUI
9 |
10 | extension Color {
11 | init(with hex: String) {
12 | if let color = hex.toColor {
13 | self.init(uiColor: color)
14 | } else {
15 | self.init(white: 1)
16 | }
17 | }
18 |
19 | init(with red: CGFloat, green: CGFloat, blue: CGFloat) {
20 | let color = UIColor(red: red / 255.0, green: green / 255.0, blue: blue / 255.0, alpha: 1)
21 | self.init(uiColor: color)
22 | }
23 | }
24 |
25 | extension Color {
26 | static let textColor = Color(uiColor: .textColor)
27 | static let textGrayColor = Color(uiColor: .textGrayColor)
28 | static let backgroundColor = Color(uiColor: .backgroundColor)
29 | static let lightBlue = Color(uiColor: .lightBlue)
30 | }
31 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/RepoContent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoContent.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/4.
6 | //
7 |
8 | import Foundation
9 |
10 | struct RepoContent: DJCodable {
11 | enum RepoContentType: String, DJCodable {
12 | case file, dir
13 | }
14 |
15 | var name: String
16 | var path: String
17 | var size: Int
18 | var url: String
19 | var content: String?
20 | var downloadUrl: String?
21 | var type: RepoContentType
22 |
23 | var deepLength: Int = 0
24 | var isExpanded: Bool = false
25 | var contents: [RepoContent] = []
26 |
27 | enum CodingKeys: String, CodingKey {
28 | case name, path, size, url, downloadUrl, type, content
29 | }
30 |
31 | var isDir: Bool {
32 | if case RepoContentType.dir = self.type {
33 | return true
34 | }
35 | return false
36 | }
37 | }
38 |
39 | struct RepoContents: DJCodable {
40 | var items: [RepoContent]
41 | }
42 |
--------------------------------------------------------------------------------
/DJGithub/Github/Store/SearchWordManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SearchWordManager.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/2.
6 | //
7 |
8 | import Foundation
9 |
10 | private let SearchWordKey = "SearchWordKey"
11 |
12 | struct SearchWordManager {
13 | static let shared = SearchWordManager()
14 |
15 | func save(with word: String) {
16 | DJUserDefaults.addHistoryWord(with: word)
17 | }
18 |
19 | func load() -> [String] {
20 | return DJUserDefaults.allHistorySearchWords()
21 | }
22 |
23 | func move(index: Int, to top: Int) {
24 | var words = self.load()
25 | guard words.count > index else { return }
26 | let word = words[index]
27 | words.remove(at: index)
28 | words.insert(word, at: 0)
29 | UserDefaults.standard.setValue(words, forKey: SearchWordKey)
30 | }
31 |
32 | func removeAll() {
33 | UserDefaults.standard.set(nil, forKey: SearchWordKey)
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Repo/Views/RepoBranchCommitCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoBranchCommitCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/28.
6 | //
7 |
8 | import UIKit
9 |
10 | class RepoBranchCommitCell: UITableViewCell {
11 |
12 | lazy var commitView: RepoBranchCommitUserView = {
13 | let view = RepoBranchCommitUserView()
14 | return view
15 | }()
16 |
17 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
18 | super.init(style: style, reuseIdentifier: reuseIdentifier)
19 |
20 | contentView.addSubview(commitView)
21 | commitView.snp.makeConstraints { make in
22 | make.edges.equalToSuperview()
23 | }
24 | }
25 |
26 | func render(with model: RepoBranchCommitInfo) {
27 | commitView.render(with: model)
28 | }
29 |
30 | required init?(coder: NSCoder) {
31 | fatalError("init(coder:) has not been implemented")
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/Views/UserContributionCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserContributionCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/16.
6 | //
7 |
8 | import UIKit
9 |
10 | class UserContributionCell: UITableViewCell {
11 |
12 | var userContributionView: UserContributionView = UserContributionView()
13 |
14 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
15 | super.init(style: style, reuseIdentifier: reuseIdentifier)
16 |
17 | setUp()
18 | }
19 |
20 | func render(with userContribution: UserContribution) {
21 | userContributionView.render(with: userContribution)
22 | }
23 |
24 | func setUp() {
25 | contentView.addSubview(userContributionView)
26 | userContributionView.snp.makeConstraints { make in
27 | make.edges.equalTo(self.contentView)
28 | }
29 | }
30 |
31 | required init?(coder: NSCoder) {
32 | super.init(coder: coder)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Feed/Views/RssFeedsItemView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RssFeedsItemView.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/29.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct RssFeedsItemView: View {
11 |
12 | let title: String
13 | let desc: String
14 |
15 | var body: some View {
16 | VStack(alignment: .leading, spacing: 5) {
17 | Text(title)
18 | .font(.system(size: 14))
19 | .foregroundColor(.textColor)
20 | Text(desc)
21 | .font(.system(size: 12))
22 | .foregroundColor(.textGrayColor)
23 | }
24 | .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
25 | }
26 | }
27 |
28 | struct RssFeedsItemView_Previews: PreviewProvider {
29 | static var previews: some View {
30 | RssFeedsItemView(
31 | title: "rss feed title", desc: "rss feed content"
32 | )
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Developer/LocalDataManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalDataManager.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/7.
6 | //
7 |
8 | import Foundation
9 |
10 | enum LocalDataType {
11 | case repo
12 | case developer
13 | }
14 |
15 | struct LocalDataViewModel {
16 |
17 | let type: LocalDataType
18 |
19 | init(type: LocalDataType) {
20 | self.type = type
21 | }
22 |
23 | func loadData(with filename: String? = nil) async -> [DJCodable] {
24 | switch type {
25 | case .developer:
26 | var rs: [DJCodable] = await DeveloperGroupManager.shared.loadFromDatabase()
27 | if rs.isEmpty {
28 | rs = await DeveloperGroupManager.shared.loadLocalDeveloperGroups()
29 | }
30 | return rs
31 | case .repo:
32 | return await LocalRepoManager.loadRepos(with: filename)
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/DJGithubUITests/DJGithubUITestsLaunchTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DJGithubUITestsLaunchTests.swift
3 | // DJGithubUITests
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import XCTest
9 |
10 | class DJGithubUITestsLaunchTests: XCTestCase {
11 |
12 | override class var runsForEachTargetApplicationUIConfiguration: Bool {
13 | true
14 | }
15 |
16 | override func setUpWithError() throws {
17 | continueAfterFailure = false
18 | }
19 |
20 | func testLaunch() throws {
21 | let app = XCUIApplication()
22 | app.launch()
23 |
24 | // Insert steps here to perform after app launch but before taking a screenshot,
25 | // such as logging into a test account or navigating somewhere in the app
26 |
27 | let attachment = XCTAttachment(screenshot: app.screenshot())
28 | attachment.name = "Launch Screen"
29 | attachment.lifetime = .keepAlways
30 | add(attachment)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/ViewModel/SettingType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingType.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2023/1/31.
6 | //
7 |
8 | import Foundation
9 |
10 | enum SettingType {
11 | case iCloud
12 | case email, weibo, github
13 | case version(String), signUp
14 | }
15 |
16 | extension SettingType {
17 | var title: String {
18 | switch self {
19 | case .email: return "355086587@qq.com"
20 | case .weibo: return "@JJJJJJJiqqqq"
21 | case .github: return "东方宜玲"
22 | case .iCloud: return "iCloud"
23 | case .version(let version): return "App Version: \(version)"
24 | case .signUp: return "SignUp"
25 | }
26 | }
27 |
28 | var iconName: String {
29 | switch self {
30 | case .email: return "email"
31 | case .weibo: return "weibo"
32 | case .github: return "github"
33 | default: return ""
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Developer/View/LocalDeveloperSectionHeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalDeveloperSectionHeaderView.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/3.
6 | //
7 |
8 | import UIKit
9 |
10 | class LocalDeveloperSectionHeaderView: UIView {
11 |
12 | lazy var titleLabel: UILabel = {
13 | let label = UILabel()
14 | label.textColor = .black
15 | label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
16 | return label
17 | }()
18 |
19 | init() {
20 | super.init(frame: .zero)
21 | self.backgroundColor = .backgroundColor
22 | addSubview(self.titleLabel)
23 | self.titleLabel.snp.makeConstraints { make in
24 | make.leading.equalTo(16)
25 | make.centerY.equalTo(self)
26 | }
27 | }
28 |
29 | func render(with title: String) {
30 | self.titleLabel.text = title
31 | }
32 |
33 | required init?(coder: NSCoder) {
34 | fatalError("init(coder:) has not been implemented")
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/GithubTrending/GithubTrendingManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrendingManager.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/19.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | class GithubTrendingManager: NSObject {
12 |
13 | @MainActor
14 | func addTrendingView(with types: [GithubTrendingType],
15 | selectedIndex: Int = 0,
16 | repoSelectedClosure: @escaping (GithubTrendingRepo) -> Void,
17 | developerSelectedClosure: @escaping (GithubTrendingDeveloper) -> Void) -> UIViewController {
18 | return UIHostingController(
19 | rootView: GithubTrendingView(
20 | types: types,
21 | selectedIndex: selectedIndex,
22 | repoSelectedClosure: repoSelectedClosure,
23 | developerSelectedClosure: developerSelectedClosure
24 | )
25 | )
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Home/GithubTrendingItemView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrendingItemView.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/30.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct GithubTrendingItemView: View {
11 |
12 | let views: [ChildView]
13 |
14 | var body: some View {
15 | ScrollView(.horizontal, showsIndicators: false) {
16 | LazyHStack(spacing: 10) {
17 | ForEach(0.. Self? {
14 | serialQueue.sync {
15 | let sql = "select count(1) from \(tableName) \(condition);"
16 | if let rs = try? SQLiteDatabase.queryCount(with: sql) {
17 | return try? DJDecoder(dict: rs).decode()
18 | }
19 | return nil
20 | }
21 | }
22 | }
23 |
24 | struct SqlMaxModel: DJCodable {
25 | var maxValue: String
26 |
27 | static func query(with tableName: String, fieldName: String, condition: String = "") -> Self? {
28 | let sql = "select max(\(fieldName)) from \(tableName) \(condition)"
29 | if let rs = try? SQLiteDatabase.queryCount(with: sql) {
30 | if let count = rs["count"] as? String {
31 | return SqlMaxModel(maxValue: count)
32 | }
33 | }
34 | return nil
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/Parse/RegularParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RegularParser.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/11.
6 | //
7 |
8 | import Foundation
9 |
10 | struct RegularParser {
11 | static func parse(with pattern: String, validateString: String) -> [String] {
12 | do {
13 | let expression = try NSRegularExpression(pattern: pattern)
14 | let matches = expression.matches(in: validateString, range: NSRange(location: 0, length: validateString.count))
15 | return matches.compactMap { (validateString as NSString).substring(with: $0.range(at: 1)) }
16 | } catch {
17 | print("regular parse error: \(error)")
18 | }
19 | return []
20 | }
21 |
22 | static func matches(with pattern: String, validateString: String) -> [NSTextCheckingResult] {
23 | do {
24 | let expression = try NSRegularExpression(pattern: pattern)
25 | return expression.matches(in: validateString, range: NSRange(location: 0, length: validateString.count))
26 | } catch {
27 | return []
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/RepoPull.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoPull.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/28.
6 | //
7 |
8 | import Foundation
9 |
10 | struct RepoPull: DJCodable {
11 | var id: Int?
12 | var number: Int
13 | var state: Issue.IssueState
14 | var title: String
15 | var body: String?
16 | var createdAt: String
17 | var updatedAt: String
18 |
19 | var merged: Bool
20 | var mergeable: Bool?
21 | var mergedBy: UserFollowing?
22 | var commits: Int
23 | var additions: Int
24 | var deletions: Int
25 | var changedFiles: Int
26 |
27 | var user: UserFollowing
28 | var head: RepoPullBranch
29 | var base: RepoPullBranch
30 |
31 | var desc: String {
32 | return self.body ?? ""
33 | }
34 | }
35 |
36 | struct RepoPullMerge: DJCodable {
37 | var merged: Bool
38 | var messsage: String?
39 | var sha: String
40 | }
41 |
42 | extension RepoPull {
43 | struct RepoPullBranch: DJCodable {
44 | var label: String
45 | var ref: String
46 | var sha: String
47 | var user: UserFollowing
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/GithubTrending/GithubTrendingRepo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrending.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/19.
6 | //
7 |
8 | import Foundation
9 |
10 | struct GithubTrendingRepo: Codable {
11 | let id = UUID()
12 |
13 | let userName: String
14 | let repoName: String
15 | let languange: String
16 | let desc: String
17 | let star: String
18 | let fork: String
19 | let footerDesc: String
20 | let languageColor: String
21 |
22 | enum CodingKeys: String, CodingKey {
23 | case userName, repoName, languange, desc, star
24 | case fork, footerDesc, languageColor
25 | }
26 | }
27 |
28 | extension GithubTrendingRepo {
29 | #if DEBUG
30 | static let sample: GithubTrendingRepo = GithubTrendingRepo(
31 | userName: "dyljqq",
32 | repoName: "DJGithub",
33 | languange: "Swift",
34 | desc: "DJGithub",
35 | star: "14",
36 | fork: "2",
37 | footerDesc: "2 stars today",
38 | languageColor: "0x000000"
39 | )
40 | #endif
41 | }
42 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Resources/Data/Swift/D-Swift 官方.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "t":"Swift.org - Welcome to Swift.org",
4 | "d":"Swift 官网",
5 | "id":"https://www.swift.org/"
6 | },
7 | {
8 | "t":"The Swift Programming Language",
9 | "d":"Swift Github 官方地址",
10 | "id":"https://github.com/apple/swift"
11 | },
12 | {
13 | "t":"Swift.org - Blog",
14 | "d":"Swift 博客",
15 | "id":"https://www.swift.org/blog/"
16 | },
17 | {
18 | "t":"The Swift Programming Language",
19 | "d":"Swift 官方手册",
20 | "id":"https://docs.swift.org/swift-book/"
21 | },
22 | {
23 | "t":"中文版 Apple 官方 Swift 教程《The Swift Programming Language》",
24 | "id":"https://github.com/SwiftGGTeam/the-swift-programming-language-in-chinese"
25 | },
26 | {
27 | "t":"WWDC Session",
28 | "id":"https://developer.apple.com/videos/"
29 | },
30 | {
31 | "t":"Exploring SwiftUI Sample Apps",
32 | "id":"https://developer.apple.com/tutorials/sample-apps"
33 | }
34 | ]
35 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Repo/Views/RepoListView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoListView.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/2/17.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct RepoListView: View {
11 |
12 | @State var repos: [Repo] = []
13 |
14 | var body: some View {
15 | ScrollView {
16 | LazyVStack() {
17 | ForEach(repos, id: \.id) { repo in
18 | SimpleRepoView(repo: repo)
19 | }
20 | }
21 | }
22 | }
23 |
24 | func loadData(from remote: Bool) {
25 | if let repos = DJUserDefaults.getStaredRepos() {
26 | self.repos = repos
27 | }
28 |
29 | Task {
30 | self.repos = await RepoManager.fetchStaredRepos(with: "dyljqq", page: 1)
31 | }
32 | }
33 | }
34 |
35 | struct RepoListView_Previews: PreviewProvider {
36 | static var previews: some View {
37 | RepoListView(
38 | repos: [
39 | .sample, .sample, .sample,
40 | .sample, .sample, .sample,
41 | .sample, .sample, .sample,
42 | ]
43 | )
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/ViewModel/UserViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserViewModel.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/22.
6 | //
7 |
8 | import UIKit
9 |
10 | @MainActor
11 | struct UserViewModel {
12 |
13 | var userObserver: DJObserverable = DJObserverable()
14 |
15 | var userViewer: UserViewer? {
16 | return userObserver.value
17 | }
18 |
19 | func fetchUser(with name: String) async {
20 | if name.isEmpty || ConfigManager.checkOwner(by: name),
21 | let userViewer = ConfigManager.viewer {
22 | userObserver.value = userViewer
23 | }
24 |
25 | Task.detached {
26 | if let viewer = await UserManager.fetchUserInfo(by: name) {
27 | await MainActor.run {
28 | userObserver.value = viewer
29 | if ConfigManager.checkOwner(by: viewer.login) {
30 | LocalUserManager.saveUser(viewer)
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
37 | mutating func update(_ userViewer: UserViewer?) {
38 | userObserver.value = userViewer
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Resources/Data/新鲜事/D-播客.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "t":"weak self",
4 | "id":"https://weakself.dev/"
5 | },
6 | {
7 | "t":"ggtalk",
8 | "id":"https://talk.swift.gg/"
9 | },
10 | {
11 | "t":"Swift by Sundell",
12 | "id":"https://swiftbysundell.com/podcast/"
13 | },
14 | {
15 | "t":"Swift Unwrapped",
16 | "id":"https://swiftunwrapped.github.io/"
17 | },
18 | {
19 | "t":"中文播客榜",
20 | "d":"枫言枫语出品",
21 | "id":"https://xyzrank.com/"
22 | },
23 | {
24 | "t":"乱翻书",
25 | "d":"这是一档关注商业、科技和互联网的从业者对话节目。关心How和Why,以及少有人注意到的What。内容主要方向是科技考古、产品复盘和热点解读,希望能够为你带来信息增量。 「乱翻书」主理人是潘乱,代表作品有《腾讯没有梦想》、字节跳动/快手早期关键节点的系列特写。",
26 | "id":"https://www.xiaoyuzhoufm.com/podcast/61358d971c5d56efe5bcb5d2"
27 | },
28 | {
29 | "t":"漫编室",
30 | "d":"编辑与漫画有关的书籍,思考与漫画有关的困境。 漫编室主编,铁雄。",
31 | "id":"https://www.xiaoyuzhoufm.com/podcast/5fab75d183c34e85dda07f5d"
32 | },
33 | {
34 | "t":"Anyway.FM 设计杂谈",
35 | "d":"由 UI 设计师 JJ Ying 和 Leon Gao 主播的 podcast,主题包括但不限于视觉设计。",
36 | "id":"https://www.xiaoyuzhoufm.com/podcast/5e280faf418a84a0461fba0e"
37 | }
38 | ]
39 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/Default+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Default+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/2.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Bool {
11 | enum False: DefaultValue {
12 | static let defaultValue = false
13 | }
14 | enum True: DefaultValue {
15 | static let defaultValue = true
16 | }
17 | }
18 |
19 | extension Default {
20 | typealias True = Default
21 | typealias False = Default
22 | }
23 |
24 | extension String: DefaultValue {
25 | static let defaultValue = ""
26 |
27 | enum UnProvidedDesc: DefaultValue {
28 | static let defaultValue = "No description provided."
29 | }
30 | enum UnProviedTitle: DefaultValue {
31 | static let defaultValue = "No title provided."
32 | }
33 | enum Company: DefaultValue {
34 | static let defaultValue = "团队"
35 | }
36 | enum Email: DefaultValue {
37 | static let defaultValue = "邮箱"
38 | }
39 | enum Location: DefaultValue {
40 | static let defaultValue = "地点"
41 | }
42 | enum Blog: DefaultValue {
43 | static let defaultValue = "个人主页"
44 | }
45 | enum Now: DefaultValue {
46 | static let defaultValue = DateHelper.standard.dateToString(Date.now)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/DJGithub/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 | UIApplicationSceneManifest
11 |
12 | UIApplicationSupportsMultipleScenes
13 |
14 | UISceneConfigurations
15 |
16 | UIWindowSceneSessionRoleApplication
17 |
18 |
19 | UISceneConfigurationName
20 | Default Configuration
21 | UISceneDelegateClassName
22 | $(PRODUCT_MODULE_NAME).SceneDelegate
23 | UISceneStoryboardFile
24 | Main
25 |
26 |
27 |
28 |
29 | LSApplicationQueriesSchemes
30 |
31 |
32 | sinaweibohd
33 | sinaweibo
34 | sinaweibosso
35 | weibosdk
36 | weibosdk2.5
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/DJGithub/DJFoundation/Protocol/DefaultValue.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DefaultValue.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/2.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol DefaultValue {
11 | associatedtype Value: Codable
12 | static var defaultValue: Value { get }
13 | }
14 |
15 | @propertyWrapper
16 | struct Default {
17 | var wrappedValue: T.Value
18 | }
19 |
20 | extension Default: Decodable {
21 | init(from decoder: Decoder) throws {
22 | let container = try decoder.singleValueContainer()
23 | if let value = try? container.decode(T.Value.self) as? String, value.isEmpty {
24 | wrappedValue = T.defaultValue
25 | } else {
26 | wrappedValue = (try? container.decode(T.Value.self)) ?? T.defaultValue
27 | }
28 | }
29 | }
30 |
31 | extension Default: Encodable {
32 | func encode(to encoder: Encoder) throws {
33 | var container = encoder.singleValueContainer()
34 | try container.encode(wrappedValue)
35 | }
36 | }
37 |
38 | extension KeyedDecodingContainer {
39 | func decode(
40 | _ type: Default.Type,
41 | forKey key: Key
42 | ) throws -> Default where T: DefaultValue {
43 | try decodeIfPresent(type, forKey: key) ?? Default(wrappedValue: T.defaultValue)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/DJGithub/Github/Widget/LanguageGradientView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LanguageGradientView.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/26.
6 | //
7 |
8 | import UIKit
9 |
10 | class LanguageGradientView: UIView {
11 |
12 | private var percent: CGFloat = 0
13 |
14 | var primaryLanguageLayer: CAShapeLayer = {
15 | let layer = CAShapeLayer()
16 | return layer
17 | }()
18 |
19 | init() {
20 | super.init(frame: CGRect.zero)
21 | setUp()
22 | }
23 |
24 | private func setUp() {
25 | backgroundColor = UIColorFromRGB(0xeeeeee)
26 | self.layer.addSublayer(primaryLanguageLayer)
27 | }
28 |
29 | required init?(coder: NSCoder) {
30 | fatalError("init(coder:) has not been implemented")
31 | }
32 |
33 | func render(with primaryLanguage: PrimaryLanguage, language: Repository.RepositotyLanguage) {
34 | guard language.totalSize > 0 else { return }
35 | percent = language.primaryPercent(with: primaryLanguage.name)
36 | primaryLanguageLayer.backgroundColor = primaryLanguage.color.toColor?.cgColor
37 | }
38 |
39 | override func layoutSubviews() {
40 | super.layoutSubviews()
41 |
42 | primaryLanguageLayer.frame = CGRect(x: 0, y: 0, width: percent * self.bounds.width, height: self.bounds.height)
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/UIImage+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/29.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIImage {
11 | static var defaultPersonImage: UIImage? {
12 | return UIImage(named: "person")
13 | }
14 | }
15 |
16 | extension UIImageView {
17 |
18 | func setImage(with url: URL?, placeHolder: UIImage? = nil) {
19 | self.kf.setImage(with: url, placeholder: placeHolder)
20 | }
21 |
22 | func setImage(with urlString: String, placeHolder: UIImage? = nil) {
23 | self.kf.setImage(with: URL(string: urlString), placeholder: placeHolder)
24 | }
25 |
26 | func setImage(with urlString: String?, placeHolder: UIImage? = nil) {
27 | self.kf.setImage(with: URL(string: urlString ?? ""), placeholder: placeHolder)
28 | }
29 |
30 | func setImage(with urlString: String?, placeHolder: UIImage? = nil, completionHandler: @escaping ((UIImage?) -> Void)) {
31 | self.kf.setImage(with: URL(string: urlString ?? ""), placeholder: placeHolder, completionHandler: { result in
32 | switch result {
33 | case .success(let r):
34 | completionHandler(r.image)
35 | case .failure(let error):
36 | print("fetch image error: \(error)")
37 | }
38 | })
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Home/RssFeedItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RssFeedItem.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2023/1/29.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct RssFeedItem: View {
11 |
12 | let item: RssFeedLatestCellModel
13 |
14 | var body: some View {
15 | HStack(alignment: .top) {
16 | VStack(alignment: .leading) {
17 | Text(item.title)
18 | .font(.headline)
19 | .foregroundColor(.textColor)
20 | .lineLimit(2)
21 | .padding(.top, 10)
22 | Spacer()
23 | HStack {
24 | Text(item.from)
25 | .font(.subheadline)
26 | .foregroundColor(.textGrayColor)
27 | .lineLimit(1)
28 | Spacer()
29 | Text(item.date)
30 | .font(.subheadline)
31 | .foregroundColor(.textGrayColor)
32 | }
33 | .padding(5)
34 | }
35 | }
36 | }
37 | }
38 |
39 | struct RssFeedItem_Previews: PreviewProvider {
40 | static var previews: some View {
41 | RssFeedItem(item: RssFeedLatestCellModel.example)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Home/ReposTrendingView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReposTrendingView.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/30.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ReposTrendingView: View {
11 |
12 | let items: [GithubTrendingRepo]
13 |
14 | var body: some View {
15 | ScrollView(.horizontal, showsIndicators: false) {
16 | LazyHStack {
17 | ForEach(0.. = DJObserverable()
13 |
14 | var feeds: Feeds? {
15 | return DJUserDefaults.getFeeds()
16 | }
17 |
18 | func fetchLocalFeedInfo() -> FeedInfo? {
19 | return DJUserDefaults.getFeedInfo()
20 | }
21 |
22 | static func asyncFetchFeedInfo() async -> FeedInfo? {
23 | if let feeds = await asyncFetchFeeds(),
24 | let feedInfo = await FeedManager.fetchFeedInfo(with: "\(feeds.currentUserUrl)&page=1") {
25 | DJUserDefaults.setFeedInfo(with: feedInfo)
26 | return feedInfo
27 | }
28 | return nil
29 | }
30 |
31 | private static func asyncFetchFeeds() async -> Feeds? {
32 | if let feeds = await FeedManager.getFeeds() {
33 | Self.updateLocalFeeds(feeds)
34 | return feeds
35 | } else {
36 | return nil
37 | }
38 | }
39 |
40 | private static func updateLocalFeeds(_ feeds: Feeds?) {
41 | DJUserDefaults.setFeeds(with: feeds)
42 | }
43 |
44 | private func fetchLocalFeeds() -> Feeds? {
45 | return DJUserDefaults.getFeeds()
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/Language.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Language.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/17.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Language: DJCodable {
11 | var id: Int?
12 | var language: String
13 | var hex: String
14 | }
15 |
16 | extension Language: SQLTable {
17 | static var tableName: String {
18 | return "language"
19 | }
20 |
21 | static var fields: [String] {
22 | return [
23 | "language",
24 | "hex"
25 | ]
26 | }
27 |
28 | static var fieldsTypeMapping: [String: FieldType] {
29 | return [
30 | "language": .text,
31 | "hex": .text
32 | ]
33 | }
34 |
35 | var fieldsValueMapping: [String: Any] {
36 | return [
37 | "language": self.language,
38 | "hex": self.hex
39 | ]
40 | }
41 |
42 | static var uniqueKeys: [String] {
43 | return ["id"]
44 | }
45 |
46 | static func get(with language: String) -> Self? {
47 | let values: [Self] = Self.select(with: " where language=\"\(language)\"")
48 | return values.first
49 | }
50 |
51 | func update(with languageName: String, color: String) {
52 | let sql = "update \(Self.tableName) set hex=\"\(color)\" where language=\"\(languageName)\""
53 | try? Self.update(with: sql)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/DJGithub/DJFoundation/Utils/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // utils.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import UIKit
9 |
10 | func UIColorFromRGB(_ rgbValue: UInt, alpha: CGFloat = 1.0) -> UIColor {
11 | return UIColor(
12 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
13 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
14 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
15 | alpha: alpha
16 | )
17 | }
18 |
19 | func isEmpty(by str: String?) -> Bool {
20 | return str == nil || str!.isEmpty
21 | }
22 |
23 | func loadBundleJSONFile(_ filename: String) -> T {
24 | guard let file = Bundle.main.url(forResource: filename, withExtension: "json") else {
25 | fatalError("Couldn't find \(filename) in main bundle.")
26 | }
27 | do {
28 | let decoder = JSONDecoder()
29 | let data = try Data(contentsOf: file)
30 | return try decoder.decode(T.self, from: data)
31 | } catch {
32 | fatalError("load data from \(filename), error: \(error)")
33 | }
34 | }
35 |
36 | func loadBundleData(_ filename: String) -> Data {
37 | let data: Data
38 | guard let file = Bundle.main.url(forResource: filename, withExtension: nil) else {
39 | fatalError("Couldn't find \(filename) in main bundle.")
40 | }
41 | do {
42 | data = try Data(contentsOf: file)
43 | return data
44 | } catch {
45 | fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/JSONSerialization+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JSONSerialization+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/30.
6 | //
7 |
8 | import Foundation
9 |
10 | extension JSONSerialization {
11 |
12 | @discardableResult
13 | static func loadJSON(withFilename filename: String) throws -> T? {
14 | let fm = FileManager.default
15 | let urls = fm.urls(for: .documentDirectory, in: .userDomainMask)
16 | if let url = urls.first {
17 | var fileURL = url.appendingPathComponent(filename)
18 | fileURL = fileURL.appendingPathExtension("json")
19 | let data = try Data(contentsOf: fileURL)
20 | return try DJDecoder(data: data).decode()
21 | }
22 | return nil
23 | }
24 |
25 | @discardableResult
26 | static func save(jsonObject: Any, toFilename filename: String) throws -> Bool {
27 | let fm = FileManager.default
28 | let urls = fm.urls(for: .documentDirectory, in: .userDomainMask)
29 | if let url = urls.first {
30 | var fileURL = url.appendingPathComponent(filename)
31 | fileURL = fileURL.appendingPathExtension("json")
32 | let data = try JSONSerialization.data(withJSONObject: jsonObject, options: [.prettyPrinted])
33 | try data.write(to: fileURL, options: [.atomicWrite])
34 | return true
35 | }
36 |
37 | return false
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/DJGithub/Github/Extension/String+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+Ext.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/16.
6 | //
7 |
8 | import UIKit
9 | import CryptoKit
10 |
11 | extension String {
12 | var toColor: UIColor? {
13 | let hexStr = self.first == "#" ? String(Array(self).dropFirst()) : self
14 | guard let v = UInt(hexStr, radix: 16) else {
15 | return nil
16 | }
17 | return UIColorFromRGB(v)
18 | }
19 |
20 | var md5: String {
21 | guard let data = data(using: .utf8) else { return self }
22 | let hashed = SHA256.hash(data: data)
23 | return hashed.compactMap { String(format: "%02x", $0) }.joined()
24 | }
25 |
26 | var splitRepoFullName: (String, String)? {
27 | let arr = self.components(separatedBy: "/")
28 | return arr.count == 2 ? (arr[0], arr[1]) : nil
29 | }
30 | }
31 |
32 | extension String {
33 |
34 | func asyncBoundingRect(with size: CGSize,
35 | options: NSStringDrawingOptions = [],
36 | attributes: [NSAttributedString.Key: Any]? = nil,
37 | context: NSStringDrawingContext?) -> CGRect? {
38 | let rect = (self as NSString).boundingRect(
39 | with: size,
40 | options: options,
41 | attributes: attributes,
42 | context: context
43 | )
44 | return rect
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Home/ViewModel/HomeViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HomeViewModel.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2024/5/13.
6 | //
7 |
8 | import Foundation
9 |
10 | @Observable
11 | class HomeViewModel {
12 |
13 | var repos: [GithubTrendingRepo] = []
14 | var developers: [GithubTrendingDeveloper] = []
15 | var pamphletModels: [PamphletSectionModel] = []
16 |
17 | static func loadRepos() async -> [GithubTrendingRepo] {
18 | if let repos = GithubTrendingItemsManager.shared.load(with: .repo) as [GithubTrendingRepo]? {
19 | return repos
20 | }
21 |
22 | let type = GithubTrendingType.repo("/swift?since=daily")
23 | let repos: [GithubTrendingRepo] = await GithubTrendingParser(urlString: type.urlString).parse(with: .repo)
24 | return repos
25 | }
26 |
27 | static func loadDevelopers() async -> [GithubTrendingDeveloper] {
28 | if let developers = GithubTrendingItemsManager.shared.load(with: .developer) as [GithubTrendingDeveloper]? {
29 | return developers
30 | }
31 |
32 | let type = GithubTrendingType.developer("/swift?since=daily")
33 | let developers: [GithubTrendingDeveloper] = await GithubTrendingParser(urlString: type.urlString).parse(with: .developer)
34 | return developers
35 | }
36 |
37 | static func loadPamphletModels() async -> [PamphletSectionModel] {
38 | return loadBundleJSONFile("PamphletData")
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/RepoBranchCommit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoBranchCommit.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/27.
6 | //
7 |
8 | import Foundation
9 |
10 | struct RepoBranchCommitInfo: DJCodable {
11 | var commit: RepoBranchCommit
12 | var url: String
13 | var htmlUrl: String
14 | var commentsUrl: String
15 | var stats: RepoBranchCommitStats?
16 |
17 | var files: [RepoPullFile]?
18 | var displayedFiles: [RepoPullFile] {
19 | return files ?? []
20 | }
21 |
22 | var author: RepoBranchCommitInfoUser?
23 | var committer: RepoBranchCommitInfoUser?
24 | }
25 |
26 | struct RepoBranchCommit: DJCodable {
27 | struct RepoBranchCommitAuthor: DJCodable {
28 | var name: String
29 | var email: String?
30 | var date: String
31 | }
32 |
33 | var message: String
34 | var commentCount: Int
35 |
36 | var author: RepoBranchCommitAuthor
37 | var committer: RepoBranchCommitAuthor
38 | }
39 |
40 | extension RepoBranchCommitInfo {
41 | struct RepoBranchCommitInfoUser: DJCodable {
42 | var id: Int
43 | var login: String
44 | var avatarUrl: String
45 | }
46 |
47 | struct RepoBranchCommitStats: DJCodable {
48 | var total: Int
49 | var additions: Int
50 | var deletions: Int
51 | }
52 | }
53 |
54 | struct PullRequestModel: DJCodable {
55 | let title: String
56 | let userName: String
57 | let repoName: String
58 | let base: String
59 | // to use compare userName + branch name,etc: dyljqq:dev
60 | let compare: String
61 | let commiterName: String
62 | }
63 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Developer/View/LocalRepoCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalRepoCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/7.
6 | //
7 |
8 | import UIKit
9 |
10 | class LocalRepoCell: UITableViewCell {
11 |
12 | lazy var titleLabel: UILabel = {
13 | let label = UILabel()
14 | label.textColor = .textColor
15 | label.font = UIFont.systemFont(ofSize: 14)
16 | return label
17 | }()
18 |
19 | lazy var descLabel: UILabel = {
20 | let label = UILabel()
21 | label.textColor = .textGrayColor
22 | label.font = UIFont.systemFont(ofSize: 12)
23 | label.numberOfLines = 0
24 | return label
25 | }()
26 |
27 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
28 | super.init(style: style, reuseIdentifier: reuseIdentifier)
29 |
30 | setUp()
31 | }
32 |
33 | func render(with repo: LocalRepo) {
34 | self.titleLabel.text = repo.id
35 | self.descLabel.text = repo.description
36 | }
37 |
38 | private func setUp() {
39 | contentView.addSubview(titleLabel)
40 | contentView.addSubview(descLabel)
41 |
42 | titleLabel.snp.makeConstraints { make in
43 | make.top.equalTo(10)
44 | make.leading.equalTo(12)
45 | }
46 | descLabel.snp.makeConstraints { make in
47 | make.bottom.equalTo(-10)
48 | make.leading.equalTo(titleLabel)
49 | make.trailing.equalTo(-12)
50 | }
51 | }
52 |
53 | required init?(coder: NSCoder) {
54 | fatalError("init(coder:) has not been implemented")
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/Parse/DateParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateParse.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/10.
6 | //
7 |
8 | import Foundation
9 |
10 | struct DateParser {
11 | let dateFormatter = DateFormatter()
12 |
13 | init(with dateFormat: String) {
14 | dateFormatter.dateFormat = dateFormat
15 | }
16 |
17 | func string(from date: Date) -> String? {
18 | return dateFormatter.string(from: date)
19 | }
20 |
21 | func date(from string: String) -> Date? {
22 | return dateFormatter.date(from: string)
23 | }
24 |
25 | }
26 |
27 | extension Date {
28 | var dateFormatString: String {
29 | let diff = (Date.now.timeIntervalSince1970 - self.timeIntervalSince1970)
30 | if diff < 60 {
31 | return "\(Int(diff)) seconds ago"
32 | } else if diff >= 60 && diff < 3600 {
33 | return "\(Int(diff / 60)) minuts ago"
34 | } else if diff >= 3600 && diff < 24 * 3600 {
35 | return "\(Int(diff / 3600)) hours ago"
36 | } else if diff >= 24 * 3600 && diff <= 24 * 30 * 3600 {
37 | return "\(Int(diff / (24 * 3600))) days ago"
38 | } else if diff >= (24 * 30 * 3600) && diff < (12 * 30 * 24 * 30 * 3600) {
39 | return "\(Int(diff / (30 * 24 * 3600))) months ago"
40 | }
41 | return normalDateParser.string(from: self) ?? ""
42 | }
43 | }
44 |
45 | /**
46 | yyyy-MM-dd'T'HH:mm:ssZ // 24小时制
47 | yyyy-MM-dd'T'hh:mm:ssZ // 12小时制
48 | */
49 | let feedDateParser = DateParser(with: "yyyy-MM-dd'T'HH:mm:ssZ")
50 | let normalDateParser = DateParser(with: "yyyy-MM-dd'T'HH:mm:ssZ")
51 |
--------------------------------------------------------------------------------
/DJGithubUITests/DJGithubUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DJGithubUITests.swift
3 | // DJGithubUITests
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import XCTest
9 |
10 | class DJGithubUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | func testExample() throws {
26 | // UI tests must launch the application that they test.
27 | let app = XCUIApplication()
28 | app.launch()
29 |
30 | // Use XCTAssert and related functions to verify your tests produce the correct results.
31 | }
32 |
33 | func testLaunchPerformance() throws {
34 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
35 | // This measures how long it takes to launch your application.
36 | measure(metrics: [XCTApplicationLaunchMetric()]) {
37 | XCUIApplication().launch()
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/Issue.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Issue.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/4.
6 | //
7 |
8 | import UIKit
9 |
10 | struct IssueItems: DJCodable {
11 | var items: [Issue]
12 | }
13 |
14 | struct IssueLayout {
15 | let issue: Issue
16 | let title: String
17 | var height: CGFloat = 0
18 | var imageName: String = ""
19 |
20 | init(issue: Issue) {
21 | self.issue = issue
22 | self.title = "#\(self.issue.number) - \(self.issue.title)"
23 | }
24 |
25 | @MainActor
26 | mutating func calHeight() {
27 | let rect = (self.title as NSString).boundingRect(
28 | with: CGSize(width: FrameGuide.screenWidth - 45, height: 0),
29 | options: .usesLineFragmentOrigin,
30 | attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14)],
31 | context: nil
32 | )
33 | self.height = rect.height + 41
34 | }
35 | }
36 |
37 | struct Issue: DJCodable {
38 | enum IssueState: String, DJCodable {
39 | case open, closed
40 | }
41 |
42 | struct PullRequest: DJCodable {
43 | var url: String
44 | var htmlUrl: String
45 | var diffUrl: String
46 | }
47 |
48 | var id: Int
49 | var number: Int
50 | var title: String
51 | var state: IssueState
52 | var comments: Int?
53 | var htmlUrl: String
54 |
55 | var createdAt: String
56 | var updatedAt: String
57 |
58 | var user: UserFollowing?
59 | var pullRequest: PullRequest?
60 | }
61 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/SettingViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingViewController.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2023/2/1.
6 | //
7 |
8 | import UIKit
9 | import SwiftUI
10 |
11 | class SettingViewController: UIViewController {
12 |
13 | lazy var vc: UIViewController = {
14 | let settingView = SettingView { [weak self] type in
15 | self?.itemDidSelected(with: type)
16 | }
17 | let vc = UIHostingController(rootView: settingView)
18 | return vc
19 | }()
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 |
24 | view.backgroundColor = .backgroundColor
25 | navigationItem.title = "Setting"
26 |
27 | view.addSubview(vc.view)
28 | vc.view.snp.makeConstraints { make in
29 | make.top.equalTo(FrameGuide.navigationBarAndStatusBarHeight)
30 | make.bottom.leading.trailing.equalToSuperview()
31 | }
32 | }
33 |
34 | func itemDidSelected(with type: SettingType) {
35 | switch type {
36 | case .email: URLRouter.open(with: "mailto: \(type.title)", jumpType: .outside)
37 | case .weibo: URLRouter.open(with: "sinaweibo://userinfo?uid=2579435503", jumpType: .outside)
38 | case .github: URLRouter.open(with: "djgithub://user?name=dyljqq")
39 | case .signUp:
40 | DJUserDefaults.clearViewerInfo()
41 | UIApplication.shared.keyWindow?.rootViewController = LoadingViewerViewController()
42 | default: break
43 | }
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/ImageCoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageCoder.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/24.
6 | //
7 |
8 | import UIKit
9 |
10 | class ImageDecoder {
11 |
12 | static func decode(data: Data, to pointSize: CGSize, scale: CGFloat, completionHandler: @Sendable @escaping (UIImage?) -> Void) {
13 | DispatchQueue.global().async {
14 | let image = downsampledImage(data: data, to: pointSize, scale: scale)
15 | DispatchQueue.main.async {
16 | completionHandler(image)
17 | }
18 | }
19 | }
20 |
21 | static func downsampledImage(data: Data, to pointSize: CGSize, scale: CGFloat) -> UIImage? {
22 | let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
23 | guard let imageSource = CGImageSourceCreateWithData(data as CFData, imageSourceOptions) else {
24 | return nil
25 | }
26 |
27 | let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
28 | let downsampleOptions = [
29 | kCGImageSourceCreateThumbnailFromImageAlways: true,
30 | kCGImageSourceShouldCacheImmediately: true,
31 | kCGImageSourceCreateThumbnailWithTransform: true,
32 | kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
33 | guard let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions) else {
34 | return nil
35 | }
36 | return UIImage(cgImage: downsampledImage)
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/DJGithub.xcodeproj/xcuserdata/polarisdev.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DJGithub.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | SnapKitPlayground (Playground) 1.xcscheme
13 |
14 | isShown
15 |
16 | orderHint
17 | 2
18 |
19 | SnapKitPlayground (Playground) 2.xcscheme
20 |
21 | isShown
22 |
23 | orderHint
24 | 3
25 |
26 | SnapKitPlayground (Playground).xcscheme
27 |
28 | isShown
29 |
30 | orderHint
31 | 1
32 |
33 | SwiftyMarkdown (Playground) 1.xcscheme
34 |
35 | isShown
36 |
37 | orderHint
38 | 5
39 |
40 | SwiftyMarkdown (Playground) 2.xcscheme
41 |
42 | isShown
43 |
44 | orderHint
45 | 6
46 |
47 | SwiftyMarkdown (Playground).xcscheme
48 |
49 | isShown
50 |
51 | orderHint
52 | 4
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Repo/Views/RepoFooterView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoFooterView.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/25.
6 | //
7 |
8 | import UIKit
9 | import WebKit
10 | import MarkdownView
11 |
12 | class RepoFooterView: UIView {
13 |
14 | var fetchHeightClosure: ((CGFloat) -> Void)?
15 | var touchLink: ((URLRequest?) -> Void)?
16 |
17 | lazy var mdView: MarkdownView = {
18 | let mdView = MarkdownView()
19 | mdView.isScrollEnabled = false
20 | return mdView
21 | }()
22 |
23 | init() {
24 | super.init(frame: .zero)
25 |
26 | addSubview(self.mdView)
27 | mdView.snp.makeConstraints { make in
28 | make.edges.equalTo(self)
29 | }
30 |
31 | self.mdView.onRendered = { [weak self] height in
32 | self?.fetchHeightClosure?(height)
33 | }
34 |
35 | self.mdView.onTouchLink = { [weak self] req in
36 | self?.touchLink?(req)
37 | return false
38 | }
39 | }
40 |
41 | func render(with content: String?) {
42 | guard let content = content else { return }
43 | DispatchQueue.global().async {
44 | if let data = NSData(base64Encoded: content, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters) as? Data,
45 | let decodedString = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as? String {
46 | DispatchQueue.main.async {
47 | self.mdView.load(markdown: decodedString, enableImage: true)
48 | }
49 | }
50 | }
51 | }
52 |
53 | required init?(coder: NSCoder) {
54 | super.init(coder: coder)
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/Views/UserInfoCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserInfoCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/8.
6 | //
7 |
8 | import UIKit
9 |
10 | class UserInfoCell: UITableViewCell {
11 |
12 | lazy var nameLabel: UILabel = {
13 | let label = UILabel()
14 | label.textColor = .textGrayColor
15 | label.font = UIFont.systemFont(ofSize: 14)
16 | return label
17 | }()
18 |
19 | lazy var contentLabel: UILabel = {
20 | let label = UILabel()
21 | label.textColor = .textColor
22 | label.font = UIFont.systemFont(ofSize: 14)
23 | label.textAlignment = .left
24 | return label
25 | }()
26 |
27 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
28 | super.init(style: style, reuseIdentifier: reuseIdentifier)
29 |
30 | setUp()
31 | }
32 |
33 | func render(with name: String, content: String?) {
34 | self.nameLabel.text = "\(name):"
35 | self.contentLabel.text = content
36 | }
37 |
38 | private func setUp() {
39 | contentView.addSubview(nameLabel)
40 | contentView.addSubview(contentLabel)
41 |
42 | nameLabel.snp.makeConstraints { make in
43 | make.leading.equalTo(12)
44 | make.centerY.equalToSuperview()
45 | }
46 | contentLabel.snp.makeConstraints { make in
47 | make.trailing.equalTo(-12)
48 | make.leading.equalTo(nameLabel.snp.trailing).offset(10)
49 | make.centerY.equalTo(nameLabel)
50 | }
51 | }
52 |
53 | required init?(coder: NSCoder) {
54 | fatalError("init(coder:) has not been implemented")
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/Views/UserCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/16.
6 | //
7 |
8 | import UIKit
9 |
10 | class UserCell: UITableViewCell {
11 |
12 | lazy var iconImageView: UIImageView = {
13 | let imageView = UIImageView()
14 | return imageView
15 | }()
16 |
17 | lazy var contentLabel: UILabel = {
18 | let label = UILabel()
19 | label.textColor = .textColor
20 | label.font = UIFont.systemFont(ofSize: 14)
21 | return label
22 | }()
23 |
24 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
25 | super.init(style: style, reuseIdentifier: reuseIdentifier)
26 |
27 | setUp()
28 | }
29 |
30 | func setUp() {
31 | contentView.addSubview(iconImageView)
32 | contentView.addSubview(contentLabel)
33 |
34 | iconImageView.snp.makeConstraints { make in
35 | make.leading.equalTo(12)
36 | make.centerY.equalTo(contentView)
37 | make.width.height.equalTo(20)
38 | }
39 | contentLabel.snp.makeConstraints { make in
40 | make.centerY.equalTo(iconImageView)
41 | make.leading.equalTo(iconImageView.snp.trailing).offset(10)
42 | make.trailing.equalTo(-12)
43 | }
44 | }
45 |
46 | func render(with iconName: String, content: String, contentColor: UIColor) {
47 | iconImageView.image = UIImage(named: iconName)
48 | contentLabel.text = content
49 | contentLabel.textColor = contentColor
50 | }
51 |
52 | required init?(coder: NSCoder) {
53 | fatalError("init(coder:) has not been implemented")
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/DJGithub/Github/Widget/NavigationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Navigation.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/24.
6 | //
7 |
8 | import UIKit
9 |
10 | class NavigationController: UINavigationController {
11 |
12 | override init(rootViewController: UIViewController) {
13 | super.init(rootViewController: rootViewController)
14 | }
15 |
16 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
17 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
18 | }
19 |
20 | required init?(coder aDecoder: NSCoder) {
21 | fatalError("init(coder:) has not been implemented")
22 | }
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 |
27 | let backButtonAppearance = UIBarButtonItemAppearance(style: .plain)
28 | backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear]
29 |
30 | let barApp = UINavigationBarAppearance()
31 | barApp.backgroundEffect = UIBlurEffect(style: .regular)
32 | barApp.backButtonAppearance = backButtonAppearance
33 | navigationBar.scrollEdgeAppearance = barApp
34 |
35 | let barAppearace = UIBarButtonItem.appearance()
36 | barAppearace.setBackButtonTitlePositionAdjustment(UIOffset(horizontal: 0, vertical: -60), for: UIBarMetrics.default)
37 |
38 | }
39 |
40 | override func pushViewController(_ viewController: UIViewController, animated: Bool) {
41 | if self.children.count == 1 {
42 | viewController.hidesBottomBarWhenPushed = true
43 | }
44 | super.pushViewController(viewController, animated: animated)
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/DJGithub/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class MyApp {
12 | static func main() {
13 | UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))
14 | }
15 | }
16 |
17 | class AppDelegate: UIResponder, UIApplicationDelegate {
18 |
19 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
20 | return true
21 | }
22 |
23 | // MARK: UISceneSession Lifecycle
24 |
25 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
26 | // Called when a new scene session is being created.
27 | // Use this method to select a configuration to create the new scene with.
28 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
29 | }
30 |
31 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
32 | // Called when the user discards a scene session.
33 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
34 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
35 | }
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Repo/Views/RepoBranchCommitFileCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepoBranchCommitFileCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/28.
6 | //
7 |
8 | import UIKit
9 |
10 | class RepoBranchCommitFileCell: UITableViewCell {
11 |
12 | lazy var titleLabel: UILabel = {
13 | let label = UILabel()
14 | label.textColor = .textColor
15 | label.font = UIFont.systemFont(ofSize: 14)
16 | return label
17 | }()
18 |
19 | lazy var descLabel: UILabel = {
20 | let label = UILabel()
21 | label.font = UIFont.systemFont(ofSize: 14)
22 | label.textColor = .textGrayColor
23 | return label
24 | }()
25 |
26 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
27 | super.init(style: style, reuseIdentifier: reuseIdentifier)
28 |
29 | setUp()
30 | }
31 |
32 | func render(with file: RepoPullFile) {
33 | titleLabel.text = file.filename
34 | descLabel.text = "\(file.additions) additions and \(file.deletions) deletions."
35 | }
36 |
37 | private func setUp() {
38 | contentView.addSubview(titleLabel)
39 | contentView.addSubview(descLabel)
40 |
41 | titleLabel.snp.makeConstraints { make in
42 | make.leading.equalTo(12)
43 | make.trailing.equalTo(-12)
44 | make.top.equalTo(10)
45 | }
46 | descLabel.snp.makeConstraints { make in
47 | make.leading.trailing.equalTo(titleLabel)
48 | make.top.equalTo(titleLabel.snp.bottom).offset(10)
49 | }
50 | }
51 |
52 | required init?(coder: NSCoder) {
53 | fatalError("init(coder:) has not been implemented")
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/View/PamphletResourceCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PamphletResourceCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/20.
6 | //
7 |
8 | import UIKit
9 |
10 | class PamphletResourceCell: UITableViewCell {
11 |
12 | lazy var titleLabel: UILabel = {
13 | let label = UILabel()
14 | label.textColor = .textColor
15 | label.font = UIFont.systemFont(ofSize: 14)
16 | label.numberOfLines = 0
17 | return label
18 | }()
19 |
20 | lazy var contentLabel: UILabel = {
21 | let label = UILabel()
22 | label.font = UIFont.systemFont(ofSize: 12)
23 | label.textColor = .textGrayColor
24 | label.numberOfLines = 0
25 | return label
26 | }()
27 |
28 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
29 | super.init(style: style, reuseIdentifier: reuseIdentifier)
30 |
31 | setUp()
32 | }
33 |
34 | func render(with model: PamphletResourceModel) {
35 | titleLabel.text = model.title
36 | contentLabel.text = model.desc
37 | }
38 |
39 | private func setUp() {
40 | contentView.addSubview(titleLabel)
41 | contentView.addSubview(contentLabel)
42 |
43 | titleLabel.snp.makeConstraints { make in
44 | make.leading.equalTo(12)
45 | make.trailing.equalTo(-12)
46 | make.top.equalTo(10)
47 | }
48 | contentLabel.snp.makeConstraints { make in
49 | make.leading.equalTo(12)
50 | make.trailing.equalTo(-12)
51 | make.bottom.equalTo(-10)
52 | }
53 | }
54 |
55 | required init?(coder: NSCoder) {
56 | fatalError("init(coder:) has not been implemented")
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/LanguageManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LanguageManager.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/17.
6 | //
7 |
8 | import UIKit
9 | import CoreData
10 |
11 | class LanguageManager {
12 |
13 | nonisolated(unsafe) static var mapping: [String: String] = [:]
14 |
15 | init() {
16 | try? Language.createTable()
17 | }
18 |
19 | static func save(_ languages: [Language]) async {
20 | Task {
21 | for language in languages {
22 | if Language.get(with: language.language) == nil {
23 | try? language.insert()
24 | }
25 | }
26 | await loadLanguageMapping()
27 | }
28 | }
29 |
30 | static func loadLanguageMapping() async {
31 | var rs = [String: String]()
32 | let languages: [Language] = Language.selectAll()
33 | for language in languages {
34 | rs[language.language] = language.hex
35 | }
36 | LanguageManager.mapping = rs
37 | }
38 |
39 | static func save(with languageName: String, color: String) async {
40 | var col = color
41 | if color.hasPrefix("#") {
42 | col = String(color.dropFirst())
43 | }
44 | if let lang = Language.get(with: languageName) {
45 | if col != lang.hex {
46 | lang.update(with: languageName, color: col)
47 | }
48 | } else {
49 | try? Language(language: languageName, hex: col).insert()
50 | }
51 | mapping[languageName] = color
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/DJGithub/LoadingViewerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import UIKit
9 |
10 | class LoadingViewerViewController: UIViewController {
11 |
12 | private let manager = AuthorizationViewManager()
13 |
14 | lazy var authorizationViewController: UIViewController = {
15 | return manager.addAuthorizationView { [weak self] isSucess in
16 | guard let strongSelf = self else { return }
17 | strongSelf.loadData(isSucess)
18 | }
19 | }()
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 | view.backgroundColor = .backgroundColor
24 |
25 | view.addSubview(authorizationViewController.view)
26 | authorizationViewController.view.snp.makeConstraints { make in
27 | make.edges.equalToSuperview()
28 | }
29 | }
30 |
31 | private func loadData(_ isSuccess: Bool) {
32 | guard isSuccess else {
33 | HUD.show(with: "Error to load viewer info.")
34 | return
35 | }
36 | UIApplication.shared.keyWindow?.rootViewController = TabBarController(nibName: nil, bundle: nil)
37 |
38 | Task {
39 | await withThrowingTaskGroup(of: Void.self) { group in
40 | group.addTask {
41 | await DeveloperGroupManager.shared.updateAll()
42 | }
43 | group.addTask {
44 | await UserFollowingManager.shared.fetchUserFollowingStatus()
45 | }
46 | }
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Resources/Data/Swift/D-SwiftUI.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "t":"SwiftUI by Example - free quick start tutorials for Swift developers",
4 | "id":"https://www.hackingwithswift.com/quick-start/swiftui"
5 | },
6 | {
7 | "t":"Advanced SwiftUI Animations – Part 1: Paths",
8 | "id":"https://swiftui-lab.com/swiftui-animations-part1/"
9 | },
10 | {
11 | "t":"【中文翻译】高级 SwiftUI 动画 — Part 1:Paths",
12 | "id":"https://mp.weixin.qq.com/s/5KinQfNtcovf_451UGwLQQ"
13 | },
14 | {
15 | "t":"Advanced SwiftUI Animations – Part 2: GeometryEffect",
16 | "id":"https://swiftui-lab.com/swiftui-animations-part2/"
17 | },
18 | {
19 | "t":"【中文翻译】高级 SwiftUI 动画 — Part 2:GeometryEffect",
20 | "id":"https://mp.weixin.qq.com/s/rE_HILLt-uxzScS7wXh5jw"
21 | },
22 | {
23 | "t":"Advanced SwiftUI Animations - Part 3: AnimatableModifier",
24 | "id":"https://swiftui-lab.com/swiftui-animations-part3/"
25 | },
26 | {
27 | "t":"【中文翻译】高级 SwiftUI 动画 — Part 3:AnimatableModifier",
28 | "id":"https://mp.weixin.qq.com/s/M6MW3idXS6jZJtl4Mz5DGQ"
29 | },
30 | {
31 | "t":"Advanced SwiftUI Animations — Part 4: TimelineView",
32 | "id":"https://swiftui-lab.com/swiftui-animations-part4/"
33 | },
34 | {
35 | "t":"【中文翻译】SwiftUI 动画进阶 — Part4:TimelineView",
36 | "id":"https://mp.weixin.qq.com/s/9OBtFNb5ddnx4_fS93Mnrg"
37 | },
38 | {
39 | "t":"Advanced SwiftUI Animations – Part 5: Canvas",
40 | "id":"https://swiftui-lab.com/swiftui-animations-part5/"
41 | }
42 | ]
43 |
--------------------------------------------------------------------------------
/DJGithub/Github/AppStyle/AppStyleUtility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppStyleMaskView.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/30.
6 | //
7 |
8 | import UIKit
9 |
10 | @MainActor
11 | struct AppStyleUtility {
12 |
13 | static let shared = AppStyleUtility()
14 |
15 | let tag = 8888
16 |
17 | var coverViews: [UIView] = []
18 |
19 | func open(with style: AppStyle) {
20 | guard let window = UIApplication.shared.keyWindow else { return }
21 | blendAppStyle(with: style, for: window)
22 | }
23 |
24 | func close() {
25 | guard let window = UIApplication.shared.keyWindow else { return }
26 | for subview in window.subviews {
27 | if subview.tag == tag {
28 | subview.removeFromSuperview()
29 | }
30 | }
31 | }
32 |
33 | private func blendAppStyle(with style: AppStyle, for maskView: UIView) {
34 | guard #available(iOS 13.0, *), !hasBlended(with: maskView) else { return }
35 |
36 | let view = UIView(frame: maskView.bounds)
37 | view.isUserInteractionEnabled = false
38 | view.backgroundColor = style.color
39 | view.layer.compositingFilter = "saturationBlendMode"
40 | view.layer.zPosition = CGFloat.greatestFiniteMagnitude
41 | maskView.addSubview(view)
42 | }
43 |
44 | private func hasBlended(with maskView: UIView) -> Bool {
45 | for subView in maskView.subviews {
46 | if subView.tag == tag {
47 | return true
48 | }
49 | }
50 | return false
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/UserViewer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserViewer.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/25.
6 | //
7 |
8 | import Foundation
9 |
10 | struct UserViewer: DJCodable {
11 | var name: String?
12 | var login: String
13 | var avatarUrl: String
14 |
15 | @Default var websiteUrl: String
16 | @Default var bio: String
17 | @Default var company: String
18 | @Default var location: String
19 | @Default var email: String
20 |
21 | var createdAt: String
22 |
23 | @Default var viewerCanFollow: Bool
24 | @Default var viewerIsFollowing: Bool
25 | @Default var isViewer: Bool
26 |
27 | var following: TotalCountModel
28 | var followers: TotalCountModel
29 | var starredRepositories: TotalCountModel
30 | var repositories: TotalCountModel
31 |
32 | var pinnedItems: PinnedRepos
33 | var userContribution: UserContribution?
34 | }
35 |
36 | struct PinnedRepos: DJCodable {
37 | var nodes: [PinnedRepoNode]
38 | }
39 |
40 | struct PinnedRepoNode: DJCodable {
41 | var name: String
42 | var nameWithOwner: String
43 | var description: String?
44 | var viewerHasStarred: Bool
45 | var owner: PinnedRepoNodeOwner
46 | var stargazers: TotalCountModel
47 | var primaryLanguage: PrimaryLanguage?
48 | }
49 |
50 | extension PinnedRepoNode {
51 | struct PinnedRepoNodeOwner: DJCodable {
52 | var avatarUrl: String
53 | }
54 | }
55 |
56 | struct PrimaryLanguage: DJCodable {
57 | var name: String
58 | var color: String
59 | }
60 |
61 | struct TotalCountModel: DJCodable {
62 | var totalCount: Int
63 | }
64 |
--------------------------------------------------------------------------------
/DJGithub/Github/Utils/GithubTrending/GithubTrendingItemsManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubTrendingItemsManager.swift
3 | // DJGithub
4 | //
5 | // Created by polaris dev on 2023/1/30.
6 | //
7 |
8 | import Foundation
9 |
10 | struct GithubTrendingItemsManager {
11 | static let shared = GithubTrendingItemsManager()
12 |
13 | func load(with type: TrendingType) -> T? {
14 | do {
15 | return try JSONSerialization.loadJSON(withFilename: type.filename)
16 | } catch {
17 | print("Error to load data: \(error)")
18 | }
19 | return nil
20 | }
21 |
22 | func save(with type: TrendingType, items: [T]) {
23 | guard let dict = DJEncoder(model: items).encode() else { return }
24 | do {
25 | try JSONSerialization.save(jsonObject: dict, toFilename: type.filename)
26 | } catch {
27 | print("Error to save file: \(error)")
28 | }
29 | }
30 |
31 | }
32 |
33 | extension GithubTrendingItemsManager {
34 | enum TrendingType {
35 | case repo
36 | case developer
37 |
38 | var dirName: String {
39 | return "GithubTrending"
40 | }
41 |
42 | var filename: String {
43 | switch self {
44 | case .repo: return "repo"
45 | case .developer: return "developer"
46 | }
47 | }
48 |
49 | var filePath: URL? {
50 | guard let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil }
51 | return documentURL.appendingPathComponent(filename, isDirectory: false)
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Resources/lib-Concurrency.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "sectionName":"介绍",
4 | "id":2111231520,
5 | "issues":[
6 | {
7 | "id":2111231521,
8 | "title":"Swift Concurrency 是什么?",
9 | "number":63
10 | },
11 | {
12 | "id":2111231524,
13 | "title":"async/await",
14 | "number":64
15 | },
16 | {
17 | "id":2111231526,
18 | "title":"Async Sequences",
19 | "number":65
20 | },
21 | {
22 | "id":2111231528,
23 | "title":"结构化并发",
24 | "number":66
25 | },
26 | {
27 | "id":2111231530,
28 | "title":"Actors",
29 | "number":67
30 | },
31 | {
32 | "id":2206271528,
33 | "title":"Distributed Actors",
34 | "number":178
35 | },
36 | {
37 | "id":2111231532,
38 | "title":"相关提案",
39 | "number":68
40 | },
41 | {
42 | "id":2111231533,
43 | "title":"学习路径",
44 | "number":69
45 | },
46 | {
47 | "id":2111231534,
48 | "title":"Swift Concurrency 和 Combine",
49 | "number":70
50 | },
51 | {
52 | "id":2206271523,
53 | "title":"Concurrency 5.7 版本更新",
54 | "number":177
55 | }
56 | ]
57 | }
58 | ]
59 |
--------------------------------------------------------------------------------
/DJGithub/DJFoundation/Utils/DJParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DJParser.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/15.
6 | //
7 |
8 | import Foundation
9 |
10 | struct DJDecoder {
11 | let decoder = JSONDecoder()
12 |
13 | private var data: Data?
14 |
15 | init(dict: [String: Any]) {
16 | let data = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
17 | self.init(data: data)
18 | }
19 |
20 | init(data: Data?) {
21 | self.data = data
22 | decoder.keyDecodingStrategy = .convertFromSnakeCase
23 | }
24 |
25 | init(value: Any) {
26 | let data = try? JSONSerialization.data(withJSONObject: value)
27 | self.init(data: data)
28 | }
29 |
30 | func decode() throws -> T? {
31 | guard let data = data else { return nil }
32 | do {
33 | return try decoder.decode(T.self, from: data)
34 | } catch {
35 | throw DJError.parseError("\(error)")
36 | }
37 | }
38 | }
39 |
40 | struct DJEncoder {
41 | let encoder = JSONEncoder()
42 |
43 | let model: T?
44 |
45 | init(model: T?) {
46 | self.model = model
47 | encoder.keyEncodingStrategy = .convertToSnakeCase
48 | }
49 |
50 | func encode() -> Any? {
51 | guard let model = model else { return nil }
52 | do {
53 | let data = try encoder.encode(model)
54 | return try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed)
55 | } catch {
56 | print("JDEncode Error: \(error)")
57 | }
58 | return nil
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/DJGithub/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/Search/Views/SearchWordHeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SearchWordHeaderView.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/10/3.
6 | //
7 |
8 | import UIKit
9 |
10 | class SearchWordHeaderView: UIView {
11 |
12 | var eraseClosure: (() -> Void)?
13 |
14 | lazy var titleLabel: UILabel = {
15 | let label = UILabel()
16 | label.text = "History search words"
17 | label.textColor = .black
18 | label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
19 | return label
20 | }()
21 |
22 | lazy var eraseImageView: UIImageView = {
23 | let imageView = UIImageView()
24 | imageView.image = ImageDecoder.downsampledImage(
25 | data: UIImage(named: "icons-erase")!.pngData()!, to: CGSize(width: 25, height: 25), scale: 1)
26 | imageView.isUserInteractionEnabled = true
27 | let tap = UITapGestureRecognizer(target: self, action: #selector(eraseAction))
28 | imageView.addGestureRecognizer(tap)
29 | return imageView
30 | }()
31 |
32 | init() {
33 | super.init(frame: .zero)
34 |
35 | setUp()
36 | }
37 |
38 | @objc func eraseAction() {
39 | eraseClosure?()
40 | }
41 |
42 | private func setUp() {
43 | addSubview(titleLabel)
44 | addSubview(eraseImageView)
45 | titleLabel.snp.makeConstraints { make in
46 | make.centerY.equalTo(self)
47 | make.leading.equalTo(12)
48 | }
49 | eraseImageView.snp.makeConstraints { make in
50 | make.centerY.equalTo(self)
51 | make.trailing.equalTo(-13)
52 | make.width.height.equalTo(25)
53 | }
54 | }
55 |
56 | required init?(coder: NSCoder) {
57 | fatalError("init(coder:) has not been implemented")
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/DJGithub/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/DJGithub/Github/Model/Repo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Repo.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/9/16.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Repo: DJCodable {
11 | var name: String
12 | var fullName: String
13 | var forksCount: Int
14 | var stargazersCount: Int
15 | var watchersCount: Int
16 | var openIssuesCount: Int
17 | var size: Int
18 | var description: String?
19 | var updatedAt: String
20 | var language: String?
21 | var defaultBranch: String?
22 |
23 | var owner: RepoOwner?
24 | var license: License?
25 |
26 | var desc: String {
27 | return self.description ?? "No description provided."
28 | }
29 | }
30 |
31 | extension Repo {
32 | var id: UUID {
33 | return UUID()
34 | }
35 | }
36 |
37 | struct RepoOwner: DJCodable {
38 | var avatarUrl: String
39 | var id: Int
40 | var login: String
41 | var type: String
42 | }
43 |
44 | struct License: DJCodable {
45 | var name: String
46 | var key: String
47 | var url: String?
48 | var spdxId: String?
49 |
50 | var licenseKey: String {
51 | return self.spdxId ?? self.key
52 | }
53 | }
54 |
55 | extension Repo {
56 | #if DEBUG
57 | static let sample = Repo(
58 | name: "DJGithub",
59 | fullName: "dyljqq/DJGithub",
60 | forksCount: 10,
61 | stargazersCount: 15,
62 | watchersCount: 3,
63 | openIssuesCount: 200,
64 | size: 10,
65 | updatedAt: "2023-02-17",
66 | language: "Swift",
67 | owner: repoOwner
68 | )
69 |
70 | static let repoOwner = RepoOwner(
71 | avatarUrl: "https://avatars.githubusercontent.com/u/8120438?v=4",
72 | id: 1,
73 | login: "dyljqq",
74 | type: "User"
75 | )
76 |
77 | #endif
78 | }
79 |
--------------------------------------------------------------------------------
/DJGithub.xcodeproj/xcuserdata/jiqinqiang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
21 |
22 |
23 |
25 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/DJGithub/Github/Widget/AvatarImageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AvatarImageView.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/10.
6 | //
7 |
8 | import UIKit
9 |
10 | class AvatarImageView: UIImageView {
11 |
12 | struct AvatarModel {
13 | let imageUrl: String?
14 | let placeholder: UIImage?
15 | let userName: String?
16 |
17 | init(imageUrl: String?, placeholder: UIImage? = nil, userName: String?) {
18 | self.imageUrl = imageUrl
19 | self.placeholder = placeholder
20 | self.userName = userName
21 | }
22 | }
23 |
24 | private var model: AvatarModel?
25 |
26 | init() {
27 | super.init(frame: .zero)
28 | setUp()
29 | }
30 |
31 | func render(with model: AvatarModel) {
32 | self.model = model
33 | self.setImage(with: model.imageUrl, placeHolder: model.placeholder)
34 | }
35 |
36 | @objc func jumpAction() {
37 | jumpToUserViewController(with: model?.userName)
38 | }
39 |
40 | private func setUp() {
41 | let tap = UITapGestureRecognizer(target: self, action: #selector(jumpAction))
42 | self.isUserInteractionEnabled = true
43 | self.addGestureRecognizer(tap)
44 | }
45 |
46 | required init?(coder: NSCoder) {
47 | fatalError("init(coder:) has not been implemented")
48 | }
49 |
50 | }
51 |
52 | extension AvatarImageView {
53 | fileprivate func jumpToUserViewController(with userName: String?) {
54 | guard let userName = userName, !userName.isEmpty else { return }
55 | var next = self.next
56 | while next != nil {
57 | if let vc = next as? UIViewController {
58 | if let navi = vc.navigationController {
59 | navi.pushToUser(with: userName)
60 | }
61 | return
62 | }
63 | next = next?.next
64 | }
65 | return
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/Resources/Data/Swift/D-Swift 技术.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "t":"Auto-generated documentation for Swift. Command-click no more.",
4 | "d":"自动生成的 Swift 文档",
5 | "id":"https://swiftdoc.org/"
6 | },
7 | {
8 | "t":"Swift 5.1 Cheat Sheet and Quick Reference",
9 | "id":"https://www.raywenderlich.com/6362977-swift-5-1-cheat-sheet-and-quick-reference"
10 | },
11 | {
12 | "t":"Learn swift in Y Minutes",
13 | "d":"快速学习 Swift",
14 | "id":"https://learnxinyminutes.com/docs/swift/"
15 | },
16 | {
17 | "t":"Stanford University's course CS193p (Developing Applications for iOS using SwiftUI)",
18 | "d":"著名斯坦福 iOS 教程",
19 | "id":"https://cs193p.sites.stanford.edu/"
20 | },
21 | {
22 | "t":"Preface · Beginning iOS Programming with Swift and SwiftUI (iOS 15) - Sample",
23 | "d":"从零到上架",
24 | "id":"https://www.appcoda.com/learnswift/"
25 | },
26 | {
27 | "t":"Discover The Standard Library on Swift by Sundell",
28 | "d":"探索标准库",
29 | "id":"https://www.swiftbysundell.com/discover/standard-library/"
30 | },
31 | {
32 | "t":"100 Days of Swift – Hacking with Swift",
33 | "id":"https://www.hackingwithswift.com/100"
34 | },
35 | {
36 | "t":"Swift Open-Source Projects",
37 | "d":"Discover trending Swift open-source projects",
38 | "id":"https://www.libhunt.com/l/swift"
39 | },
40 | {
41 | "t":"iOS Example",
42 | "d":"A nice collection of often useful examples done in Objective-C and Swift.",
43 | "id":"https://iosexample.com/"
44 | },
45 | {
46 | "t":"Custom Controls for iOS, iPadOS, macOS, tvOS, and watchOS - Cocoa Controls",
47 | "id":"https://www.cocoacontrols.com/"
48 | }
49 | ]
50 |
--------------------------------------------------------------------------------
/DJGithub/Github/ViewController/User/SettingView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingView.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2023/1/31.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct SettingRow: View {
11 | let type: SettingType
12 |
13 | @State var isSync: Bool = false
14 |
15 | var body: some View {
16 | HStack {
17 | switch type {
18 | case .signUp:
19 | signUp
20 | case .iCloud:
21 | Text(type.title)
22 | Spacer()
23 | Toggle("sync to iCloud", isOn: $isSync)
24 | default:
25 | Text(type.title)
26 | Spacer()
27 | if let image = UIImage(named: type.iconName) {
28 | Image(uiImage: image)
29 | .resizable()
30 | .frame(width: 20, height: 20)
31 | }
32 | }
33 | }
34 | }
35 |
36 | var signUp: some View {
37 | Text(type.title)
38 | .font(.system(size: 18))
39 | .foregroundColor(.blue)
40 | }
41 |
42 | }
43 |
44 | struct SettingView: View {
45 |
46 | @State var setting = Setting()
47 |
48 | var itemDidSelectedClosure: (SettingType) -> Void
49 |
50 | var body: some View {
51 | List {
52 | ForEach(setting.dataSource, id: \.id) { section in
53 | Section(section.name) {
54 | ForEach(0.. SQLiteDatabase? {
13 | let db: SQLiteDatabase?
14 | do {
15 | let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
16 | .appendingPathComponent("github.sqlite")
17 | db = try SQLiteDatabase.open(path: fileURL.path)
18 | print("Successfully opened connection to database.")
19 | } catch {
20 | print("Unable to open database.")
21 | db = nil
22 | }
23 |
24 | return db
25 | }
26 |
27 | class ConfigManager: @unchecked Sendable {
28 |
29 | static let shared = ConfigManager()
30 | var config: Config = Config()
31 |
32 | let rssFeedManager = RssFeedManager.shared
33 | let languageManager = LanguageManager()
34 |
35 | static var viewer: UserViewer? {
36 | return LocalUserManager.getUser()
37 | }
38 |
39 | var viewerName: String {
40 | return ConfigManager.viewer?.login ?? LocalUserManager.getViewerName()
41 | }
42 |
43 | static var isLoadedViewer: Bool {
44 | return !LocalUserManager.getViewerName().isEmpty
45 | }
46 |
47 | func load() {
48 | loadConfig()
49 | }
50 |
51 | func loadConfig(completionHandler: ((Config) -> Void)? = nil) {
52 | config = loadBundleJSONFile("config")
53 | }
54 |
55 | static func checkOwner(by userName: String) -> Bool {
56 | if let viewer = viewer {
57 | return viewer.login == userName
58 | }
59 | return userName == ConfigManager.shared.config.userName
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/DJGithub/Pamphlet/View/PamphletSimpleCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PamphletSimpleCell.swift
3 | // DJGithub
4 | //
5 | // Created by jiqinqiang on 2022/11/20.
6 | //
7 |
8 | import UIKit
9 |
10 | class PamphletSimpleCell: UITableViewCell {
11 |
12 | lazy var titleLabel: UILabel = {
13 | let label = UILabel()
14 | label.textColor = .textColor
15 | label.font = UIFont.systemFont(ofSize: 14)
16 | return label
17 | }()
18 |
19 | lazy var iconImageView: UIImageView = {
20 | let imageView = UIImageView()
21 | return imageView
22 | }()
23 |
24 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
25 | super.init(style: style, reuseIdentifier: reuseIdentifier)
26 |
27 | setUp()
28 | }
29 |
30 | func render(with model: PamphletViewController.SectionItemModel?) {
31 | guard let model else { return }
32 | if let imageName = model.imageName, !imageName.isEmpty {
33 | iconImageView.image = UIImage(named: imageName)
34 | titleLabel.snp.updateConstraints { make in
35 | make.leading.equalTo(52)
36 | }
37 | } else {
38 | titleLabel.snp.updateConstraints { make in
39 | make.leading.equalTo(12)
40 | }
41 | }
42 | titleLabel.text = model.title
43 | }
44 |
45 | private func setUp() {
46 | contentView.backgroundColor = .white
47 |
48 | contentView.addSubview(titleLabel)
49 | contentView.addSubview(iconImageView)
50 |
51 | iconImageView.snp.makeConstraints { make in
52 | make.centerY.equalToSuperview()
53 | make.leading.equalTo(12)
54 | make.width.height.equalTo(30)
55 | }
56 | titleLabel.snp.makeConstraints { make in
57 | make.leading.equalTo(52)
58 | make.trailing.equalToSuperview().offset(-12)
59 | make.centerY.equalTo(iconImageView)
60 | }
61 | }
62 |
63 | required init?(coder: NSCoder) {
64 | fatalError("init(coder:) has not been implemented")
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------