diff --git a/App/Main/AppDelegate.swift b/App/Main/AppDelegate.swift index 5f50afa5a..7b3e783f6 100644 --- a/App/Main/AppDelegate.swift +++ b/App/Main/AppDelegate.swift @@ -59,6 +59,9 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { if ForumsClient.shared.isLoggedIn { setRootViewController(rootViewControllerStack.rootViewController, animated: false, completion: nil) } else { + if loginViewController == nil { + newLoginController() + } setRootViewController(loginViewController.enclosingNavigationController, animated: false, completion: nil) } @@ -121,13 +124,13 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { return true } - func applicationWillResignActive(_ application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { SmilieKeyboardSetIsAwfulAppActive(false) updateShortcutItems() } - func applicationDidBecomeActive(_ application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { SmilieKeyboardSetIsAwfulAppActive(true) // Screen brightness may have changed while the app wasn't paying attention. @@ -155,12 +158,19 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { try! managedObjectContext.save() } + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { + AppDelegate.instance.application(app, open: url, + sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String, + annotation: options[UIApplication.OpenURLOptionsKey.annotation] as Any + ) + } + func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { guard ForumsClient.shared.isLoggedIn, let route = try? AwfulRoute(url) - else { return false } - + else { return false } + open(route: route) return true } @@ -170,23 +180,29 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { return router.route(route) } + func fullReset() { + UserDefaults.standard.removeAllObjectsInMainBundleDomain() + emptyCache() + dataStore.deleteStoreAndReset() + logOut() + } + func logOut() { - // Logging out doubles as an "empty cache" button. let cookieJar = HTTPCookieStorage.shared for cookie in cookieJar.cookies ?? [] { cookieJar.deleteCookie(cookie) } - UserDefaults.standard.removeAllObjectsInMainBundleDomain() - emptyCache() - - // Do this after resetting settings so that it gets the default baseURL. + updateClientBaseURL() + if loginViewController == nil { + newLoginController() + } + setRootViewController(loginViewController.enclosingNavigationController, animated: true) { [weak self] in self?._rootViewControllerStack = nil + self?.urlRouter = nil - - self?.dataStore.deleteStoreAndReset() } } @@ -255,7 +271,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { return stack } - private lazy var loginViewController: LoginViewController! = { + private func createLoginViewController() -> LoginViewController! { let loginVC = LoginViewController.newFromStoryboard() loginVC.completionBlock = { [weak self] (login) in guard let self = self else { return } @@ -266,7 +282,16 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { }) } return loginVC + } + + private lazy var loginViewController : LoginViewController! = { + return self.createLoginViewController() }() + + private func newLoginController() { + loginViewController = createLoginViewController() + } + } private extension AppDelegate { diff --git a/App/Resources/Assets.xcassets/onepassword-button.imageset/Contents.json b/App/Resources/Assets.xcassets/onepassword-button.imageset/Contents.json deleted file mode 100644 index ef1c4c57a..000000000 --- a/App/Resources/Assets.xcassets/onepassword-button.imageset/Contents.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "images" : [ - { - "filename" : "onepassword-button.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "onepassword-button-light.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "onepassword-button@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "onepassword-button-light@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "onepassword-button@3x.png", - "idiom" : "universal", - "scale" : "3x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "onepassword-button-light@3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light.png b/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light.png deleted file mode 100644 index 6f4b019ea..000000000 Binary files a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light.png and /dev/null differ diff --git a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light@2x.png b/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light@2x.png deleted file mode 100644 index 2257425a6..000000000 Binary files a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light@2x.png and /dev/null differ diff --git a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light@3x.png b/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light@3x.png deleted file mode 100644 index 95bf09fc9..000000000 Binary files a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button-light@3x.png and /dev/null differ diff --git a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button.png b/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button.png deleted file mode 100644 index 05d6cf999..000000000 Binary files a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button.png and /dev/null differ diff --git a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button@2x.png b/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button@2x.png deleted file mode 100644 index 8de12de93..000000000 Binary files a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button@2x.png and /dev/null differ diff --git a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button@3x.png b/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button@3x.png deleted file mode 100644 index 749ff2fe3..000000000 Binary files a/App/Resources/Assets.xcassets/onepassword-button.imageset/onepassword-button@3x.png and /dev/null differ diff --git a/App/Settings/Settings.plist b/App/Settings/Settings.plist index 3df71a6ef..c04b4c22f 100644 --- a/App/Settings/Settings.plist +++ b/App/Settings/Settings.plist @@ -8,7 +8,7 @@ TitleKey username Explanation - Logging out erases all cached forums, threads, and posts. + Full reset erases all cached forums, threads, and posts. Action ShowProfile Settings @@ -25,6 +25,12 @@ Action EmptyCache + + Title + Full Reset + Action + FullReset + diff --git a/App/Templates/Acknowledgements.html.stencil b/App/Templates/Acknowledgements.html.stencil index 197b0752e..14550a4bf 100644 --- a/App/Templates/Acknowledgements.html.stencil +++ b/App/Templates/Acknowledgements.html.stencil @@ -146,34 +146,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -
-
-

1Password App Extension

- github.com/AgileBits/onepassword-app-extension -
- -
-Copyright (c) 2014 AgileBits Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-

PromiseKit

diff --git a/App/View Controllers/Login.storyboard b/App/View Controllers/Login.storyboard index ba25e514c..fb657323c 100644 --- a/App/View Controllers/Login.storyboard +++ b/App/View Controllers/Login.storyboard @@ -1,9 +1,10 @@ - + - + + @@ -42,7 +43,7 @@ - + @@ -63,27 +64,14 @@ - + - - + @@ -96,10 +84,7 @@ - - - @@ -207,11 +192,9 @@ - - diff --git a/App/View Controllers/LoginViewController.swift b/App/View Controllers/LoginViewController.swift index 4664aa84b..400d790be 100644 --- a/App/View Controllers/LoginViewController.swift +++ b/App/View Controllers/LoginViewController.swift @@ -3,7 +3,6 @@ // Copyright 2014 Awful Contributors. CC BY-NC-SA 3.0 US https://github.com/Awful/Awful.app import AwfulCore -import MiniOnePassword import UIKit private let Log = Logger.get() @@ -23,9 +22,6 @@ class LoginViewController: ViewController { @IBOutlet weak var activityIndicator: UIActivityIndicatorView! @IBOutlet private var consentToTermsTextView: UITextView! - @IBOutlet weak var onePasswordButton: UIButton! - @IBOutlet var onePasswordUnavailableConstraints: [NSLayoutConstraint]! - fileprivate enum State { case awaitingUsername case awaitingPassword @@ -72,13 +68,6 @@ class LoginViewController: ViewController { // Can't set this in the storyboard for some reason. nextBarButtonItem.isEnabled = false - - onePasswordButton.setImage(UIImage(named: "onepassword-button"), for: .normal) - - if !OnePassword.isAvailable { - onePasswordButton.removeFromSuperview() - view.addConstraints(onePasswordUnavailableConstraints) - } consentToTermsTextView.attributedText = { let format = NSAttributedString(string: LocalizedString("login.consent-to-terms.full-text")) @@ -129,29 +118,6 @@ class LoginViewController: ViewController { } } - @IBAction func didTapOnePassword(_ sender: UIButton) { - view.endEditing(true) - - OnePassword.findLogin( - urlString: "forums.somethingawful.com", - presentingViewController: self, - sender: .view(sender), - completion: { result in - switch result { - case let .success(loginInfo): - self.usernameTextField.text = loginInfo.username - self.passwordTextField.text = loginInfo.password - self.state = .canAttemptLogin - - case .failure(.userCancelled): - break - - case let .failure(error): - Log.e("1Password extension failed: \(error)") - } - }) - } - fileprivate func attemptToLogIn() { assert(state == .canAttemptLogin, "unexpected state") state = .attemptingLogin diff --git a/App/View Controllers/Settings/SettingsViewController.swift b/App/View Controllers/Settings/SettingsViewController.swift index 69350a699..5c8a7d682 100644 --- a/App/View Controllers/Settings/SettingsViewController.swift +++ b/App/View Controllers/Settings/SettingsViewController.swift @@ -370,26 +370,45 @@ final class SettingsViewController: TableViewController { defer { tableView.deselectRow(at: indexPath, animated: true) } let setting = self.setting(at: indexPath) + let settingTitle = setting["Title"] as? String + switch (setting["Action"] as? String, setting["ViewController"] as? String) { case ("LogOut"?, _): let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert) - alert.title = "Log Out" + alert.title = settingTitle ?? "Log Out" alert.message = "Are you sure you want to log out?" alert.addCancelActionWithHandler(nil) - alert.addActionWithTitle("Log Out", handler: { AppDelegate.instance.logOut() }) + alert.addActionWithTitle(settingTitle ?? "Log Out", handler: { + AppDelegate.instance.logOut() + }) present(alert, animated: true) case ("EmptyCache"?, _): - let usageBefore = URLCache.shared.currentDiskUsage - AppDelegate.instance.emptyCache(); - let usageAfter = URLCache.shared.currentDiskUsage - let message = "You cleared up \((usageBefore - usageAfter)/(1024*1024)) megabytes! Great job, go hog wild!!" - let alertController = UIAlertController(title: "Cache Cleared", message: message, preferredStyle: .alert) - let okAction = UIAlertAction(title: "OK", style: .default) { action in - self.dismiss(animated: true) - } - alertController.addAction(okAction) - self.present(alertController, animated: true) + let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert) + alert.title = settingTitle ?? "Empty Cache" + alert.message = "Are you sure you want to empty the cache?" + alert.addCancelActionWithHandler(nil) + alert.addActionWithTitle(settingTitle ?? "Empty Cache", handler: { + AppDelegate.instance.emptyCache(); + let message = "You emptied the cache! Great job, go hog wild!!" + let alertController = UIAlertController(title: "Cache Cleared", message: message, preferredStyle: .alert) + let okAction = UIAlertAction(title: "OK", style: .default) { action in + self.dismiss(animated: true) + } + alertController.addAction(okAction) + self.present(alertController, animated: true) + }) + present(alert, animated: true) + + case ("FullReset"?, _): + let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert) + alert.title = settingTitle ?? "Full Reset" + alert.message = "This will reset all settings, clear all caches and log out. Are you sure?" + alert.addCancelActionWithHandler(nil) + alert.addActionWithTitle(settingTitle ?? "Full Reset", handler: { + AppDelegate.instance.fullReset() + }) + present(alert, animated: true) case ("GoToAwfulThread"?, _): guard let threadID = setting["ThreadID"] as? String else { diff --git a/Awful.xcworkspace/contents.xcworkspacedata b/Awful.xcworkspace/contents.xcworkspacedata index 590e507c0..ef7f611ec 100644 --- a/Awful.xcworkspace/contents.xcworkspacedata +++ b/Awful.xcworkspace/contents.xcworkspacedata @@ -19,9 +19,6 @@ - - diff --git a/MiniOnePassword/.gitignore b/MiniOnePassword/.gitignore deleted file mode 100644 index 02c087533..000000000 --- a/MiniOnePassword/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj diff --git a/MiniOnePassword/.swiftpm/xcode/xcshareddata/xcschemes/MiniOnePassword.xcscheme b/MiniOnePassword/.swiftpm/xcode/xcshareddata/xcschemes/MiniOnePassword.xcscheme deleted file mode 100644 index c7a13b67c..000000000 --- a/MiniOnePassword/.swiftpm/xcode/xcshareddata/xcschemes/MiniOnePassword.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MiniOnePassword/Package.swift b/MiniOnePassword/Package.swift deleted file mode 100644 index c214b94c8..000000000 --- a/MiniOnePassword/Package.swift +++ /dev/null @@ -1,17 +0,0 @@ -// swift-tools-version:5.1 - -import PackageDescription - -let package = Package( - name: "MiniOnePassword", - products: [ - .library( - name: "MiniOnePassword", - targets: ["MiniOnePassword"]), - ], - targets: [ - .target( - name: "MiniOnePassword", - dependencies: []), - ] -) diff --git a/MiniOnePassword/README.md b/MiniOnePassword/README.md deleted file mode 100644 index 9457f34e3..000000000 --- a/MiniOnePassword/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# MiniOnePassword - -There's an [official 1Password library for loading passwords](https://github.com/agilebits/onepassword-app-extension) but it's way more than we need and has historically been unhelpfully packaged. MiniOnePassword just does the bits we need and is less of a pain to deal with. diff --git a/MiniOnePassword/Sources/MiniOnePassword/MiniOnePassword.swift b/MiniOnePassword/Sources/MiniOnePassword/MiniOnePassword.swift deleted file mode 100644 index 1c51b20fe..000000000 --- a/MiniOnePassword/Sources/MiniOnePassword/MiniOnePassword.swift +++ /dev/null @@ -1,173 +0,0 @@ -import CoreServices -import UIKit - -/* - Roughly ported from https://github.com/agilebits/onepassword-app-extension, which is unusable from UIKit for Mac because of its references to `UIWebView`. This code is not meaningfully different from that code, so here's its license and you should adhere to it: - - Copyright (c) 2014 AgileBits Inc. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/// Asks 1Password (or other compliant password managers) to supply a username and password. -public enum OnePassword { - - /// Checks if the 1Password extension (or similar) is available. You might hide the 1Password button if this returns `false`. - public static var isAvailable: Bool { - return UIApplication.shared.canOpenURL(URL(string: "org-appextension-feature-password-management://")!) - } - - /** - Finds the first available login among all logins matching the domain of `urlString` by using the system share sheet. - - For example, passing a `urlString` of `https://example.com` will match logins for both `spiffy.example.com` and `excellent.example.com`. - - 1Password will show a "Show All Logins" button if no logins are found matching `urlString`. - - - Parameter urlString: A domain filter for the logins shown by 1Password. Only the domain is considered, and subdomains are included. Passing `https://example.com` will match logins for all of `example.com`, `spiffy.example.com`, and `excellent.example.com`. - - Parameter sender: Where the share sheet popover should point. Note that `.none` is likely to crash on non-phone devices. - - Parameter completion: A block to call after attempting to find login info. The block is called on the main queue. - - - Note: Must be called on the main queue. - */ - public static func findLogin( - urlString: String, - presentingViewController: UIViewController, - sender: Sender, - completion: @escaping FindLoginCompletion) - { - guard isAvailable else { - return completion(.failure(.cannotOpenExtensionURL)) - } - - let item: [String: Any] = ["version_number": 184, "url_string": urlString] - let itemProvider = NSItemProvider(item: item as NSDictionary, typeIdentifier: "org.appextension.find-login-action") - let extensionItem = NSExtensionItem() - extensionItem.attachments = [itemProvider] - let activityVC = UIActivityViewController(activityItems: [extensionItem], applicationActivities: nil) - - activityVC.completionWithItemsHandler = { activityType, completed, returnedItems, activityError in - guard let returnedItem = returnedItems?.first else { - let error = activityError.map { OnePasswordError.activityError($0) } - ?? .userCancelled - return completion(.failure(error)) - } - - processReturnedItem(returnedItem, completion: completion) - } - - presentingViewController.present(activityVC, animated: true) - - switch sender { - case let .barButton(button): - activityVC.popoverPresentationController?.barButtonItem = button - - case let .view(view): - activityVC.popoverPresentationController?.sourceView = view - activityVC.popoverPresentationController?.sourceRect = view.bounds - - case .none where UIDevice.current.userInterfaceIdiom != .phone: - print("The sender parameter passed to OnePassword.findLogin(…) is likely required to not be .none; if you see a UIKit exception shortly, this might be why") - - case .none: - break // ok - } - } - - private static func processReturnedItem( - _ returnedItem: Any, - completion: @escaping FindLoginCompletion) - { - guard - let extensionItem = returnedItem as? NSExtensionItem, - let itemProvider = extensionItem.attachments?.first, - itemProvider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) else - { - return completion(.failure(.noPropertyListAttachment)) - } - - itemProvider.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil, completionHandler: { - rawItemDictionary, itemProviderError in - DispatchQueue.main.async { - guard let itemDictionary = rawItemDictionary as? [String: Any] else { - return completion(.failure(.missingPropertyList(itemProviderError))) - } - - guard - let username = itemDictionary["username"] as? String, - let password = itemDictionary["password"] as? String else - { - return completion(.failure(.missingKeyInPropertyListAttachment)) - } - - completion(.success(.init(username: username, password: password))) - } - }) - } - - /// - Seealso: `findLogin(urlString:presentingViewController:sender:completion:)`. - public typealias FindLoginCompletion = (Result) -> Void - - /** - Login info provided by 1Password. Use this to fill in your login form automatically for the user. - - - Seealso: `findLogin(urlString:presentingViewController:sender:completion:)`. - */ - public struct LoginInfo { - public let username: String - public let password: String - } - - /** - Where the share sheet popover should point. - - - Seealso: `findLogin(urlString:presentingViewController:sender:completion:)`. - */ - public enum Sender { - case barButton(UIBarButtonItem) - case view(UIView) - - /// Will likely crash with a UIKit exception on non-phones. - case none - } -} - -public enum OnePasswordError: Error { - - /// The system share sheet failed for some reason, and it wasn't because the user cancelled (that's `.userCancelled`). - case activityError(Error) - - /// No app seems to be installed that acts as a password manager. - case cannotOpenExtensionURL - - /// The password manager's provided login was missing either `username` or `password`. - case missingKeyInPropertyListAttachment - - /// The password manager did not return a dictionary property list. - case missingPropertyList(Error?) - - /// The share provider did not include any attachments. - case noAttachments - - /// The share provider did not include a property list among the attachments. - case noPropertyListAttachment - - /// The user decided not to find a login in their password manager. - case userCancelled -} diff --git a/Xcode/Awful.xcodeproj/project.pbxproj b/Xcode/Awful.xcodeproj/project.pbxproj index 6f3f83a28..cab4bed37 100644 --- a/Xcode/Awful.xcodeproj/project.pbxproj +++ b/Xcode/Awful.xcodeproj/project.pbxproj @@ -272,7 +272,6 @@ 1CA45D961F2C19AA005BEEC5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1CA45D951F2C19AA005BEEC5 /* Localizable.strings */; }; 1CA56FEB1A009BDF009A91AE /* PotentiallyObjectionableTexts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1CA56FEA1A009BDF009A91AE /* PotentiallyObjectionableTexts.plist */; }; 1CA887B01F40AE1A0059FEEC /* User+Presentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA887AF1F40AE1A0059FEEC /* User+Presentation.swift */; }; - 1CAEA24322D14FFE009CB9EB /* MiniOnePassword in Frameworks */ = {isa = PBXBuildFile; productRef = 1CAEA24222D14FFE009CB9EB /* MiniOnePassword */; }; 1CAF2372250C8CE400033F61 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = 1CAF2371250C8CE400033F61 /* Nuke */; }; 1CB15BCF1A9CEB8800176E73 /* Themes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CB15BCE1A9CEB8800176E73 /* Themes.swift */; }; 1CB15BEE1A9D33F600176E73 /* URLMenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CB15BED1A9D33F600176E73 /* URLMenuPresenter.swift */; }; @@ -1051,7 +1050,6 @@ 1C453F282338457A007AC6CD /* Stencil in Frameworks */, 1CD72E79265CA0D500FF3BF4 /* AwfulCore in Frameworks */, 1C5C2B8D22D195BF00EA5A80 /* ImgurAnonymousAPI in Frameworks */, - 1CAEA24322D14FFE009CB9EB /* MiniOnePassword in Frameworks */, D5035BC16B0E9C1817003AF2 /* Pods_Awful.framework in Frameworks */, 1C47122A2664CB8000E5AA74 /* Smilies in Frameworks */, 1C6BDD24265CB31E005475CE /* Logger in Frameworks */, @@ -2147,7 +2145,6 @@ ); name = Awful; packageProductDependencies = ( - 1CAEA24222D14FFE009CB9EB /* MiniOnePassword */, 1C5C2B8C22D195BF00EA5A80 /* ImgurAnonymousAPI */, 1C453F272338457A007AC6CD /* Stencil */, 1CAF2371250C8CE400033F61 /* Nuke */, @@ -3474,10 +3471,6 @@ package = 1CCBDFF822CB02D500E1BE6A /* XCRemoteSwiftPackageReference "HTMLReader" */; productName = HTMLReader; }; - 1CAEA24222D14FFE009CB9EB /* MiniOnePassword */ = { - isa = XCSwiftPackageProductDependency; - productName = MiniOnePassword; - }; 1CAF2371250C8CE400033F61 /* Nuke */ = { isa = XCSwiftPackageProductDependency; package = 1CAF2370250C8CE400033F61 /* XCRemoteSwiftPackageReference "Nuke" */;