diff --git a/Localizations/Localizable.strings b/Localizations/Localizable.strings index b406bd3..9003aa6 100644 --- a/Localizations/Localizable.strings +++ b/Localizations/Localizable.strings @@ -85,7 +85,7 @@ "registration.terms-of-service" = "Terms of service"; "registration.agree-to-server-rules-and-terms-of-service" = "I agree to the server rules and terms of service"; "registration.password-confirmation-mismatch" = "Password and password confirmation do not match"; -"secondary-navigation.manage-accounts" = "Manage Accounts"; +"secondary-navigation.accounts" = "Accounts"; "secondary-navigation.lists" = "Lists"; "secondary-navigation.my-profile" = "My Profile"; "secondary-navigation.preferences" = "Preferences"; diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index 0a19adb..9b00b26 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -38,6 +38,7 @@ D036EBC2259FE2AD00EC1CFC /* UIVIewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E7AD3825870B13005F5E2D /* UIVIewController+Extensions.swift */; }; D036EBC7259FE2B700EC1CFC /* KingfisherOptionsInfo+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D46E24F76169001EBDBB /* KingfisherOptionsInfo+Extensions.swift */; }; D03B1B2A253818F3008F964B /* MediaPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B1B29253818F3008F964B /* MediaPreferencesView.swift */; }; + D03D87F425C23C44004DCBB2 /* SecondaryNavigationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */; }; D04226FD2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04226FC2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift */; }; D04F9E8E259E9C950081B0C9 /* ViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D04F9E8D259E9C950081B0C9 /* ViewModels */; }; D05936CF25A8D79800754FDF /* EditAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */; }; @@ -226,6 +227,7 @@ D036AA0B254B612B009094DF /* NotificationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentConfiguration.swift; sourceTree = ""; }; D036AA16254CA823009094DF /* StatusBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBodyView.swift; sourceTree = ""; }; D03B1B29253818F3008F964B /* MediaPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreferencesView.swift; sourceTree = ""; }; + D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryNavigationTitleView.swift; sourceTree = ""; }; D04226FC2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartupAndSyncingPreferencesView.swift; sourceTree = ""; }; D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; }; D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAttachmentViewController.swift; sourceTree = ""; }; @@ -548,6 +550,7 @@ D0C7D42724F76169001EBDBB /* RootView.swift */, D02E1F94250B13210071AD56 /* SafariView.swift */, D035F8C625B96A4000DC75ED /* SecondaryNavigationButton.swift */, + D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */, D0C7D42924F76169001EBDBB /* SecondaryNavigationView.swift */, D04226FC2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift */, D0625E55250F086B00502611 /* Status */, @@ -899,6 +902,7 @@ D059373325AAEA7000754FDF /* CompositionPollView.swift in Sources */, D08B8D8D2544E6EC00B1EBEF /* PollResultView.swift in Sources */, D0C7D4D524F7616A001EBDBB /* String+Extensions.swift in Sources */, + D03D87F425C23C44004DCBB2 /* SecondaryNavigationTitleView.swift in Sources */, D07EC7F225B13E57006DF726 /* EmojiView.swift in Sources */, D05936CF25A8D79800754FDF /* EditAttachmentViewController.swift in Sources */, D0C7D4A224F7616A001EBDBB /* NotificationTypesPreferencesView.swift in Sources */, diff --git a/View Controllers/MainNavigationViewController.swift b/View Controllers/MainNavigationViewController.swift index 9dd8b34..9902001 100644 --- a/View Controllers/MainNavigationViewController.swift +++ b/View Controllers/MainNavigationViewController.swift @@ -129,6 +129,7 @@ private extension MainNavigationViewController { hostingController.navigationItem.leftBarButtonItem = UIBarButtonItem( systemItem: .close, primaryAction: UIAction { [weak self] _ in self?.viewModel.presentingSecondaryNavigation = false }) + hostingController.navigationItem.titleView = SecondaryNavigationTitleView(viewModel: viewModel) let navigationController = UINavigationController(rootViewController: hostingController) diff --git a/Views/SecondaryNavigationTitleView.swift b/Views/SecondaryNavigationTitleView.swift new file mode 100644 index 0000000..d994c0c --- /dev/null +++ b/Views/SecondaryNavigationTitleView.swift @@ -0,0 +1,87 @@ +// Copyright © 2021 Metabolist. All rights reserved. + +import Kingfisher +import UIKit +import ViewModels + +final class SecondaryNavigationTitleView: UIView { + private let viewModel: NavigationViewModel + private let avatarImageView = AnimatedImageView() + private let displayNameLabel = UILabel() + private let accountLabel = UILabel() + private let stackView = UIStackView() + + init(viewModel: NavigationViewModel) { + self.viewModel = viewModel + + super.init(frame: .zero) + + initialSetup() + applyViewModel() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension SecondaryNavigationTitleView { + func initialSetup() { + addSubview(avatarImageView) + avatarImageView.translatesAutoresizingMaskIntoConstraints = false + avatarImageView.layer.cornerRadius = .barButtonItemDimension / 2 + avatarImageView.autoPlayAnimatedImage = viewModel.identityContext.appPreferences.animateAvatars == .everywhere + avatarImageView.contentMode = .scaleAspectFill + avatarImageView.clipsToBounds = true + + addSubview(stackView) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.axis = .vertical + stackView.spacing = .ultraCompactSpacing + + stackView.addArrangedSubview(displayNameLabel) + displayNameLabel.adjustsFontForContentSizeCategory = true + displayNameLabel.adjustsFontSizeToFitWidth = true + displayNameLabel.minimumScaleFactor = 0.5 + displayNameLabel.font = .preferredFont(forTextStyle: .headline) + + stackView.addArrangedSubview(accountLabel) + accountLabel.adjustsFontForContentSizeCategory = true + accountLabel.adjustsFontSizeToFitWidth = true + accountLabel.minimumScaleFactor = 0.5 + accountLabel.font = .preferredFont(forTextStyle: .footnote) + accountLabel.textColor = .secondaryLabel + + NSLayoutConstraint.activate([ + avatarImageView.widthAnchor.constraint(equalToConstant: .barButtonItemDimension), + avatarImageView.heightAnchor.constraint(equalToConstant: .barButtonItemDimension), + avatarImageView.leadingAnchor.constraint(equalTo: leadingAnchor), + avatarImageView.centerYAnchor.constraint(equalTo: centerYAnchor), + stackView.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: .defaultSpacing), + stackView.topAnchor.constraint(equalTo: topAnchor), + stackView.trailingAnchor.constraint(equalTo: trailingAnchor), + stackView.bottomAnchor.constraint(equalTo: bottomAnchor) + ]) + } + + func applyViewModel() { + avatarImageView.kf.setImage(with: viewModel.identityContext.identity.image) + + if let displayName = viewModel.identityContext.identity.account?.displayName, + !displayName.isEmpty { + let mutableDisplayName = NSMutableAttributedString(string: displayName) + + if let emojis = viewModel.identityContext.identity.account?.emojis { + mutableDisplayName.insert(emojis: emojis, view: displayNameLabel) + mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight) + } + + displayNameLabel.attributedText = mutableDisplayName + } else { + displayNameLabel.isHidden = true + } + + accountLabel.text = viewModel.identityContext.identity.handle + } +} diff --git a/Views/SecondaryNavigationView.swift b/Views/SecondaryNavigationView.swift index 914b3b9..0f48fa3 100644 --- a/Views/SecondaryNavigationView.swift +++ b/Views/SecondaryNavigationView.swift @@ -25,43 +25,9 @@ struct SecondaryNavigationView: View { } NavigationLink( destination: IdentitiesView(viewModel: .init(identityContext: viewModel.identityContext)) - .environmentObject(rootViewModel), - label: { - HStack { - KFImage(viewModel.identityContext.identity.image) - .downsampled(dimension: .avatarDimension, scaleFactor: displayScale) - VStack(alignment: .leading) { - if viewModel.identityContext.identity.authenticated { - if let account = viewModel.identityContext.identity.account { - CustomEmojiText( - text: account.displayName, - emojis: account.emojis, - textStyle: .headline) - } - Text(viewModel.identityContext.identity.handle) - .font(.subheadline) - .foregroundColor(.secondary) - .lineLimit(1) - .minimumScaleFactor(0.5) - } else { - Text(viewModel.identityContext.identity.handle) - .font(.headline) - if let instance = viewModel.identityContext.identity.instance { - Text(instance.uri) - .font(.subheadline) - .foregroundColor(.secondary) - .lineLimit(1) - .minimumScaleFactor(0.5) - } - } - - Spacer() - Text("secondary-navigation.manage-accounts") - .font(.subheadline) - } - .padding() - } - }) + .environmentObject(rootViewModel)) { + Label("secondary-navigation.accounts", systemImage: "rectangle.stack.person.crop") + } } Section { NavigationLink(destination: ListsView(viewModel: .init(identityContext: viewModel.identityContext))