forked from zelo72/mastodon-ios
feat: add compose view
This commit is contained in:
parent
7804f679c5
commit
079e611f33
|
@ -491,6 +491,8 @@
|
|||
DBC6462926A1736700B0E31B /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98338525C945ED00AD9700 /* Strings.swift */; };
|
||||
DBC6462B26A1738900B0E31B /* MastodonUI in Frameworks */ = {isa = PBXBuildFile; productRef = DBC6462A26A1738900B0E31B /* MastodonUI */; };
|
||||
DBC6462C26A176B000B0E31B /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98338625C945ED00AD9700 /* Assets.swift */; };
|
||||
DBC6463326A195DB00B0E31B /* AppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; };
|
||||
DBC6463726A195DB00B0E31B /* CoreDataStack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB89B9EE25C10FD0008580ED /* CoreDataStack.framework */; };
|
||||
DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC7A671260C897100E57475 /* StatusContentWarningEditorView.swift */; };
|
||||
DBC7A67C260DFADE00E57475 /* StatusPublishService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC7A67B260DFADE00E57475 /* StatusPublishService.swift */; };
|
||||
DBCBCBF4267CB070000F5B51 /* Decode85.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBCBF3267CB070000F5B51 /* Decode85.swift */; };
|
||||
|
@ -615,6 +617,20 @@
|
|||
remoteGlobalIDString = DBC6461126A170AB00B0E31B;
|
||||
remoteInfo = ShareActionExtension;
|
||||
};
|
||||
DBC6463526A195DB00B0E31B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DB427DCA25BAA00100D1B89D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = DB68047E2637CD4C00430867;
|
||||
remoteInfo = AppShared;
|
||||
};
|
||||
DBC6463926A195DB00B0E31B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DB427DCA25BAA00100D1B89D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = DB89B9ED25C10FD0008580ED;
|
||||
remoteInfo = CoreDataStack;
|
||||
};
|
||||
DBF8AE18263293E400C9C23C /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DB427DCA25BAA00100D1B89D /* Project object */;
|
||||
|
@ -1281,6 +1297,8 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DBC6462526A1720B00B0E31B /* MastodonUI in Frameworks */,
|
||||
DBC6463726A195DB00B0E31B /* CoreDataStack.framework in Frameworks */,
|
||||
DBC6463326A195DB00B0E31B /* AppShared.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3012,6 +3030,8 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
DBC6463626A195DB00B0E31B /* PBXTargetDependency */,
|
||||
DBC6463A26A195DB00B0E31B /* PBXTargetDependency */,
|
||||
);
|
||||
name = ShareActionExtension;
|
||||
packageProductDependencies = (
|
||||
|
@ -3955,6 +3975,16 @@
|
|||
target = DBC6461126A170AB00B0E31B /* ShareActionExtension */;
|
||||
targetProxy = DBC6461A26A170AB00B0E31B /* PBXContainerItemProxy */;
|
||||
};
|
||||
DBC6463626A195DB00B0E31B /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = DB68047E2637CD4C00430867 /* AppShared */;
|
||||
targetProxy = DBC6463526A195DB00B0E31B /* PBXContainerItemProxy */;
|
||||
};
|
||||
DBC6463A26A195DB00B0E31B /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = DB89B9ED25C10FD0008580ED /* CoreDataStack */;
|
||||
targetProxy = DBC6463926A195DB00B0E31B /* PBXContainerItemProxy */;
|
||||
};
|
||||
DBF8AE19263293E400C9C23C /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = DBF8AE12263293E400C9C23C /* NotificationService */;
|
||||
|
@ -4434,14 +4464,15 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 40;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.9.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4454,14 +4485,15 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 40;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.9.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4474,14 +4506,15 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 40;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.9.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4494,14 +4527,15 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 40;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.9.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
|
|
@ -12,37 +12,37 @@
|
|||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>21</integer>
|
||||
<integer>20</integer>
|
||||
</dict>
|
||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
<integer>5</integer>
|
||||
</dict>
|
||||
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
<integer>7</integer>
|
||||
</dict>
|
||||
<key>Mastodon - Release.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
<key>Mastodon.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>22</integer>
|
||||
<integer>21</integer>
|
||||
</dict>
|
||||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>30</integer>
|
||||
<integer>22</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -105,8 +105,8 @@
|
|||
"repositoryURL": "https://github.com/onevcat/Kingfisher.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "15d199e84677303a7004ed2c5ecaa1a90f3863f8",
|
||||
"version": "6.2.1"
|
||||
"revision": "44450a8f564d7c0165f736ba2250649ff8d3e556",
|
||||
"version": "6.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -123,8 +123,8 @@
|
|||
"repositoryURL": "https://github.com/kean/Nuke.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "69ae6d5b8c4b898450432f94bd35f863d3830cfc",
|
||||
"version": "10.3.0"
|
||||
"revision": "83e1edaa5a30c567eb129c21c6d00f2f552d2c6f",
|
||||
"version": "10.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
// Created by MainasuK Cirno on 2021-2-5.
|
||||
//
|
||||
|
||||
|
||||
#if DEBUG
|
||||
import os.log
|
||||
import UIKit
|
||||
import CoreData
|
||||
import CoreDataStack
|
||||
|
||||
#if DEBUG
|
||||
import FLEX
|
||||
import SwiftUI
|
||||
import MastodonUI
|
||||
|
||||
extension HomeTimelineViewController {
|
||||
var debugMenu: UIMenu {
|
||||
|
@ -55,6 +57,10 @@ extension HomeTimelineViewController {
|
|||
guard let self = self else { return }
|
||||
self.showThreadAction(action)
|
||||
},
|
||||
UIAction(title: "Show Share Action Compose", image: UIImage(systemName: "square.and.arrow.up"), attributes: []) { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.showShareActionExtensionComposeView(action)
|
||||
},
|
||||
UIAction(title: "Settings", image: UIImage(systemName: "gear"), attributes: []) { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.showSettings(action)
|
||||
|
@ -363,5 +369,14 @@ extension HomeTimelineViewController {
|
|||
transition: .modal(animated: true, completion: nil)
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func showShareActionExtensionComposeView(_ sender: UIAction) {
|
||||
let viewController = UIHostingController(
|
||||
rootView: ComposeView().environmentObject(MastodonUI.ComposeViewModel())
|
||||
)
|
||||
let navigationController = UINavigationController(rootViewController: viewController)
|
||||
present(navigationController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,7 @@ import PackageDescription
|
|||
let package = Package(
|
||||
name: "MastodonSDK",
|
||||
platforms: [
|
||||
.iOS(.v13),
|
||||
.iOS(.v14),
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
|
@ -22,6 +22,8 @@ let package = Package(
|
|||
dependencies: [
|
||||
.package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.0"),
|
||||
.package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"),
|
||||
.package(url: "https://github.com/kean/Nuke.git", from: "10.3.1"),
|
||||
.package(name: "NukeFLAnimatedImagePlugin", url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"),
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
|
@ -35,7 +37,11 @@ let package = Package(
|
|||
),
|
||||
.target(
|
||||
name: "MastodonUI",
|
||||
dependencies: ["MastodonExtension"]
|
||||
dependencies: [
|
||||
"MastodonExtension",
|
||||
"Nuke",
|
||||
"NukeFLAnimatedImagePlugin"
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "MastodonExtension",
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// AnimatedImage.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-16.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Nuke
|
||||
import FLAnimatedImage
|
||||
|
||||
struct AnimatedImage: UIViewRepresentable {
|
||||
|
||||
let imageURL: URL?
|
||||
|
||||
func makeUIView(context: Context) -> FLAnimatedImageViewProxy {
|
||||
let proxy = FLAnimatedImageViewProxy(frame: .zero)
|
||||
Nuke.loadImage(with: imageURL, into: proxy.imageView)
|
||||
return proxy
|
||||
}
|
||||
|
||||
func updateUIView(_ proxy: FLAnimatedImageViewProxy, context: Context) {
|
||||
Nuke.cancelRequest(for: proxy.imageView)
|
||||
Nuke.loadImage(with: imageURL, into: proxy.imageView)
|
||||
}
|
||||
}
|
||||
|
||||
final class FLAnimatedImageViewProxy: UIView {
|
||||
let imageView = FLAnimatedImageView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(imageView)
|
||||
NSLayoutConstraint.activate([
|
||||
imageView.topAnchor.constraint(equalTo: topAnchor),
|
||||
imageView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
imageView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
imageView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
struct AnimatedImage_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
AnimatedImage(
|
||||
imageURL: URL(string: "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif")
|
||||
)
|
||||
.frame(width: 300, height: 300)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// ComposeView.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-16.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
public struct ComposeView: View {
|
||||
|
||||
@EnvironmentObject public var viewModel: ComposeViewModel
|
||||
|
||||
public init() { }
|
||||
|
||||
public var body: some View {
|
||||
GeometryReader { proxy in
|
||||
ScrollView(.vertical) {
|
||||
StatusAuthorView(
|
||||
avatarImageURL: viewModel.avatarImageURL,
|
||||
name: viewModel.authorName,
|
||||
username: viewModel.authorUsername
|
||||
)
|
||||
TextEditorView(
|
||||
string: $viewModel.statusContent,
|
||||
width: viewModel.frame.width,
|
||||
attributedString: viewModel.statusContentAttributedString
|
||||
)
|
||||
.frame(width: viewModel.frame.width)
|
||||
.frame(minHeight: 100)
|
||||
ForEach(viewModel.attachments, id: \.self) { image in
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
.aspectRatio(16.0/9.0, contentMode: .fill)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.gray)
|
||||
.cornerRadius(4)
|
||||
}
|
||||
} // end ScrollView
|
||||
.preference(
|
||||
key: ComposeViewFramePreferenceKey.self,
|
||||
value: proxy.frame(in: .local)
|
||||
)
|
||||
.onPreferenceChange(ComposeViewFramePreferenceKey.self) { frame in
|
||||
viewModel.frame = frame
|
||||
print(frame)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ComposeViewFramePreferenceKey: PreferenceKey {
|
||||
static var defaultValue: CGRect = .zero
|
||||
static func reduce(value: inout CGRect, nextValue: () -> CGRect) { }
|
||||
}
|
||||
|
||||
struct ComposeView_Previews: PreviewProvider {
|
||||
|
||||
static let viewModel: ComposeViewModel = {
|
||||
let viewModel = ComposeViewModel()
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
ComposeView().environmentObject(viewModel)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// ComposeViewModel.swift
|
||||
// ShareActionExtension
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-16.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
public class ComposeViewModel: ObservableObject {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
@Published var frame: CGRect = .zero
|
||||
|
||||
@Published var avatarImageURL: URL?
|
||||
@Published var authorName: String = ""
|
||||
@Published var authorUsername: String = ""
|
||||
|
||||
@Published var statusContent = ""
|
||||
@Published var statusContentAttributedString = NSAttributedString()
|
||||
@Published var contentWarningContent = ""
|
||||
|
||||
@Published var attachments: [UIImage] = []
|
||||
|
||||
public init() {
|
||||
$statusContent
|
||||
.map { NSAttributedString(string: $0) }
|
||||
.assign(to: &$statusContentAttributedString)
|
||||
|
||||
#if DEBUG
|
||||
avatarImageURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif")
|
||||
authorName = "Alice"
|
||||
authorUsername = "alice"
|
||||
attachments = [
|
||||
UIImage(systemName: "photo")!,
|
||||
UIImage(systemName: "photo")!,
|
||||
UIImage(systemName: "photo")!,
|
||||
UIImage(systemName: "photo")!,
|
||||
]
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// StatusAuthorView.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-16.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Nuke
|
||||
import NukeFLAnimatedImagePlugin
|
||||
import FLAnimatedImage
|
||||
|
||||
struct StatusAuthorView: View {
|
||||
|
||||
let avatarImageURL: URL?
|
||||
let name: String
|
||||
let username: String
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 5) {
|
||||
AnimatedImage(imageURL: avatarImageURL)
|
||||
.frame(width: 42, height: 42)
|
||||
.cornerRadius(4)
|
||||
VStack(alignment: .leading) {
|
||||
Text(name)
|
||||
.font(.headline)
|
||||
Text("@" + username)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct StatusAuthorView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
StatusAuthorView(
|
||||
avatarImageURL: URL(string: "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"),
|
||||
name: "Alice",
|
||||
username: "alice"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// TextEditorView.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
public struct TextEditorView: UIViewRepresentable {
|
||||
|
||||
@Binding var string: String
|
||||
|
||||
let width: CGFloat
|
||||
let attributedString: NSAttributedString
|
||||
|
||||
public init(
|
||||
string: Binding<String>,
|
||||
width: CGFloat,
|
||||
attributedString: NSAttributedString
|
||||
) {
|
||||
self._string = string
|
||||
self.width = width
|
||||
self.attributedString = attributedString
|
||||
}
|
||||
|
||||
public func makeUIView(context: Context) -> UITextView {
|
||||
let textView = UITextView(frame: .zero)
|
||||
|
||||
textView.isScrollEnabled = false
|
||||
textView.font = .preferredFont(forTextStyle: .body)
|
||||
textView.textColor = .label
|
||||
|
||||
textView.delegate = context.coordinator
|
||||
|
||||
textView.translatesAutoresizingMaskIntoConstraints = false
|
||||
let widthLayoutConstraint = textView.widthAnchor.constraint(equalToConstant: 100)
|
||||
widthLayoutConstraint.priority = .required - 1
|
||||
context.coordinator.widthLayoutConstraint = widthLayoutConstraint
|
||||
|
||||
|
||||
return textView
|
||||
}
|
||||
|
||||
public func updateUIView(_ textView: UITextView, context: Context) {
|
||||
// update content
|
||||
// textView.attributedText = attributedString
|
||||
textView.text = string
|
||||
|
||||
// update layout
|
||||
context.coordinator.updateLayout(width: width)
|
||||
}
|
||||
|
||||
public func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
}
|
||||
|
||||
public class Coordinator: NSObject, UITextViewDelegate {
|
||||
var parent: TextEditorView
|
||||
var widthLayoutConstraint: NSLayoutConstraint?
|
||||
|
||||
init(_ parent: TextEditorView) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
public func textViewDidChange(_ textView: UITextView) {
|
||||
parent.string = textView.text
|
||||
}
|
||||
|
||||
func updateLayout(width: CGFloat) {
|
||||
guard let widthLayoutConstraint = widthLayoutConstraint else { return }
|
||||
widthLayoutConstraint.constant = width
|
||||
widthLayoutConstraint.isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -17,24 +17,24 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationRule</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||
<integer>4</integer>
|
||||
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsText</key>
|
||||
<true/>
|
||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>NSExtensionActivationRule</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||
<integer>4</integer>
|
||||
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsText</key>
|
||||
<true/>
|
||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSExtensionMainStoryboard</key>
|
||||
<string>MainInterface</string>
|
||||
|
|
|
@ -9,6 +9,7 @@ import os.log
|
|||
import UIKit
|
||||
import Combine
|
||||
import MastodonUI
|
||||
import SwiftUI
|
||||
|
||||
class ShareViewController: UIViewController {
|
||||
|
||||
|
@ -45,19 +46,8 @@ class ShareViewController: UIViewController {
|
|||
return barButtonItem
|
||||
}()
|
||||
|
||||
// let tableView: ComposeTableView = {
|
||||
// let tableView = ComposeTableView()
|
||||
// tableView.register(ComposeStatusContentTableViewCell.self, forCellReuseIdentifier: String(describing: ComposeStatusContentTableViewCell.self))
|
||||
// tableView.register(ComposeStatusAttachmentTableViewCell.self, forCellReuseIdentifier: String(describing: ComposeStatusAttachmentTableViewCell.self))
|
||||
// tableView.alwaysBounceVertical = true
|
||||
// tableView.separatorStyle = .none
|
||||
// tableView.tableFooterView = UIView()
|
||||
// return tableView
|
||||
// }()
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension ShareViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
@ -74,6 +64,21 @@ extension ShareViewController {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
let hostingViewController = UIHostingController(
|
||||
rootView: ComposeView().environmentObject(viewModel.composeViewModel)
|
||||
)
|
||||
addChild(hostingViewController)
|
||||
view.addSubview(hostingViewController.view)
|
||||
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(hostingViewController.view)
|
||||
NSLayoutConstraint.activate([
|
||||
hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
])
|
||||
hostingViewController.didMove(toParent: self)
|
||||
|
||||
// viewModel.authentication
|
||||
// .receive(on: DispatchQueue.main)
|
||||
// .sink { [weak self] result in
|
||||
|
|
|
@ -10,6 +10,7 @@ import Foundation
|
|||
import Combine
|
||||
import CoreData
|
||||
import CoreDataStack
|
||||
import MastodonUI
|
||||
|
||||
final class ShareViewModel {
|
||||
|
||||
|
@ -27,6 +28,7 @@ final class ShareViewModel {
|
|||
let isFetchAuthentication = CurrentValueSubject<Bool, Never>(true)
|
||||
let isBusy = CurrentValueSubject<Bool, Never>(true)
|
||||
let isValid = CurrentValueSubject<Bool, Never>(false)
|
||||
let composeViewModel = ComposeViewModel()
|
||||
|
||||
init() {
|
||||
viewDidAppear.receive(on: DispatchQueue.main)
|
||||
|
|
Loading…
Reference in New Issue