feat: update account list UI
This commit is contained in:
parent
66af30da2a
commit
46ebdd8059
|
@ -534,6 +534,9 @@
|
||||||
"show_next": "Show Next",
|
"show_next": "Show Next",
|
||||||
"show_previous": "Show Previous"
|
"show_previous": "Show Previous"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"account_list": {
|
||||||
|
"add_account": "Add Account"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -425,6 +425,9 @@
|
||||||
DBA465952696E387002B41DB /* AppPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA465942696E387002B41DB /* AppPreference.swift */; };
|
DBA465952696E387002B41DB /* AppPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA465942696E387002B41DB /* AppPreference.swift */; };
|
||||||
DBA4B0F626C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; };
|
DBA4B0F626C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; };
|
||||||
DBA4B0F726C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; };
|
DBA4B0F726C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; };
|
||||||
|
DBA5A52F26F07ED800CACBAA /* PanModal in Frameworks */ = {isa = PBXBuildFile; productRef = DBA5A52E26F07ED800CACBAA /* PanModal */; };
|
||||||
|
DBA5A53126F08EF000CACBAA /* DragIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */; };
|
||||||
|
DBA5A53526F0A36A00CACBAA /* AddAccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5A53426F0A36A00CACBAA /* AddAccountTableViewCell.swift */; };
|
||||||
DBA5E7A3263AD0A3004598BB /* PhotoLibraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */; };
|
DBA5E7A3263AD0A3004598BB /* PhotoLibraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */; };
|
||||||
DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */; };
|
DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */; };
|
||||||
DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */; };
|
DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */; };
|
||||||
|
@ -1225,6 +1228,8 @@
|
||||||
DBA4B0EF26C153B20077136E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
DBA4B0EF26C153B20077136E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
DBA4B0F526C2621D0077136E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = "<group>"; };
|
DBA4B0F526C2621D0077136E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = "<group>"; };
|
||||||
DBA4B0F826C269880077136E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Intents.stringsdict; sourceTree = "<group>"; };
|
DBA4B0F826C269880077136E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Intents.stringsdict; sourceTree = "<group>"; };
|
||||||
|
DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DragIndicatorView.swift; sourceTree = "<group>"; };
|
||||||
|
DBA5A53426F0A36A00CACBAA /* AddAccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryService.swift; sourceTree = "<group>"; };
|
DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryService.swift; sourceTree = "<group>"; };
|
||||||
DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewModel.swift; sourceTree = "<group>"; };
|
DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewModel.swift; sourceTree = "<group>"; };
|
||||||
DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewController.swift; sourceTree = "<group>"; };
|
DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1387,6 +1392,7 @@
|
||||||
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */,
|
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */,
|
||||||
DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */,
|
DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */,
|
||||||
DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */,
|
DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */,
|
||||||
|
DBA5A52F26F07ED800CACBAA /* PanModal in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -2785,13 +2791,31 @@
|
||||||
DB9F58ED26EF435800E7BBE9 /* Account */ = {
|
DB9F58ED26EF435800E7BBE9 /* Account */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DBA5A53226F08EF300CACBAA /* View */,
|
||||||
|
DBA5A53326F0932E00CACBAA /* Cell */,
|
||||||
DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */,
|
DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */,
|
||||||
DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */,
|
DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */,
|
||||||
DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */,
|
|
||||||
);
|
);
|
||||||
path = Account;
|
path = Account;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
DBA5A53226F08EF300CACBAA /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
DBA5A53326F0932E00CACBAA /* Cell */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */,
|
||||||
|
DBA5A53426F0A36A00CACBAA /* AddAccountTableViewCell.swift */,
|
||||||
|
);
|
||||||
|
path = Cell;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
DBA5E7A6263BD298004598BB /* ContextMenu */ = {
|
DBA5E7A6263BD298004598BB /* ContextMenu */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -3161,6 +3185,7 @@
|
||||||
DB01E23226A98F0900C3965B /* MastodonMeta */,
|
DB01E23226A98F0900C3965B /* MastodonMeta */,
|
||||||
DB01E23426A98F0900C3965B /* MetaTextKit */,
|
DB01E23426A98F0900C3965B /* MetaTextKit */,
|
||||||
DB552D4E26BBD10C00E481F6 /* OrderedCollections */,
|
DB552D4E26BBD10C00E481F6 /* OrderedCollections */,
|
||||||
|
DBA5A52E26F07ED800CACBAA /* PanModal */,
|
||||||
);
|
);
|
||||||
productName = Mastodon;
|
productName = Mastodon;
|
||||||
productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */;
|
productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */;
|
||||||
|
@ -3420,6 +3445,7 @@
|
||||||
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */,
|
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */,
|
||||||
DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */,
|
DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */,
|
||||||
DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */,
|
DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */,
|
||||||
|
DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */,
|
||||||
);
|
);
|
||||||
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
|
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
@ -3773,6 +3799,7 @@
|
||||||
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
|
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
|
||||||
DB6180EF26391CA50018D199 /* MediaPreviewImageViewController.swift in Sources */,
|
DB6180EF26391CA50018D199 /* MediaPreviewImageViewController.swift in Sources */,
|
||||||
DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */,
|
DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */,
|
||||||
|
DBA5A53126F08EF000CACBAA /* DragIndicatorView.swift in Sources */,
|
||||||
DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */,
|
DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */,
|
||||||
DB6180F626391D580018D199 /* MediaPreviewableViewController.swift in Sources */,
|
DB6180F626391D580018D199 /* MediaPreviewableViewController.swift in Sources */,
|
||||||
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */,
|
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */,
|
||||||
|
@ -4042,6 +4069,7 @@
|
||||||
DB6D9F6326357848008423CD /* SettingService.swift in Sources */,
|
DB6D9F6326357848008423CD /* SettingService.swift in Sources */,
|
||||||
2D650FAB25ECDC9300851B58 /* Mastodon+Entity+Error+Detail.swift in Sources */,
|
2D650FAB25ECDC9300851B58 /* Mastodon+Entity+Error+Detail.swift in Sources */,
|
||||||
2D24E12D2626FD2E00A59D4F /* NotificationViewModel+LoadOldestState.swift in Sources */,
|
2D24E12D2626FD2E00A59D4F /* NotificationViewModel+LoadOldestState.swift in Sources */,
|
||||||
|
DBA5A53526F0A36A00CACBAA /* AddAccountTableViewCell.swift in Sources */,
|
||||||
2DB72C8C262D764300CE6173 /* Mastodon+Entity+Notification+Type.swift in Sources */,
|
2DB72C8C262D764300CE6173 /* Mastodon+Entity+Notification+Type.swift in Sources */,
|
||||||
2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */,
|
2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */,
|
||||||
DB084B5725CBC56C00F898ED /* Status.swift in Sources */,
|
DB084B5725CBC56C00F898ED /* Status.swift in Sources */,
|
||||||
|
@ -5845,6 +5873,14 @@
|
||||||
minimumVersion = 1.4.1;
|
minimumVersion = 1.4.1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/slackhq/PanModal.git";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 1.2.7;
|
||||||
|
};
|
||||||
|
};
|
||||||
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */ = {
|
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/ra1028/DifferenceKit.git";
|
repositoryURL = "https://github.com/ra1028/DifferenceKit.git";
|
||||||
|
@ -5957,6 +5993,11 @@
|
||||||
package = DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */;
|
package = DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */;
|
||||||
productName = "UITextView+Placeholder";
|
productName = "UITextView+Placeholder";
|
||||||
};
|
};
|
||||||
|
DBA5A52E26F07ED800CACBAA /* PanModal */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */;
|
||||||
|
productName = PanModal;
|
||||||
|
};
|
||||||
DBAC6482267D0B21007FE9FD /* DifferenceKit */ = {
|
DBAC6482267D0B21007FE9FD /* DifferenceKit */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */;
|
package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */;
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
<key>AppShared.xcscheme_^#shared#^_</key>
|
<key>AppShared.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>24</integer>
|
<integer>22</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>23</integer>
|
<integer>24</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>25</integer>
|
<integer>26</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>22</integer>
|
<integer>23</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
|
|
@ -127,6 +127,15 @@
|
||||||
"version": "3.6.2"
|
"version": "3.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"package": "PanModal",
|
||||||
|
"repositoryURL": "https://github.com/slackhq/PanModal.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "b012aecb6b67a8e46369227f893c12544846613f",
|
||||||
|
"version": "1.2.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "SDWebImage",
|
"package": "SDWebImage",
|
||||||
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
|
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import SafariServices
|
import SafariServices
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import PanModal
|
||||||
|
|
||||||
final public class SceneCoordinator {
|
final public class SceneCoordinator {
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ extension SceneCoordinator {
|
||||||
case show // push
|
case show // push
|
||||||
case showDetail // replace
|
case showDetail // replace
|
||||||
case modal(animated: Bool, completion: (() -> Void)? = nil)
|
case modal(animated: Bool, completion: (() -> Void)? = nil)
|
||||||
|
case panModal
|
||||||
case custom(transitioningDelegate: UIViewControllerTransitioningDelegate)
|
case custom(transitioningDelegate: UIViewControllerTransitioningDelegate)
|
||||||
case customPush
|
case customPush
|
||||||
case safariPresent(animated: Bool, completion: (() -> Void)? = nil)
|
case safariPresent(animated: Bool, completion: (() -> Void)? = nil)
|
||||||
|
@ -66,6 +68,7 @@ extension SceneCoordinator {
|
||||||
case hashtagTimeline(viewModel: HashtagTimelineViewModel)
|
case hashtagTimeline(viewModel: HashtagTimelineViewModel)
|
||||||
|
|
||||||
// profile
|
// profile
|
||||||
|
case accountList
|
||||||
case profile(viewModel: ProfileViewModel)
|
case profile(viewModel: ProfileViewModel)
|
||||||
case favorite(viewModel: FavoriteViewModel)
|
case favorite(viewModel: FavoriteViewModel)
|
||||||
|
|
||||||
|
@ -87,7 +90,6 @@ extension SceneCoordinator {
|
||||||
case activityViewController(activityViewController: UIActivityViewController, sourceView: UIView?, barButtonItem: UIBarButtonItem?)
|
case activityViewController(activityViewController: UIActivityViewController, sourceView: UIView?, barButtonItem: UIBarButtonItem?)
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
case accountList
|
|
||||||
case publicTimeline
|
case publicTimeline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -185,6 +187,13 @@ extension SceneCoordinator {
|
||||||
}
|
}
|
||||||
presentingViewController.present(modalNavigationController, animated: animated, completion: completion)
|
presentingViewController.present(modalNavigationController, animated: animated, completion: completion)
|
||||||
|
|
||||||
|
case .panModal:
|
||||||
|
guard let panModalPresentable = viewController as? PanModalPresentable & UIViewController else {
|
||||||
|
assertionFailure()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
presentingViewController.presentPanModal(panModalPresentable)
|
||||||
|
|
||||||
case .custom(let transitioningDelegate):
|
case .custom(let transitioningDelegate):
|
||||||
viewController.modalPresentationStyle = .custom
|
viewController.modalPresentationStyle = .custom
|
||||||
viewController.transitioningDelegate = transitioningDelegate
|
viewController.transitioningDelegate = transitioningDelegate
|
||||||
|
@ -274,6 +283,9 @@ private extension SceneCoordinator {
|
||||||
let _viewController = HashtagTimelineViewController()
|
let _viewController = HashtagTimelineViewController()
|
||||||
_viewController.viewModel = viewModel
|
_viewController.viewModel = viewModel
|
||||||
viewController = _viewController
|
viewController = _viewController
|
||||||
|
case .accountList:
|
||||||
|
let _viewController = AccountListViewController()
|
||||||
|
viewController = _viewController
|
||||||
case .profile(let viewModel):
|
case .profile(let viewModel):
|
||||||
let _viewController = ProfileViewController()
|
let _viewController = ProfileViewController()
|
||||||
_viewController.viewModel = viewModel
|
_viewController.viewModel = viewModel
|
||||||
|
@ -322,9 +334,6 @@ private extension SceneCoordinator {
|
||||||
_viewController.viewModel = viewModel
|
_viewController.viewModel = viewModel
|
||||||
viewController = _viewController
|
viewController = _viewController
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
case .accountList:
|
|
||||||
let _viewController = AccountListViewController()
|
|
||||||
viewController = _viewController
|
|
||||||
case .publicTimeline:
|
case .publicTimeline:
|
||||||
let _viewController = PublicTimelineViewController()
|
let _viewController = PublicTimelineViewController()
|
||||||
_viewController.viewModel = PublicTimelineViewModel(context: appContext)
|
_viewController.viewModel = PublicTimelineViewModel(context: appContext)
|
||||||
|
|
|
@ -20,6 +20,8 @@ extension MetaLabel {
|
||||||
case titleView
|
case titleView
|
||||||
case settingTableFooter
|
case settingTableFooter
|
||||||
case autoCompletion
|
case autoCompletion
|
||||||
|
case accountListName
|
||||||
|
case accountListUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(style: Style) {
|
convenience init(style: Style) {
|
||||||
|
@ -74,6 +76,12 @@ extension MetaLabel {
|
||||||
case .autoCompletion:
|
case .autoCompletion:
|
||||||
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 22)
|
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 22)
|
||||||
textColor = Asset.Colors.brandBlue.color
|
textColor = Asset.Colors.brandBlue.color
|
||||||
|
case .accountListName:
|
||||||
|
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22)
|
||||||
|
textColor = Asset.Colors.Label.primary.color
|
||||||
|
case .accountListUsername:
|
||||||
|
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20)
|
||||||
|
textColor = Asset.Colors.Label.secondary.color
|
||||||
}
|
}
|
||||||
|
|
||||||
self.font = font
|
self.font = font
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
//
|
|
||||||
// AccountListTableViewCell.swift
|
|
||||||
// Mastodon
|
|
||||||
//
|
|
||||||
// Created by Cirno MainasuK on 2021-9-13.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
final class AccountListTableViewCell: UITableViewCell {
|
|
||||||
|
|
||||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
|
||||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
|
||||||
_init()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
_init()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension AccountListTableViewCell {
|
|
||||||
|
|
||||||
private func _init() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -5,11 +5,11 @@
|
||||||
// Created by Cirno MainasuK on 2021-9-13.
|
// Created by Cirno MainasuK on 2021-9-13.
|
||||||
//
|
//
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import MastodonMeta
|
||||||
|
|
||||||
final class AccountListViewModel {
|
final class AccountListViewModel {
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ final class AccountListViewModel {
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
snapshot.appendSections([.main])
|
snapshot.appendSections([.main])
|
||||||
snapshot.appendItems(authentications, toSection: .main)
|
snapshot.appendItems(authentications, toSection: .main)
|
||||||
|
snapshot.appendItems([.addAccount], toSection: .main)
|
||||||
|
|
||||||
diffableDataSource.apply(snapshot)
|
diffableDataSource.apply(snapshot)
|
||||||
}
|
}
|
||||||
|
@ -58,6 +59,7 @@ extension AccountListViewModel {
|
||||||
|
|
||||||
enum Item: Hashable {
|
enum Item: Hashable {
|
||||||
case authentication(objectID: NSManagedObjectID)
|
case authentication(objectID: NSManagedObjectID)
|
||||||
|
case addAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupDiffableDataSource(
|
func setupDiffableDataSource(
|
||||||
|
@ -70,11 +72,37 @@ extension AccountListViewModel {
|
||||||
let authentication = managedObjectContext.object(with: objectID) as! MastodonAuthentication
|
let authentication = managedObjectContext.object(with: objectID) as! MastodonAuthentication
|
||||||
let user = authentication.user
|
let user = authentication.user
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AccountListTableViewCell.self), for: indexPath) as! AccountListTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AccountListTableViewCell.self), for: indexPath) as! AccountListTableViewCell
|
||||||
cell.textLabel?.text = user.acctWithDomain
|
AccountListViewModel.configure(cell: cell, user: user)
|
||||||
|
return cell
|
||||||
|
case .addAccount:
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AddAccountTableViewCell.self), for: indexPath) as! AddAccountTableViewCell
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
|
snapshot.appendSections([.main])
|
||||||
|
diffableDataSource?.apply(snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func configure(
|
||||||
|
cell: AccountListTableViewCell,
|
||||||
|
user: MastodonUser
|
||||||
|
) {
|
||||||
|
// avatar
|
||||||
|
cell.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: user.avatarImageURL()))
|
||||||
|
|
||||||
|
// name
|
||||||
|
do {
|
||||||
|
let content = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojiMeta)
|
||||||
|
let metaContent = try MastodonMetaContent.convert(document: content)
|
||||||
|
cell.nameLabel.configure(content: metaContent)
|
||||||
|
} catch {
|
||||||
|
assertionFailure()
|
||||||
|
cell.nameLabel.configure(content: PlaintextMetaContent(string: user.displayNameWithFallback))
|
||||||
|
}
|
||||||
|
|
||||||
|
// username
|
||||||
|
cell.usernameLabel.configure(content: PlaintextMetaContent(string: user.acctWithDomain))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
// Created by Cirno MainasuK on 2021-9-13.
|
// Created by Cirno MainasuK on 2021-9-13.
|
||||||
//
|
//
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
import os.log
|
import os.log
|
||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import PanModal
|
||||||
|
|
||||||
final class AccountListViewController: UIViewController, NeedsDependency {
|
final class AccountListViewController: UIViewController, NeedsDependency {
|
||||||
|
|
||||||
|
@ -32,25 +31,61 @@ final class AccountListViewController: UIViewController, NeedsDependency {
|
||||||
return barButtonItem
|
return barButtonItem
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
let dragIndicatorView = DragIndicatorView()
|
||||||
|
|
||||||
private(set) lazy var tableView: UITableView = {
|
private(set) lazy var tableView: UITableView = {
|
||||||
let tableView = UITableView()
|
let tableView = UITableView()
|
||||||
tableView.register(AccountListTableViewCell.self, forCellReuseIdentifier: String(describing: AccountListTableViewCell.self))
|
tableView.register(AccountListTableViewCell.self, forCellReuseIdentifier: String(describing: AccountListTableViewCell.self))
|
||||||
|
tableView.register(AddAccountTableViewCell.self, forCellReuseIdentifier: String(describing: AddAccountTableViewCell.self))
|
||||||
|
tableView.backgroundColor = .clear
|
||||||
|
tableView.tableFooterView = UIView()
|
||||||
|
tableView.separatorStyle = .none
|
||||||
return tableView
|
return tableView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - PanModalPresentable
|
||||||
|
extension AccountListViewController: PanModalPresentable {
|
||||||
|
var panScrollable: UIScrollView? { tableView }
|
||||||
|
var showDragIndicator: Bool { false }
|
||||||
|
|
||||||
|
var shortFormHeight: PanModalHeight {
|
||||||
|
return .contentHeight(300)
|
||||||
|
}
|
||||||
|
|
||||||
|
var longFormHeight: PanModalHeight {
|
||||||
|
return .maxHeightWithTopInset(40)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension AccountListViewController {
|
extension AccountListViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
view.backgroundColor = .systemBackground
|
view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor.withAlphaComponent(0.9)
|
||||||
|
ThemeService.shared.currentTheme
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
.sink { [weak self] theme in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.setupBackgroundColor(theme: theme)
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
navigationItem.rightBarButtonItem = addBarButtonItem
|
navigationItem.rightBarButtonItem = addBarButtonItem
|
||||||
|
|
||||||
|
dragIndicatorView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
view.addSubview(dragIndicatorView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
dragIndicatorView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||||
|
dragIndicatorView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||||
|
dragIndicatorView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||||
|
dragIndicatorView.heightAnchor.constraint(equalToConstant: DragIndicatorView.height).priority(.required - 1),
|
||||||
|
])
|
||||||
|
|
||||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(tableView)
|
view.addSubview(tableView)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
tableView.topAnchor.constraint(equalTo: view.topAnchor),
|
tableView.topAnchor.constraint(equalTo: dragIndicatorView.bottomAnchor),
|
||||||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||||
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||||
|
@ -62,6 +97,11 @@ extension AccountListViewController {
|
||||||
managedObjectContext: context.managedObjectContext
|
managedObjectContext: context.managedObjectContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func setupBackgroundColor(theme: Theme) {
|
||||||
|
view.backgroundColor = theme.systemBackgroundColor.withAlphaComponent(0.9)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AccountListViewController {
|
extension AccountListViewController {
|
||||||
|
@ -79,9 +119,11 @@ extension AccountListViewController: UITableViewDelegate {
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
|
|
||||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||||
guard case let .authentication(objectID) = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||||
assert(Thread.isMainThread)
|
|
||||||
|
|
||||||
|
switch item {
|
||||||
|
case .authentication(let objectID):
|
||||||
|
assert(Thread.isMainThread)
|
||||||
let authentication = context.managedObjectContext.object(with: objectID) as! MastodonAuthentication
|
let authentication = context.managedObjectContext.object(with: objectID) as! MastodonAuthentication
|
||||||
context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID)
|
context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID)
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
|
@ -90,9 +132,9 @@ extension AccountListViewController: UITableViewDelegate {
|
||||||
self.coordinator.setup()
|
self.coordinator.setup()
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
case .addAccount:
|
||||||
|
// TODO: add dismiss entry for welcome scene
|
||||||
|
coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
//
|
||||||
|
// AccountListTableViewCell.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by Cirno MainasuK on 2021-9-13.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import FLAnimatedImage
|
||||||
|
import MetaTextKit
|
||||||
|
|
||||||
|
final class CircleAvatarButton: AvatarButton {
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
|
||||||
|
layer.masksToBounds = true
|
||||||
|
layer.cornerRadius = frame.width * 0.5
|
||||||
|
layer.borderColor = UIColor.systemFill.cgColor
|
||||||
|
layer.borderWidth = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class AccountListTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
|
let avatarButton = CircleAvatarButton()
|
||||||
|
let nameLabel = MetaLabel(style: .accountListName)
|
||||||
|
let usernameLabel = MetaLabel(style: .accountListUsername)
|
||||||
|
let separatorLine = UIView.separatorLine
|
||||||
|
|
||||||
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountListTableViewCell {
|
||||||
|
|
||||||
|
private func _init() {
|
||||||
|
avatarButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(avatarButton)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
avatarButton.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
|
||||||
|
avatarButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
||||||
|
avatarButton.heightAnchor.constraint(equalTo: avatarButton.widthAnchor, multiplier: 1.0).priority(.required - 1),
|
||||||
|
avatarButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).priority(.required - 1),
|
||||||
|
])
|
||||||
|
avatarButton.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||||
|
avatarButton.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||||
|
|
||||||
|
let labelContainerStackView = UIStackView()
|
||||||
|
labelContainerStackView.axis = .vertical
|
||||||
|
labelContainerStackView.distribution = .equalCentering
|
||||||
|
labelContainerStackView.spacing = 2
|
||||||
|
labelContainerStackView.distribution = .fillProportionally
|
||||||
|
labelContainerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(labelContainerStackView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
labelContainerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
|
||||||
|
labelContainerStackView.leadingAnchor.constraint(equalTo: avatarButton.trailingAnchor, constant: 10),
|
||||||
|
contentView.bottomAnchor.constraint(equalTo: labelContainerStackView.bottomAnchor, constant: 10),
|
||||||
|
avatarButton.heightAnchor.constraint(equalTo: labelContainerStackView.heightAnchor, multiplier: 0.8).priority(.required - 10),
|
||||||
|
labelContainerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||||
|
])
|
||||||
|
|
||||||
|
labelContainerStackView.addArrangedSubview(nameLabel)
|
||||||
|
labelContainerStackView.addArrangedSubview(usernameLabel)
|
||||||
|
|
||||||
|
avatarButton.isUserInteractionEnabled = false
|
||||||
|
nameLabel.isUserInteractionEnabled = false
|
||||||
|
usernameLabel.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
separatorLine.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(separatorLine)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
separatorLine.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
|
||||||
|
separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||||
|
separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||||
|
separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - AvatarConfigurableView
|
||||||
|
extension AccountListTableViewCell: AvatarConfigurableView {
|
||||||
|
static var configurableAvatarImageSize: CGSize { CGSize(width: 30, height: 30) }
|
||||||
|
static var configurableAvatarImageCornerRadius: CGFloat { 0 }
|
||||||
|
var configurableAvatarImageView: FLAnimatedImageView? { avatarButton.avatarImageView }
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// AddAccountTableViewCell.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by Cirno MainasuK on 2021-9-14.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import MetaTextKit
|
||||||
|
|
||||||
|
final class AddAccountTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
|
let iconImageView: UIImageView = {
|
||||||
|
let image = UIImage(systemName: "plus.circle.fill")!
|
||||||
|
let imageView = UIImageView(image: image)
|
||||||
|
imageView.tintColor = Asset.Colors.Label.primary.color
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
let titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22)
|
||||||
|
label.textColor = Asset.Colors.Label.primary.color
|
||||||
|
label.text = "Add Account" // TODO: i18n
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
let usernameLabel = MetaLabel(style: .accountListUsername)
|
||||||
|
let separatorLine = UIView.separatorLine
|
||||||
|
|
||||||
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AddAccountTableViewCell {
|
||||||
|
|
||||||
|
private func _init() {
|
||||||
|
iconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(iconImageView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
iconImageView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
|
||||||
|
iconImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
||||||
|
iconImageView.heightAnchor.constraint(equalTo: iconImageView.widthAnchor, multiplier: 1.0).priority(.required - 1),
|
||||||
|
iconImageView.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).priority(.required - 1),
|
||||||
|
])
|
||||||
|
iconImageView.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||||
|
iconImageView.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||||
|
|
||||||
|
titleLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(titleLabel)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 19),
|
||||||
|
titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 10),
|
||||||
|
contentView.bottomAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 19),
|
||||||
|
iconImageView.heightAnchor.constraint(equalTo: titleLabel.heightAnchor, multiplier: 1.0).priority(.required - 10),
|
||||||
|
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||||
|
])
|
||||||
|
|
||||||
|
separatorLine.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(separatorLine)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||||
|
separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||||
|
separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||||
|
separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
//
|
||||||
|
// DragIndicatorView.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by Cirno MainasuK on 2021-9-14.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
final class DragIndicatorView: UIView {
|
||||||
|
|
||||||
|
static let height: CGFloat = 38
|
||||||
|
|
||||||
|
let barView = UIView()
|
||||||
|
let separatorLine = UIView.separatorLine
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DragIndicatorView {
|
||||||
|
|
||||||
|
private func _init() {
|
||||||
|
barView.backgroundColor = Asset.Colors.Label.secondary.color
|
||||||
|
barView.layer.masksToBounds = true
|
||||||
|
barView.layer.cornerRadius = 2.5
|
||||||
|
|
||||||
|
barView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
addSubview(barView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
barView.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||||
|
barView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||||
|
barView.heightAnchor.constraint(equalToConstant: 5).priority(.required - 1),
|
||||||
|
barView.widthAnchor.constraint(equalToConstant: 36).priority(.required - 1),
|
||||||
|
])
|
||||||
|
|
||||||
|
separatorLine.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
addSubview(separatorLine)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
separatorLine.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||||
|
separatorLine.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||||
|
separatorLine.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||||
|
separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: self)),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ import SafariServices
|
||||||
|
|
||||||
class MainTabBarController: UITabBarController {
|
class MainTabBarController: UITabBarController {
|
||||||
|
|
||||||
|
let logger = Logger(subsystem: "MainTabBarController", category: "UI")
|
||||||
|
|
||||||
var disposeBag = Set<AnyCancellable>()
|
var disposeBag = Set<AnyCancellable>()
|
||||||
|
|
||||||
weak var context: AppContext!
|
weak var context: AppContext!
|
||||||
|
@ -25,6 +27,10 @@ class MainTabBarController: UITabBarController {
|
||||||
case notification
|
case notification
|
||||||
case me
|
case me
|
||||||
|
|
||||||
|
var tag: Int {
|
||||||
|
return rawValue
|
||||||
|
}
|
||||||
|
|
||||||
var title: String {
|
var title: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .home: return L10n.Common.Controls.Tabs.home
|
case .home: return L10n.Common.Controls.Tabs.home
|
||||||
|
@ -121,6 +127,7 @@ extension MainTabBarController {
|
||||||
let tabs = Tab.allCases
|
let tabs = Tab.allCases
|
||||||
let viewControllers: [UIViewController] = tabs.map { tab in
|
let viewControllers: [UIViewController] = tabs.map { tab in
|
||||||
let viewController = tab.viewController(context: context, coordinator: coordinator)
|
let viewController = tab.viewController(context: context, coordinator: coordinator)
|
||||||
|
viewController.tabBarItem.tag = tab.tag
|
||||||
viewController.tabBarItem.title = tab.title
|
viewController.tabBarItem.title = tab.title
|
||||||
viewController.tabBarItem.image = tab.image
|
viewController.tabBarItem.image = tab.image
|
||||||
viewController.tabBarItem.accessibilityLabel = tab.title
|
viewController.tabBarItem.accessibilityLabel = tab.title
|
||||||
|
@ -204,6 +211,10 @@ extension MainTabBarController {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer()
|
||||||
|
tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:)))
|
||||||
|
tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer)
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// selectedIndex = 1
|
// selectedIndex = 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -211,6 +222,33 @@ extension MainTabBarController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension MainTabBarController {
|
||||||
|
@objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) {
|
||||||
|
guard sender.state == .began else { return }
|
||||||
|
|
||||||
|
var _tab: Tab?
|
||||||
|
let location = sender.location(in: tabBar)
|
||||||
|
for item in tabBar.items ?? [] {
|
||||||
|
guard let tab = Tab(rawValue: item.tag) else { continue }
|
||||||
|
guard let view = item.value(forKey: "view") as? UIView else { continue }
|
||||||
|
guard view.frame.contains(location) else { continue}
|
||||||
|
|
||||||
|
_tab = tab
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let tab = _tab else { return }
|
||||||
|
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): long press \(tab.title) tab")
|
||||||
|
|
||||||
|
switch tab {
|
||||||
|
case .me:
|
||||||
|
coordinator.present(scene: .accountList, from: nil, transition: .panModal)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension MainTabBarController {
|
extension MainTabBarController {
|
||||||
|
|
||||||
var notificationViewController: NotificationViewController? {
|
var notificationViewController: NotificationViewController? {
|
||||||
|
|
|
@ -70,6 +70,7 @@ The app is compatible with [toot-relay](https://github.com/DagAgren/toot-relay)
|
||||||
- [Nuke-FLAnimatedImage-Plugin](https://github.com/kean/Nuke-FLAnimatedImage-Plugin)
|
- [Nuke-FLAnimatedImage-Plugin](https://github.com/kean/Nuke-FLAnimatedImage-Plugin)
|
||||||
- [Nuke](https://github.com/kean/Nuke)
|
- [Nuke](https://github.com/kean/Nuke)
|
||||||
- [Pageboy](https://github.com/uias/Pageboy#the-basics)
|
- [Pageboy](https://github.com/uias/Pageboy#the-basics)
|
||||||
|
- [PanModal](https://github.com/slackhq/PanModal.git)
|
||||||
- [SDWebImage](https://github.com/SDWebImage/SDWebImage)
|
- [SDWebImage](https://github.com/SDWebImage/SDWebImage)
|
||||||
- [swift-collections](https://github.com/apple/swift-collections)
|
- [swift-collections](https://github.com/apple/swift-collections)
|
||||||
- [swift-nio](https://github.com/apple/swift-nio)
|
- [swift-nio](https://github.com/apple/swift-nio)
|
||||||
|
|
Loading…
Reference in New Issue