├── Twidere ├── Resources │ └── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ ├── iPad.png │ │ ├── iPad@2x.png │ │ ├── iPadPro@2x.png │ │ ├── iPhone@2x.png │ │ ├── iPhone@3x.png │ │ └── Contents.json │ │ ├── Toolbar Send.imageset │ │ ├── Toolbar Send.pdf │ │ └── Contents.json │ │ ├── Button Follow.imageset │ │ ├── Button Follow.pdf │ │ └── Contents.json │ │ ├── Tab Icon Home.imageset │ │ ├── Tab Icon Home.pdf │ │ └── Contents.json │ │ ├── Tab Icon User.imageset │ │ ├── Tab Icon User.pdf │ │ └── Contents.json │ │ ├── Text Icon Web.imageset │ │ ├── Text Icon Web.pdf │ │ └── Contents.json │ │ ├── Grid Item Edit.imageset │ │ ├── Grid Item Edit.pdf │ │ └── Contents.json │ │ ├── Text Icon Link.imageset │ │ ├── Text Icon Link.pdf │ │ └── Contents.json │ │ ├── Text Icon Time.imageset │ │ ├── Text Icon Time.pdf │ │ └── Contents.json │ │ ├── Toolbar Camera.imageset │ │ ├── Toolbar Camera.pdf │ │ └── Contents.json │ │ ├── Grid Item Remove.imageset │ │ ├── Grid Item Remove.pdf │ │ └── Contents.json │ │ ├── Tab Icon Message.imageset │ │ ├── Tab Icon Message.pdf │ │ └── Contents.json │ │ ├── Toolbar Location.imageset │ │ ├── Toolbar Location.pdf │ │ └── Contents.json │ │ ├── Toolbar Settings.imageset │ │ ├── Toolbar Settings.pdf │ │ └── Contents.json │ │ ├── Button Action More.imageset │ │ ├── Button Action More.pdf │ │ └── Contents.json │ │ ├── Button Action Star.imageset │ │ ├── Button Action Star.pdf │ │ └── Contents.json │ │ ├── Button Follow Edit.imageset │ │ ├── Button Follow Edit.pdf │ │ └── Contents.json │ │ ├── NavBar Button Back.imageset │ │ ├── NavBar Button Back.pdf │ │ └── Contents.json │ │ ├── Text Icon Location.imageset │ │ ├── Text Icon Location.pdf │ │ └── Contents.json │ │ ├── Button Action Reply.imageset │ │ ├── Button Action Reply.pdf │ │ └── Contents.json │ │ ├── Button Action Share.imageset │ │ ├── Button Action Share.pdf │ │ └── Contents.json │ │ ├── Button Follow Block.imageset │ │ ├── Button Follow Block.pdf │ │ └── Contents.json │ │ ├── Button Follow Empty.imageset │ │ ├── Button Follow Empty.pdf │ │ └── Contents.json │ │ ├── Button Follow Mutual.imageset │ │ ├── Button Follow Mutual.pdf │ │ └── Contents.json │ │ ├── Button Action Retweet.imageset │ │ ├── Button Action Retweet.pdf │ │ └── Contents.json │ │ ├── Button Follow Pending.imageset │ │ ├── Button Follow Pending.pdf │ │ └── Contents.json │ │ ├── Profile Image Default.imageset │ │ ├── Profile Image Default.pdf │ │ └── Contents.json │ │ ├── Tab Icon Notification.imageset │ │ ├── Tab Icon Notification.pdf │ │ └── Contents.json │ │ ├── Button Follow Incoming.imageset │ │ ├── Button Follow Incoming.pdf │ │ └── Contents.json │ │ ├── Button Follow Outgoing.imageset │ │ ├── Button Follow Outgoing.pdf │ │ └── Contents.json │ │ ├── Toolbar Status Compose.imageset │ │ ├── Toolbar Status Compose.pdf │ │ └── Contents.json │ │ └── Toolbar Location Outline.imageset │ │ ├── Toolbar Location Outline.pdf │ │ └── Contents.json └── Sources │ ├── Twidere-Bridging-Header.h │ ├── Extensions │ ├── UserKey+MicroBlog.swift │ ├── UIImageViewExtension.swift │ ├── KotlinLike.swift │ ├── YYText+ALSLayouts.swift │ ├── CoreLocationExtensions.swift │ ├── Model │ │ ├── Date+MicroBlog.swift │ │ ├── UserKey+Value.swift │ │ └── SpanItemExtension.swift │ ├── SQLite │ │ ├── SQLite+UserVersion.swift │ │ ├── Enum+Value.swift │ │ └── SQLite+Array.swift │ ├── UIViewExtension.swift │ ├── NSShadowExtension.swift │ ├── UIRefreshControlExtension.swift │ ├── StringLiteral.swift │ ├── UIViewControllerPreviewingExtension.swift │ ├── Promise+TaskMessage.swift │ ├── ObjectMapper │ │ ├── Enum+Transform.swift │ │ └── UserKey+Transform.swift │ ├── UIImageExtensions.swift │ ├── UIBarButtonItemExtension.swift │ ├── Number+LocalizedString.swift │ ├── PersistableUserExtension.swift │ ├── CALayerExtension.swift │ └── DateExtension.swift │ ├── Constants │ ├── CoreConstants.swift │ ├── DatabaseConstants.swift │ ├── UIConstants.swift │ └── ServiceConstants.swift │ ├── ViewControllers │ ├── SignIn │ │ └── SignInTypeChooserViewController.swift │ └── MainViewController.swift │ ├── Utils │ ├── AccountUtils.swift │ ├── CollectionUtils.swift │ └── DefaultsKeys.swift │ ├── Models │ ├── SimpleRefreshTaskParam.swift │ ├── RefreshTaskParam.swift │ ├── ItemIndices.swift │ ├── Paging.swift │ └── StatusUpdate.swift │ └── Info.plist ├── TwidereCore ├── MicroBlog │ ├── Sources │ │ ├── Models │ │ │ ├── Twitter │ │ │ │ ├── CardEntity.swift │ │ │ │ ├── MediaEntity.swift │ │ │ │ ├── EntitySupport.swift │ │ │ │ ├── HashtagEntity.swift │ │ │ │ ├── UserEntities.swift │ │ │ │ ├── Entities.swift │ │ │ │ ├── UserMentionEntity.swift │ │ │ │ ├── UrlEntity.swift │ │ │ │ └── MediaUploadResponse.swift │ │ │ ├── Place.swift │ │ │ ├── GeoLocation.swift │ │ │ ├── ResponseCode.swift │ │ │ ├── GeoPoint.swift │ │ │ ├── Fanfou │ │ │ │ └── Photo.swift │ │ │ └── GNUSocial │ │ │ │ ├── Attention.swift │ │ │ │ └── Attachment.swift │ │ ├── API │ │ │ ├── AccountAPI.swift │ │ │ ├── FavoritesAPI.swift │ │ │ ├── OAuthAPI.swift │ │ │ └── TwitterUploadAPI.swift │ │ ├── MicroBlog.h │ │ ├── Info.plist │ │ ├── MicroBlogError.swift │ │ └── Utils │ │ │ └── ResponseSerializers.swift │ └── Generated │ │ ├── AccountAPI+RestImpl.swift │ │ ├── FavoritesAPI+RestImpl.swift │ │ ├── CardEntity+JsonMapper.swift │ │ ├── MediaEntity+JsonMapper.swift │ │ ├── Place+JsonMapper.swift │ │ ├── MediaUploadResponse+JsonMapper.swift │ │ ├── MediaUploadResponse.Image+JsonMapper.swift │ │ ├── MediaUploadResponse.Video+JsonMapper.swift │ │ ├── MediaUploadResponse.ProcessingInfo+JsonMapper.swift │ │ ├── Status.CurrentUserRetweet+JsonMapper.swift │ │ ├── UserEntities+JsonMapper.swift │ │ ├── Photo+JsonMapper.swift │ │ ├── Attention+JsonMapper.swift │ │ ├── UserMentionEntity+JsonMapper.swift │ │ ├── GeoPoint+JsonMapper.swift │ │ ├── HashtagEntity+JsonMapper.swift │ │ ├── OAuthAPI+RestImpl.swift │ │ ├── UrlEntity+JsonMapper.swift │ │ ├── Status.ExtendedTweet+JsonMapper.swift │ │ ├── Attachment+JsonMapper.swift │ │ ├── TwitterUploadAPI+RestImpl.swift │ │ └── Entities+JsonMapper.swift ├── Sources │ ├── Model │ │ ├── Draft.swift │ │ ├── PersistableCardEntity.swift │ │ ├── MentionItem.swift │ │ ├── SpanItem.swift │ │ ├── PersistableLiteUser.swift │ │ ├── AccountCredentials.swift │ │ └── AccountDetails.swift │ ├── Utils │ │ ├── TwidereError.swift │ │ └── HtmlBuilder.swift │ ├── Extensions │ │ ├── DateExtensions.swift │ │ ├── AccountDetailsExtension.swift │ │ ├── MicroBlog │ │ │ ├── CardEntityExtension.swift │ │ │ ├── UserMentionEntityExtension.swift │ │ │ └── UserExtension.swift │ │ ├── JsonMapperExtension.swift │ │ ├── Mastodon │ │ │ └── MastodonStatusExtension.swift │ │ ├── Model │ │ │ └── PersistableStatusExtension.swift │ │ └── SimpleTypesFieldConverters.swift │ ├── Constants │ │ └── ServiceConstants.swift │ ├── TwidereCore.h │ ├── Info.plist │ └── Tasks │ │ ├── Implementations │ │ └── CreateFavoriteTask.swift │ │ ├── AbstractTask.swift │ │ └── AbsAccountRequestTask.swift ├── Mastodon │ ├── Sources │ │ ├── Models │ │ │ ├── Card.swift │ │ │ ├── StatusUpdate.swift │ │ │ ├── Mention.swift │ │ │ ├── Instance.swift │ │ │ ├── Status.swift │ │ │ ├── Notification.swift │ │ │ ├── ErrorResponse.swift │ │ │ ├── RegisteredApplication.swift │ │ │ ├── Context.swift │ │ │ ├── LinkHeaderList.swift │ │ │ ├── Application.swift │ │ │ ├── Attachment.swift │ │ │ └── Account.swift │ │ ├── API │ │ │ └── AccountsAPI.swift │ │ ├── Mastodon.h │ │ ├── Info.plist │ │ └── ResponseSerializers.swift │ └── Generated │ │ ├── AccountsAPI+RestImpl.swift │ │ ├── Card+JsonMapper.swift │ │ ├── Status+JsonMapper.swift │ │ ├── Context+JsonMapper.swift │ │ ├── Mention+JsonMapper.swift │ │ ├── Instance+JsonMapper.swift │ │ ├── Notification+JsonMapper.swift │ │ ├── ErrorResponse+JsonMapper.swift │ │ ├── RegisteredApplication+JsonMapper.swift │ │ ├── Application+JsonMapper.swift │ │ ├── Attachment+JsonMapper.swift │ │ └── Account+JsonMapper.swift └── Generated │ ├── SpanItem+JsonMapper.swift │ ├── MentionItem+JsonMapper.swift │ ├── EmptyCredentials+JsonMapper.swift │ ├── MediaItem.VideoInfo+JsonMapper.swift │ ├── AccountDetails.Extras+JsonMapper.swift │ ├── PersistableCardEntity+JsonMapper.swift │ ├── MediaItem.VideoInfo.Variant+JsonMapper.swift │ ├── OAuth2Credentials+JsonMapper.swift │ ├── PersistableActivity.RelatedObject+JsonMapper.swift │ ├── BasicCredentials+JsonMapper.swift │ ├── AccountDetails.Credentials+JsonMapper.swift │ ├── PersistableActivity.SummaryLine+JsonMapper.swift │ ├── OAuthCredentials+JsonMapper.swift │ ├── PersistableLiteUser+JsonMapper.swift │ ├── MediaItem+JsonMapper.swift │ └── PersistableUser.Extras+JsonMapper.swift ├── sourcery_generate.sh ├── RestCommons └── Sources │ ├── RestClientExtension.swift │ ├── RestCommons.h │ ├── Info.plist │ ├── RestError.swift │ ├── ResponseSerializers.swift │ └── DateFieldConverters.swift ├── RestClient └── Sources │ ├── RestClient.h │ ├── RestClient.swift │ ├── Info.plist │ └── Endpoint.swift ├── Twidere.xcworkspace └── contents.xcworkspacedata ├── README.md └── .gitignore /Twidere/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Twidere/Sources/Twidere-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPad.png -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPad@2x.png -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPadPro@2x.png -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPhone@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPhone@2x.png -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPhone@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/AppIcon.appiconset/iPhone@3x.png -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/CardEntity.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class CardEntity { 3 | 4 | required public init() { 5 | 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/MediaEntity.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | class MediaEntity: UrlEntity { 3 | 4 | required init() { 5 | 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Send.imageset/Toolbar Send.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Toolbar Send.imageset/Toolbar Send.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow.imageset/Button Follow.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow.imageset/Button Follow.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon Home.imageset/Tab Icon Home.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Tab Icon Home.imageset/Tab Icon Home.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon User.imageset/Tab Icon User.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Tab Icon User.imageset/Tab Icon User.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Web.imageset/Text Icon Web.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Text Icon Web.imageset/Text Icon Web.pdf -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/EntitySupport.swift: -------------------------------------------------------------------------------- 1 | public protocol EntitySupport { 2 | 3 | var entities: Entities? { get } 4 | 5 | var extendedEntities: Entities? { get } 6 | } 7 | -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Grid Item Edit.imageset/Grid Item Edit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Grid Item Edit.imageset/Grid Item Edit.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Link.imageset/Text Icon Link.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Text Icon Link.imageset/Text Icon Link.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Time.imageset/Text Icon Time.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Text Icon Time.imageset/Text Icon Time.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Camera.imageset/Toolbar Camera.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Toolbar Camera.imageset/Toolbar Camera.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Grid Item Remove.imageset/Grid Item Remove.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Grid Item Remove.imageset/Grid Item Remove.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon Message.imageset/Tab Icon Message.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Tab Icon Message.imageset/Tab Icon Message.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Location.imageset/Toolbar Location.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Toolbar Location.imageset/Toolbar Location.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Settings.imageset/Toolbar Settings.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Toolbar Settings.imageset/Toolbar Settings.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action More.imageset/Button Action More.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Action More.imageset/Button Action More.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Star.imageset/Button Action Star.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Action Star.imageset/Button Action Star.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Edit.imageset/Button Follow Edit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow Edit.imageset/Button Follow Edit.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/NavBar Button Back.imageset/NavBar Button Back.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/NavBar Button Back.imageset/NavBar Button Back.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Location.imageset/Text Icon Location.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Text Icon Location.imageset/Text Icon Location.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Reply.imageset/Button Action Reply.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Action Reply.imageset/Button Action Reply.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Share.imageset/Button Action Share.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Action Share.imageset/Button Action Share.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Block.imageset/Button Follow Block.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow Block.imageset/Button Follow Block.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Empty.imageset/Button Follow Empty.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow Empty.imageset/Button Follow Empty.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Mutual.imageset/Button Follow Mutual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow Mutual.imageset/Button Follow Mutual.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Retweet.imageset/Button Action Retweet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Action Retweet.imageset/Button Action Retweet.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Pending.imageset/Button Follow Pending.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow Pending.imageset/Button Follow Pending.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Profile Image Default.imageset/Profile Image Default.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Profile Image Default.imageset/Profile Image Default.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon Notification.imageset/Tab Icon Notification.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Tab Icon Notification.imageset/Tab Icon Notification.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Incoming.imageset/Button Follow Incoming.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow Incoming.imageset/Button Follow Incoming.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Outgoing.imageset/Button Follow Outgoing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Button Follow Outgoing.imageset/Button Follow Outgoing.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Status Compose.imageset/Toolbar Status Compose.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Toolbar Status Compose.imageset/Toolbar Status Compose.pdf -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Location Outline.imageset/Toolbar Location Outline.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwidereProject/Twidere-iOS/HEAD/Twidere/Resources/Assets.xcassets/Toolbar Location Outline.imageset/Toolbar Location Outline.pdf -------------------------------------------------------------------------------- /TwidereCore/Sources/Model/Draft.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Draft.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | public class Draft { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/UserKey+MicroBlog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserKey+MicroBlog.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /sourcery_generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for project in TwidereCore TwidereCore/Mastodon TwidereCore/MicroBlog Twidere; do 4 | rm $project/Generated/* 5 | Pods/Sourcery/bin/sourcery --templates Templates/ --sources $project/Sources --output $project/Generated 6 | done 7 | -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon Home.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Tab Icon Home.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon User.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Tab Icon User.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Web.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Text Icon Web.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Send.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Toolbar Send.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Grid Item Edit.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Grid Item Edit.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Link.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Text Icon Link.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Time.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Text Icon Time.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Camera.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Toolbar Camera.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Sources/Constants/CoreConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoreConstants.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/5. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | let defaultLoadItemLimit: Int = 20 -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action More.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Action More.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Star.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Action Star.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Edit.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow Edit.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Grid Item Remove.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Grid Item Remove.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/NavBar Button Back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "NavBar Button Back.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon Message.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Tab Icon Message.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Text Icon Location.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Text Icon Location.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Location.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Toolbar Location.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Settings.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Toolbar Settings.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Place.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // sourcery: jsonParse 4 | public class Place { 5 | 6 | // sourcery: jsonField=full_name 7 | public var fullName: String! 8 | 9 | required public init() { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Reply.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Action Reply.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Share.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Action Share.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Block.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow Block.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Empty.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow Empty.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Mutual.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow Mutual.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Action Retweet.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Action Retweet.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Incoming.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow Incoming.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Outgoing.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow Outgoing.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Button Follow Pending.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Button Follow Pending.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Profile Image Default.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Profile Image Default.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Tab Icon Notification.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Tab Icon Notification.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Status Compose.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Toolbar Status Compose.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/Toolbar Location Outline.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Toolbar Location Outline.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/UIImageViewExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageViewExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/16. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SDWebImage 11 | 12 | extension UIImageView { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Utils/TwidereError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TwidereError.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum TwidereError: Error { 12 | case accountNotFound 13 | } 14 | -------------------------------------------------------------------------------- /Twidere/Sources/ViewControllers/SignIn/SignInTypeChooserViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mariotaku Lee on 2017/6/13. 3 | // Copyright (c) 2017 Mariotaku Dev. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | import UIKit 8 | 9 | class SignInTypeChooserViewController: UITableViewController { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/GeoLocation.swift: -------------------------------------------------------------------------------- 1 | public struct GeoLocation { 2 | public var latitude: Double = Double.nan 3 | public var longitude: Double = Double.nan 4 | 5 | public init(latitude: Double, longitude: Double) { 6 | self.latitude = latitude 7 | self.longitude = longitude 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/HashtagEntity.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class HashtagEntity { 3 | 4 | // sourcery: jsonField=text 5 | public var text: String! 6 | // sourcery: jsonField=indices 7 | public var indices: [Int32]! 8 | 9 | 10 | required public init() { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Card.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Card.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Card { 13 | 14 | required public init() { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/StatusUpdate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusUpdate.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class StatusUpdate { 12 | 13 | required public init() { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Mention.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Mention.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Mention { 13 | 14 | required public init() { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/UserEntities.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class UserEntities { 3 | 4 | // sourcery: jsonField=url 5 | public var url: Entities! 6 | 7 | // sourcery: jsonField=description 8 | public var description: Entities! 9 | 10 | 11 | required public init() { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Instance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Instance.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Instance { 13 | 14 | required public init() { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/DateExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateExtensions.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/5/4. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | extension Date { 10 | 11 | var millisSince1970: Int64 { 12 | return Int64(timeIntervalSince1970 * 1000) 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Status.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Status.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Status { 13 | 14 | required public init() { 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/ResponseCode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseCode.swift 3 | // MicroBlog 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | public struct ResponseCode { 10 | public let code: Int 11 | 12 | public init(code: Int) { 13 | self.code = code 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Notification.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notification.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Notification { 13 | 14 | required public init() { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/ErrorResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ErrorResponse.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class ErrorResponse { 13 | 14 | required public init() { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/RegisteredApplication.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegisteredApplication.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class RegisteredApplication { 13 | 14 | required public init() { 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/AccountDetailsExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountDetailsExtension.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | 11 | public extension AccountDetails { 12 | public static func get(_ accountKey: UserKey) -> AccountDetails! { 13 | return nil 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Model/PersistableCardEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PersistableCardEntity.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class PersistableCardEntity { 13 | public var name: String! 14 | 15 | required public init() { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/KotlinLike.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mariotaku Lee on 2017/6/11. 3 | // Copyright (c) 2017 Mariotaku Dev. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | protocol KotlinProtocol { 9 | 10 | } 11 | 12 | extension KotlinProtocol { 13 | func also(closure: (_ it: Self) -> Void) -> Self { 14 | closure(self) 15 | return self 16 | } 17 | } 18 | 19 | extension NSObject: KotlinProtocol { 20 | } -------------------------------------------------------------------------------- /Twidere/Sources/Constants/DatabaseConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DatabaseConstants.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/6. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import SQLite 10 | 11 | let databaseVersion: Int = 4 12 | 13 | let accountsTable: Table = Table("accounts") 14 | let homeStatusesTable: Table = Table("home_statuses") 15 | let interactionsTable: Table = Table("interactions") 16 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/YYText+ALSLayouts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextExtensions.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/7. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import ALSLayouts 10 | import YYText 11 | 12 | extension YYLabel: ALSBaselineSupport { 13 | 14 | public func calculateBaselineBottomValue() -> CGFloat { 15 | return font.ascender 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/Entities.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class Entities { 3 | 4 | // sourcery: jsonField=urls 5 | public var urls: [UrlEntity]! 6 | 7 | // sourcery: jsonField=hashtags 8 | public var hashtags: [HashtagEntity]! 9 | 10 | // sourcery: jsonField=mentions 11 | public var mentions: [UserMentionEntity]! 12 | 13 | required public init() { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/UserMentionEntity.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class UserMentionEntity { 3 | // sourcery: id 4 | public var id: String! 5 | // sourcery: screen_name 6 | public var screenName: String! 7 | // sourcery: name 8 | public var name: String! 9 | // sourcery: jsonField=indices 10 | public var indices: [Int32]! 11 | 12 | required public init() { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /RestCommons/Sources/RestClientExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mariotaku Lee on 2017/6/8. 3 | // Copyright (c) 2017 Mariotaku Lee. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | import RestClient 8 | 9 | public extension Endpoint { 10 | 11 | public func getService(auth: Authorization!, type: T.Type) -> T { 12 | let client = RestClient(endpoint: self, auth: auth) 13 | return type.init(client: client) 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Context.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Context.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Context { 13 | 14 | public var ancestors: [Status]! 15 | public var descendants: [Status]! 16 | 17 | required public init() { 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/CoreLocationExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoreLocationExtensions.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/14. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | extension CLAuthorizationStatus { 12 | var hasAuthorization: Bool { 13 | get { 14 | return self == .authorizedAlways || self == .authorizedWhenInUse 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Model/MentionItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MentionItem.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery:jsonParse 12 | public class MentionItem { 13 | 14 | var key: UserKey! 15 | 16 | var name: String! 17 | 18 | var screen_name: String! 19 | 20 | required public init() { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/Model/Date+MicroBlog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Date+MicroBlog.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/1. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import PMJackson 11 | 12 | private let twitterDateFormatter: DateFormatter = { 13 | let f = DateFormatter() 14 | f.locale = Locale(identifier: "en_US_POSIX") 15 | f.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy" 16 | return f 17 | }() 18 | -------------------------------------------------------------------------------- /Twidere/Sources/Constants/UIConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIConstants.swift 3 | // 4 | // 5 | // Created by Mariotaku Lee on 16/7/9. 6 | // 7 | // 8 | 9 | import UIKit 10 | 11 | let materialLightGreen = UIColor(red: 139 / 255, green: 195 / 255, blue: 74 / 255, alpha: 1) 12 | let materialYellow = UIColor(red:0.976, green:0.917, blue:0.309, alpha:1) 13 | let materialAmber = UIColor(red:0.937, green:0.752, blue:0.18, alpha:1) 14 | let materialLightBlue300 = UIColor(red:0.462, green:0.838, blue:1, alpha:1) 15 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/SQLite/SQLite+UserVersion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SQLite+UserVersion.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/5. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import SQLite 10 | 11 | extension Connection { 12 | 13 | public var userVersion: Int { 14 | get { return try! Int(scalar("PRAGMA user_version") as! Int64) } 15 | set { try! _ = run("PRAGMA user_version = \(newValue)") } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Model/SpanItem.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class SpanItem { 3 | 4 | public var start: Int = 0 5 | public var end: Int = 0 6 | public var origStart: Int = -1 7 | public var origEnd: Int = -1 8 | 9 | public var link: String! 10 | public var type: SpanType = .link 11 | 12 | required public init() { 13 | 14 | } 15 | 16 | public enum SpanType: Int { 17 | case hide = -1, link = 0, mention = 1 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/LinkHeaderList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkHeaderArray.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct LinkHeaderList { 12 | public let data: [T] 13 | private(set) public var linkParts: [String: String] 14 | 15 | public init(data: [T]) { 16 | self.data = data 17 | self.linkParts = [:] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/UrlEntity.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class UrlEntity { 3 | 4 | // sourcery: jsonField=url 5 | public var url: String! 6 | // sourcery: jsonField=display_url 7 | public var displayUrl: String! 8 | // sourcery: jsonField=expanded_url 9 | public var expandedUrl: String! 10 | 11 | // sourcery: jsonField=indices 12 | public var indices: [Int32]! 13 | 14 | required public init() { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/MicroBlog/CardEntityExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterCardEntityExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import MicroBlog 10 | 11 | extension CardEntity { 12 | func toPersistable(accountKey: UserKey, accountType: AccountDetails.AccountType?) -> PersistableCardEntity { 13 | let obj = PersistableCardEntity() 14 | return obj 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Application.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Application.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Application { 13 | 14 | // sourcery:jsonField=name 15 | var name: String! 16 | 17 | // sourcery:jsonField=website 18 | var website: String! 19 | 20 | required public init() { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/UIViewExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/7. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIView { 12 | 13 | func makeCircular(border: CALayerBorder? = nil, shadow: CALayerShadow? = nil) { 14 | self.layer.makeCircular(border: border, shadow: shadow) 15 | 16 | self.clipsToBounds = true 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/API/AccountAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterAccountService.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/2. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | 11 | // sourcery: restProtocol 12 | protocol AccountAPI { 13 | 14 | // sourcery: restMethod=GET 15 | // sourcery: restPath=/account/verify_credentials.json 16 | // sourcery: restSerializer=UserJsonMapper.singleton.responseSerializer 17 | func verifyCredentials() -> Promise 18 | 19 | } 20 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Constants/ServiceConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServiceConstants.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/10. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | public let defaultApiUrlFormat = "https://[DOMAIN.]twitter.com/" 10 | public let defaultAuthType: AccountDetails.CredentialsType = .oauth 11 | public let defaultTwitterConsumerKey = "DNvvSlrMIIyvxjmY37NBwA" 12 | public let defaultTwitterConsumerSecret = "UXZHBtDpWOEKYOE67KjpkeIcw93uvaz5KE4cwULVrsk" 13 | 14 | public let oauthCallbackOob = "oob" 15 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/API/AccountsAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MastodonAccountsService.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/2. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | 11 | // sourcery: restProtocol 12 | public protocol AccountsAPI { 13 | 14 | // sourcery: restMethod=GET 15 | // sourcery: restPath=/v1/accounts/\(id) 16 | // sourcery: restSerializer=AccountJsonMapper.singleton.responseSerializer 17 | func getAccount(id: String) -> Promise 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Twidere/Sources/Constants/ServiceConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServiceConstants.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/10. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import TwidereCore 11 | 12 | let defaultApiUrlFormat = "https://[DOMAIN.]twitter.com/" 13 | let defaultAuthType: AccountDetails.CredentialsType = .oauth 14 | let defaultTwitterConsumerKey = "DNvvSlrMIIyvxjmY37NBwA" 15 | let defaultTwitterConsumerSecret = "UXZHBtDpWOEKYOE67KjpkeIcw93uvaz5KE4cwULVrsk" 16 | 17 | let oauthCallbackOob = "oob" 18 | -------------------------------------------------------------------------------- /Twidere/Sources/Utils/AccountUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountUtils.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/16. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftyUserDefaults 11 | import SQLite 12 | import TwidereCore 13 | 14 | func defaultAccount() throws -> AccountDetails? { 15 | return nil 16 | } 17 | 18 | func allAccounts() throws -> [AccountDetails] { 19 | return [AccountDetails]() 20 | } 21 | 22 | func getAccount(forKey key: UserKey) -> AccountDetails? { 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/NSShadowExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSShadowExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/9/25. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension NSShadow { 12 | func shadowedImageInset(size: CGSize) -> UIEdgeInsets { 13 | let border = CGSize(width: fabs(shadowOffset.width) + shadowBlurRadius, height: fabs(shadowOffset.height) + shadowBlurRadius) 14 | return UIEdgeInsetsMake(border.height, -border.width, border.height, -border.width) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/GeoPoint.swift: -------------------------------------------------------------------------------- 1 | // sourcery: jsonParse 2 | public class GeoPoint { 3 | // sourcery: jsonField=coordinates 4 | public var coordinates: [Double]! 5 | 6 | // sourcery: jsonField=type 7 | public var type: String! 8 | 9 | public var geoLocation: GeoLocation! { 10 | guard let coords = coordinates, coords.count == 2 else { 11 | return nil 12 | } 13 | return GeoLocation(latitude: coords[0], longitude: coords[1]) 14 | } 15 | 16 | required public init() { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/MicroBlog/UserMentionEntityExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterMentionEntityExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import MicroBlog 10 | 11 | extension UserMentionEntity { 12 | 13 | func toPersistable(_ host: String?) -> MentionItem { 14 | let obj = MentionItem() 15 | obj.key = UserKey(id: id, host: host) 16 | obj.name = name 17 | obj.screen_name = screenName 18 | return obj 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/UIRefreshControlExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIRefreshControlExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/9/21. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIRefreshControl { 12 | 13 | func beginRefreshingManually() { 14 | if let scrollView = superview as? UIScrollView { 15 | scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: true) 16 | } 17 | beginRefreshing() 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Mastodon.h: -------------------------------------------------------------------------------- 1 | // 2 | // Mastodon.h 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/5/4. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Mastodon. 12 | FOUNDATION_EXPORT double MastodonVersionNumber; 13 | 14 | //! Project version string for Mastodon. 15 | FOUNDATION_EXPORT const unsigned char MastodonVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /RestClient/Sources/RestClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // RestClient.h 3 | // RestClient 4 | // 5 | // Created by Mariotaku Lee on 2017/5/4. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for RestClient. 12 | FOUNDATION_EXPORT double RestClientVersionNumber; 13 | 14 | //! Project version string for RestClient. 15 | FOUNDATION_EXPORT const unsigned char RestClientVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/MicroBlog.h: -------------------------------------------------------------------------------- 1 | // 2 | // MicroBlog.h 3 | // MicroBlog 4 | // 5 | // Created by Mariotaku Lee on 2017/5/4. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for MicroBlog. 12 | FOUNDATION_EXPORT double MicroBlogVersionNumber; 13 | 14 | //! Project version string for MicroBlog. 15 | FOUNDATION_EXPORT const unsigned char MicroBlogVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /RestCommons/Sources/RestCommons.h: -------------------------------------------------------------------------------- 1 | // 2 | // RestCommons.h 3 | // RestCommons 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for RestCommons. 12 | FOUNDATION_EXPORT double RestCommonsVersionNumber; 13 | 14 | //! Project version string for RestCommons. 15 | FOUNDATION_EXPORT const unsigned char RestCommonsVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /TwidereCore/Sources/TwidereCore.h: -------------------------------------------------------------------------------- 1 | // 2 | // TwidereCore.h 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/5/4. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for TwidereCore. 12 | FOUNDATION_EXPORT double TwidereCoreVersionNumber; 13 | 14 | //! Project version string for TwidereCore. 15 | FOUNDATION_EXPORT const unsigned char TwidereCoreVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Twidere/Sources/Utils/CollectionUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionUtils.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/10. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | From http://stackoverflow.com/a/25739498/859190 13 | */ 14 | func uniq(source: S) -> [T] where S.Iterator.Element == T { 15 | var buffer = [T]() 16 | var added = Set() 17 | for elem in source { 18 | if !added.contains(elem) { 19 | buffer.append(elem) 20 | added.insert(elem) 21 | } 22 | } 23 | return buffer 24 | } 25 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/StringLiteral.swift: -------------------------------------------------------------------------------- 1 | // If you want types initializable from String literals 2 | // but don't want to implement three separate initializers. 3 | 4 | 5 | extension ExpressibleByUnicodeScalarLiteral where Self: ExpressibleByStringLiteral, Self.StringLiteralType == String { 6 | public init(unicodeScalarLiteral value: String) { 7 | self.init(stringLiteral: value) 8 | } 9 | } 10 | 11 | extension ExpressibleByExtendedGraphemeClusterLiteral where Self: ExpressibleByStringLiteral, Self.StringLiteralType == String { 12 | public init(extendedGraphemeClusterLiteral value: String) { 13 | self.init(stringLiteral: value) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Fanfou/Photo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FanfouPhoto.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/1. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Photo { 13 | // sourcery: jsonField=url 14 | public var url: String! 15 | // sourcery: jsonField=imageurl 16 | public var imageUrl: String! 17 | // sourcery: jsonField=thumburl 18 | public var thumbUrl: String! 19 | // sourcery: jsonField=largeurl 20 | public var largeUrl: String! 21 | 22 | required public init() { 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/JsonMapperExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JsonMapperExtension.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/5/5. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import PMJackson 10 | import PMJSON 11 | 12 | extension JsonMapper where T: JsonMappable { 13 | 14 | func parse(json: String) -> T! { 15 | guard let data = json.data(using: .utf8) else { 16 | return nil 17 | } 18 | let options = JSONParserOptions(strict: false, useDecimals: false, streaming: true) 19 | return parse(JsonParser(JSON.parser(for: data, options: options))) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/SQLite/Enum+Value.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Enum+Value.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/9/29. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SQLite 11 | 12 | extension Activity.Action: Value { 13 | static var declaredDatatype: String { 14 | return String.declaredDatatype 15 | } 16 | 17 | static func fromDatatypeValue(_ datatypeValue: String) -> Activity.Action? { 18 | return Activity.Action(rawValue: datatypeValue.lowercasingFirstLetter()) 19 | } 20 | 21 | var datatypeValue: String { 22 | return self.rawValue 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/UIViewControllerPreviewingExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewControllerPreviewingExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/9. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private var shouldPresentViewControllerKey: UInt = 0 12 | 13 | extension UIViewControllerPreviewing { 14 | 15 | var shouldPresentViewController: Bool { 16 | get { return (objc_getAssociatedObject(self, &shouldPresentViewControllerKey) as? Bool) == true } 17 | set { objc_setAssociatedObject(self, &shouldPresentViewControllerKey, newValue, .OBJC_ASSOCIATION_COPY) } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Twidere/Sources/Models/SimpleRefreshTaskParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleRefreshTaskParam.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/6. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import TwidereCore 10 | 11 | class SimpleRefreshTaskParam: RefreshTaskParam { 12 | var accounts: [AccountDetails] 13 | 14 | var maxIds: [String?]? = nil 15 | 16 | var sinceIds: [String?]? = nil 17 | 18 | var maxSortIds: [Int64]? = nil 19 | 20 | var sinceSortIds: [Int64]? = nil 21 | 22 | var isLoadingMore: Bool = false 23 | 24 | init(accounts: [AccountDetails]) { 25 | self.accounts = accounts 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/AccountsAPI+RestImpl.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PromiseKit 5 | import RestClient 6 | 7 | public class AccountsAPIRestImpl: AccountsAPI, RestAPIProtocol { 8 | 9 | let client: RestClient 10 | 11 | required public init(client: RestClient) { 12 | self.client = client 13 | } 14 | 15 | public func getAccount(id: String) -> Promise { 16 | let call = RestCall() 17 | call.method = .get 18 | call.path = "/v1/accounts/\(id)" 19 | call.serializer = AccountJsonMapper.singleton.responseSerializer 20 | return client.toPromise(call) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/AccountAPI+RestImpl.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PromiseKit 5 | import RestClient 6 | 7 | internal class AccountAPIRestImpl: AccountAPI, RestAPIProtocol { 8 | 9 | let client: RestClient 10 | 11 | required internal init(client: RestClient) { 12 | self.client = client 13 | } 14 | 15 | internal func verifyCredentials() -> Promise { 16 | let call = RestCall() 17 | call.method = .get 18 | call.path = "/account/verify_credentials.json" 19 | call.serializer = UserJsonMapper.singleton.responseSerializer 20 | return client.toPromise(call) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/GNUSocial/Attention.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GNUSocialAttention.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/1. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | // sourcery: jsonParse 10 | public class Attention { 11 | // sourcery: jsonField=fullname 12 | public var fullName: String! 13 | // sourcery: jsonField=id 14 | public var id: String! 15 | // sourcery: jsonField=ostatus_uri 16 | public var ostatusUri: String! 17 | // sourcery: jsonField=profileurl 18 | public var profileUrl: String! 19 | // sourcery: jsonField=screen_name 20 | public var screenName: String! 21 | 22 | required public init() { 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/Mastodon/MastodonStatusExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mariotaku Lee on 2017/6/8. 3 | // Copyright (c) 2017 Mariotaku Lee. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | import Mastodon 8 | 9 | public extension Status { 10 | 11 | func toPersistable(details: AccountDetails) -> PersistableStatus { 12 | let obj = toPersistable(accountKey: details.key) 13 | obj.account_color = details.color 14 | return obj 15 | } 16 | 17 | func toPersistable(accountKey: UserKey) -> PersistableStatus { 18 | let result = PersistableStatus() 19 | apply(to: result, accountKey: accountKey) 20 | return result 21 | } 22 | 23 | func apply(to result: PersistableStatus, accountKey: UserKey) { 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /Twidere/Sources/ViewControllers/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mariotaku Lee on 2017/6/10. 3 | // Copyright (c) 2017 Mariotaku Dev. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | import UIKit 8 | 9 | class MainViewController: UIViewController { 10 | 11 | override func viewDidLoad() { 12 | super.viewDidLoad() 13 | } 14 | 15 | override func viewDidAppear(_ animated: Bool) { 16 | super.viewDidAppear(animated) 17 | 18 | let navController = UINavigationController() 19 | navController.viewControllers = [ 20 | SignInViewController(nibName: nil, bundle: nil).also { it in 21 | it.cancellable = false 22 | } 23 | ] 24 | present(navController, animated: false) 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Twidere.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 18 | 19 | 21 | 22 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /RestClient/Sources/RestClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MicroBlogService.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/9. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Alamofire 10 | import PromiseKit 11 | 12 | typealias HttpResult = (request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: NSError?) 13 | 14 | public class RestClient { 15 | 16 | let endpoint: Endpoint 17 | let auth: Authorization? 18 | let userAgent: String? 19 | 20 | public init(endpoint: Endpoint, auth: Authorization? = nil, userAgent: String? = nil) { 21 | self.endpoint = endpoint 22 | self.auth = auth 23 | self.userAgent = userAgent 24 | } 25 | 26 | } 27 | 28 | public protocol RestAPIProtocol { 29 | 30 | init(client: RestClient) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/Promise+TaskMessage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Promise+TaskMessage.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/21. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | import JDStatusBarNotification 11 | 12 | extension Promise { 13 | func showStatusBarNotificationAfterTask(success: String, failure: String) { 14 | self.then { _ -> Void in 15 | JDStatusBarNotification.show(withStatus: success, dismissAfter: 1.5, styleName: JDStatusBarStyleSuccess) 16 | }.catch { error in 17 | if (error.isCancelledError) { 18 | return 19 | } 20 | JDStatusBarNotification.show(withStatus: failure, dismissAfter: 1.5, styleName: JDStatusBarStyleError) 21 | } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/API/FavoritesAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FavoritesAPI.swift 3 | // MicroBlog 4 | // 5 | // Created by Mariotaku Lee on 2017/6/6. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | 11 | // sourcery: restProtocol 12 | public protocol FavoritesAPI { 13 | 14 | // sourcery: restMethod=POST 15 | // sourcery: restPath=/favorites/create.json 16 | // sourcery: restSerializer=StatusJsonMapper.singleton.responseSerializer 17 | func createFavorite(/* sourcery: param=id*/id: String) -> Promise 18 | 19 | // sourcery: restMethod=POST 20 | // sourcery: restPath=/favorites/destroy.json 21 | // sourcery: restSerializer=StatusJsonMapper.singleton.responseSerializer 22 | func destroyFavorite(/* sourcery: param=id*/id: String) -> Promise 23 | 24 | } 25 | -------------------------------------------------------------------------------- /RestClient/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /RestCommons/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Utils/HtmlBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HtmlBuilder.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class HtmlBuilder { 12 | 13 | private let source: String.UnicodeScalarView 14 | private let throwExceptions: Bool 15 | private let sourceIsEscaped: Bool 16 | private let shouldReEscape: Bool 17 | 18 | init(_ source: String.UnicodeScalarView, throwExceptions: Bool, sourceIsEscaped: Bool, shouldReEscape: Bool) { 19 | self.source = source 20 | self.throwExceptions = throwExceptions 21 | self.sourceIsEscaped = sourceIsEscaped 22 | self.shouldReEscape = shouldReEscape 23 | } 24 | 25 | func buildWithIndices() -> (String, [SpanItem]) { 26 | return ("", []) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Twidere for iOS 2 | 3 | ### License 4 | 5 | Twidere for iOS is licensed under GNU General Public License, version 3. Each sub modules may have different license, see `LICENSE` file respectively. 6 | 7 | Please remind that since Twidere for iOS is a project licensed under GPL, you cannot publish it to App Store. 8 | 9 | ### Donation 10 | 11 | **Donation methods** 12 | 13 | PayPal & AliPay: `String.format("%s@%s", "mariotaku.lee", "gmail.com");` 14 | 15 | Bitcoin: `1FHAVAzge7cj1LfCTMfnLL49DgA3mVUCuW` 16 | 17 | **Donators** 18 | 19 | [@TwidereProject/donators](https://twitter.com/TwidereProject/lists/donators), if you haven't find your name, please contact @TwidereProject :) 20 | 21 | Buy me a ~~bread~~ [game](http://steamcommunity.com/id/mariotaku/wishlist) or anything you want :) 22 | 23 | [帮我支付宝账户里随便加点钱](https://twitter.com/xmxsuperstar/status/724094631621750785) 24 | 25 | --- 26 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/ObjectMapper/Enum+Transform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Enum+Transform.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/9/29. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import ObjectMapper 10 | 11 | class MediaTypeTransform: TransformType { 12 | typealias Object = MediaItem.MediaType 13 | typealias JSON = String 14 | 15 | func transformFromJSON(_ value: Any?) -> MediaItem.MediaType? { 16 | if let string = value as? String , !string.isEmpty { 17 | return MediaItem.MediaType(rawValue: string.lowercasingFirstLetter()) 18 | } 19 | return nil 20 | } 21 | 22 | func transformToJSON(_ value: MediaItem.MediaType?) -> String? { 23 | if let userKey = value { 24 | return userKey.rawValue 25 | } 26 | return nil 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Twidere/Sources/Models/RefreshTaskParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RefreshTaskParam.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/5. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import TwidereCore 11 | 12 | protocol RefreshTaskParam { 13 | 14 | var accounts: [AccountDetails] { get } 15 | 16 | var maxIds: [String?]? { get } 17 | 18 | var sinceIds: [String?]? { get } 19 | 20 | var maxSortIds: [Int64]? { get } 21 | 22 | var sinceSortIds: [Int64]? { get } 23 | 24 | var isLoadingMore: Bool { get } 25 | 26 | } 27 | 28 | extension RefreshTaskParam { 29 | var maxIds: [String?]? { return nil } 30 | 31 | var sinceIds: [String?]? { return nil } 32 | 33 | var maxSortIds: [Int64]? { return nil } 34 | 35 | var sinceSortIds: [Int64]? { return nil } 36 | 37 | var isLoadingMore: Bool { return false } 38 | } 39 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/Model/UserKey+Value.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserKey+SQLite.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/8/22. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SQLite 11 | import TwidereCore 12 | 13 | extension UserKey: Value { 14 | public static var declaredDatatype: String { 15 | return String.declaredDatatype 16 | } 17 | 18 | public static func fromDatatypeValue(_ datatypeValue: String) -> UserKey { 19 | return UserKey(stringLiteral: datatypeValue) 20 | } 21 | 22 | public var datatypeValue: String { 23 | return self.string 24 | } 25 | } 26 | 27 | extension UserKey: ArrayValue { 28 | static func arrayFromDatatypeValue(_ datatypeValue: String) -> [UserKey]? { 29 | return UserKey.arrayFrom(string: datatypeValue) 30 | } 31 | 32 | static func arrayToDatatypeValue(array: [UserKey]) -> String { 33 | return array.string 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Model/PersistableLiteUser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PersistableLiteUser.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | 10 | //sourcery: jsonParse 11 | public class PersistableLiteUser { 12 | 13 | // sourcery: jsonField=account_key 14 | // sourcery: jsonFieldConverter=UserKeyFieldConverter 15 | public var account_key: UserKey! 16 | 17 | // sourcery: jsonField=key 18 | // sourcery: jsonFieldConverter=UserKeyFieldConverter 19 | public var key: UserKey! 20 | // sourcery: jsonField=name 21 | public var name: String! 22 | // sourcery: jsonField=screen_name 23 | public var screen_name: String! 24 | // sourcery: jsonField=profile_image_url 25 | public var profile_image_url: String! 26 | // sourcery: jsonField=is_following 27 | public var is_following: Bool = false 28 | 29 | required public init() { 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /RestCommons/Sources/RestError.swift: -------------------------------------------------------------------------------- 1 | public enum RestError: Error { 2 | case networkError 3 | case serviceError(errors: [ErrorInfo]) 4 | case requestError(code:Int, message:String?) 5 | case decodeError 6 | case argumentError(message: String?) 7 | 8 | public struct ErrorInfo { 9 | let code: Int 10 | let name: String? 11 | let message: String 12 | } 13 | 14 | } 15 | 16 | public extension RestError { 17 | var errorMessage: String { 18 | switch self { 19 | case .networkError: 20 | return "Network error" 21 | case .decodeError: 22 | return "Server returned invalid response" 23 | case let .serviceError(errors): 24 | return errors.first!.message 25 | case let .requestError(code, message): 26 | // TODO return human readable message 27 | return "Request error \(code): \(message ?? "nil")" 28 | default: 29 | return "Internal error" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/MicroBlogError.swift: -------------------------------------------------------------------------------- 1 | 2 | enum MicroBlogError: Error { 3 | case networkError 4 | case serviceError(errors: [ErrorInfo]) 5 | case requestError(code:Int, message:String?) 6 | case decodeError 7 | case argumentError(message: String?) 8 | 9 | struct ErrorInfo { 10 | let code: Int 11 | let name: String? 12 | let message: String 13 | } 14 | 15 | } 16 | 17 | extension MicroBlogError { 18 | var errorMessage: String { 19 | switch self { 20 | case .networkError: 21 | return "Network error" 22 | case .decodeError: 23 | return "Server returned invalid response" 24 | case let .serviceError(errors): 25 | return errors.first!.message 26 | case let .requestError(code, message): 27 | // TODO return human readable message 28 | return "Request error \(code): \(message ?? "nil")" 29 | default: 30 | return "Internal error" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/UIImageExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageExtensions.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/9/23. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import FXImageView 12 | 13 | extension UIImage { 14 | 15 | static func withColor(_ color: UIColor) -> UIImage { 16 | let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0) 17 | UIGraphicsBeginImageContext(rect.size) 18 | let context = UIGraphicsGetCurrentContext() 19 | 20 | context?.setFillColor(color.cgColor) 21 | context?.fill(rect) 22 | 23 | let image = UIGraphicsGetImageFromCurrentImageContext() 24 | UIGraphicsEndImageContext() 25 | 26 | return image! 27 | } 28 | 29 | func withShadow(_ shadow: NSShadow) -> UIImage { 30 | return self.withShadowColor(shadow.shadowColor! as! UIColor, offset: shadow.shadowOffset, blur: shadow.shadowBlurRadius) 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/ResponseSerializers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelConverter.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/10. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | import RestCommons 12 | import RestClient 13 | import PMJackson 14 | import PMJSON 15 | 16 | public extension JsonMapper where T: JsonMappable { 17 | 18 | var linkHeaderListResponseSerializer: DataResponseSerializer> { 19 | return DataResponseSerializer { (req, resp, data, err) -> Alamofire.Result> in 20 | if err != nil, let resp = resp { 21 | return .failure(RestError.requestError(code: resp.statusCode, message: nil)) 22 | } else if let data = data { 23 | let parser = JsonParser(JSON.parser(for: data)) 24 | let list = LinkHeaderList(data: self.parseArray(parser)) 25 | return .success(list) 26 | } 27 | return .failure(RestError.networkError) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/UIBarButtonItemExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIBarButtonItemExtensions.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/9/23. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private var originalImageKey: UInt8 = 0 12 | 13 | extension UIBarButtonItem { 14 | 15 | convenience init(tappableCustomView: UIView, target: Any?, action: Selector?) { 16 | tappableCustomView.addGestureRecognizer(UITapGestureRecognizer(target: target, action: action)) 17 | self.init(customView: tappableCustomView) 18 | } 19 | 20 | func makeShadowed(_ shadow: NSShadow) { 21 | let origImage: UIImage? 22 | if let obj = objc_getAssociatedObject(self, &originalImageKey) as? UIImage { 23 | origImage = obj 24 | } else { 25 | origImage = self.image 26 | objc_setAssociatedObject(self, &originalImageKey, origImage, .OBJC_ASSOCIATION_RETAIN) 27 | } 28 | self.image = origImage?.withShadow(shadow).withRenderingMode(.alwaysOriginal) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Twidere/Sources/Models/ItemIndices.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ItemIndices.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/1. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ItemIndices { 12 | 13 | private var data: [Int] 14 | 15 | init(_ count: Int) { 16 | data = [Int](repeating: 0, count: count) 17 | } 18 | 19 | func getItemCountIndex(position: Int) -> Int { 20 | var sum: Int = 0 21 | for idx in 0.. Int { 32 | return self.data[0.. Int { 36 | get { return data[index] } 37 | set { data[index] = newValue } 38 | } 39 | 40 | var count: Int { 41 | return data.reduce(0) { $0 + $1 } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/GNUSocial/Attachment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GNUSocialAttachment.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/1. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | // sourcery: jsonParse 10 | public class Attachment { 11 | // sourcery: jsonField=width 12 | public var width: Int32 = 0 13 | // sourcery: jsonField=height 14 | public var height: Int32 = 0 15 | // sourcery: jsonField=url 16 | public var url: String! 17 | // sourcery: jsonField=thumb_url 18 | public var thumbUrl: String! 19 | // sourcery: jsonField=large_thumb_url 20 | public var largeThumbUrl: String! 21 | // sourcery: jsonField=mimetype 22 | public var mimetype: String! 23 | // sourcery: jsonField=id 24 | public var id: Int64 = -1 25 | // sourcery: jsonField=oembed 26 | public var oembed: Bool = false 27 | // sourcery: jsonField=size 28 | public var size: Int64 = -1 29 | // sourcery: jsonField=version 30 | public var version: String! 31 | 32 | required public init() { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/Number+LocalizedString.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Number+LocalizedString.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/11. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Int64 { 12 | private static let countUnits = ["", "K", "M", "B"] 13 | 14 | var shortLocalizedString: String { 15 | if (self < 1000) { 16 | return String(self) 17 | } 18 | var value: Double = Double(self) 19 | var index: Int = 0 20 | while index < Int64.countUnits.count { 21 | if (value < 1000) { 22 | break 23 | } 24 | value = value / 1000.0 25 | index += 1 26 | } 27 | let remainder = value.remainder(dividingBy: 1) 28 | if (value < 10 && remainder >= 0.049 && remainder < 0.5) { 29 | return String(format: "%.1f %@", locale: Locale.current, value, Int64.countUnits[index]); 30 | } else { 31 | return String(format: "%.0f %@", locale: Locale.current, value, Int64.countUnits[index]); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Twidere/Sources/Models/Paging.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Paging.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/5. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Paging { 12 | fileprivate var params: [String: Any] = [:] 13 | 14 | var count: Int? { 15 | get { return params["count"] as? Int } 16 | set { params["count"] = newValue } 17 | } 18 | 19 | var maxId: String? { 20 | get { return params["max_id"] as? String } 21 | set { params["max_id"] = newValue } 22 | } 23 | 24 | var sinceId: String? { 25 | get { return params["since_id"] as? String } 26 | set { params["since_id"] = newValue } 27 | } 28 | 29 | var latestResults: Bool? { 30 | get { return params["latest_results"] as? Bool } 31 | set { params["latest_results"] = newValue } 32 | } 33 | 34 | var queries: [String: String] { 35 | var result = [String: String]() 36 | for (k, v) in params { 37 | result[k] = String(describing: v) 38 | } 39 | return result 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/PersistableUserExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PersistableUserExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/5. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import TwidereCore 11 | 12 | extension PersistableUser { 13 | 14 | private static let twitterProfileImageRegex = try! NSRegularExpression(pattern: "(https?://)?(twimg[\\d\\w\\-]+\\.akamaihd\\.net|[\\w\\d]+\\.twimg\\.com)/profile_images/([\\d\\w\\-_]+)/([\\d\\w\\-_]+)_(bigger|normal|mini|reasonably_small)(\\.?(png|jpeg|jpg|gif|bmp))?") 15 | 16 | func getProfileImageUrl(forSize size: ProfileImageSize) -> String! { 17 | guard let url = profile_image_url else { 18 | return nil 19 | } 20 | let range = NSMakeRange(0, url.utf16.count) 21 | if (!PersistableUser.twitterProfileImageRegex.matches(in: url, options: [], range: range).isEmpty) { 22 | return PersistableUser.twitterProfileImageRegex.stringByReplacingMatches(in: url, options: [], range: range, withTemplate: "$1$2/profile_images/$3/$4\(size.suffix)$6") 23 | } 24 | return url 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Card+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Card: JsonMappable { 7 | 8 | } 9 | 10 | public class CardJsonMapper: JsonMapper { 11 | 12 | public static let singleton = CardJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Card! { 15 | let instance = Card() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Card, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Status+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Status: JsonMappable { 7 | 8 | } 9 | 10 | public class StatusJsonMapper: JsonMapper { 11 | 12 | public static let singleton = StatusJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Status! { 15 | let instance = Status() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Status, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Generated/SpanItem+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension SpanItem: JsonMappable { 7 | 8 | } 9 | 10 | public class SpanItemJsonMapper: JsonMapper { 11 | 12 | public static let singleton = SpanItemJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> SpanItem! { 15 | let instance = SpanItem() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: SpanItem, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Context+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Context: JsonMappable { 7 | 8 | } 9 | 10 | public class ContextJsonMapper: JsonMapper { 11 | 12 | public static let singleton = ContextJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Context! { 15 | let instance = Context() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Context, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Mention+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Mention: JsonMappable { 7 | 8 | } 9 | 10 | public class MentionJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MentionJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Mention! { 15 | let instance = Mention() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Mention, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/FavoritesAPI+RestImpl.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PromiseKit 5 | import RestClient 6 | 7 | public class FavoritesAPIRestImpl: FavoritesAPI, RestAPIProtocol { 8 | 9 | let client: RestClient 10 | 11 | required public init(client: RestClient) { 12 | self.client = client 13 | } 14 | 15 | public func createFavorite(id: String) -> Promise { 16 | let call = RestCall() 17 | call.method = .post 18 | call.path = "/favorites/create.json" 19 | call.params = [ 20 | "id": id, 21 | ] 22 | call.serializer = StatusJsonMapper.singleton.responseSerializer 23 | return client.toPromise(call) 24 | } 25 | 26 | public func destroyFavorite(id: String) -> Promise { 27 | let call = RestCall() 28 | call.method = .post 29 | call.path = "/favorites/destroy.json" 30 | call.params = [ 31 | "id": id, 32 | ] 33 | call.serializer = StatusJsonMapper.singleton.responseSerializer 34 | return client.toPromise(call) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Instance+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Instance: JsonMappable { 7 | 8 | } 9 | 10 | public class InstanceJsonMapper: JsonMapper { 11 | 12 | public static let singleton = InstanceJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Instance! { 15 | let instance = Instance() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Instance, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Generated/MentionItem+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MentionItem: JsonMappable { 7 | 8 | } 9 | 10 | public class MentionItemJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MentionItemJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MentionItem! { 15 | let instance = MentionItem() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MentionItem, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/CardEntity+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension CardEntity: JsonMappable { 7 | 8 | } 9 | 10 | public class CardEntityJsonMapper: JsonMapper { 11 | 12 | public static let singleton = CardEntityJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> CardEntity! { 15 | let instance = CardEntity() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: CardEntity, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Attachment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Attachment.swift 3 | // Mastodon 4 | // 5 | // Created by Mariotaku Lee on 2017/6/8. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | public class Attachment { 13 | /** 14 | * ID of the attachment 15 | */ 16 | //sourcery: jsonField=id 17 | var id: String! 18 | /** 19 | * One of: `image`, `video`, `gifv` 20 | */ 21 | //sourcery: jsonField=type 22 | var type: String! 23 | /** 24 | * URL of the locally hosted version of the image 25 | */ 26 | //sourcery: jsonField=url 27 | var url: String! 28 | /** 29 | * For remote images, the remote URL of the original image 30 | */ 31 | //sourcery: jsonField=remote_url 32 | var remoteUrl: String! 33 | /** 34 | * URL of the preview image 35 | */ 36 | //sourcery: jsonField=preview_url 37 | var previewUrl: String! 38 | /** 39 | * Shorter URL for the image, for insertion into text (only present on local images) 40 | */ 41 | //sourcery: jsonField=text_url 42 | var textUrl: String! 43 | 44 | required public init() { 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Notification+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Notification: JsonMappable { 7 | 8 | } 9 | 10 | public class NotificationJsonMapper: JsonMapper { 11 | 12 | public static let singleton = NotificationJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Notification! { 15 | let instance = Notification() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Notification, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/MediaEntity+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | internal class MediaEntityJsonMapper: JsonMapper { 7 | 8 | internal static let singleton = MediaEntityJsonMapper() 9 | 10 | override internal func parse(_ parser: JsonParser) -> MediaEntity! { 11 | let instance = MediaEntity() 12 | if (parser.currentEvent == nil) { 13 | parser.nextEvent() 14 | } 15 | 16 | if (parser.currentEvent != .objectStart) { 17 | parser.skipChildren() 18 | return nil 19 | } 20 | 21 | while (parser.nextEvent() != .objectEnd) { 22 | let fieldName = parser.currentName! 23 | parser.nextEvent() 24 | parseField(instance, fieldName, parser) 25 | parser.skipChildren() 26 | } 27 | return instance 28 | } 29 | 30 | override internal func parseField(_ instance: MediaEntity, _ fieldName: String, _ parser: JsonParser) { 31 | switch fieldName { 32 | default: 33 | UrlEntityJsonMapper.singleton.parseField(instance, fieldName, parser) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/ErrorResponse+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension ErrorResponse: JsonMappable { 7 | 8 | } 9 | 10 | public class ErrorResponseJsonMapper: JsonMapper { 11 | 12 | public static let singleton = ErrorResponseJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> ErrorResponse! { 15 | let instance = ErrorResponse() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: ErrorResponse, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/API/OAuthAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OAuthService.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/10. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | import RestClient 11 | 12 | // sourcery: restProtocol 13 | public protocol OAuthAPI { 14 | 15 | // sourcery: restMethod=POST 16 | // sourcery: restPath=/oauth/request_token 17 | // sourcery: restSerializer=OAuthTokenResponseSerializer 18 | func getRequestToken(/* sourcery: param=oauth_callback */_ oauthCallback: String) -> Promise 19 | 20 | // sourcery: restMethod=POST 21 | // sourcery: restPath=/oauth/access_token 22 | // sourcery: restSerializer=OAuthTokenResponseSerializer 23 | // sourcery: restParams=x_auth_mode%3Dclient_auth 24 | func getAccessToken(/* sourcery: param=x_auth_username */_ username: String, /* sourcery: param=x_auth_password */_ password: String) -> Promise 25 | 26 | 27 | // sourcery: restMethod=POST 28 | // sourcery: restPath=/oauth/access_token 29 | // sourcery: restSerializer=OAuthTokenResponseSerializer 30 | func getAccessToken(/* sourcery: param=oauth_verifier */_ verifier: String?) -> Promise 31 | 32 | } 33 | -------------------------------------------------------------------------------- /TwidereCore/Generated/EmptyCredentials+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | public class EmptyCredentialsJsonMapper: JsonMapper { 7 | 8 | public static let singleton = EmptyCredentialsJsonMapper() 9 | 10 | override public func parse(_ parser: JsonParser) -> EmptyCredentials! { 11 | let instance = EmptyCredentials() 12 | if (parser.currentEvent == nil) { 13 | parser.nextEvent() 14 | } 15 | 16 | if (parser.currentEvent != .objectStart) { 17 | parser.skipChildren() 18 | return nil 19 | } 20 | 21 | while (parser.nextEvent() != .objectEnd) { 22 | let fieldName = parser.currentName! 23 | parser.nextEvent() 24 | parseField(instance, fieldName, parser) 25 | parser.skipChildren() 26 | } 27 | return instance 28 | } 29 | 30 | override public func parseField(_ instance: EmptyCredentials, _ fieldName: String, _ parser: JsonParser) { 31 | switch fieldName { 32 | default: 33 | AccountDetailsCredentialsJsonMapper.singleton.parseField(instance, fieldName, parser) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/Place+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Place: JsonMappable { 7 | 8 | } 9 | 10 | public class PlaceJsonMapper: JsonMapper { 11 | 12 | public static let singleton = PlaceJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Place! { 15 | let instance = Place() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Place, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "full_name": 37 | instance.fullName = parser.getValueAsString() 38 | default: 39 | break 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /TwidereCore/Generated/MediaItem.VideoInfo+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MediaItem.VideoInfo: JsonMappable { 7 | 8 | } 9 | 10 | public class MediaItemVideoInfoJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MediaItemVideoInfoJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MediaItem.VideoInfo! { 15 | let instance = MediaItem.VideoInfo() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MediaItem.VideoInfo, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Generated/AccountDetails.Extras+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension AccountDetails.Extras: JsonMappable { 7 | 8 | } 9 | 10 | public class AccountDetailsExtrasJsonMapper: JsonMapper { 11 | 12 | public static let singleton = AccountDetailsExtrasJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> AccountDetails.Extras! { 15 | let instance = AccountDetails.Extras() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: AccountDetails.Extras, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/MediaUploadResponse+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MediaUploadResponse: JsonMappable { 7 | 8 | } 9 | 10 | public class MediaUploadResponseJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MediaUploadResponseJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MediaUploadResponse! { 15 | let instance = MediaUploadResponse() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MediaUploadResponse, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /RestCommons/Sources/ResponseSerializers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelConverter.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/10. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | import RestClient 12 | import PMJackson 13 | import PMJSON 14 | 15 | public extension JsonMapper where T: JsonMappable { 16 | var responseSerializer: DataResponseSerializer { 17 | return DataResponseSerializer { (req, resp, data, err) -> Alamofire.Result in 18 | if err != nil, let resp = resp { 19 | return .failure(RestError.requestError(code: resp.statusCode, message: nil)) 20 | } else if let data = data { 21 | let parser = JsonParser(JSON.parser(for: data)) 22 | return .success(self.parse(parser)) 23 | } 24 | return .failure(RestError.networkError) 25 | } 26 | } 27 | 28 | } 29 | 30 | public let StatusCodeResponseSerializer: DataResponseSerializer = DataResponseSerializer { (req, resp, data, err) -> Alamofire.Result in 31 | if let resp = resp { 32 | return .success(resp.statusCode) 33 | } else if err != nil { 34 | return .failure(err!) 35 | } 36 | return .failure(RestError.networkError) 37 | } 38 | -------------------------------------------------------------------------------- /TwidereCore/Generated/PersistableCardEntity+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension PersistableCardEntity: JsonMappable { 7 | 8 | } 9 | 10 | public class PersistableCardEntityJsonMapper: JsonMapper { 11 | 12 | public static let singleton = PersistableCardEntityJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> PersistableCardEntity! { 15 | let instance = PersistableCardEntity() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: PersistableCardEntity, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/RegisteredApplication+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension RegisteredApplication: JsonMappable { 7 | 8 | } 9 | 10 | public class RegisteredApplicationJsonMapper: JsonMapper { 11 | 12 | public static let singleton = RegisteredApplicationJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> RegisteredApplication! { 15 | let instance = RegisteredApplication() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: RegisteredApplication, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Twidere/Sources/Utils/DefaultsKeys.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultsKeys.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/11. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import SwiftyUserDefaults 10 | import TwidereCore 11 | 12 | extension DefaultsKeys { 13 | static let apiUrlFormat = DefaultsKey("apiUrlFormat") 14 | static let authType = DefaultsKey("authType") 15 | static let sameOAuthSigningUrl = DefaultsKey("sameOAuthSigningUrl") 16 | static let noVersionSuffix = DefaultsKey("noVersionSuffix") 17 | static let consumerKey = DefaultsKey("consumerKey") 18 | static let consumerSecret = DefaultsKey("consumerSecret") 19 | 20 | static let attachLocation = DefaultsKey("attachLocation") 21 | static let attachPreciseLocation = DefaultsKey("attachPreciseLocation") 22 | 23 | static let defaultAccount = DefaultsKey("defaultAccount") 24 | 25 | static let loadItemLimit = DefaultsKey("loadItemLimit") 26 | } 27 | 28 | 29 | extension UserDefaults { 30 | subscript(key: DefaultsKey) -> AccountDetails.CredentialsType? { 31 | get { return self.unarchive(key) } 32 | set { self.archive(key, newValue) } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Tasks/Implementations/CreateFavoriteTask.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateFavoriteTask.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | import RestClient 11 | import MicroBlog 12 | import Mastodon 13 | 14 | public class CreateFavoriteTask: AbsAccountRequestTask { 15 | 16 | let status: PersistableStatus 17 | 18 | required public init(accountKey: UserKey!, status: PersistableStatus) { 19 | self.status = status 20 | super.init(accountKey: accountKey) 21 | } 22 | 23 | override open func createTaskPromise(account: AccountDetails) -> Promise { 24 | switch account.type { 25 | case .mastodon: 26 | let service = account.getService(endpointConfig: EndpointConfig.twitter, type: StatusesResourcesRestImpl.self) 27 | return service.favouriteStatus(id: status.id).then { $0.toPersistable(details: account) } 28 | default: 29 | let service = account.getService(endpointConfig: EndpointConfig.twitter, type: FavoritesAPIRestImpl.self) 30 | return service.createFavorite(id: status.id).then { $0.toPersistable(details: account) } 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/MediaUploadResponse.Image+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MediaUploadResponse.Image: JsonMappable { 7 | 8 | } 9 | 10 | public class MediaUploadResponseImageJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MediaUploadResponseImageJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MediaUploadResponse.Image! { 15 | let instance = MediaUploadResponse.Image() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MediaUploadResponse.Image, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/MediaUploadResponse.Video+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MediaUploadResponse.Video: JsonMappable { 7 | 8 | } 9 | 10 | public class MediaUploadResponseVideoJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MediaUploadResponseVideoJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MediaUploadResponse.Video! { 15 | let instance = MediaUploadResponse.Video() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MediaUploadResponse.Video, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Generated/MediaItem.VideoInfo.Variant+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MediaItem.VideoInfo.Variant: JsonMappable { 7 | 8 | } 9 | 10 | public class MediaItemVideoInfoVariantJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MediaItemVideoInfoVariantJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MediaItem.VideoInfo.Variant! { 15 | let instance = MediaItem.VideoInfo.Variant() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MediaItem.VideoInfo.Variant, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/Model/PersistableStatusExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PersistableStatusExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension PersistableStatus { 12 | 13 | func addFilterFlag(_ flag : PersistableStatus.FilterFlag) { 14 | filter_flags = filter_flags.union(flag) 15 | } 16 | 17 | public var quoted: PersistableStatus! { 18 | if (quoted_id == nil || quoted_user_key == nil) { 19 | return nil 20 | } 21 | let obj = PersistableStatus() 22 | obj.account_key = account_key 23 | obj.id = quoted_id 24 | obj.timestamp = quoted_timestamp 25 | obj.user_key = quoted_user_key 26 | obj.user_name = quoted_user_name 27 | obj.user_screen_name = quoted_user_screen_name 28 | obj.user_profile_image_url = quoted_user_profile_image 29 | obj.user_is_protected = quoted_user_is_protected 30 | obj.user_is_verified = quoted_user_is_verified 31 | obj.text_plain = quoted_text_plain 32 | obj.text_unescaped = quoted_text_unescaped 33 | obj.source = quoted_source 34 | obj.spans = quoted_spans 35 | obj.media = quoted_media 36 | return obj 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TwidereCore/Generated/OAuth2Credentials+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | public class OAuth2CredentialsJsonMapper: JsonMapper { 7 | 8 | public static let singleton = OAuth2CredentialsJsonMapper() 9 | 10 | override public func parse(_ parser: JsonParser) -> OAuth2Credentials! { 11 | let instance = OAuth2Credentials() 12 | if (parser.currentEvent == nil) { 13 | parser.nextEvent() 14 | } 15 | 16 | if (parser.currentEvent != .objectStart) { 17 | parser.skipChildren() 18 | return nil 19 | } 20 | 21 | while (parser.nextEvent() != .objectEnd) { 22 | let fieldName = parser.currentName! 23 | parser.nextEvent() 24 | parseField(instance, fieldName, parser) 25 | parser.skipChildren() 26 | } 27 | return instance 28 | } 29 | 30 | override public func parseField(_ instance: OAuth2Credentials, _ fieldName: String, _ parser: JsonParser) { 31 | switch fieldName { 32 | case "access_token": 33 | instance.access_token = parser.getValueAsString() 34 | default: 35 | AccountDetailsCredentialsJsonMapper.singleton.parseField(instance, fieldName, parser) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TwidereCore/Generated/PersistableActivity.RelatedObject+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension PersistableActivity.RelatedObject: JsonMappable { 7 | 8 | } 9 | 10 | public class PersistableActivityRelatedObjectJsonMapper: JsonMapper { 11 | 12 | public static let singleton = PersistableActivityRelatedObjectJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> PersistableActivity.RelatedObject! { 15 | let instance = PersistableActivity.RelatedObject() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: PersistableActivity.RelatedObject, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Application+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Application: JsonMappable { 7 | 8 | } 9 | 10 | public class ApplicationJsonMapper: JsonMapper { 11 | 12 | public static let singleton = ApplicationJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Application! { 15 | let instance = Application() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Application, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "name": 37 | instance.name = parser.getValueAsString() 38 | case "website": 39 | instance.website = parser.getValueAsString() 40 | default: 41 | break 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/ObjectMapper/UserKey+Transform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserKey+Transform.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/13. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectMapper 11 | 12 | class UserKeyTransform: TransformType { 13 | 14 | typealias Object = UserKey 15 | typealias JSON = String 16 | 17 | func transformFromJSON(_ value: Any?) -> UserKey? { 18 | if let string = value as? String { 19 | return UserKey(rawValue: string) 20 | } 21 | return nil 22 | } 23 | 24 | func transformToJSON(_ value: UserKey?) -> String? { 25 | if let userKey = value { 26 | return userKey.string 27 | } 28 | return nil 29 | } 30 | } 31 | 32 | class UserKeyArrayTransform: TransformType { 33 | typealias Object = UserKeyArray 34 | typealias JSON = [String] 35 | 36 | func transformFromJSON(_ value: Any?) -> UserKeyArray? { 37 | if let stringArray = value as? [String] { 38 | return UserKeyArray(stringArray.map { UserKey(rawValue: $0) }) 39 | } 40 | return nil 41 | } 42 | 43 | func transformToJSON(_ value: UserKeyArray?) -> [String]? { 44 | if let userKey = value { 45 | return userKey.array.map{ $0.string } 46 | } 47 | return nil 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/MediaUploadResponse.ProcessingInfo+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MediaUploadResponse.ProcessingInfo: JsonMappable { 7 | 8 | } 9 | 10 | public class MediaUploadResponseProcessingInfoJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MediaUploadResponseProcessingInfoJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MediaUploadResponse.ProcessingInfo! { 15 | let instance = MediaUploadResponse.ProcessingInfo() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MediaUploadResponse.ProcessingInfo, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | default: 37 | break 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/Status.CurrentUserRetweet+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Status.CurrentUserRetweet: JsonMappable { 7 | 8 | } 9 | 10 | public class StatusCurrentUserRetweetJsonMapper: JsonMapper { 11 | 12 | public static let singleton = StatusCurrentUserRetweetJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Status.CurrentUserRetweet! { 15 | let instance = Status.CurrentUserRetweet() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Status.CurrentUserRetweet, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "id": 37 | instance.id = parser.getValueAsString() 38 | default: 39 | break 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/UserEntities+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension UserEntities: JsonMappable { 7 | 8 | } 9 | 10 | public class UserEntitiesJsonMapper: JsonMapper { 11 | 12 | public static let singleton = UserEntitiesJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> UserEntities! { 15 | let instance = UserEntities() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: UserEntities, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "url": 37 | instance.url = EntitiesJsonMapper.singleton.parse(parser) 38 | case "description": 39 | instance.description = EntitiesJsonMapper.singleton.parse(parser) 40 | default: 41 | break 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TwidereCore/Generated/BasicCredentials+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | public class BasicCredentialsJsonMapper: JsonMapper { 7 | 8 | public static let singleton = BasicCredentialsJsonMapper() 9 | 10 | override public func parse(_ parser: JsonParser) -> BasicCredentials! { 11 | let instance = BasicCredentials() 12 | if (parser.currentEvent == nil) { 13 | parser.nextEvent() 14 | } 15 | 16 | if (parser.currentEvent != .objectStart) { 17 | parser.skipChildren() 18 | return nil 19 | } 20 | 21 | while (parser.nextEvent() != .objectEnd) { 22 | let fieldName = parser.currentName! 23 | parser.nextEvent() 24 | parseField(instance, fieldName, parser) 25 | parser.skipChildren() 26 | } 27 | return instance 28 | } 29 | 30 | override public func parseField(_ instance: BasicCredentials, _ fieldName: String, _ parser: JsonParser) { 31 | switch fieldName { 32 | case "username": 33 | instance.username = parser.getValueAsString() 34 | case "password": 35 | instance.password = parser.getValueAsString() 36 | default: 37 | AccountDetailsCredentialsJsonMapper.singleton.parseField(instance, fieldName, parser) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Models/Twitter/MediaUploadResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MediaUploadResponse.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/9/13. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | // sourcery: jsonParse 10 | public class MediaUploadResponse { 11 | 12 | public internal(set) var mediaId: String! 13 | public internal(set) var size: Int64! 14 | public internal(set) var image: Image! 15 | public internal(set) var video: Video! 16 | public internal(set) var processingInfo: ProcessingInfo! 17 | 18 | required public init() { 19 | 20 | } 21 | 22 | // sourcery: jsonParse 23 | public class Image { 24 | 25 | var width: Int! 26 | var height: Int! 27 | var imageType: String! 28 | 29 | required public init() { 30 | 31 | } 32 | 33 | } 34 | 35 | // sourcery: jsonParse 36 | public class Video { 37 | 38 | var videoType: String! 39 | 40 | required public init() { 41 | 42 | } 43 | 44 | } 45 | 46 | // sourcery: jsonParse 47 | public class ProcessingInfo { 48 | 49 | var state: String! 50 | var checkAfterSecs: Int64! 51 | var progressPercent: Int! 52 | // var error: ErrorInfo! 53 | 54 | required public init() { 55 | } 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Model/AccountCredentials.swift: -------------------------------------------------------------------------------- 1 | // sourcery:jsonParse 2 | public class OAuthCredentials: AccountDetails.Credentials { 3 | 4 | // sourcery: jsonField=consumer_key 5 | public var consumer_key: String! 6 | // sourcery: jsonField=consumer_secret 7 | public var consumer_secret: String! 8 | 9 | // sourcery: jsonField=access_token 10 | public var access_token: String! 11 | // sourcery: jsonField=access_token_secret 12 | public var access_token_secret: String! 13 | 14 | // sourcery: jsonField=same_oauth_signing_url 15 | public var same_oauth_signing_url: Bool = false 16 | 17 | required public init() { 18 | 19 | } 20 | 21 | } 22 | 23 | // sourcery:jsonParse 24 | public class OAuth2Credentials: AccountDetails.Credentials { 25 | 26 | // sourcery: jsonField=access_token 27 | public var access_token: String! 28 | 29 | required public init() { 30 | 31 | } 32 | } 33 | 34 | // sourcery:jsonParse 35 | public class BasicCredentials: AccountDetails.Credentials { 36 | 37 | // sourcery: jsonField=username 38 | public var username: String! 39 | // sourcery: jsonField=password 40 | public var password: String! 41 | 42 | required public init() { 43 | 44 | } 45 | } 46 | 47 | // sourcery:jsonParse 48 | public class EmptyCredentials: AccountDetails.Credentials { 49 | 50 | required public init() { 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /RestCommons/Sources/DateFieldConverters.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterDateFieldConverter.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PMJackson 10 | 11 | public struct JavaScriptDateFieldConverter: JsonFieldConverter { 12 | public typealias T = Date 13 | 14 | private static let twitterDateFormatter: DateFormatter = { 15 | let f = DateFormatter() 16 | f.locale = Locale(identifier: "en_US_POSIX") 17 | f.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy" 18 | return f 19 | }() 20 | 21 | public static func parse(_ parser: JsonParser) -> Date! { 22 | guard let str = parser.getValueAsString() else { 23 | return nil 24 | } 25 | return twitterDateFormatter.date(from: str) 26 | } 27 | 28 | } 29 | 30 | 31 | public struct ISO8601DateFieldConverter: JsonFieldConverter { 32 | public typealias T = Date 33 | 34 | private static let twitterDateFormatter: DateFormatter = { 35 | let f = DateFormatter() 36 | f.locale = Locale(identifier: "en_US_POSIX") 37 | f.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 38 | return f 39 | }() 40 | 41 | public static func parse(_ parser: JsonParser) -> Date! { 42 | guard let str = parser.getValueAsString() else { 43 | return nil 44 | } 45 | return twitterDateFormatter.date(from: str) 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/Photo+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Photo: JsonMappable { 7 | 8 | } 9 | 10 | public class PhotoJsonMapper: JsonMapper { 11 | 12 | public static let singleton = PhotoJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Photo! { 15 | let instance = Photo() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Photo, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "url": 37 | instance.url = parser.getValueAsString() 38 | case "imageurl": 39 | instance.imageUrl = parser.getValueAsString() 40 | case "thumburl": 41 | instance.thumbUrl = parser.getValueAsString() 42 | case "largeurl": 43 | instance.largeUrl = parser.getValueAsString() 44 | default: 45 | break 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TwidereCore/Generated/AccountDetails.Credentials+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension AccountDetails.Credentials: JsonMappable { 7 | 8 | } 9 | 10 | public class AccountDetailsCredentialsJsonMapper: JsonMapper { 11 | 12 | public static let singleton = AccountDetailsCredentialsJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> AccountDetails.Credentials! { 15 | let instance = AccountDetails.Credentials() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: AccountDetails.Credentials, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "api_url_format": 37 | instance.api_url_format = parser.getValueAsString() 38 | case "no_version_suffix": 39 | instance.no_version_suffix = parser.getValueAsBool() 40 | default: 41 | break 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Tasks/AbstractTask.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractTask.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/6/6. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | 11 | open class AbstractTask { 12 | 13 | public weak var callback: Callback! 14 | 15 | public var params: Params! 16 | 17 | public func execute() -> Promise { 18 | beforeExecute() 19 | let tp = createTaskPromise() 20 | return tp.then { result -> Result in 21 | self.afterExecute(callback: self.callback, result: result, error: nil) 22 | self.onSucceed(callback: self.callback, result: result) 23 | return result 24 | }.catch { error in 25 | self.afterExecute(callback: self.callback, result: nil, error: error) 26 | self.onError(callback: self.callback, error: error) 27 | } 28 | } 29 | 30 | open func createTaskPromise() -> Promise { 31 | return Promise(error: AbstractTaskError.notImplemented) 32 | } 33 | 34 | open func beforeExecute() { 35 | 36 | } 37 | 38 | open func afterExecute(callback: Callback!, result: Result!, error: Error!) { 39 | 40 | } 41 | 42 | open func onSucceed(callback: Callback?, result: Result) { 43 | } 44 | 45 | open func onError(callback: Callback?, error: Error) { 46 | } 47 | 48 | } 49 | 50 | public enum AbstractTaskError: Error { 51 | case notImplemented 52 | } 53 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/SimpleTypesFieldConverters.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserKeyFieldConverter.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PMJackson 10 | import MicroBlog 11 | 12 | public class UserKeyFieldConverter: JsonFieldConverter { 13 | public typealias T = UserKey 14 | 15 | public static func parse(_ parser: JsonParser) -> UserKey! { 16 | guard let str = parser.getValueAsString() else { 17 | return nil 18 | } 19 | return UserKey(stringLiteral: str) 20 | } 21 | } 22 | 23 | public class GeoLocationFieldConverter: JsonFieldConverter { 24 | public typealias T = GeoLocation 25 | 26 | public static func parse(_ parser: JsonParser) -> GeoLocation! { 27 | guard let str = parser.getValueAsString() else { 28 | return nil 29 | } 30 | let components = str.components(separatedBy: ",") 31 | if (components.count != 2) { 32 | return nil 33 | } 34 | guard let lat = Double(components[0]), let lng = Double(components[1]) else { 35 | return nil 36 | } 37 | return GeoLocation(latitude: lat, longitude: lng) 38 | } 39 | 40 | } 41 | 42 | public struct MediaItemTypeFieldConverter: JsonFieldConverter { 43 | public typealias T = MediaItem.MediaType 44 | 45 | public static func parse(_ parser: JsonParser) -> MediaItem.MediaType! { 46 | return MediaItem.MediaType(rawValue: parser.getValueAsString()) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/CALayerExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CALayerExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/9. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CALayer { 12 | 13 | func makeRoundedCorner(radius: CGFloat, borderColor: CGColor = UIColor.lightGray.cgColor, borderWidth: CGFloat = 0.5) { 14 | self.cornerRadius = radius 15 | 16 | self.borderColor = borderColor 17 | self.borderWidth = borderWidth 18 | } 19 | 20 | func makeCircular(border: CALayerBorder? = nil, shadow: CALayerShadow? = nil) { 21 | self.cornerRadius = self.frame.size.width / 2 22 | self.masksToBounds = true 23 | 24 | if let border = border { 25 | self.borderColor = border.color 26 | self.borderWidth = border.width 27 | } 28 | 29 | if let shadow = shadow { 30 | self.shadowOffset = shadow.offset 31 | self.shadowRadius = shadow.blurRadius 32 | self.shadowColor = shadow.color 33 | self.shadowOpacity = shadow.opacity 34 | self.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.cornerRadius).cgPath 35 | } 36 | 37 | } 38 | 39 | } 40 | 41 | struct CALayerBorder { 42 | var color: CGColor = UIColor.clear.cgColor 43 | var width: CGFloat = 1 44 | } 45 | 46 | struct CALayerShadow { 47 | var color: CGColor 48 | var offset: CGSize 49 | var blurRadius: CGFloat 50 | var opacity: Float 51 | } 52 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/Utils/ResponseSerializers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelConverter.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/10. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | import RestCommons 12 | import RestClient 13 | import PMJackson 14 | import PMJSON 15 | 16 | public extension JsonMapper where T: JsonMappable { 17 | 18 | } 19 | 20 | public let OAuthTokenResponseSerializer = DataResponseSerializer { req, resp, data, err -> Result in 21 | var oauthToken = "", oauthTokenSecret = "", userId = "", screenName = "" 22 | for paramString in String(data: data!, encoding: .utf8)!.components(separatedBy: "&") { 23 | 24 | if (paramString.contains("=")) { 25 | let param = paramString.components(separatedBy: "=").map { s -> String in 26 | return s.removingPercentEncoding! 27 | } 28 | if (param.count == 2) { 29 | switch (param[0]) { 30 | case "oauth_token": 31 | oauthToken = param[1] 32 | case "oauth_token_secret": 33 | oauthTokenSecret = param[1] 34 | case "user_id": 35 | userId = param[1] 36 | case "screen_name": 37 | screenName = param[1] 38 | default: break 39 | } 40 | } 41 | } 42 | } 43 | let token = OAuthToken(oauthToken, oauthTokenSecret) 44 | token.userId = userId 45 | token.screenName = screenName 46 | return .success(token) 47 | } 48 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Extensions/MicroBlog/UserExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MicroBlogUserExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/3. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import MicroBlog 10 | 11 | extension User { 12 | var key: UserKey? { 13 | return UserKey(id: id, host: self.host) 14 | } 15 | 16 | var host: String? { 17 | if (isFanfouUser) { 18 | return "fanfou.com" 19 | } else if let url = statusnetProfileUrl { 20 | return NSURLComponents(string: url)?.host 21 | } else { 22 | return "twitter.com" 23 | } 24 | } 25 | 26 | var isFanfouUser: Bool { 27 | return uniqueId != nil && profileImageUrlLarge != nil 28 | } 29 | 30 | func getProfileImage(ofSize: String) -> String! { 31 | if ("normal" != ofSize) { 32 | if let larger = profileImageUrlLarge { 33 | return larger 34 | } 35 | } 36 | let profileImage = profileImageUrlHttps ?? profileImageUrl 37 | //return Utils.getTwitterProfileImageOfSize(profileImage, size) ?: profileImage 38 | return profileImage 39 | } 40 | 41 | 42 | static func getUserHost(_ url: String!, def: String? = nil) -> String! { 43 | let def = def ?? "twitter.com" 44 | if (url == nil) { 45 | return def 46 | } 47 | guard let authority = NSURLComponents(string: url)?.host else { 48 | return nil 49 | } 50 | // TODO: replace invalid characters 51 | return authority 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/Attention+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Attention: JsonMappable { 7 | 8 | } 9 | 10 | public class AttentionJsonMapper: JsonMapper { 11 | 12 | public static let singleton = AttentionJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Attention! { 15 | let instance = Attention() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Attention, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "fullname": 37 | instance.fullName = parser.getValueAsString() 38 | case "id": 39 | instance.id = parser.getValueAsString() 40 | case "ostatus_uri": 41 | instance.ostatusUri = parser.getValueAsString() 42 | case "profileurl": 43 | instance.profileUrl = parser.getValueAsString() 44 | case "screen_name": 45 | instance.screenName = parser.getValueAsString() 46 | default: 47 | break 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/UserMentionEntity+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension UserMentionEntity: JsonMappable { 7 | 8 | } 9 | 10 | public class UserMentionEntityJsonMapper: JsonMapper { 11 | 12 | public static let singleton = UserMentionEntityJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> UserMentionEntity! { 15 | let instance = UserMentionEntity() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: UserMentionEntity, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "indices": 37 | if (parser.currentEvent == .arrayStart) { 38 | var array: [Int32] = [] 39 | while (parser.nextEvent() != .arrayEnd) { 40 | array.append(parser.getValueAsInt32()) 41 | } 42 | instance.indices = array 43 | } else { 44 | instance.indices = nil 45 | } 46 | default: 47 | break 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/GeoPoint+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension GeoPoint: JsonMappable { 7 | 8 | } 9 | 10 | public class GeoPointJsonMapper: JsonMapper { 11 | 12 | public static let singleton = GeoPointJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> GeoPoint! { 15 | let instance = GeoPoint() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: GeoPoint, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "coordinates": 37 | if (parser.currentEvent == .arrayStart) { 38 | var array: [Double] = [] 39 | while (parser.nextEvent() != .arrayEnd) { 40 | array.append(parser.getValueAsDouble()) 41 | } 42 | instance.coordinates = array 43 | } else { 44 | instance.coordinates = nil 45 | } 46 | case "type": 47 | instance.type = parser.getValueAsString() 48 | default: 49 | break 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TwidereCore/Generated/PersistableActivity.SummaryLine+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension PersistableActivity.SummaryLine: JsonMappable { 7 | 8 | } 9 | 10 | public class PersistableActivitySummaryLineJsonMapper: JsonMapper { 11 | 12 | public static let singleton = PersistableActivitySummaryLineJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> PersistableActivity.SummaryLine! { 15 | let instance = PersistableActivity.SummaryLine() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: PersistableActivity.SummaryLine, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "key": 37 | instance.key = UserKeyFieldConverter.parse(parser) 38 | case "name": 39 | instance.name = parser.getValueAsString() 40 | case "screen_name": 41 | instance.screen_name = parser.getValueAsString() 42 | case "content": 43 | instance.content = parser.getValueAsString() 44 | default: 45 | break 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/HashtagEntity+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension HashtagEntity: JsonMappable { 7 | 8 | } 9 | 10 | public class HashtagEntityJsonMapper: JsonMapper { 11 | 12 | public static let singleton = HashtagEntityJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> HashtagEntity! { 15 | let instance = HashtagEntity() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: HashtagEntity, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "text": 37 | instance.text = parser.getValueAsString() 38 | case "indices": 39 | if (parser.currentEvent == .arrayStart) { 40 | var array: [Int32] = [] 41 | while (parser.nextEvent() != .arrayEnd) { 42 | array.append(parser.getValueAsInt32()) 43 | } 44 | instance.indices = array 45 | } else { 46 | instance.indices = nil 47 | } 48 | default: 49 | break 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/OAuthAPI+RestImpl.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PromiseKit 5 | import RestClient 6 | 7 | public class OAuthAPIRestImpl: OAuthAPI, RestAPIProtocol { 8 | 9 | let client: RestClient 10 | 11 | required public init(client: RestClient) { 12 | self.client = client 13 | } 14 | 15 | public func getRequestToken(_ oauthCallback: String) -> Promise { 16 | let call = RestCall() 17 | call.method = .post 18 | call.path = "/oauth/request_token" 19 | call.params = [ 20 | "oauth_callback": oauthCallback, 21 | ] 22 | call.serializer = OAuthTokenResponseSerializer 23 | return client.toPromise(call) 24 | } 25 | 26 | public func getAccessToken(_ username: String, _ password: String) -> Promise { 27 | let call = RestCall() 28 | call.method = .post 29 | call.path = "/oauth/access_token" 30 | call.params = [ 31 | "x_auth_password": password, 32 | "x_auth_username": username, 33 | "x_auth_mode": "client_auth", 34 | ] 35 | call.serializer = OAuthTokenResponseSerializer 36 | return client.toPromise(call) 37 | } 38 | 39 | public func getAccessToken(_ verifier: String?) -> Promise { 40 | let call = RestCall() 41 | call.method = .post 42 | call.path = "/oauth/access_token" 43 | call.params = [ 44 | "oauth_verifier": verifier, 45 | ] 46 | call.serializer = OAuthTokenResponseSerializer 47 | return client.toPromise(call) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Attachment+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Attachment: JsonMappable { 7 | 8 | } 9 | 10 | public class AttachmentJsonMapper: JsonMapper { 11 | 12 | public static let singleton = AttachmentJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Attachment! { 15 | let instance = Attachment() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Attachment, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "id": 37 | instance.id = parser.getValueAsString() 38 | case "type": 39 | instance.type = parser.getValueAsString() 40 | case "url": 41 | instance.url = parser.getValueAsString() 42 | case "remote_url": 43 | instance.remoteUrl = parser.getValueAsString() 44 | case "preview_url": 45 | instance.previewUrl = parser.getValueAsString() 46 | case "text_url": 47 | instance.textUrl = parser.getValueAsString() 48 | default: 49 | break 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xcuserstate 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots 68 | fastlane/test_output 69 | 70 | # IDEA related 71 | 72 | .idea/ 73 | *.iml 74 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/DateExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSDateExtensions.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/8/22. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import DateTools 11 | 12 | extension Date { 13 | 14 | init(timeIntervalSince1970Millis: Int64) { 15 | self.init(timeIntervalSince1970: Double(timeIntervalSince1970Millis) / 1000.0) 16 | } 17 | 18 | var timeIntervalSince1970Millis: Int64 { 19 | get { 20 | return Int64(self.timeIntervalSince1970 * 1000) 21 | } 22 | } 23 | 24 | } 25 | 26 | extension Date { 27 | var dateTimeString: String { 28 | let date = self as NSDate 29 | let timeString = date.formattedDate(withFormat: "H:mm")! 30 | if (date.daysAgo() < 1) { 31 | return timeString 32 | } 33 | return "\(date.formattedDate(with: .long)!) \(timeString)" 34 | } 35 | } 36 | 37 | extension Date { 38 | struct Formatter { 39 | static let iso8601: DateFormatter = { 40 | let formatter = DateFormatter() 41 | formatter.calendar = Calendar(identifier: .iso8601) 42 | formatter.locale = Locale(identifier: "en_US_POSIX") 43 | formatter.timeZone = TimeZone(secondsFromGMT: 0) 44 | formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" 45 | return formatter 46 | }() 47 | } 48 | var iso8601String: String { 49 | return Formatter.iso8601.string(from: self) 50 | } 51 | 52 | init?(iso8601String: String) { 53 | guard let parsed = Date.Formatter.iso8601.date(from: iso8601String) else { 54 | return nil 55 | } 56 | self = parsed 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/Model/SpanItemExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpanItemExtension.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/6. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import YYText 11 | import TwidereCore 12 | 13 | extension Array where Element: SpanItem { 14 | func applyToAttributedText(_ string: NSMutableAttributedString, linkColor: UIColor) { 15 | for span in self { 16 | string.yy_setTextHighlight(NSMakeRange(span.start, span.length), color: linkColor, backgroundColor: nil, userInfo: [highlightUserInfoKey: span]) 17 | } 18 | } 19 | 20 | } 21 | 22 | let highlightUserInfoKey: String = "twidere.span" 23 | 24 | extension SpanItem { 25 | 26 | var length: Int { 27 | return end - start 28 | } 29 | 30 | func createViewController(accountKey: UserKey) -> (UIViewController, Bool)? { 31 | switch self { 32 | // case let span as LinkSpanItem: 33 | // let vc = SafariBrowserController(url: URL(string: span.link)!) 34 | // return (vc, true) 35 | // case let span as HashtagSpanItem: 36 | // let vc = SafariBrowserController(url: URL(string: "https://twitter.com/search?q=\(span.hashtag)")!) 37 | // return (vc, true) 38 | // case let span as MentionSpanItem: 39 | // let storyboard = UIStoryboard(name: "Viewers", bundle: nil) 40 | // let vc = storyboard.instantiateViewController(withIdentifier: "UserProfile") as! UserProfileController 41 | // vc.loadUser(userInfo: (accountKey, span.key, span.screenName)) 42 | // return (vc, false) 43 | default: 44 | break 45 | } 46 | return nil 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /TwidereCore/Generated/OAuthCredentials+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | public class OAuthCredentialsJsonMapper: JsonMapper { 7 | 8 | public static let singleton = OAuthCredentialsJsonMapper() 9 | 10 | override public func parse(_ parser: JsonParser) -> OAuthCredentials! { 11 | let instance = OAuthCredentials() 12 | if (parser.currentEvent == nil) { 13 | parser.nextEvent() 14 | } 15 | 16 | if (parser.currentEvent != .objectStart) { 17 | parser.skipChildren() 18 | return nil 19 | } 20 | 21 | while (parser.nextEvent() != .objectEnd) { 22 | let fieldName = parser.currentName! 23 | parser.nextEvent() 24 | parseField(instance, fieldName, parser) 25 | parser.skipChildren() 26 | } 27 | return instance 28 | } 29 | 30 | override public func parseField(_ instance: OAuthCredentials, _ fieldName: String, _ parser: JsonParser) { 31 | switch fieldName { 32 | case "consumer_key": 33 | instance.consumer_key = parser.getValueAsString() 34 | case "consumer_secret": 35 | instance.consumer_secret = parser.getValueAsString() 36 | case "access_token": 37 | instance.access_token = parser.getValueAsString() 38 | case "access_token_secret": 39 | instance.access_token_secret = parser.getValueAsString() 40 | case "same_oauth_signing_url": 41 | instance.same_oauth_signing_url = parser.getValueAsBool() 42 | default: 43 | AccountDetailsCredentialsJsonMapper.singleton.parseField(instance, fieldName, parser) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TwidereCore/Generated/PersistableLiteUser+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension PersistableLiteUser: JsonMappable { 7 | 8 | } 9 | 10 | public class PersistableLiteUserJsonMapper: JsonMapper { 11 | 12 | public static let singleton = PersistableLiteUserJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> PersistableLiteUser! { 15 | let instance = PersistableLiteUser() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: PersistableLiteUser, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "account_key": 37 | instance.account_key = UserKeyFieldConverter.parse(parser) 38 | case "key": 39 | instance.key = UserKeyFieldConverter.parse(parser) 40 | case "name": 41 | instance.name = parser.getValueAsString() 42 | case "screen_name": 43 | instance.screen_name = parser.getValueAsString() 44 | case "profile_image_url": 45 | instance.profile_image_url = parser.getValueAsString() 46 | case "is_following": 47 | instance.is_following = parser.getValueAsBool() 48 | default: 49 | break 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/UrlEntity+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension UrlEntity: JsonMappable { 7 | 8 | } 9 | 10 | public class UrlEntityJsonMapper: JsonMapper { 11 | 12 | public static let singleton = UrlEntityJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> UrlEntity! { 15 | let instance = UrlEntity() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: UrlEntity, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "url": 37 | instance.url = parser.getValueAsString() 38 | case "display_url": 39 | instance.displayUrl = parser.getValueAsString() 40 | case "expanded_url": 41 | instance.expandedUrl = parser.getValueAsString() 42 | case "indices": 43 | if (parser.currentEvent == .arrayStart) { 44 | var array: [Int32] = [] 45 | while (parser.nextEvent() != .arrayEnd) { 46 | array.append(parser.getValueAsInt32()) 47 | } 48 | instance.indices = array 49 | } else { 50 | instance.indices = nil 51 | } 52 | default: 53 | break 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Sources/API/TwitterUploadAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterUploadService.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/4. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | 11 | // sourcery: restProtocol 12 | // sourcery: extraImports=RestCommons 13 | public protocol TwitterUploadAPI { 14 | 15 | // sourcery: restMethod=POST 16 | // sourcery: restPath=/media/upload.json 17 | // sourcery: restSerializer=MediaUploadResponseJsonMapper.singleton.responseSerializer 18 | // sourcery: restParams=command%3DINIT 19 | func initUploadMedia(/* sourcery: param=media_type */mediaType: String, /* sourcery: restParam=total_bytes */totalBytes: Int, /* sourcery: param=additional_owners */additionalOwners: [String]?) -> Promise 20 | 21 | // sourcery: restMethod=POST 22 | // sourcery: restPath=/media/upload.json 23 | // sourcery: restSerializer=StatusCodeResponseSerializer 24 | // sourcery: restParams=command%3DAPPEND 25 | func appendUploadMedia(/* sourcery: param=media_id */id: String, /* sourcery: param=segment_index */segmentIndex: Int, /* sourcery: param=media */media: Data) -> Promise 26 | 27 | // sourcery: restMethod=POST 28 | // sourcery: restPath=/media/upload.json 29 | // sourcery: restSerializer=MediaUploadResponseJsonMapper.singleton.responseSerializer 30 | // sourcery: restParams=command%3DFINALIZE 31 | func finalizeUploadMedia(/* sourcery: param=media_id */id: String) -> Promise 32 | 33 | 34 | // sourcery: restMethod=POST 35 | // sourcery: restPath=/media/upload.json 36 | // sourcery: restSerializer=MediaUploadResponseJsonMapper.singleton.responseSerializer 37 | // sourcery: restParams=command%3DSTATUS 38 | func getUploadMediaStatus(/* sourcery: param=media_id */id: String) -> Promise 39 | } 40 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Tasks/AbsAccountRequestTask.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbsAccountRequestTask.swift 3 | // TwidereCore 4 | // 5 | // Created by Mariotaku Lee on 2017/6/7. 6 | // Copyright © 2017年 Mariotaku Lee. All rights reserved. 7 | // 8 | 9 | import PromiseKit 10 | 11 | open class AbsAccountRequestTask : AbstractTask { 12 | 13 | internal(set) public var accountKey: UserKey! 14 | 15 | public init(accountKey: UserKey!) { 16 | self.accountKey = accountKey 17 | } 18 | 19 | override open func createTaskPromise() -> Promise { 20 | return DispatchQueue.global().promise { () -> AccountDetails in 21 | guard let key = self.accountKey, let account = AccountDetails.get(key) else { 22 | throw TwidereError.accountNotFound 23 | } 24 | return account 25 | }.then(execute: createTaskPromise) 26 | } 27 | 28 | open func createTaskPromise(account: AccountDetails) -> Promise { 29 | return Promise(error: AbstractTaskError.notImplemented) 30 | } 31 | 32 | 33 | open func onCleanup(account: AccountDetails, params: Params, result: Result?, error: Error?) { 34 | if let result = result { 35 | onCleanup(account: account, params: params, result: result) 36 | } else if let error = error { 37 | onCleanup(account: account, params: params, error: error) 38 | } 39 | } 40 | 41 | open func onCleanup(account: AccountDetails, params: Params, result: Result) {} 42 | open func onCleanup(account: AccountDetails, params: Params, error: Error) {} 43 | 44 | open func createDraft() -> Draft? { 45 | return nil 46 | } 47 | 48 | open func deleteDraftOnError(account: AccountDetails, params: Params, error: Error) -> Bool { 49 | return false 50 | } 51 | 52 | override open func onError(callback: Callback?, error: Error) { 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/Status.ExtendedTweet+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Status.ExtendedTweet: JsonMappable { 7 | 8 | } 9 | 10 | public class StatusExtendedTweetJsonMapper: JsonMapper { 11 | 12 | public static let singleton = StatusExtendedTweetJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Status.ExtendedTweet! { 15 | let instance = Status.ExtendedTweet() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Status.ExtendedTweet, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "full_text": 37 | instance.fullText = parser.getValueAsString() 38 | case "entities": 39 | instance.entities = EntitiesJsonMapper.singleton.parse(parser) 40 | case "extended_entities": 41 | instance.extendedEntities = EntitiesJsonMapper.singleton.parse(parser) 42 | case "display_text_range": 43 | if (parser.currentEvent == .arrayStart) { 44 | var array: [Int] = [] 45 | while (parser.nextEvent() != .arrayEnd) { 46 | array.append(parser.getValueAsInt()) 47 | } 48 | instance.displayTextRange = array 49 | } else { 50 | instance.displayTextRange = nil 51 | } 52 | default: 53 | break 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/Attachment+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Attachment: JsonMappable { 7 | 8 | } 9 | 10 | public class AttachmentJsonMapper: JsonMapper { 11 | 12 | public static let singleton = AttachmentJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Attachment! { 15 | let instance = Attachment() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Attachment, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "width": 37 | instance.width = parser.getValueAsInt32() 38 | case "height": 39 | instance.height = parser.getValueAsInt32() 40 | case "url": 41 | instance.url = parser.getValueAsString() 42 | case "thumb_url": 43 | instance.thumbUrl = parser.getValueAsString() 44 | case "large_thumb_url": 45 | instance.largeThumbUrl = parser.getValueAsString() 46 | case "mimetype": 47 | instance.mimetype = parser.getValueAsString() 48 | case "id": 49 | instance.id = parser.getValueAsInt64() 50 | case "oembed": 51 | instance.oembed = parser.getValueAsBool() 52 | case "size": 53 | instance.size = parser.getValueAsInt64() 54 | case "version": 55 | instance.version = parser.getValueAsString() 56 | default: 57 | break 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Twidere/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "iPhone@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "iPhone@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "idiom" : "ipad", 47 | "size" : "20x20", 48 | "scale" : "1x" 49 | }, 50 | { 51 | "idiom" : "ipad", 52 | "size" : "20x20", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "idiom" : "ipad", 57 | "size" : "29x29", 58 | "scale" : "1x" 59 | }, 60 | { 61 | "idiom" : "ipad", 62 | "size" : "29x29", 63 | "scale" : "2x" 64 | }, 65 | { 66 | "idiom" : "ipad", 67 | "size" : "40x40", 68 | "scale" : "1x" 69 | }, 70 | { 71 | "idiom" : "ipad", 72 | "size" : "40x40", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "76x76", 77 | "idiom" : "ipad", 78 | "filename" : "iPad.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "76x76", 83 | "idiom" : "ipad", 84 | "filename" : "iPad@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "83.5x83.5", 89 | "idiom" : "ipad", 90 | "filename" : "iPadPro@2x.png", 91 | "scale" : "2x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /TwidereCore/Generated/MediaItem+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension MediaItem: JsonMappable { 7 | 8 | } 9 | 10 | public class MediaItemJsonMapper: JsonMapper { 11 | 12 | public static let singleton = MediaItemJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> MediaItem! { 15 | let instance = MediaItem() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: MediaItem, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "url": 37 | instance.url = parser.getValueAsString() 38 | case "media_url": 39 | instance.mediaUrl = parser.getValueAsString() 40 | case "preview_url": 41 | instance.previewUrl = parser.getValueAsString() 42 | case "type": 43 | instance.type = MediaItemTypeFieldConverter.parse(parser) 44 | case "width": 45 | instance.width = parser.getValueAsInt() 46 | case "height": 47 | instance.height = parser.getValueAsInt() 48 | case "video_info": 49 | instance.videoInfo = MediaItemVideoInfoJsonMapper.singleton.parse(parser) 50 | case "page_url": 51 | instance.pageUrl = parser.getValueAsString() 52 | case "open_browser": 53 | instance.openBrowser = parser.getValueAsBool() 54 | case "alt_text": 55 | instance.altText = parser.getValueAsString() 56 | default: 57 | break 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Twidere/Sources/Models/StatusUpdate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusUpdate.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/14. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import TwidereCore 11 | import MicroBlog 12 | 13 | class StatusUpdate { 14 | var accounts: [AccountDetails] 15 | var text: String 16 | var media: [MediaUpdate]? = nil 17 | var location: GeoLocation? = nil 18 | var displayCoordinates: Bool = false 19 | var inReplyToStatus: PersistableStatus? = nil 20 | var repostStatusId: String? = nil 21 | var attachmentUrl: String? = nil 22 | var possiblySensitive: Bool = false 23 | 24 | init(accounts: [AccountDetails], text: String) { 25 | self.accounts = accounts 26 | self.text = text 27 | } 28 | 29 | } 30 | 31 | class PendingStatusUpdate { 32 | 33 | let length: Int 34 | 35 | var sharedMediaIds: [String]? = nil 36 | var sharedMediaOwners: [UserKey]? = nil 37 | 38 | var overrideTexts: [String] 39 | var mediaIds: [[String]?] 40 | 41 | var mediaUploadResults: [MediaUploadResult?] 42 | var statusShortenResults: [StatusShortenResult?] 43 | 44 | init(length: Int, defaultText: String) { 45 | self.length = length 46 | overrideTexts = Array(repeating: defaultText, count: length) 47 | mediaUploadResults = Array(repeating: nil, count: length) 48 | statusShortenResults = Array(repeating: nil, count: length) 49 | mediaIds = Array(repeating: nil, count: length) 50 | } 51 | 52 | } 53 | 54 | class MediaUpdate { 55 | var path: String 56 | var type: MediaType 57 | var altText: String? = nil 58 | 59 | init(path: String, type: MediaType) { 60 | self.path = path 61 | self.type = type 62 | } 63 | 64 | enum MediaType: String { 65 | case image, video 66 | } 67 | } 68 | 69 | class MediaUploadResult { 70 | 71 | } 72 | 73 | class StatusShortenResult { 74 | 75 | } 76 | 77 | class UpdateStatusResult { 78 | let statuses: [PersistableStatus] 79 | 80 | init(statuses: [PersistableStatus]) { 81 | self.statuses = statuses 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /Twidere/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | Fabric 24 | 25 | APIKey 26 | dc4ee756d3b705e00011782f1426fc8656ad3bd9 27 | Kits 28 | 29 | 30 | KitInfo 31 | 32 | KitName 33 | Crashlytics 34 | 35 | 36 | 37 | LSRequiresIPhoneOS 38 | 39 | NSAppTransportSecurity 40 | 41 | NSAllowsArbitraryLoads 42 | 43 | 44 | NSLocationWhenInUseUsageDescription 45 | Attach location to your tweets 46 | NSPhotoLibraryUsageDescription 47 | Attach photos and videos to your tweets 48 | UILaunchStoryboardName 49 | LaunchScreen 50 | UIRequiredDeviceCapabilities 51 | 52 | armv7 53 | 54 | UISupportedInterfaceOrientations 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationLandscapeLeft 58 | UIInterfaceOrientationLandscapeRight 59 | 60 | UISupportedInterfaceOrientations~ipad 61 | 62 | UIInterfaceOrientationPortrait 63 | UIInterfaceOrientationPortraitUpsideDown 64 | UIInterfaceOrientationLandscapeLeft 65 | UIInterfaceOrientationLandscapeRight 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/TwitterUploadAPI+RestImpl.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PromiseKit 5 | import RestClient 6 | import RestCommons 7 | 8 | public class TwitterUploadAPIRestImpl: TwitterUploadAPI, RestAPIProtocol { 9 | 10 | let client: RestClient 11 | 12 | required public init(client: RestClient) { 13 | self.client = client 14 | } 15 | 16 | public func initUploadMedia(mediaType: String, totalBytes: Int, additionalOwners: [String]?) -> Promise { 17 | let call = RestCall() 18 | call.method = .post 19 | call.path = "/media/upload.json" 20 | call.params = [ 21 | "additional_owners": additionalOwners, 22 | "command": "INIT", 23 | "media_type": mediaType, 24 | ] 25 | call.serializer = MediaUploadResponseJsonMapper.singleton.responseSerializer 26 | return client.toPromise(call) 27 | } 28 | 29 | public func appendUploadMedia(id: String, segmentIndex: Int, media: Data) -> Promise { 30 | let call = RestCall() 31 | call.method = .post 32 | call.path = "/media/upload.json" 33 | call.params = [ 34 | "media": media, 35 | "media_id": id, 36 | "command": "APPEND", 37 | "segment_index": segmentIndex, 38 | ] 39 | call.serializer = StatusCodeResponseSerializer 40 | return client.toPromise(call) 41 | } 42 | 43 | public func finalizeUploadMedia(id: String) -> Promise { 44 | let call = RestCall() 45 | call.method = .post 46 | call.path = "/media/upload.json" 47 | call.params = [ 48 | "command": "FINALIZE", 49 | "media_id": id, 50 | ] 51 | call.serializer = MediaUploadResponseJsonMapper.singleton.responseSerializer 52 | return client.toPromise(call) 53 | } 54 | 55 | public func getUploadMediaStatus(id: String) -> Promise { 56 | let call = RestCall() 57 | call.method = .post 58 | call.path = "/media/upload.json" 59 | call.params = [ 60 | "command": "STATUS", 61 | "media_id": id, 62 | ] 63 | call.serializer = MediaUploadResponseJsonMapper.singleton.responseSerializer 64 | return client.toPromise(call) 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /TwidereCore/MicroBlog/Generated/Entities+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension Entities: JsonMappable { 7 | 8 | } 9 | 10 | public class EntitiesJsonMapper: JsonMapper { 11 | 12 | public static let singleton = EntitiesJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> Entities! { 15 | let instance = Entities() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: Entities, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "urls": 37 | if (parser.currentEvent == .arrayStart) { 38 | var array: [UrlEntity] = [] 39 | while (parser.nextEvent() != .arrayEnd) { 40 | array.append(UrlEntityJsonMapper.singleton.parse(parser)) 41 | } 42 | instance.urls = array 43 | } else { 44 | instance.urls = nil 45 | } 46 | case "hashtags": 47 | if (parser.currentEvent == .arrayStart) { 48 | var array: [HashtagEntity] = [] 49 | while (parser.nextEvent() != .arrayEnd) { 50 | array.append(HashtagEntityJsonMapper.singleton.parse(parser)) 51 | } 52 | instance.hashtags = array 53 | } else { 54 | instance.hashtags = nil 55 | } 56 | case "mentions": 57 | if (parser.currentEvent == .arrayStart) { 58 | var array: [UserMentionEntity] = [] 59 | while (parser.nextEvent() != .arrayEnd) { 60 | array.append(UserMentionEntityJsonMapper.singleton.parse(parser)) 61 | } 62 | instance.mentions = array 63 | } else { 64 | instance.mentions = nil 65 | } 66 | default: 67 | break 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Generated/Account+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | import RestCommons 6 | 7 | extension Account: JsonMappable { 8 | 9 | } 10 | 11 | public class AccountJsonMapper: JsonMapper { 12 | 13 | public static let singleton = AccountJsonMapper() 14 | 15 | override public func parse(_ parser: JsonParser) -> Account! { 16 | let instance = Account() 17 | if (parser.currentEvent == nil) { 18 | parser.nextEvent() 19 | } 20 | 21 | if (parser.currentEvent != .objectStart) { 22 | parser.skipChildren() 23 | return nil 24 | } 25 | 26 | while (parser.nextEvent() != .objectEnd) { 27 | let fieldName = parser.currentName! 28 | parser.nextEvent() 29 | parseField(instance, fieldName, parser) 30 | parser.skipChildren() 31 | } 32 | return instance 33 | } 34 | 35 | override public func parseField(_ instance: Account, _ fieldName: String, _ parser: JsonParser) { 36 | switch fieldName { 37 | case "id": 38 | instance.id = parser.getValueAsString() 39 | case "username": 40 | instance.username = parser.getValueAsString() 41 | case "acct": 42 | instance.acct = parser.getValueAsString() 43 | case "display_name": 44 | instance.displayName = parser.getValueAsString() 45 | case "locked": 46 | instance.locked = parser.getValueAsBool() 47 | case "created_at": 48 | instance.createdAt = ISO8601DateFieldConverter.parse(parser) 49 | case "followers_count": 50 | instance.followersCount = parser.getValueAsInt64() 51 | case "following_count": 52 | instance.followingCount = parser.getValueAsInt64() 53 | case "statuses_count": 54 | instance.statusesCount = parser.getValueAsInt64() 55 | case "note": 56 | instance.note = parser.getValueAsString() 57 | case "url": 58 | instance.url = parser.getValueAsString() 59 | case "avatar": 60 | instance.avatar = parser.getValueAsString() 61 | case "avatar_static": 62 | instance.avatarStatic = parser.getValueAsString() 63 | case "header": 64 | instance.header = parser.getValueAsString() 65 | case "header_static": 66 | instance.headerStatic = parser.getValueAsString() 67 | default: 68 | break 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /TwidereCore/Sources/Model/AccountDetails.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountDetails.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/4. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import PMJackson 10 | import PMJSON 11 | 12 | public class AccountDetails { 13 | 14 | public var key: UserKey! 15 | 16 | public var type: AccountType = .twitter 17 | 18 | public var credentialsType: CredentialsType = .oauth 19 | 20 | public var user: PersistableUser! 21 | 22 | public var color: Int = 0 23 | 24 | public var position: Int = 0 25 | 26 | public var activated: Bool = false 27 | 28 | var _credentialsJson: String! 29 | var _credentials: Credentials! 30 | 31 | var _extrasJson: String! 32 | var _extras: Extras! 33 | 34 | public var credentials: Credentials! { 35 | get { 36 | if (_credentials != nil) { 37 | return _credentials 38 | } 39 | guard let json = _credentialsJson else { 40 | return nil 41 | } 42 | switch (credentialsType) { 43 | case .oauth, .xauth: 44 | _credentials = OAuthCredentialsJsonMapper.singleton.parse(json: json) 45 | case .oauth2: 46 | _credentials = OAuth2CredentialsJsonMapper.singleton.parse(json: json) 47 | case .basic: 48 | _credentials = BasicCredentialsJsonMapper.singleton.parse(json: json) 49 | case .empty: 50 | _credentials = EmptyCredentialsJsonMapper.singleton.parse(json: json) 51 | } 52 | return _credentials 53 | } 54 | set { 55 | _credentials = newValue 56 | } 57 | } 58 | 59 | 60 | public enum AccountType: String { 61 | case twitter = "twitter", statusnet = "statusnet", fanfou = "fanfou", mastodon = "mastodon" 62 | } 63 | 64 | public enum CredentialsType: String { 65 | case oauth = "oauth", xauth = "xauth", basic = "basic", empty = "empty", oauth2 = "oauth2" 66 | } 67 | 68 | //sourcery: jsonParse 69 | public class Credentials { 70 | //sourcery: jsonField=api_url_format 71 | public var api_url_format: String! 72 | //sourcery: jsonField=no_version_suffix 73 | public var no_version_suffix: Bool = false 74 | 75 | required public init() { 76 | 77 | } 78 | } 79 | 80 | //sourcery: jsonParse 81 | public class Extras { 82 | 83 | required public init() { 84 | 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /RestClient/Sources/Endpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Endpoint.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 16/7/9. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | public class Endpoint { 10 | 11 | public typealias FixUrl = ((String) -> String) 12 | 13 | public let base: String 14 | let fixUrl: FixUrl? 15 | 16 | public init(base: String, fixUrl: FixUrl? = nil) { 17 | self.base = base 18 | self.fixUrl = fixUrl 19 | } 20 | 21 | func constructUrl(_ path: String, queries: [String: String?]? = nil) -> String { 22 | let url = Endpoint.construct(base, path: path, queries: queries) 23 | if (fixUrl != nil) { 24 | return fixUrl!(url) 25 | } 26 | return url 27 | } 28 | 29 | public static func construct(_ base: String, path: String, queries: [String: String?]? = nil) -> String { 30 | var components = URLComponents(string: base)! 31 | var basePath = components.path 32 | if (basePath.hasSuffix("/")) { 33 | basePath = basePath.substring(to: basePath.characters.index(basePath.endIndex, offsetBy: -1)) 34 | } 35 | if (path.hasPrefix("/")) { 36 | components.path = "\(basePath)\(path)" 37 | } else { 38 | components.path = "\(basePath)/\(path)" 39 | } 40 | var queryItems = [URLQueryItem]() 41 | if (components.queryItems != nil) { 42 | queryItems.append(contentsOf: components.queryItems!) 43 | } 44 | queries?.forEach{ k, v in 45 | queryItems.append(URLQueryItem(name: k, value: v)) 46 | } 47 | if (queryItems.isEmpty) { 48 | components.queryItems = nil 49 | } else { 50 | components.queryItems = queryItems 51 | } 52 | return components.string! 53 | } 54 | 55 | 56 | } 57 | 58 | public class OAuthEndpoint: Endpoint { 59 | 60 | public let signingBase: String 61 | 62 | public override init(base: String, fixUrl: FixUrl? = nil) { 63 | self.signingBase = base 64 | super.init(base: base, fixUrl: fixUrl) 65 | } 66 | 67 | public init(base: String, signingBase: String, fixUrl: FixUrl? = nil) { 68 | self.signingBase = signingBase 69 | super.init(base: base, fixUrl: fixUrl) 70 | } 71 | 72 | 73 | public func constructSigningUrl(_ path: String, queries: [String: String?]? = nil) -> String { 74 | let url = Endpoint.construct(signingBase, path: path, queries: queries) 75 | if (fixUrl != nil) { 76 | return fixUrl!(url) 77 | } 78 | return url 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /TwidereCore/Mastodon/Sources/Models/Account.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MastodonAccount.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2017/5/2. 6 | // Copyright © 2017年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // sourcery: jsonParse 12 | // sourcery: extraImports=RestCommons 13 | public class Account { 14 | /** 15 | * The ID of the account 16 | */ 17 | //sourcery: jsonField=id 18 | public var id: String! 19 | /** 20 | * The username of the account 21 | */ 22 | //sourcery: jsonField=username 23 | public var username: String! 24 | /** 25 | * Equals `username` for local users, includes `@domain` for remote ones 26 | */ 27 | //sourcery: jsonField=acct 28 | public var acct: String! 29 | /** 30 | * The account's display name 31 | */ 32 | //sourcery: jsonField=display_name 33 | public var displayName: String! 34 | /** 35 | * Boolean for when the account cannot be followed without waiting for approval first 36 | */ 37 | //sourcery: jsonField=locked 38 | public var locked: Bool = false 39 | /** 40 | * The time the account was created 41 | */ 42 | //sourcery: jsonField=created_at 43 | // sourcery: jsonFieldConverter=ISO8601DateFieldConverter 44 | public var createdAt: Date! 45 | /** 46 | * The number of followers for the account 47 | */ 48 | //sourcery: jsonField=followers_count 49 | public var followersCount: Int64 = 0 50 | /** 51 | * The number of accounts the given account is following 52 | */ 53 | //sourcery: jsonField=following_count 54 | public var followingCount: Int64 = 0 55 | /** 56 | * The number of statuses the account has made 57 | */ 58 | //sourcery: jsonField=statuses_count 59 | public var statusesCount: Int64 = 0 60 | /** 61 | * Biography of user 62 | */ 63 | //sourcery: jsonField=note 64 | public var note: String! 65 | /** 66 | * URL of the user's profile page (can be remote) 67 | */ 68 | //sourcery: jsonField=url 69 | public var url: String! 70 | /** 71 | * URL to the avatar image 72 | */ 73 | //sourcery: jsonField=avatar 74 | public var avatar: String! 75 | /** 76 | * URL to the avatar static image (gif) 77 | */ 78 | //sourcery: jsonField=avatar_static 79 | public var avatarStatic: String! 80 | /** 81 | * URL to the header image 82 | */ 83 | //sourcery: jsonField=header 84 | public var header: String! 85 | /** 86 | * URL to the header static image (gif) 87 | */ 88 | //sourcery: jsonField=header_static 89 | public var headerStatic: String! 90 | 91 | required public init() { 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Twidere/Sources/Extensions/SQLite/SQLite+Array.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SQLite+Array.swift 3 | // Twidere 4 | // 5 | // Created by Mariotaku Lee on 2016/10/14. 6 | // Copyright © 2016年 Mariotaku Dev. All rights reserved. 7 | // 8 | 9 | import SQLite 10 | 11 | extension Row { 12 | func get(_ column: Expression<[V]>) -> [V] { 13 | let wrapped: Expression = column.wrapped() 14 | let datatypeValue = self.get(wrapped)! 15 | let array = V.arrayFromDatatypeValue(datatypeValue)! 16 | return array.map {item in return item as! V} 17 | } 18 | 19 | func get(_ column: Expression<[V]?>) -> [V]? { 20 | let wrapped: Expression = column.wrapped() 21 | guard let datatypeValue = self.get(wrapped) else { 22 | return nil 23 | } 24 | guard let array = V.arrayFromDatatypeValue(datatypeValue) else { 25 | return nil 26 | } 27 | return array.map {item in return item as! V} 28 | } 29 | } 30 | 31 | extension TableBuilder { 32 | 33 | func column(_ name: Expression<[V]>, unique: Bool = false, check: Expression? = nil, defaultValue: Expression<[V]>? = nil) { 34 | let name: Expression = name.wrapped() 35 | let defaultValue: Expression? = defaultValue?.wrapped() 36 | self.column(name, unique: unique, check: check, defaultValue: defaultValue) 37 | } 38 | 39 | func column(_ name: Expression<[V]?>, unique: Bool = false, check: Expression? = nil, defaultValue: Expression<[V]>? = nil) { 40 | let name: Expression = name.wrapped() 41 | let defaultValue: Expression? = defaultValue?.wrapped() 42 | self.column(name, unique: unique, check: check, defaultValue: defaultValue) 43 | } 44 | 45 | } 46 | 47 | func <-(column: Expression<[V]>, value: [V]) -> Setter { 48 | let column: Expression = column.wrapped() 49 | return column <- V.arrayToDatatypeValue(array: value.map{ $0 as! V.ArrayValueType }) 50 | } 51 | 52 | func <-(column: Expression<[V]?>, value: [V]?) -> Setter { 53 | let column: Expression = column.wrapped() 54 | guard let value: [V] = value else { 55 | return column <- nil 56 | } 57 | return column <- V.arrayToDatatypeValue(array: value.map{ $0 as! V.ArrayValueType }) 58 | } 59 | 60 | extension Expression { 61 | func wrapped() -> Expression { 62 | return Expression(self) 63 | } 64 | } 65 | 66 | protocol ArrayValue { 67 | 68 | associatedtype ArrayValueType = Self 69 | 70 | static func arrayFromDatatypeValue(_ datatypeValue: String) -> [ArrayValueType]? 71 | 72 | static func arrayToDatatypeValue(array: [ArrayValueType]) -> String 73 | } 74 | -------------------------------------------------------------------------------- /TwidereCore/Generated/PersistableUser.Extras+JsonMapper.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.6.1 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import PMJackson 5 | 6 | extension PersistableUser.Extras: JsonMappable { 7 | 8 | } 9 | 10 | public class PersistableUserExtrasJsonMapper: JsonMapper { 11 | 12 | public static let singleton = PersistableUserExtrasJsonMapper() 13 | 14 | override public func parse(_ parser: JsonParser) -> PersistableUser.Extras! { 15 | let instance = PersistableUser.Extras() 16 | if (parser.currentEvent == nil) { 17 | parser.nextEvent() 18 | } 19 | 20 | if (parser.currentEvent != .objectStart) { 21 | parser.skipChildren() 22 | return nil 23 | } 24 | 25 | while (parser.nextEvent() != .objectEnd) { 26 | let fieldName = parser.currentName! 27 | parser.nextEvent() 28 | parseField(instance, fieldName, parser) 29 | parser.skipChildren() 30 | } 31 | return instance 32 | } 33 | 34 | override public func parseField(_ instance: PersistableUser.Extras, _ fieldName: String, _ parser: JsonParser) { 35 | switch fieldName { 36 | case "statusnet_profile_url": 37 | instance.statusnet_profile_url = parser.getValueAsString() 38 | case "ostatus_uri": 39 | instance.ostatus_uri = parser.getValueAsString() 40 | case "profile_image_url_original": 41 | instance.profile_image_url_original = parser.getValueAsString() 42 | case "profile_image_url_fallback": 43 | instance.profile_image_url_fallback = parser.getValueAsString() 44 | case "groups_count": 45 | instance.groups_count = parser.getValueAsInt64() 46 | case "unique_id": 47 | instance.unique_id = parser.getValueAsString() 48 | case "blocking": 49 | instance.blocking = parser.getValueAsBool() 50 | case "blocked_by": 51 | instance.blocked_by = parser.getValueAsBool() 52 | case "followed_by": 53 | instance.followed_by = parser.getValueAsBool() 54 | case "muting": 55 | instance.muting = parser.getValueAsBool() 56 | case "notifications_enabled": 57 | instance.notifications_enabled = parser.getValueAsBool() 58 | case "pinned_status_ids": 59 | if (parser.currentEvent == .arrayStart) { 60 | var array: [String] = [] 61 | while (parser.nextEvent() != .arrayEnd) { 62 | array.append(parser.getValueAsString()) 63 | } 64 | instance.pinned_status_ids = array 65 | } else { 66 | instance.pinned_status_ids = nil 67 | } 68 | default: 69 | break 70 | } 71 | } 72 | } 73 | --------------------------------------------------------------------------------