mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2025-01-31 09:35:13 +01:00
feat: add compose scene
This commit is contained in:
parent
7556e57de9
commit
97ecbb1bfb
@ -173,6 +173,12 @@
|
||||
},
|
||||
"public_timeline": {
|
||||
"title": "Public"
|
||||
},
|
||||
"compose": {
|
||||
"title": {
|
||||
"new_toot": "New Toot",
|
||||
"new_reply": "New Reply"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -149,6 +149,11 @@
|
||||
DB59F10425EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F10325EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift */; };
|
||||
DB59F10E25EF724F001F1DAB /* APIService+Poll.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F10D25EF724F001F1DAB /* APIService+Poll.swift */; };
|
||||
DB59F11825EFA35B001F1DAB /* StripProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F11725EFA35B001F1DAB /* StripProgressView.swift */; };
|
||||
DB66728C25F9F8DC00D60309 /* ComposeViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66728B25F9F8DC00D60309 /* ComposeViewModel+Diffable.swift */; };
|
||||
DB66729625F9F91600D60309 /* ComposeStatusSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729525F9F91600D60309 /* ComposeStatusSection.swift */; };
|
||||
DB66729C25F9F91F00D60309 /* ComposeStatusItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */; };
|
||||
DB6672A325F9FDE500D60309 /* TwitterTextEditor in Frameworks */ = {isa = PBXBuildFile; productRef = DB6672A225F9FDE500D60309 /* TwitterTextEditor */; };
|
||||
DB6672A425F9FDE500D60309 /* TwitterTextEditor in Embed Frameworks */ = {isa = PBXBuildFile; productRef = DB6672A225F9FDE500D60309 /* TwitterTextEditor */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */; };
|
||||
DB68A04A25E9027700CFDF14 /* DarkContentStatusBarStyleNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A04925E9027700CFDF14 /* DarkContentStatusBarStyleNavigationController.swift */; };
|
||||
DB68A05D25E9055900CFDF14 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DB68A05C25E9055900CFDF14 /* Settings.bundle */; };
|
||||
@ -156,6 +161,10 @@
|
||||
DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */; };
|
||||
DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; };
|
||||
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; };
|
||||
DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */; };
|
||||
DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */; };
|
||||
DB789A1C25F9F76A0071ACA0 /* ComposeTootContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1B25F9F76A0071ACA0 /* ComposeTootContentTableViewCell.swift */; };
|
||||
DB789A2B25F9F7AB0071ACA0 /* ComposeRepliedToTootContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A2A25F9F7AB0071ACA0 /* ComposeRepliedToTootContentTableViewCell.swift */; };
|
||||
DB89B9F725C10FD0008580ED /* CoreDataStack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB89B9EE25C10FD0008580ED /* CoreDataStack.framework */; };
|
||||
DB89B9FE25C10FD0008580ED /* CoreDataStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB89B9FD25C10FD0008580ED /* CoreDataStackTests.swift */; };
|
||||
DB89BA0025C10FD0008580ED /* CoreDataStack.h in Headers */ = {isa = PBXBuildFile; fileRef = DB89B9F025C10FD0008580ED /* CoreDataStack.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@ -244,6 +253,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
DB6672A425F9FDE500D60309 /* TwitterTextEditor in Embed Frameworks */,
|
||||
DB89BA0425C10FD0008580ED /* CoreDataStack.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
@ -401,6 +411,9 @@
|
||||
DB59F10325EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewCellHeightCacheableContainer.swift; sourceTree = "<group>"; };
|
||||
DB59F10D25EF724F001F1DAB /* APIService+Poll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Poll.swift"; sourceTree = "<group>"; };
|
||||
DB59F11725EFA35B001F1DAB /* StripProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StripProgressView.swift; sourceTree = "<group>"; };
|
||||
DB66728B25F9F8DC00D60309 /* ComposeViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ComposeViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
||||
DB66729525F9F91600D60309 /* ComposeStatusSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusSection.swift; sourceTree = "<group>"; };
|
||||
DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusItem.swift; sourceTree = "<group>"; };
|
||||
DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSKeyValueObservation.swift; sourceTree = "<group>"; };
|
||||
DB68A04925E9027700CFDF14 /* DarkContentStatusBarStyleNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarkContentStatusBarStyleNavigationController.swift; sourceTree = "<group>"; };
|
||||
DB68A05C25E9055900CFDF14 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
||||
@ -408,6 +421,10 @@
|
||||
DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Entity+Error.swift"; sourceTree = "<group>"; };
|
||||
DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = "<group>"; };
|
||||
DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = "<group>"; };
|
||||
DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewController.swift; sourceTree = "<group>"; };
|
||||
DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewModel.swift; sourceTree = "<group>"; };
|
||||
DB789A1B25F9F76A0071ACA0 /* ComposeTootContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeTootContentTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DB789A2A25F9F7AB0071ACA0 /* ComposeRepliedToTootContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeRepliedToTootContentTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DB89B9EE25C10FD0008580ED /* CoreDataStack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreDataStack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DB89B9F025C10FD0008580ED /* CoreDataStack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreDataStack.h; sourceTree = "<group>"; };
|
||||
DB89B9F125C10FD0008580ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@ -461,6 +478,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DB6672A325F9FDE500D60309 /* TwitterTextEditor in Frameworks */,
|
||||
DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */,
|
||||
DB89BA0325C10FD0008580ED /* CoreDataStack.framework in Frameworks */,
|
||||
2D42FF6125C8177C004A627A /* ActiveLabel in Frameworks */,
|
||||
@ -718,6 +736,7 @@
|
||||
DB4481C525EE2ADA00BEFB67 /* PollSection.swift */,
|
||||
DB1FD44325F26CCC004CFCFC /* PickServerSection.swift */,
|
||||
DB1E346725F518E20079D7DF /* CategoryPickerSection.swift */,
|
||||
DB66729525F9F91600D60309 /* ComposeStatusSection.swift */,
|
||||
);
|
||||
path = Section;
|
||||
sourceTree = "<group>";
|
||||
@ -765,6 +784,7 @@
|
||||
DB4481CB25EE2AFE00BEFB67 /* PollItem.swift */,
|
||||
DB1E347725F519300079D7DF /* PickServerItem.swift */,
|
||||
DB1FD45925F27898004CFCFC /* CategoryPickerItem.swift */,
|
||||
DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */,
|
||||
);
|
||||
path = Item;
|
||||
sourceTree = "<group>";
|
||||
@ -996,6 +1016,26 @@
|
||||
path = ServerRules;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB789A1025F9F29B0071ACA0 /* Compose */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB789A2125F9F76D0071ACA0 /* TableViewCell */,
|
||||
DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */,
|
||||
DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */,
|
||||
DB66728B25F9F8DC00D60309 /* ComposeViewModel+Diffable.swift */,
|
||||
);
|
||||
path = Compose;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB789A2125F9F76D0071ACA0 /* TableViewCell */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB789A2A25F9F7AB0071ACA0 /* ComposeRepliedToTootContentTableViewCell.swift */,
|
||||
DB789A1B25F9F76A0071ACA0 /* ComposeTootContentTableViewCell.swift */,
|
||||
);
|
||||
path = TableViewCell;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB89B9EF25C10FD0008580ED /* CoreDataStack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1097,6 +1137,7 @@
|
||||
DB9D6BEE25E4F5370051B173 /* Search */,
|
||||
DB9D6BFD25E4F57B0051B173 /* Notification */,
|
||||
DB9D6C0825E4F5A60051B173 /* Profile */,
|
||||
DB789A1025F9F29B0071ACA0 /* Compose */,
|
||||
);
|
||||
path = Scene;
|
||||
sourceTree = "<group>";
|
||||
@ -1253,6 +1294,7 @@
|
||||
DB5086B725CC0D6400C2C187 /* Kingfisher */,
|
||||
2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */,
|
||||
2D939AC725EE14620076FA61 /* CropViewController */,
|
||||
DB6672A225F9FDE500D60309 /* TwitterTextEditor */,
|
||||
);
|
||||
productName = Mastodon;
|
||||
productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */;
|
||||
@ -1382,6 +1424,7 @@
|
||||
DB5086B625CC0D6400C2C187 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */,
|
||||
2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */,
|
||||
DB6672A125F9FDE500D60309 /* XCRemoteSwiftPackageReference "TwitterTextEditor" */,
|
||||
);
|
||||
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
|
||||
projectDirPath = "";
|
||||
@ -1576,6 +1619,7 @@
|
||||
5DF1054125F886D400D6C0D4 /* ViedeoPlaybackService.swift in Sources */,
|
||||
0FB3D2F725E4C24D00AAD544 /* MastodonPickServerViewModel.swift in Sources */,
|
||||
2D61335E25C1894B00CAE157 /* APIService.swift in Sources */,
|
||||
DB66729625F9F91600D60309 /* ComposeStatusSection.swift in Sources */,
|
||||
2D38F1F725CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift in Sources */,
|
||||
0FB3D33225E5F50E00AAD544 /* PickServerSearchCell.swift in Sources */,
|
||||
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
|
||||
@ -1593,6 +1637,7 @@
|
||||
2D42FF8525C8224F004A627A /* HitTestExpandedButton.swift in Sources */,
|
||||
DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */,
|
||||
2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */,
|
||||
DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */,
|
||||
0FAA102725E1126A0017CCDE /* MastodonPickServerViewController.swift in Sources */,
|
||||
DB59F0FE25EF5D96001F1DAB /* StatusProvider+UITableViewDelegate.swift in Sources */,
|
||||
DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */,
|
||||
@ -1617,6 +1662,7 @@
|
||||
2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */,
|
||||
DB59F11825EFA35B001F1DAB /* StripProgressView.swift in Sources */,
|
||||
DB59F10425EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift in Sources */,
|
||||
DB66728C25F9F8DC00D60309 /* ComposeViewModel+Diffable.swift in Sources */,
|
||||
DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */,
|
||||
2DF75B9B25D0E27500694EC8 /* StatusProviderFacade.swift in Sources */,
|
||||
DB5086A525CC0B7000C2C187 /* AvatarBarButtonItem.swift in Sources */,
|
||||
@ -1641,6 +1687,7 @@
|
||||
DB59F10E25EF724F001F1DAB /* APIService+Poll.swift in Sources */,
|
||||
2D42FF7E25C82218004A627A /* ActionToolBarContainer.swift in Sources */,
|
||||
DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */,
|
||||
DB789A1C25F9F76A0071ACA0 /* ComposeTootContentTableViewCell.swift in Sources */,
|
||||
DB1FD43625F26899004CFCFC /* MastodonPickServerViewModel+LoadIndexedServerState.swift in Sources */,
|
||||
2D939AE825EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift in Sources */,
|
||||
DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */,
|
||||
@ -1705,10 +1752,13 @@
|
||||
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
|
||||
DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */,
|
||||
0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */,
|
||||
DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */,
|
||||
2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */,
|
||||
DB66729C25F9F91F00D60309 /* ComposeStatusItem.swift in Sources */,
|
||||
0FB3D31E25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift in Sources */,
|
||||
5DF1057925F88A1D00D6C0D4 /* MosaicPlayerView.swift in Sources */,
|
||||
DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */,
|
||||
DB789A2B25F9F7AB0071ACA0 /* ComposeRepliedToTootContentTableViewCell.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -2295,6 +2345,14 @@
|
||||
minimumVersion = 6.1.0;
|
||||
};
|
||||
};
|
||||
DB6672A125F9FDE500D60309 /* XCRemoteSwiftPackageReference "TwitterTextEditor" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/twitter/TwitterTextEditor.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
@ -2337,6 +2395,11 @@
|
||||
package = DB5086B625CC0D6400C2C187 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||
productName = Kingfisher;
|
||||
};
|
||||
DB6672A225F9FDE500D60309 /* TwitterTextEditor */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DB6672A125F9FDE500D60309 /* XCRemoteSwiftPackageReference "TwitterTextEditor" */;
|
||||
productName = TwitterTextEditor;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
|
@ -99,6 +99,15 @@
|
||||
"revision": "dad97167bf1be16aeecd109130900995dd01c515",
|
||||
"version": "2.6.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "TwitterTextEditor",
|
||||
"repositoryURL": "https://github.com/twitter/TwitterTextEditor.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "8aa914134c5b6aa46e862de63f239ec0e3b52a91",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -47,6 +47,9 @@ extension SceneCoordinator {
|
||||
case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel)
|
||||
case mastodonResendEmail(viewModel: MastodonResendEmailViewModel)
|
||||
|
||||
// compose
|
||||
case compose(viewModel: ComposeViewModel)
|
||||
|
||||
// misc
|
||||
case alertController(alertController: UIAlertController)
|
||||
|
||||
@ -190,6 +193,10 @@ private extension SceneCoordinator {
|
||||
let _viewController = MastodonResendEmailViewController()
|
||||
_viewController.viewModel = viewModel
|
||||
viewController = _viewController
|
||||
case .compose(let viewModel):
|
||||
let _viewController = ComposeViewController()
|
||||
_viewController.viewModel = viewModel
|
||||
viewController = _viewController
|
||||
case .alertController(let alertController):
|
||||
if let popoverPresentationController = alertController.popoverPresentationController {
|
||||
assert(
|
||||
|
34
Mastodon/Diffiable/Item/ComposeStatusItem.swift
Normal file
34
Mastodon/Diffiable/Item/ComposeStatusItem.swift
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// ComposeStatusItem.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
enum ComposeStatusItem {
|
||||
case replyTo(tootObjectID: NSManagedObjectID)
|
||||
case toot(attribute: InputAttribute)
|
||||
}
|
||||
|
||||
extension ComposeStatusItem: Hashable { }
|
||||
|
||||
extension ComposeStatusItem {
|
||||
class InputAttribute: Hashable {
|
||||
let hasReplyTo: Bool
|
||||
|
||||
init(hasReplyTo: Bool) {
|
||||
self.hasReplyTo = hasReplyTo
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(hasReplyTo)
|
||||
}
|
||||
|
||||
static func == (lhs: ComposeStatusItem.InputAttribute, rhs: ComposeStatusItem.InputAttribute) -> Bool {
|
||||
return lhs.hasReplyTo == rhs.hasReplyTo
|
||||
}
|
||||
}
|
||||
}
|
13
Mastodon/Diffiable/Section/ComposeStatusSection.swift
Normal file
13
Mastodon/Diffiable/Section/ComposeStatusSection.swift
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// ComposeStatusSection.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ComposeStatusSection: Equatable, Hashable {
|
||||
case repliedTo
|
||||
case status
|
||||
}
|
@ -127,6 +127,14 @@ internal enum L10n {
|
||||
}
|
||||
|
||||
internal enum Scene {
|
||||
internal enum Compose {
|
||||
internal enum Title {
|
||||
/// New Reply
|
||||
internal static let newReply = L10n.tr("Localizable", "Scene.Compose.Title.NewReply")
|
||||
/// New Toot
|
||||
internal static let newToot = L10n.tr("Localizable", "Scene.Compose.Title.NewToot")
|
||||
}
|
||||
}
|
||||
internal enum ConfirmEmail {
|
||||
/// We just sent an email to %@,\ntap the link to confirm your account.
|
||||
internal static func subtitle(_ p1: Any) -> String {
|
||||
|
@ -34,6 +34,8 @@
|
||||
"Common.Controls.Timeline.LoadMore" = "Load More";
|
||||
"Common.Countable.Photo.Multiple" = "photos";
|
||||
"Common.Countable.Photo.Single" = "photo";
|
||||
"Scene.Compose.Title.NewReply" = "New Reply";
|
||||
"Scene.Compose.Title.NewToot" = "New Toot";
|
||||
"Scene.ConfirmEmail.Button.DontReceiveEmail" = "I never got an email";
|
||||
"Scene.ConfirmEmail.Button.OpenEmailApp" = "Open Email App";
|
||||
"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Check if your email address is correct as well as your junk folder if you haven’t.";
|
||||
|
102
Mastodon/Scene/Compose/ComposeViewController.swift
Normal file
102
Mastodon/Scene/Compose/ComposeViewController.swift
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// ComposeViewController.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import UIKit
|
||||
import Combine
|
||||
import TwitterTextEditor
|
||||
|
||||
final class ComposeViewController: UIViewController, NeedsDependency {
|
||||
|
||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
var viewModel: ComposeViewModel!
|
||||
|
||||
let tableView: UITableView = {
|
||||
let tableView = ControlContainableTableView()
|
||||
tableView.register(ComposeRepliedToTootContentTableViewCell.self, forCellReuseIdentifier: String(describing: ComposeRepliedToTootContentTableViewCell.self))
|
||||
tableView.register(ComposeTootContentTableViewCell.self, forCellReuseIdentifier: String(describing: ComposeTootContentTableViewCell.self))
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.separatorStyle = .none
|
||||
return tableView
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = Asset.Colors.Background.systemBackground.color
|
||||
viewModel.title
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] title in
|
||||
guard let self = self else { return }
|
||||
self.title = title
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(title: L10n.Common.Controls.Actions.cancel, style: .plain, target: self, action: #selector(ComposeViewController.cancelBarButtonItemPressed(_:)))
|
||||
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(tableView)
|
||||
NSLayoutConstraint.activate([
|
||||
tableView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
])
|
||||
|
||||
tableView.delegate = self
|
||||
viewModel.setupDiffableDataSource(for: tableView)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewController {
|
||||
|
||||
@objc private func cancelBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - TextEditorViewTextAttributesDelegate
|
||||
extension ComposeViewController: TextEditorViewTextAttributesDelegate {
|
||||
|
||||
func textEditorView(_ textEditorView: TextEditorView, updateAttributedString attributedString: NSAttributedString, completion: @escaping (NSAttributedString?) -> Void) {
|
||||
// TODO:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
extension ComposeViewController: UITableViewDelegate {
|
||||
|
||||
}
|
||||
|
||||
// MARK: - ComposeViewController
|
||||
extension ComposeViewController: UIAdaptivePresentationControllerDelegate {
|
||||
|
||||
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
|
||||
return viewModel.shouldDismiss.value
|
||||
}
|
||||
|
||||
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
|
||||
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
|
||||
}
|
40
Mastodon/Scene/Compose/ComposeViewModel+Diffable.swift
Normal file
40
Mastodon/Scene/Compose/ComposeViewModel+Diffable.swift
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// ComposeViewModel+Diffable.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension ComposeViewModel {
|
||||
|
||||
func setupDiffableDataSource(for tableView: UITableView) {
|
||||
diffableDataSource = UITableViewDiffableDataSource(tableView: tableView) { [weak self] tableView, indexPath, item -> UITableViewCell? in
|
||||
guard let self = self else { return nil }
|
||||
|
||||
switch item {
|
||||
case .replyTo(let tootObjectID):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ComposeRepliedToTootContentTableViewCell.self), for: indexPath) as! ComposeRepliedToTootContentTableViewCell
|
||||
// TODO:
|
||||
return cell
|
||||
case .toot(let attribute):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ComposeTootContentTableViewCell.self), for: indexPath) as! ComposeTootContentTableViewCell
|
||||
// TODO:
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<ComposeStatusSection, ComposeStatusItem>()
|
||||
snapshot.appendSections([.repliedTo, .status])
|
||||
switch composeKind {
|
||||
case .replyToot(let tootObjectID):
|
||||
snapshot.appendItems([.replyTo(tootObjectID: tootObjectID)], toSection: .repliedTo)
|
||||
snapshot.appendItems([.toot(attribute: ComposeStatusItem.InputAttribute(hasReplyTo: true))], toSection: .status)
|
||||
case .toot:
|
||||
snapshot.appendItems([.toot(attribute: ComposeStatusItem.InputAttribute(hasReplyTo: false))], toSection: .status)
|
||||
}
|
||||
diffableDataSource.apply(snapshot, animatingDifferences: false)
|
||||
}
|
||||
|
||||
}
|
44
Mastodon/Scene/Compose/ComposeViewModel.swift
Normal file
44
Mastodon/Scene/Compose/ComposeViewModel.swift
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// ComposeViewModel.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
import CoreData
|
||||
import CoreDataStack
|
||||
|
||||
final class ComposeViewModel {
|
||||
|
||||
// input
|
||||
let context: AppContext
|
||||
let composeKind: ComposeKind
|
||||
|
||||
// output
|
||||
var diffableDataSource: UITableViewDiffableDataSource<ComposeStatusSection, ComposeStatusItem>!
|
||||
let title: CurrentValueSubject<String, Never>
|
||||
let shouldDismiss = CurrentValueSubject<Bool, Never>(true)
|
||||
|
||||
init(
|
||||
context: AppContext,
|
||||
composeKind: ComposeKind
|
||||
) {
|
||||
self.context = context
|
||||
self.composeKind = composeKind
|
||||
switch composeKind {
|
||||
case .toot: self.title = CurrentValueSubject(L10n.Scene.Compose.Title.newToot)
|
||||
case .replyToot: self.title = CurrentValueSubject(L10n.Scene.Compose.Title.newReply)
|
||||
}
|
||||
// end init
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewModel {
|
||||
enum ComposeKind {
|
||||
case toot
|
||||
case replyToot(tootObjectID: NSManagedObjectID)
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
//
|
||||
// ComposeRepliedToTootContentTableViewCell.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class ComposeRepliedToTootContentTableViewCell: UITableViewCell {
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
_init()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
_init()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeRepliedToTootContentTableViewCell {
|
||||
|
||||
private func _init() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
//
|
||||
// ComposeTootContentTableViewCell.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class ComposeTootContentTableViewCell: UITableViewCell {
|
||||
|
||||
let statusView = StatusView()
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
_init()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
_init()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeTootContentTableViewCell {
|
||||
|
||||
private func _init() {
|
||||
statusView.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(statusView)
|
||||
NSLayoutConstraint.activate([
|
||||
statusView.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||
statusView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||
statusView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||
statusView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -166,7 +166,8 @@ extension HomeTimelineViewController {
|
||||
|
||||
@objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
|
||||
let composeViewModel = ComposeViewModel(context: context, composeKind: .toot)
|
||||
coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
|
||||
}
|
||||
|
||||
@objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
|
||||
|
@ -53,5 +53,6 @@ arch -x86_64 pod install
|
||||
- [Kingfisher](https://github.com/onevcat/Kingfisher)
|
||||
- [SwiftGen](https://github.com/SwiftGen/SwiftGen)
|
||||
- [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)
|
||||
- [TwitterTextEditor](https://github.com/twitter/TwitterTextEditor)
|
||||
|
||||
## License
|
||||
|
Loading…
x
Reference in New Issue
Block a user