New status / share extension setup

This commit is contained in:
Justin Mazzocchi 2020-12-05 19:10:27 -08:00
parent 9725fb7d1d
commit 0416edc083
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
15 changed files with 479 additions and 3 deletions

View file

@ -35,6 +35,7 @@
"attachment.media-hidden" = "Media hidden";
"bookmarks" = "Bookmarks";
"cancel" = "Cancel";
"error" = "Error";
"favorites" = "Favorites";
"registration.review-terms-of-use-and-privacy-policy-%@" = "Please review %@'s Terms of Use and Privacy Policy to continue";
"registration.username" = "Username";
@ -134,6 +135,7 @@
"report.target-%@" = "Reporting %@";
"report.forward.hint" = "The account is from another server. Send an anonymized copy of the report there as well?";
"report.forward-%@" = "Forward report to %@";
"share-extension-error.no-account-found" = "No account found";
"status.bookmark" = "Bookmark";
"status.reblogged-by" = "%@ boosted";
"status.pinned-post" = "Pinned post";

View file

@ -41,6 +41,15 @@
D08B8D8D2544E6EC00B1EBEF /* PollResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B8D8C2544E6EC00B1EBEF /* PollResultView.swift */; };
D08E512125786A6600FA2C5F /* UIButton+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E512025786A6600FA2C5F /* UIButton+Extensions.swift */; };
D08E52612579D2E100FA2C5F /* DomainBlocksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E52602579D2E100FA2C5F /* DomainBlocksView.swift */; };
D08E5276257C36CA00FA2C5F /* Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = D08E526C257C36CA00FA2C5F /* Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D08E5292257C53B600FA2C5F /* NewStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E5291257C53B600FA2C5F /* NewStatusViewController.swift */; };
D08E529C257C58D600FA2C5F /* NewStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E529B257C58D600FA2C5F /* NewStatusView.swift */; };
D08E52A6257C61C000FA2C5F /* ShareExtensionNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E52A5257C61C000FA2C5F /* ShareExtensionNavigationViewController.swift */; };
D08E52B8257C62D500FA2C5F /* ViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D08E52B7257C62D500FA2C5F /* ViewModels */; };
D08E52BD257C635800FA2C5F /* NewStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E5291257C53B600FA2C5F /* NewStatusViewController.swift */; };
D08E52C7257C7AEE00FA2C5F /* ShareErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E52C6257C7AEE00FA2C5F /* ShareErrorViewController.swift */; };
D08E52CC257C80E300FA2C5F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0C7D45724F76169001EBDBB /* Localizable.strings */; };
D08E52D2257C811200FA2C5F /* ShareExtensionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E52D1257C811200FA2C5F /* ShareExtensionError.swift */; };
D0A1F4F7252E7D4B004435BF /* TableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A1F4F6252E7D4B004435BF /* TableViewDataSource.swift */; };
D0A7AC7325748BFF00E4E8AB /* ReportStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A7AC7225748BFF00E4E8AB /* ReportStatusView.swift */; };
D0B32F50250B373600311912 /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B32F4F250B373600311912 /* RegistrationView.swift */; };
@ -100,6 +109,13 @@
remoteGlobalIDString = D047FA8B24C3E21200AF17C5;
remoteInfo = "Metatext (iOS)";
};
D08E5274257C36CA00FA2C5F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D047FA8024C3E21000AF17C5 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D08E526B257C36CA00FA2C5F;
remoteInfo = "Share Extension";
};
D0E5361E24E3EB4D00FB1CE1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D047FA8024C3E21000AF17C5 /* Project object */;
@ -117,6 +133,7 @@
dstSubfolderSpec = 13;
files = (
D0E5362024E3EB4D00FB1CE1 /* Notification Service Extension.appex in Embed App Extensions */,
D08E5276257C36CA00FA2C5F /* Share Extension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
@ -161,6 +178,14 @@
D08B8D8C2544E6EC00B1EBEF /* PollResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollResultView.swift; sourceTree = "<group>"; };
D08E512025786A6600FA2C5F /* UIButton+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Extensions.swift"; sourceTree = "<group>"; };
D08E52602579D2E100FA2C5F /* DomainBlocksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainBlocksView.swift; sourceTree = "<group>"; };
D08E526C257C36CA00FA2C5F /* Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
D08E5273257C36CA00FA2C5F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D08E5277257C36CB00FA2C5F /* Share Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Share Extension.entitlements"; sourceTree = "<group>"; };
D08E5291257C53B600FA2C5F /* NewStatusViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewStatusViewController.swift; sourceTree = "<group>"; };
D08E529B257C58D600FA2C5F /* NewStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewStatusView.swift; sourceTree = "<group>"; };
D08E52A5257C61C000FA2C5F /* ShareExtensionNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionNavigationViewController.swift; sourceTree = "<group>"; };
D08E52C6257C7AEE00FA2C5F /* ShareErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareErrorViewController.swift; sourceTree = "<group>"; };
D08E52D1257C811200FA2C5F /* ShareExtensionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionError.swift; sourceTree = "<group>"; };
D0A1F4F6252E7D4B004435BF /* TableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewDataSource.swift; sourceTree = "<group>"; };
D0A7AC7225748BFF00E4E8AB /* ReportStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusView.swift; sourceTree = "<group>"; };
D0AD03552505814D0085A466 /* Base16 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Base16; sourceTree = "<group>"; };
@ -239,6 +264,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D08E5269257C36CA00FA2C5F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D08E52B8257C62D500FA2C5F /* ViewModels in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D0E5361624E3EB4D00FB1CE1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -271,6 +304,7 @@
D047FA8D24C3E21200AF17C5 /* Products */,
D0BECB962501BCE0002C1B13 /* Secrets */,
D0BDF66524FD7A6400C7FA1C /* ServiceLayer */,
D08E526D257C36CA00FA2C5F /* Share Extension */,
D0C7D41D24F76169001EBDBB /* Supporting Files */,
D0C7D45324F76169001EBDBB /* System */,
D0666A2224C677B400F3F04B /* Tests */,
@ -287,6 +321,7 @@
D047FA8C24C3E21200AF17C5 /* Metatext.app */,
D0666A2124C677B400F3F04B /* Tests.xctest */,
D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */,
D08E526C257C36CA00FA2C5F /* Share Extension.appex */,
);
name = Products;
sourceTree = "<group>";
@ -332,6 +367,18 @@
path = Transitions;
sourceTree = "<group>";
};
D08E526D257C36CA00FA2C5F /* Share Extension */ = {
isa = PBXGroup;
children = (
D08E5273257C36CA00FA2C5F /* Info.plist */,
D08E5277257C36CB00FA2C5F /* Share Extension.entitlements */,
D08E52C6257C7AEE00FA2C5F /* ShareErrorViewController.swift */,
D08E52D1257C811200FA2C5F /* ShareExtensionError.swift */,
D08E52A5257C61C000FA2C5F /* ShareExtensionNavigationViewController.swift */,
);
path = "Share Extension";
sourceTree = "<group>";
};
D0A1F4F5252E7D2A004435BF /* Data Sources */ = {
isa = PBXGroup;
children = (
@ -373,6 +420,7 @@
D0E569DF252931B100FA1D72 /* LoadMoreContentConfiguration.swift */,
D0E569DA2529319100FA1D72 /* LoadMoreView.swift */,
D03B1B29253818F3008F964B /* MediaPreferencesView.swift */,
D08E529B257C58D600FA2C5F /* NewStatusView.swift */,
D036AA0B254B612B009094DF /* NotificationContentConfiguration.swift */,
D036AA01254B6101009094DF /* NotificationListCell.swift */,
D0C7D42D24F76169001EBDBB /* NotificationTypesPreferencesView.swift */,
@ -402,9 +450,10 @@
D0C7D43024F76169001EBDBB /* View Controllers */ = {
isa = PBXGroup;
children = (
D08B8D41253F92B600B1EBEF /* ImagePageViewController.swift */,
D08B8D49253FC36500B1EBEF /* ImageNavigationController.swift */,
D08B8D41253F92B600B1EBEF /* ImagePageViewController.swift */,
D08B8D3C253F929E00B1EBEF /* ImageViewController.swift */,
D08E5291257C53B600FA2C5F /* NewStatusViewController.swift */,
D06BC5E525202AD90079541D /* ProfileViewController.swift */,
D0F0B12D251A97E400942152 /* TableViewController.swift */,
);
@ -481,6 +530,7 @@
);
dependencies = (
D0E5361F24E3EB4D00FB1CE1 /* PBXTargetDependency */,
D08E5275257C36CA00FA2C5F /* PBXTargetDependency */,
);
name = Metatext;
packageProductDependencies = (
@ -512,6 +562,26 @@
productReference = D0666A2124C677B400F3F04B /* Tests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
D08E526B257C36CA00FA2C5F /* Share Extension */ = {
isa = PBXNativeTarget;
buildConfigurationList = D08E5278257C36CB00FA2C5F /* Build configuration list for PBXNativeTarget "Share Extension" */;
buildPhases = (
D08E5268257C36CA00FA2C5F /* Sources */,
D08E5269257C36CA00FA2C5F /* Frameworks */,
D08E526A257C36CA00FA2C5F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Share Extension";
packageProductDependencies = (
D08E52B7257C62D500FA2C5F /* ViewModels */,
);
productName = "Share Extension";
productReference = D08E526C257C36CA00FA2C5F /* Share Extension.appex */;
productType = "com.apple.product-type.app-extension";
};
D0E5361824E3EB4D00FB1CE1 /* Notification Service Extension */ = {
isa = PBXNativeTarget;
buildConfigurationList = D0E5362124E3EB4D00FB1CE1 /* Build configuration list for PBXNativeTarget "Notification Service Extension" */;
@ -539,7 +609,7 @@
D047FA8024C3E21000AF17C5 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1200;
LastSwiftUpdateCheck = 1220;
LastUpgradeCheck = 1200;
ORGANIZATIONNAME = Metabolist;
TargetAttributes = {
@ -551,6 +621,9 @@
LastSwiftMigration = 1200;
TestTargetID = D047FA8B24C3E21200AF17C5;
};
D08E526B257C36CA00FA2C5F = {
CreatedOnToolsVersion = 12.2;
};
D0E5361824E3EB4D00FB1CE1 = {
CreatedOnToolsVersion = 12.0;
};
@ -575,6 +648,7 @@
D047FA8B24C3E21200AF17C5 /* Metatext */,
D0666A2024C677B400F3F04B /* Tests */,
D0E5361824E3EB4D00FB1CE1 /* Notification Service Extension */,
D08E526B257C36CA00FA2C5F /* Share Extension */,
);
};
/* End PBXProject section */
@ -597,6 +671,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D08E526A257C36CA00FA2C5F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D08E52CC257C80E300FA2C5F /* Localizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D0E5361724E3EB4D00FB1CE1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -648,6 +730,7 @@
D0BEB1F324F8EE8C001B0F04 /* StatusAttachmentView.swift in Sources */,
D0C7D49A24F7616A001EBDBB /* TableView.swift in Sources */,
D08B8D622540DE3B00B1EBEF /* ZoomTransitionController.swift in Sources */,
D08E529C257C58D600FA2C5F /* NewStatusView.swift in Sources */,
D0F0B12E251A97E400942152 /* TableViewController.swift in Sources */,
D0DD50CB256B1F24004A04F7 /* ReportView.swift in Sources */,
D0FE1C8F253686F9003EF1EB /* PlayerView.swift in Sources */,
@ -662,6 +745,7 @@
D0B5FE9B251583DB00478838 /* ProfileCollection+Extensions.swift in Sources */,
D0C7D49E24F7616A001EBDBB /* SecondaryNavigationView.swift in Sources */,
D08B8D602540DE3B00B1EBEF /* ZoomAnimator.swift in Sources */,
D08E5292257C53B600FA2C5F /* NewStatusViewController.swift in Sources */,
D08B8D672540DEB200B1EBEF /* ZoomAnimatableView.swift in Sources */,
D08B8D822544D80000B1EBEF /* PollOptionButton.swift in Sources */,
D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */,
@ -714,6 +798,17 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D08E5268257C36CA00FA2C5F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D08E52A6257C61C000FA2C5F /* ShareExtensionNavigationViewController.swift in Sources */,
D08E52BD257C635800FA2C5F /* NewStatusViewController.swift in Sources */,
D08E52D2257C811200FA2C5F /* ShareExtensionError.swift in Sources */,
D08E52C7257C7AEE00FA2C5F /* ShareErrorViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D0E5361524E3EB4D00FB1CE1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -730,6 +825,11 @@
target = D047FA8B24C3E21200AF17C5 /* Metatext */;
targetProxy = D0666A2624C677B400F3F04B /* PBXContainerItemProxy */;
};
D08E5275257C36CA00FA2C5F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D08E526B257C36CA00FA2C5F /* Share Extension */;
targetProxy = D08E5274257C36CA00FA2C5F /* PBXContainerItemProxy */;
};
D0E5361F24E3EB4D00FB1CE1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D0E5361824E3EB4D00FB1CE1 /* Notification Service Extension */;
@ -952,6 +1052,55 @@
};
name = Release;
};
D08E5279257C36CB00FA2C5F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 82HL67AXQ2;
INFOPLIST_FILE = "Share Extension/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 14.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 0.1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.metabolist.metatext.share-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
D08E527A257C36CB00FA2C5F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 82HL67AXQ2;
INFOPLIST_FILE = "Share Extension/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 14.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 0.1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.metabolist.metatext.share-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D0E5362224E3EB4D00FB1CE1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -1031,6 +1180,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D08E5278257C36CB00FA2C5F /* Build configuration list for PBXNativeTarget "Share Extension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D08E5279257C36CB00FA2C5F /* Debug */,
D08E527A257C36CB00FA2C5F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D0E5362124E3EB4D00FB1CE1 /* Build configuration list for PBXNativeTarget "Notification Service Extension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@ -1059,6 +1217,10 @@
package = D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */;
productName = KingfisherSwiftUI;
};
D08E52B7257C62D500FA2C5F /* ViewModels */ = {
isa = XCSwiftPackageProductDependency;
productName = ViewModels;
};
D0BECB972501C0FC002C1B13 /* Secrets */ = {
isa = XCSwiftPackageProductDependency;
productName = Secrets;

View file

@ -228,6 +228,10 @@ public extension IdentityService {
func domainBlocksService() -> DomainBlocksService {
DomainBlocksService(mastodonAPIClient: mastodonAPIClient)
}
func newStatusService() -> NewStatusService {
NewStatusService(id: id, identityDatabase: identityDatabase, environment: environment)
}
}
private extension IdentityService {

View file

@ -0,0 +1,35 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Combine
import DB
import Foundation
import Mastodon
import MastodonAPI
import Secrets
public struct NewStatusService {
private var id: Identity.Id
private let identityDatabase: IdentityDatabase
private let environment: AppEnvironment
public init(id: Identity.Id, identityDatabase: IdentityDatabase, environment: AppEnvironment) {
self.id = id
self.identityDatabase = identityDatabase
self.environment = environment
}
}
extension NewStatusService {
func mastodonAPIClient() throws -> MastodonAPIClient {
let secrets = Secrets(
identityId: id,
keychain: environment.keychain)
let mastodonAPIClient = MastodonAPIClient(
session: environment.session,
instanceURL: try secrets.getInstanceURL())
mastodonAPIClient.accessToken = try secrets.getAccessToken()
return mastodonAPIClient
}
}

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Share Extension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>4</integer>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
<key>NSExtensionPrincipalClass</key>
<string>ShareExtensionNavigationViewController</string>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.metabolist.metatext</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.metabolist.metatext</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,44 @@
// Copyright © 2020 Metabolist. All rights reserved.
import UIKit
class ShareErrorViewController: UIViewController {
let error: Error
init(error: Error) {
self.error = error
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.adjustsFontForContentSizeCategory = true
label.textAlignment = .center
label.font = .preferredFont(forTextStyle: .callout)
label.text = (error as? LocalizedError)?.errorDescription ?? NSLocalizedString("error", comment: "")
navigationItem.leftBarButtonItem = .init(
systemItem: .close,
primaryAction: UIAction { [weak self] _ in self?.extensionContext?.completeRequest(returningItems: nil) })
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
label.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
label.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
label.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor)
])
}
}

