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 */; };
|
DBC6462926A1736700B0E31B /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98338525C945ED00AD9700 /* Strings.swift */; };
|
||||||
DBC6462B26A1738900B0E31B /* MastodonUI in Frameworks */ = {isa = PBXBuildFile; productRef = DBC6462A26A1738900B0E31B /* MastodonUI */; };
|
DBC6462B26A1738900B0E31B /* MastodonUI in Frameworks */ = {isa = PBXBuildFile; productRef = DBC6462A26A1738900B0E31B /* MastodonUI */; };
|
||||||
DBC6462C26A176B000B0E31B /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98338625C945ED00AD9700 /* Assets.swift */; };
|
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 */; };
|
DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC7A671260C897100E57475 /* StatusContentWarningEditorView.swift */; };
|
||||||
DBC7A67C260DFADE00E57475 /* StatusPublishService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC7A67B260DFADE00E57475 /* StatusPublishService.swift */; };
|
DBC7A67C260DFADE00E57475 /* StatusPublishService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC7A67B260DFADE00E57475 /* StatusPublishService.swift */; };
|
||||||
DBCBCBF4267CB070000F5B51 /* Decode85.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBCBF3267CB070000F5B51 /* Decode85.swift */; };
|
DBCBCBF4267CB070000F5B51 /* Decode85.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBCBF3267CB070000F5B51 /* Decode85.swift */; };
|
||||||
|
@ -615,6 +617,20 @@
|
||||||
remoteGlobalIDString = DBC6461126A170AB00B0E31B;
|
remoteGlobalIDString = DBC6461126A170AB00B0E31B;
|
||||||
remoteInfo = ShareActionExtension;
|
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 */ = {
|
DBF8AE18263293E400C9C23C /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = DB427DCA25BAA00100D1B89D /* Project object */;
|
containerPortal = DB427DCA25BAA00100D1B89D /* Project object */;
|
||||||
|
@ -1281,6 +1297,8 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
DBC6462526A1720B00B0E31B /* MastodonUI in Frameworks */,
|
DBC6462526A1720B00B0E31B /* MastodonUI in Frameworks */,
|
||||||
|
DBC6463726A195DB00B0E31B /* CoreDataStack.framework in Frameworks */,
|
||||||
|
DBC6463326A195DB00B0E31B /* AppShared.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -3012,6 +3030,8 @@
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
DBC6463626A195DB00B0E31B /* PBXTargetDependency */,
|
||||||
|
DBC6463A26A195DB00B0E31B /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = ShareActionExtension;
|
name = ShareActionExtension;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
|
@ -3955,6 +3975,16 @@
|
||||||
target = DBC6461126A170AB00B0E31B /* ShareActionExtension */;
|
target = DBC6461126A170AB00B0E31B /* ShareActionExtension */;
|
||||||
targetProxy = DBC6461A26A170AB00B0E31B /* PBXContainerItemProxy */;
|
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 */ = {
|
DBF8AE19263293E400C9C23C /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = DBF8AE12263293E400C9C23C /* NotificationService */;
|
target = DBF8AE12263293E400C9C23C /* NotificationService */;
|
||||||
|
@ -4434,14 +4464,15 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 40;
|
||||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 0.9.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
@ -4454,14 +4485,15 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 40;
|
||||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 0.9.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
@ -4474,14 +4506,15 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 40;
|
||||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 0.9.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
@ -4494,14 +4527,15 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 40;
|
||||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 0.9.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
|
|
@ -12,37 +12,37 @@
|
||||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>21</integer>
|
<integer>20</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>2</integer>
|
<integer>5</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>3</integer>
|
<integer>7</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - Release.xcscheme_^#shared#^_</key>
|
<key>Mastodon - Release.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>1</integer>
|
<integer>3</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon.xcscheme_^#shared#^_</key>
|
<key>Mastodon.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>0</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>22</integer>
|
<integer>21</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>30</integer>
|
<integer>22</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
|
|
@ -105,8 +105,8 @@
|
||||||
"repositoryURL": "https://github.com/onevcat/Kingfisher.git",
|
"repositoryURL": "https://github.com/onevcat/Kingfisher.git",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "15d199e84677303a7004ed2c5ecaa1a90f3863f8",
|
"revision": "44450a8f564d7c0165f736ba2250649ff8d3e556",
|
||||||
"version": "6.2.1"
|
"version": "6.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -123,8 +123,8 @@
|
||||||
"repositoryURL": "https://github.com/kean/Nuke.git",
|
"repositoryURL": "https://github.com/kean/Nuke.git",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "69ae6d5b8c4b898450432f94bd35f863d3830cfc",
|
"revision": "83e1edaa5a30c567eb129c21c6d00f2f552d2c6f",
|
||||||
"version": "10.3.0"
|
"version": "10.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,13 +5,15 @@
|
||||||
// Created by MainasuK Cirno on 2021-2-5.
|
// Created by MainasuK Cirno on 2021-2-5.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
import os.log
|
import os.log
|
||||||
import UIKit
|
import UIKit
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
import FLEX
|
import FLEX
|
||||||
|
import SwiftUI
|
||||||
|
import MastodonUI
|
||||||
|
|
||||||
extension HomeTimelineViewController {
|
extension HomeTimelineViewController {
|
||||||
var debugMenu: UIMenu {
|
var debugMenu: UIMenu {
|
||||||
|
@ -55,6 +57,10 @@ extension HomeTimelineViewController {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.showThreadAction(action)
|
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
|
UIAction(title: "Settings", image: UIImage(systemName: "gear"), attributes: []) { [weak self] action in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.showSettings(action)
|
self.showSettings(action)
|
||||||
|
@ -363,5 +369,14 @@ extension HomeTimelineViewController {
|
||||||
transition: .modal(animated: true, completion: nil)
|
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
|
#endif
|
||||||
|
|
|
@ -6,7 +6,7 @@ import PackageDescription
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "MastodonSDK",
|
name: "MastodonSDK",
|
||||||
platforms: [
|
platforms: [
|
||||||
.iOS(.v13),
|
.iOS(.v14),
|
||||||
],
|
],
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
|
@ -22,6 +22,8 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.0"),
|
.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/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: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
// 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(
|
.target(
|
||||||
name: "MastodonUI",
|
name: "MastodonUI",
|
||||||
dependencies: ["MastodonExtension"]
|
dependencies: [
|
||||||
|
"MastodonExtension",
|
||||||
|
"Nuke",
|
||||||
|
"NukeFLAnimatedImagePlugin"
|
||||||
|
]
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "MastodonExtension",
|
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>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>$(MARKETING_VERSION)</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>NSExtension</key>
|
<key>NSExtension</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionAttributes</key>
|
<key>NSExtensionAttributes</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionActivationRule</key>
|
<key>NSExtensionActivationRule</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||||
<integer>4</integer>
|
<integer>4</integer>
|
||||||
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
||||||
<integer>1</integer>
|
<integer>1</integer>
|
||||||
<key>NSExtensionActivationSupportsText</key>
|
<key>NSExtensionActivationSupportsText</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||||
<integer>1</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSExtensionMainStoryboard</key>
|
<key>NSExtensionMainStoryboard</key>
|
||||||
<string>MainInterface</string>
|
<string>MainInterface</string>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import os.log
|
||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
import MastodonUI
|
import MastodonUI
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
class ShareViewController: UIViewController {
|
class ShareViewController: UIViewController {
|
||||||
|
|
||||||
|
@ -45,19 +46,8 @@ class ShareViewController: UIViewController {
|
||||||
return barButtonItem
|
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 {
|
extension ShareViewController {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
|
@ -74,6 +64,21 @@ extension ShareViewController {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.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
|
// viewModel.authentication
|
||||||
// .receive(on: DispatchQueue.main)
|
// .receive(on: DispatchQueue.main)
|
||||||
// .sink { [weak self] result in
|
// .sink { [weak self] result in
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import MastodonUI
|
||||||
|
|
||||||
final class ShareViewModel {
|
final class ShareViewModel {
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ final class ShareViewModel {
|
||||||
let isFetchAuthentication = CurrentValueSubject<Bool, Never>(true)
|
let isFetchAuthentication = CurrentValueSubject<Bool, Never>(true)
|
||||||
let isBusy = CurrentValueSubject<Bool, Never>(true)
|
let isBusy = CurrentValueSubject<Bool, Never>(true)
|
||||||
let isValid = CurrentValueSubject<Bool, Never>(false)
|
let isValid = CurrentValueSubject<Bool, Never>(false)
|
||||||
|
let composeViewModel = ComposeViewModel()
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
viewDidAppear.receive(on: DispatchQueue.main)
|
viewDidAppear.receive(on: DispatchQueue.main)
|
||||||
|
|
Loading…
Reference in New Issue