Merge pull request #552 from j-f1/notifications-tab-a11y
Improve accessibility of the notifications tab
This commit is contained in:
commit
6532f60cd5
|
@ -96,7 +96,7 @@
|
|||
"tabs": {
|
||||
"home": "Home",
|
||||
"search": "Search",
|
||||
"notification": "Notification",
|
||||
"notifications": "Notifications",
|
||||
"profile": "Profile"
|
||||
},
|
||||
"keyboard": {
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
"tabs": {
|
||||
"home": "Home",
|
||||
"search": "Search",
|
||||
"notification": "Notification",
|
||||
"notifications": "Notifications",
|
||||
"profile": "Profile"
|
||||
},
|
||||
"keyboard": {
|
||||
|
|
|
@ -71,8 +71,8 @@ final public class SceneCoordinator {
|
|||
self.setup()
|
||||
try await Task.sleep(nanoseconds: .second * 1)
|
||||
|
||||
// redirect to notification tab
|
||||
self.switchToTabBar(tab: .notification)
|
||||
// redirect to notifications tab
|
||||
self.switchToTabBar(tab: .notifications)
|
||||
|
||||
// Delay in next run loop
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
|
|
@ -51,7 +51,7 @@ class MainTabBarController: UITabBarController {
|
|||
case home
|
||||
case search
|
||||
case compose
|
||||
case notification
|
||||
case notifications
|
||||
case me
|
||||
|
||||
var tag: Int {
|
||||
|
@ -63,7 +63,7 @@ class MainTabBarController: UITabBarController {
|
|||
case .home: return L10n.Common.Controls.Tabs.home
|
||||
case .search: return L10n.Common.Controls.Tabs.search
|
||||
case .compose: return L10n.Common.Controls.Actions.compose
|
||||
case .notification: return L10n.Common.Controls.Tabs.notification
|
||||
case .notifications: return L10n.Common.Controls.Tabs.notifications
|
||||
case .me: return L10n.Common.Controls.Tabs.profile
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ class MainTabBarController: UITabBarController {
|
|||
case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate)
|
||||
case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate)
|
||||
case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate)
|
||||
case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate)
|
||||
case .notifications: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate)
|
||||
case .me: return UIImage(systemName: "person")!
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class MainTabBarController: UITabBarController {
|
|||
case .home: return Asset.ObjectsAndTools.houseFill.image.withRenderingMode(.alwaysTemplate)
|
||||
case .search: return Asset.ObjectsAndTools.magnifyingglassFill.image.withRenderingMode(.alwaysTemplate)
|
||||
case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate)
|
||||
case .notification: return Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate)
|
||||
case .notifications: return Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate)
|
||||
case .me: return UIImage(systemName: "person.fill")!
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ class MainTabBarController: UITabBarController {
|
|||
case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80))
|
||||
case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80))
|
||||
case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80))
|
||||
case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80))
|
||||
case .notifications: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80))
|
||||
case .me: return UIImage(systemName: "person", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ class MainTabBarController: UITabBarController {
|
|||
case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate)
|
||||
case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate)
|
||||
case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate)
|
||||
case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate)
|
||||
case .notifications: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate)
|
||||
case .me: return UIImage(systemName: "person")!
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ class MainTabBarController: UITabBarController {
|
|||
viewController = _viewController
|
||||
case .compose:
|
||||
viewController = UIViewController()
|
||||
case .notification:
|
||||
case .notifications:
|
||||
let _viewController = NotificationViewController()
|
||||
_viewController.context = context
|
||||
_viewController.coordinator = coordinator
|
||||
|
@ -274,7 +274,7 @@ extension MainTabBarController {
|
|||
} ?? false
|
||||
|
||||
let image: UIImage = {
|
||||
if currentTab == .notification {
|
||||
if currentTab == .notifications {
|
||||
return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadgeFill.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate)
|
||||
} else {
|
||||
return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadge.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate)
|
||||
|
@ -654,7 +654,7 @@ extension MainTabBarController {
|
|||
let tabs: [Tab] = [
|
||||
.home,
|
||||
.search,
|
||||
.notification,
|
||||
.notifications,
|
||||
.me
|
||||
]
|
||||
for (i, tab) in tabs.enumerated() {
|
||||
|
|
|
@ -100,7 +100,7 @@ extension SidebarViewModel {
|
|||
.store(in: &cell.disposeBag)
|
||||
|
||||
switch item {
|
||||
case .notification:
|
||||
case .notifications:
|
||||
Publishers.CombineLatest(
|
||||
self.context.notificationService.unreadNotificationCountDidUpdate,
|
||||
self.$currentTab
|
||||
|
@ -116,7 +116,7 @@ extension SidebarViewModel {
|
|||
}()
|
||||
|
||||
let image: UIImage = {
|
||||
if currentTab == .notification {
|
||||
if currentTab == .notifications {
|
||||
return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadgeFill.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate)
|
||||
} else {
|
||||
return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadge.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate)
|
||||
|
@ -193,7 +193,7 @@ extension SidebarViewModel {
|
|||
let items: [Item] = [
|
||||
.tab(.home),
|
||||
.tab(.search),
|
||||
.tab(.notification),
|
||||
.tab(.notifications),
|
||||
.tab(.me),
|
||||
.setting,
|
||||
]
|
||||
|
|
|
@ -111,6 +111,7 @@ extension NotificationView {
|
|||
self.viewModel.notificationIndicatorText = nil
|
||||
return
|
||||
}
|
||||
self.viewModel.type = type
|
||||
|
||||
func createMetaContent(text: String, emojis: MastodonContent.Emojis) -> MetaContent {
|
||||
let content = MastodonContent(content: text, emojis: emojis)
|
||||
|
|
|
@ -96,7 +96,6 @@ extension StatusThreadRootTableViewCell {
|
|||
override var accessibilityElements: [Any]? {
|
||||
get {
|
||||
var elements = [
|
||||
statusView.headerContainerView,
|
||||
statusView.authorView,
|
||||
statusView.viewModel.isContentReveal
|
||||
? statusView.contentMetaText.textView
|
||||
|
|
|
@ -175,7 +175,7 @@ extension SceneDelegate {
|
|||
return false
|
||||
}
|
||||
|
||||
coordinator.switchToTabBar(tab: .notification)
|
||||
coordinator.switchToTabBar(tab: .notifications)
|
||||
|
||||
case "org.joinmastodon.app.new-post":
|
||||
if coordinator?.tabBarController.topMost is ComposeViewController {
|
||||
|
|
|
@ -1,241 +1,257 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Alamofire",
|
||||
"repositoryURL": "https://github.com/Alamofire/Alamofire.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "8dd85aee02e39dd280c75eef88ffdb86eed4b07b",
|
||||
"version": "5.6.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "AlamofireImage",
|
||||
"repositoryURL": "https://github.com/Alamofire/AlamofireImage.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "98cbb00ce0ec5fc8e52a5b50a6bfc08d3e5aee10",
|
||||
"version": "4.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "CommonOSLog",
|
||||
"repositoryURL": "https://github.com/MainasuK/CommonOSLog",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c121624a30698e9886efe38aebb36ff51c01b6c2",
|
||||
"version": "0.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "FaviconFinder",
|
||||
"repositoryURL": "https://github.com/will-lumley/FaviconFinder.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a",
|
||||
"version": "3.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "FLAnimatedImage",
|
||||
"repositoryURL": "https://github.com/Flipboard/FLAnimatedImage.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "d4f07b6f164d53c1212c3e54d6460738b1981e9f",
|
||||
"version": "1.0.17"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "FPSIndicator",
|
||||
"repositoryURL": "https://github.com/MainasuK/FPSIndicator.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "e4a5067ccd5293b024c767f09e51056afd4a4796",
|
||||
"version": "1.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Fuzi",
|
||||
"repositoryURL": "https://github.com/cezheng/Fuzi.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f08c8323da21e985f3772610753bcfc652c2103f",
|
||||
"version": "3.1.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "KeychainAccess",
|
||||
"repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "84e546727d66f1adc5439debad16270d0fdd04e7",
|
||||
"version": "4.2.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "MetaTextKit",
|
||||
"repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "dcd5255d6930c2fab408dc8562c577547e477624",
|
||||
"version": "2.2.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Nuke",
|
||||
"repositoryURL": "https://github.com/kean/Nuke.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "a002b7fd786f2df2ed4333fe73a9727499fd9d97",
|
||||
"version": "10.11.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "NukeFLAnimatedImagePlugin",
|
||||
"repositoryURL": "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b59c346a7d536336db3b0f12c72c6e53ee709e16",
|
||||
"version": "8.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Pageboy",
|
||||
"repositoryURL": "https://github.com/uias/Pageboy",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "af8fa81788b893205e1ff42ddd88c5b0b315d7c5",
|
||||
"version": "3.7.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "PanModal",
|
||||
"repositoryURL": "https://github.com/slackhq/PanModal.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b012aecb6b67a8e46369227f893c12544846613f",
|
||||
"version": "1.2.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SDWebImage",
|
||||
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "9248fe561a2a153916fb9597e3af4434784c6d32",
|
||||
"version": "5.13.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-collections",
|
||||
"repositoryURL": "https://github.com/apple/swift-collections.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f504716c27d2e5d4144fa4794b12129301d17729",
|
||||
"version": "1.0.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "546610d52b19be3e19935e0880bb06b9c03f5cef",
|
||||
"version": "1.14.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-zlib-support",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "37760e9a52030bb9011972c5213c3350fa9d41fd",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftSoup",
|
||||
"repositoryURL": "https://github.com/scinfu/SwiftSoup.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "6778575285177365cbad3e5b8a72f2a20583cfec",
|
||||
"version": "2.4.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Introspect",
|
||||
"repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f2616860a41f9d9932da412a8978fec79c06fe24",
|
||||
"version": "0.1.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftyJSON",
|
||||
"repositoryURL": "https://github.com/SwiftyJSON/SwiftyJSON.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07",
|
||||
"version": "5.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "TabBarPager",
|
||||
"repositoryURL": "https://github.com/TwidereProject/TabBarPager.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "488aa66d157a648901b61721212c0dec23d27ee5",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Tabman",
|
||||
"repositoryURL": "https://github.com/uias/Tabman",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "4a4f7c755b875ffd4f9ef10d67a67883669d2465",
|
||||
"version": "2.13.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "ThirdPartyMailer",
|
||||
"repositoryURL": "https://github.com/vtourraine/ThirdPartyMailer.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "44c1cfaa6969963f22691aa67f88a69e3b6d651f",
|
||||
"version": "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "TOCropViewController",
|
||||
"repositoryURL": "https://github.com/TimOliver/TOCropViewController.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "d0470491f56e734731bbf77991944c0dfdee3e0e",
|
||||
"version": "2.6.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "UIHostingConfigurationBackport",
|
||||
"repositoryURL": "https://github.com/woxtu/UIHostingConfigurationBackport.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "6091f2d38faa4b24fc2ca0389c651e2f666624a3",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "UITextView+Placeholder",
|
||||
"repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "20f513ded04a040cdf5467f0891849b1763ede3b",
|
||||
"version": "1.4.1"
|
||||
}
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "alamofire",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/Alamofire/Alamofire.git",
|
||||
"state" : {
|
||||
"revision" : "8dd85aee02e39dd280c75eef88ffdb86eed4b07b",
|
||||
"version" : "5.6.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"identity" : "alamofireimage",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/Alamofire/AlamofireImage.git",
|
||||
"state" : {
|
||||
"revision" : "98cbb00ce0ec5fc8e52a5b50a6bfc08d3e5aee10",
|
||||
"version" : "4.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "commonoslog",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/MainasuK/CommonOSLog",
|
||||
"state" : {
|
||||
"revision" : "c121624a30698e9886efe38aebb36ff51c01b6c2",
|
||||
"version" : "0.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "faviconfinder",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/will-lumley/FaviconFinder.git",
|
||||
"state" : {
|
||||
"revision" : "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a",
|
||||
"version" : "3.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "flanimatedimage",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/Flipboard/FLAnimatedImage.git",
|
||||
"state" : {
|
||||
"revision" : "d4f07b6f164d53c1212c3e54d6460738b1981e9f",
|
||||
"version" : "1.0.17"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "fpsindicator",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/MainasuK/FPSIndicator.git",
|
||||
"state" : {
|
||||
"revision" : "e4a5067ccd5293b024c767f09e51056afd4a4796",
|
||||
"version" : "1.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "fuzi",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/cezheng/Fuzi.git",
|
||||
"state" : {
|
||||
"revision" : "f08c8323da21e985f3772610753bcfc652c2103f",
|
||||
"version" : "3.1.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "keychainaccess",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kishikawakatsumi/KeychainAccess.git",
|
||||
"state" : {
|
||||
"revision" : "84e546727d66f1adc5439debad16270d0fdd04e7",
|
||||
"version" : "4.2.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "kingfisher",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/onevcat/Kingfisher.git",
|
||||
"state" : {
|
||||
"revision" : "44e891bdb61426a95e31492a67c7c0dfad1f87c5",
|
||||
"version" : "7.4.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "metatextkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/TwidereProject/MetaTextKit.git",
|
||||
"state" : {
|
||||
"revision" : "dcd5255d6930c2fab408dc8562c577547e477624",
|
||||
"version" : "2.2.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "nextlevelsessionexporter",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/NextLevel/NextLevelSessionExporter.git",
|
||||
"state" : {
|
||||
"revision" : "b6c0cce1aa37fe1547d694f958fac3c3524b74da",
|
||||
"version" : "0.4.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "nuke",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kean/Nuke.git",
|
||||
"state" : {
|
||||
"revision" : "a002b7fd786f2df2ed4333fe73a9727499fd9d97",
|
||||
"version" : "10.11.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "nuke-flanimatedimage-plugin",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
|
||||
"state" : {
|
||||
"revision" : "b59c346a7d536336db3b0f12c72c6e53ee709e16",
|
||||
"version" : "8.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "pageboy",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/uias/Pageboy",
|
||||
"state" : {
|
||||
"revision" : "af8fa81788b893205e1ff42ddd88c5b0b315d7c5",
|
||||
"version" : "3.7.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "panmodal",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/slackhq/PanModal.git",
|
||||
"state" : {
|
||||
"revision" : "b012aecb6b67a8e46369227f893c12544846613f",
|
||||
"version" : "1.2.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "sdwebimage",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/SDWebImage/SDWebImage.git",
|
||||
"state" : {
|
||||
"revision" : "9248fe561a2a153916fb9597e3af4434784c6d32",
|
||||
"version" : "5.13.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "stripes",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/eneko/Stripes.git",
|
||||
"state" : {
|
||||
"revision" : "d533fd44b8043a3abbf523e733599173d6f98c11",
|
||||
"version" : "0.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-collections",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-collections.git",
|
||||
"state" : {
|
||||
"revision" : "f504716c27d2e5d4144fa4794b12129301d17729",
|
||||
"version" : "1.0.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio.git",
|
||||
"state" : {
|
||||
"revision" : "546610d52b19be3e19935e0880bb06b9c03f5cef",
|
||||
"version" : "1.14.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-zlib-support",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-zlib-support.git",
|
||||
"state" : {
|
||||
"revision" : "37760e9a52030bb9011972c5213c3350fa9d41fd",
|
||||
"version" : "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftsoup",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/scinfu/SwiftSoup.git",
|
||||
"state" : {
|
||||
"revision" : "6778575285177365cbad3e5b8a72f2a20583cfec",
|
||||
"version" : "2.4.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftui-introspect",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
|
||||
"state" : {
|
||||
"revision" : "f2616860a41f9d9932da412a8978fec79c06fe24",
|
||||
"version" : "0.1.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "tabbarpager",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/TwidereProject/TabBarPager.git",
|
||||
"state" : {
|
||||
"revision" : "488aa66d157a648901b61721212c0dec23d27ee5",
|
||||
"version" : "0.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "tabman",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/uias/Tabman",
|
||||
"state" : {
|
||||
"revision" : "4a4f7c755b875ffd4f9ef10d67a67883669d2465",
|
||||
"version" : "2.13.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "thirdpartymailer",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/vtourraine/ThirdPartyMailer.git",
|
||||
"state" : {
|
||||
"revision" : "44c1cfaa6969963f22691aa67f88a69e3b6d651f",
|
||||
"version" : "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "tocropviewcontroller",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/TimOliver/TOCropViewController.git",
|
||||
"state" : {
|
||||
"revision" : "d0470491f56e734731bbf77991944c0dfdee3e0e",
|
||||
"version" : "2.6.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "uihostingconfigurationbackport",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/woxtu/UIHostingConfigurationBackport.git",
|
||||
"state" : {
|
||||
"revision" : "6091f2d38faa4b24fc2ca0389c651e2f666624a3",
|
||||
"version" : "0.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "uitextview-placeholder",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/MainasuK/UITextView-Placeholder.git",
|
||||
"state" : {
|
||||
"revision" : "20f513ded04a040cdf5467f0891849b1763ede3b",
|
||||
"version" : "1.4.1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public enum MastodonNotificationType: RawRepresentable {
|
||||
public enum MastodonNotificationType: RawRepresentable, Equatable {
|
||||
case follow
|
||||
case followRequest
|
||||
case mention
|
||||
|
|
|
@ -366,8 +366,8 @@ public enum L10n {
|
|||
public enum Tabs {
|
||||
/// Home
|
||||
public static let home = L10n.tr("Localizable", "Common.Controls.Tabs.Home", fallback: "Home")
|
||||
/// Notification
|
||||
public static let notification = L10n.tr("Localizable", "Common.Controls.Tabs.Notification", fallback: "Notification")
|
||||
/// Notifications
|
||||
public static let notifications = L10n.tr("Localizable", "Common.Controls.Tabs.Notifications", fallback: "Notifications")
|
||||
/// Profile
|
||||
public static let profile = L10n.tr("Localizable", "Common.Controls.Tabs.Profile", fallback: "Profile")
|
||||
/// Search
|
||||
|
|
|
@ -131,7 +131,7 @@ Please check your internet connection.";
|
|||
"Common.Controls.Status.Visibility.PrivateFromMe" = "Only my followers can see this post.";
|
||||
"Common.Controls.Status.Visibility.Unlisted" = "Everyone can see this post but not display in the public timeline.";
|
||||
"Common.Controls.Tabs.Home" = "Home";
|
||||
"Common.Controls.Tabs.Notification" = "Notification";
|
||||
"Common.Controls.Tabs.Notifications" = "Notifications";
|
||||
"Common.Controls.Tabs.Profile" = "Profile";
|
||||
"Common.Controls.Tabs.Search" = "Search";
|
||||
"Common.Controls.Timeline.Filtered" = "Filtered";
|
||||
|
|
|
@ -25,7 +25,8 @@ extension NotificationView {
|
|||
let logger = Logger(subsystem: "NotificationView", category: "ViewModel")
|
||||
|
||||
@Published public var authContext: AuthContext?
|
||||
|
||||
|
||||
@Published public var type: MastodonNotificationType?
|
||||
@Published public var notificationIndicatorText: MetaContent?
|
||||
|
||||
@Published public var authorAvatarImage: UIImage?
|
||||
|
@ -54,7 +55,7 @@ extension NotificationView.ViewModel {
|
|||
bindAuthor(notificationView: notificationView)
|
||||
bindAuthorMenu(notificationView: notificationView)
|
||||
bindFollowRequest(notificationView: notificationView)
|
||||
|
||||
|
||||
$authContext
|
||||
.assign(to: \.authContext, on: notificationView.statusView.viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
@ -100,20 +101,21 @@ extension NotificationView.ViewModel {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
// timestamp
|
||||
Publishers.CombineLatest(
|
||||
let formattedTimestamp = Publishers.CombineLatest(
|
||||
$timestamp,
|
||||
timestampUpdatePublisher.prepend(Date()).eraseToAnyPublisher()
|
||||
)
|
||||
.sink { [weak self] timestamp, _ in
|
||||
guard let timestamp = timestamp else {
|
||||
notificationView.dateLabel.configure(content: PlaintextMetaContent(string: ""))
|
||||
return
|
||||
}
|
||||
|
||||
let text = timestamp.localizedTimeAgoSinceNow
|
||||
notificationView.dateLabel.configure(content: PlaintextMetaContent(string: text))
|
||||
.map { timestamp, _ in
|
||||
timestamp?.localizedTimeAgoSinceNow ?? ""
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
.removeDuplicates()
|
||||
|
||||
formattedTimestamp
|
||||
.sink { timestamp in
|
||||
notificationView.dateLabel.configure(content: PlaintextMetaContent(string: timestamp))
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// notification type indicator
|
||||
$notificationIndicatorText
|
||||
.sink { text in
|
||||
|
@ -124,6 +126,76 @@ extension NotificationView.ViewModel {
|
|||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
Publishers.CombineLatest4(
|
||||
$authorName,
|
||||
$authorUsername,
|
||||
$notificationIndicatorText,
|
||||
formattedTimestamp
|
||||
)
|
||||
.sink { name, username, type, timestamp in
|
||||
notificationView.accessibilityLabel = [
|
||||
"\(name?.string ?? "") \(type?.string ?? "")",
|
||||
username.map { "@\($0)" } ?? "",
|
||||
timestamp
|
||||
].joined(separator: ", ")
|
||||
if !notificationView.statusView.isHidden {
|
||||
notificationView.accessibilityLabel! += ", " + (notificationView.statusView.accessibilityLabel ?? "")
|
||||
}
|
||||
if !notificationView.quoteStatusViewContainerView.isHidden {
|
||||
notificationView.accessibilityLabel! += ", " + (notificationView.quoteStatusView.accessibilityLabel ?? "")
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
Publishers.CombineLatest(
|
||||
$authorAvatarImage,
|
||||
$type
|
||||
)
|
||||
.sink { avatarImage, type in
|
||||
var actions = [UIAccessibilityCustomAction]()
|
||||
|
||||
// these notifications can be directly actioned to view the profile
|
||||
if type != .follow, type != .followRequest {
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Status.showUserProfile,
|
||||
image: avatarImage
|
||||
) { [weak notificationView] _ in
|
||||
guard let notificationView = notificationView, let delegate = notificationView.delegate else { return false }
|
||||
delegate.notificationView(notificationView, authorAvatarButtonDidPressed: notificationView.avatarButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if type == .followRequest {
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Actions.confirm,
|
||||
image: Asset.Editing.checkmark20.image
|
||||
) { [weak notificationView] _ in
|
||||
guard let notificationView = notificationView, let delegate = notificationView.delegate else { return false }
|
||||
delegate.notificationView(notificationView, acceptFollowRequestButtonDidPressed: notificationView.acceptFollowRequestButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Actions.delete,
|
||||
image: Asset.Circles.forbidden20.image
|
||||
) { [weak notificationView] _ in
|
||||
guard let notificationView = notificationView, let delegate = notificationView.delegate else { return false }
|
||||
delegate.notificationView(notificationView, rejectFollowRequestButtonDidPressed: notificationView.rejectFollowRequestButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
notificationView.notificationActions = actions
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
private func bindAuthorMenu(notificationView: NotificationView) {
|
||||
|
@ -146,7 +218,9 @@ extension NotificationView.ViewModel {
|
|||
isMyself: isMyself,
|
||||
isBookmarking: false // no bookmark action display for notification item
|
||||
)
|
||||
notificationView.menuButton.menu = notificationView.setupAuthorMenu(menuContext: menuContext)
|
||||
let (menu, actions) = notificationView.setupAuthorMenu(menuContext: menuContext)
|
||||
notificationView.menuButton.menu = menu
|
||||
notificationView.authorActions = actions
|
||||
notificationView.menuButton.showsMenuAsPrimaryAction = true
|
||||
|
||||
notificationView.menuButton.isHidden = menuContext.isMyself
|
||||
|
@ -206,5 +280,5 @@ extension NotificationView.ViewModel {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -46,7 +46,10 @@ public final class NotificationView: UIView {
|
|||
|
||||
var _disposeBag = Set<AnyCancellable>()
|
||||
public var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
|
||||
var notificationActions = [UIAccessibilityCustomAction]()
|
||||
var authorActions = [UIAccessibilityCustomAction]()
|
||||
|
||||
public private(set) lazy var viewModel: ViewModel = {
|
||||
let viewModel = ViewModel()
|
||||
viewModel.bind(notificationView: self)
|
||||
|
@ -372,6 +375,30 @@ extension NotificationView {
|
|||
|
||||
statusView.delegate = self
|
||||
quoteStatusView.delegate = self
|
||||
|
||||
isAccessibilityElement = true
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationView {
|
||||
public override var accessibilityElements: [Any]? {
|
||||
get { [] }
|
||||
set {}
|
||||
}
|
||||
|
||||
public override var accessibilityCustomActions: [UIAccessibilityCustomAction]? {
|
||||
get {
|
||||
var actions = notificationActions
|
||||
actions += authorActions
|
||||
if !statusView.isHidden {
|
||||
actions += statusView.accessibilityCustomActions ?? []
|
||||
}
|
||||
if !quoteStatusViewContainerView.isHidden {
|
||||
actions += quoteStatusView.accessibilityCustomActions ?? []
|
||||
}
|
||||
return actions
|
||||
}
|
||||
set {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,7 +457,7 @@ extension NotificationView: AdaptiveContainerView {
|
|||
extension NotificationView {
|
||||
public typealias AuthorMenuContext = StatusAuthorView.AuthorMenuContext
|
||||
|
||||
public func setupAuthorMenu(menuContext: AuthorMenuContext) -> UIMenu {
|
||||
public func setupAuthorMenu(menuContext: AuthorMenuContext) -> (UIMenu, [UIAccessibilityCustomAction]) {
|
||||
var actions: [MastodonMenu.Action] = []
|
||||
|
||||
actions = [
|
||||
|
@ -456,8 +483,13 @@ extension NotificationView {
|
|||
actions: actions,
|
||||
delegate: self
|
||||
)
|
||||
|
||||
return menu
|
||||
|
||||
let accessibilityActions = MastodonMenu.setupAccessibilityActions(
|
||||
actions: actions,
|
||||
delegate: self
|
||||
)
|
||||
|
||||
return (menu, accessibilityActions)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -239,12 +239,11 @@ extension StatusView.ViewModel {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
// username
|
||||
let usernamePublisher = $authorUsername
|
||||
$authorUsername
|
||||
.map { text -> String in
|
||||
guard let text = text else { return "" }
|
||||
return "@\(text)"
|
||||
}
|
||||
usernamePublisher
|
||||
.sink { username in
|
||||
let metaContent = PlaintextMetaContent(string: username)
|
||||
authorView.authorUsernameLabel.configure(content: metaContent)
|
||||
|
@ -271,18 +270,6 @@ extension StatusView.ViewModel {
|
|||
authorView.dateLabel.configure(content: PlaintextMetaContent(string: text))
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// accessibility label
|
||||
Publishers.CombineLatest4($authorName, usernamePublisher, $timestampText, $timestamp)
|
||||
.map { name, username, timestampText, timestamp in
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .medium
|
||||
formatter.timeStyle = .short
|
||||
let longTimestamp = timestamp.map { formatter.string(from: $0) } ?? ""
|
||||
return "\(name?.string ?? "") \(username), \(timestampText). \(longTimestamp)"
|
||||
}
|
||||
.assign(to: \.accessibilityLabel, on: authorView)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
private func bindContent(statusView: StatusView) {
|
||||
|
@ -635,7 +622,7 @@ extension StatusView.ViewModel {
|
|||
}
|
||||
|
||||
private func bindAccessibility(statusView: StatusView) {
|
||||
let authorAccessibilityLabel = Publishers.CombineLatest3(
|
||||
let shortAuthorAccessibilityLabel = Publishers.CombineLatest3(
|
||||
$header,
|
||||
$authorName,
|
||||
$timestampText
|
||||
|
@ -645,19 +632,56 @@ extension StatusView.ViewModel {
|
|||
|
||||
switch header {
|
||||
case .none:
|
||||
break
|
||||
strings.append(authorName?.string)
|
||||
case .reply(let info):
|
||||
strings.append(authorName?.string)
|
||||
strings.append(info.header.string)
|
||||
case .repost(let info):
|
||||
strings.append(info.header.string)
|
||||
strings.append(authorName?.string)
|
||||
}
|
||||
|
||||
strings.append(authorName?.string)
|
||||
strings.append(timestamp)
|
||||
|
||||
return strings.compactMap { $0 }.joined(separator: ", ")
|
||||
}
|
||||
|
||||
|
||||
let longTimestampFormatter = DateFormatter()
|
||||
longTimestampFormatter.dateStyle = .medium
|
||||
longTimestampFormatter.timeStyle = .short
|
||||
let longTimestampLabel = Publishers.CombineLatest(
|
||||
$timestampText,
|
||||
$timestamp.map { timestamp in
|
||||
if let timestamp {
|
||||
return longTimestampFormatter.string(from: timestamp)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
)
|
||||
.map { timestampText, longTimestamp in
|
||||
"\(timestampText). \(longTimestamp)"
|
||||
}
|
||||
|
||||
Publishers.CombineLatest4(
|
||||
$header,
|
||||
$authorName,
|
||||
$authorUsername,
|
||||
longTimestampLabel
|
||||
)
|
||||
.map { header, name, username, timestamp in
|
||||
let nameAndUsername = "\(name?.string ?? "") @\(username ?? "")"
|
||||
switch header {
|
||||
case .none:
|
||||
return "\(nameAndUsername), \(timestamp)"
|
||||
case .repost(info: let info):
|
||||
return "\(info.header.string) \(nameAndUsername), \(timestamp)"
|
||||
case .reply(info: let info):
|
||||
return "\(nameAndUsername) \(info.header.string), \(timestamp)"
|
||||
}
|
||||
}
|
||||
.assign(to: \.accessibilityLabel, on: statusView.authorView)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
let contentAccessibilityLabel = Publishers.CombineLatest3(
|
||||
$isContentReveal,
|
||||
$spoilerContent,
|
||||
|
@ -695,8 +719,8 @@ extension StatusView.ViewModel {
|
|||
statusView.spoilerOverlayView.accessibilityLabel = contentAccessibilityLabel
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
let meidaAccessibilityLabel = $mediaViewConfigurations
|
||||
|
||||
let mediaAccessibilityLabel = $mediaViewConfigurations
|
||||
.map { configurations -> String? in
|
||||
let count = configurations.count
|
||||
return L10n.Plural.Count.media(count)
|
||||
|
@ -705,18 +729,18 @@ extension StatusView.ViewModel {
|
|||
// TODO: Toolbar
|
||||
|
||||
Publishers.CombineLatest3(
|
||||
authorAccessibilityLabel,
|
||||
shortAuthorAccessibilityLabel,
|
||||
contentAccessibilityLabel,
|
||||
meidaAccessibilityLabel
|
||||
mediaAccessibilityLabel
|
||||
)
|
||||
.map { author, content, media in
|
||||
let group = [
|
||||
author,
|
||||
content,
|
||||
media
|
||||
]
|
||||
|
||||
return group
|
||||
var labels: [String?] = [content, media]
|
||||
|
||||
if statusView.style != .notification {
|
||||
labels.insert(author, at: 0)
|
||||
}
|
||||
|
||||
return labels
|
||||
.compactMap { $0 }
|
||||
.joined(separator: ", ")
|
||||
}
|
||||
|
|
|
@ -241,6 +241,7 @@ extension StatusView {
|
|||
// header
|
||||
headerIconImageView.isUserInteractionEnabled = false
|
||||
headerInfoLabel.isUserInteractionEnabled = false
|
||||
headerInfoLabel.isAccessibilityElement = false
|
||||
let headerTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
headerTapGestureRecognizer.addTarget(self, action: #selector(StatusView.headerDidPressed(_:)))
|
||||
headerContainerView.addGestureRecognizer(headerTapGestureRecognizer)
|
||||
|
|
Loading…
Reference in New Issue