View file

@ -0,0 +1,16 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Foundation
enum ShareExtensionError: Error {
case noAccountFound
}
extension ShareExtensionError: LocalizedError {
var errorDescription: String? {
switch self {
case .noAccountFound:
return NSLocalizedString("share-extension-error.no-account-found", comment: "")
}
}
}

View file

@ -0,0 +1,50 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Combine
import ServiceLayer
import UIKit
import ViewModels
@objc(ShareExtensionNavigationViewController)
class ShareExtensionNavigationViewController: UINavigationController {
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
let vm: NewStatusViewModel
do {
vm = try newStatusViewModel()
} catch {
setViewControllers([ShareErrorViewController(error: error)], animated: false)
return
}
setViewControllers([NewStatusViewController(viewModel: vm)], animated: false)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
private extension ShareExtensionNavigationViewController {
func newStatusViewModel() throws -> NewStatusViewModel {
let environment = AppEnvironment.live(
userNotificationCenter: .current(),
reduceMotion: { UIAccessibility.isReduceMotionEnabled })
let allIdentitiesService = try AllIdentitiesService(environment: environment)
var id: Identity.Id?
_ = allIdentitiesService.immediateMostRecentlyUsedIdentityIdPublisher()
.sink { _ in } receiveValue: { id = $0 }
guard let idd = id else { throw ShareExtensionError.noAccountFound }
let newStatusService = try allIdentitiesService.identityService(id: idd).newStatusService()
return NewStatusViewModel(service: newStatusService)
}
}

View file

@ -0,0 +1,37 @@
// Copyright © 2020 Metabolist. All rights reserved.
import UIKit
import ViewModels
class NewStatusViewController: UIViewController {
private let viewModel: NewStatusViewModel
init(viewModel: NewStatusViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
navigationItem.leftBarButtonItem = .init(
systemItem: .close,
primaryAction: UIAction { [weak self] _ in self?.extensionContext?.completeRequest(returningItems: nil) })
}
override func didMove(toParent parent: UIViewController?) {
super.didMove(toParent: parent)
parent?.navigationItem.leftBarButtonItem = .init(
systemItem: .close,
primaryAction: UIAction { [weak self] _ in self?.presentingViewController?.dismiss(animated: true) })
}
}

View file

@ -90,4 +90,12 @@ public extension DomainBlocksViewModel {
static let preview = DomainBlocksViewModel(service: .init(mastodonAPIClient: .preview))
}
public extension NewStatusViewModel {
static let preview = NewStatusViewModel(
service: .init(
id: identityId,
identityDatabase: db,
environment: environment))
}
// swiftlint:enable force_try

View file

@ -17,6 +17,7 @@ public final class NavigationViewModel: ObservableObject {
}
@Published public private(set) var timelinesAndLists: [Timeline]
@Published public var presentingSecondaryNavigation = false
@Published public var presentingNewStatus = false
@Published public var alertItem: AlertItem?
public private(set) var timelineViewModel: CollectionItemsViewModel
@ -152,6 +153,10 @@ public extension NavigationViewModel {
collectionService: identification.service.service(timeline: .bookmarks),
identification: identification)
}
func newStatusViewModel() -> NewStatusViewModel {
NewStatusViewModel(service: identification.service.newStatusService())
}
}
extension NavigationViewModel.Tab: Identifiable {

View file

@ -0,0 +1,14 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Combine
import Foundation
import Mastodon
import ServiceLayer
public final class NewStatusViewModel: ObservableObject {
private let service: NewStatusService
public init(service: NewStatusService) {
self.service = service
}
}

22
Views/NewStatusView.swift Normal file
View file

@ -0,0 +1,22 @@
// Copyright © 2020 Metabolist. All rights reserved.
import SwiftUI
import ViewModels
struct NewStatusView: UIViewControllerRepresentable {
let viewModelClosure: () -> NewStatusViewModel
func makeUIViewController(context: Context) -> NewStatusViewController {
NewStatusViewController(viewModel: viewModelClosure())
}
func updateUIViewController(_ uiViewController: NewStatusViewController, context: Context) {
}
}
struct NewStatusView_Previews: PreviewProvider {
static var previews: some View {
NewStatusView { .preview }
}
}

View file

@ -37,6 +37,18 @@ struct TabNavigationView: View {
.environmentObject(viewModel)
.environmentObject(rootViewModel)
}
.background(
EmptyView()
.fullScreenCover(isPresented: $viewModel.presentingNewStatus) {
NavigationView {
NewStatusView(viewModelClosure: viewModel.newStatusViewModel)
.edgesIgnoringSafeArea(.all)
.navigationBarTitleDisplayMode(.inline)
}
.navigationViewStyle(StackNavigationViewStyle())
.environmentObject(viewModel)
.environmentObject(rootViewModel)
})
.alertItem($viewModel.alertItem)
.onAppear(perform: viewModel.refreshIdentity)
.onReceive(NotificationCenter.default
@ -152,7 +164,7 @@ private extension TabNavigationView {
if viewModel.identification.identity.authenticated
&& !viewModel.identification.identity.pending {
Button {
viewModel.presentingNewStatus = true
} label: {
ZStack {
Circle()