From f1b5c52815b7ad15ae6d9ba8b8f7f7557ce0f7ae Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 18 Oct 2022 19:01:31 +0800 Subject: [PATCH] feat: restore the compose toolbar layout using SwiftUI --- Mastodon.xcodeproj/project.pbxproj | 12 +- .../xcschemes/xcschememanagement.plist | 4 +- .../Scene/Compose/ComposeViewController.swift | 102 +---------- .../Scene/Compose/Contents.json | 9 + .../Compose/Earth.imageset/Contents.json | 15 ++ .../Scene/Compose/Earth.imageset/Earth.pdf | 169 ++++++++++++++++++ .../button.tint.colorset/Contents.json | 38 ++++ .../chat.warning.imageset/Contents.json | 15 ++ .../chat.warning.imageset/chat.warning.pdf | 101 +++++++++++ .../Compose/emoji.imageset/Contents.json | 15 ++ .../Scene/Compose/emoji.imageset/emoji.pdf | 99 ++++++++++ .../Compose/media.imageset/Contents.json | 15 ++ .../Scene/Compose/media.imageset/media.pdf | 111 ++++++++++++ .../Scene/Compose/poll.imageset/Contents.json | 15 ++ .../Scene/Compose/poll.imageset/poll.pdf | 113 ++++++++++++ .../MastodonAsset/Generated/Assets.swift | 8 + .../Entity/Mastodon+Entity+Status.swift | 2 +- .../ComposeContentViewController.swift | 135 ++++++++++++++ .../ComposeContentToolbarView+ViewModel.swift | 57 ++++++ .../View/ComposeContentToolbarView.swift | 82 +++++++++ 20 files changed, 1007 insertions(+), 110 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Earth.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/button.tint.colorset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/chat.warning.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/emoji.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/media.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/poll.pdf create mode 100644 MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView+ViewModel.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index d2eda9b89..66c28a399 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -3048,7 +3048,7 @@ DB025B8E278D6448002F581E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; - buildActionMask = 8; + buildActionMask = 12; files = ( ); inputFileListPaths = ( @@ -3059,14 +3059,14 @@ ); outputPaths = ( ); - runOnlyForDeploymentPostprocessing = 1; + runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "if [[ -f \"${PODS_ROOT}/Sourcery/bin/sourcery\" ]]; then\n \"${PODS_ROOT}/Sourcery/bin/sourcery\" --config ./MastodonSDK/Sources/CoreDataStack\nelse\n echo \"warning: Sourcery is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n"; }; DB3D100425BAA71500EAA174 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; - buildActionMask = 8; + buildActionMask = 12; files = ( ); inputFileListPaths = ( @@ -3077,14 +3077,14 @@ ); outputPaths = ( ); - runOnlyForDeploymentPostprocessing = 1; + runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "if [[ -f \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" ]]; then\n \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" \nelse\n echo \"warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n"; }; DB697DD2278F48D5004EF2F7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; - buildActionMask = 8; + buildActionMask = 12; files = ( ); inputFileListPaths = ( @@ -3095,7 +3095,7 @@ ); outputPaths = ( ); - runOnlyForDeploymentPostprocessing = 1; + runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "if [[ -f \"${PODS_ROOT}/Sourcery/bin/sourcery\" ]]; then\n \"${PODS_ROOT}/Sourcery/bin/sourcery\" --config ./Mastodon\nelse\n echo \"warning: Sourcery is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n"; }; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 33eda54f1..31423978e 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -112,12 +112,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 18 + 17 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 17 + 18 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index 1d847f040..c94db4def 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -207,24 +207,6 @@ extension ComposeViewController { // self.title = title // } // .store(in: &disposeBag) -// self.setupBackgroundColor(theme: ThemeService.shared.currentTheme.value) -// ThemeService.shared.currentTheme -// .receive(on: RunLoop.main) -// .sink { [weak self] theme in -// guard let self = self else { return } -// self.setupBackgroundColor(theme: theme) -// } -// .store(in: &disposeBag) -// -// -// scrollView.translatesAutoresizingMaskIntoConstraints = false -// view.addSubview(scrollView) -// NSLayoutConstraint.activate([ -// scrollView.topAnchor.constraint(equalTo: view.topAnchor), -// scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), -// scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), -// scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), -// ]) // // composeToolbarView.translatesAutoresizingMaskIntoConstraints = false // view.addSubview(composeToolbarView) @@ -286,89 +268,7 @@ extension ComposeViewController { // // update layout when keyboard show/dismiss // view.layoutIfNeeded() // -// let keyboardHasShortcutBar = CurrentValueSubject(traitCollection.userInterfaceIdiom == .pad) // update default value later -// let keyboardEventPublishers = Publishers.CombineLatest3( -// KeyboardResponderService.shared.isShow, -// KeyboardResponderService.shared.state, -// KeyboardResponderService.shared.endFrame -// ) -// Publishers.CombineLatest3( -// keyboardEventPublishers, -// viewModel.$isCustomEmojiComposing, -// viewModel.$autoCompleteInfo -// ) -// .sink(receiveValue: { [weak self] keyboardEvents, isCustomEmojiComposing, autoCompleteInfo in -// guard let self = self else { return } -// -// let (isShow, state, endFrame) = keyboardEvents -// -// switch self.traitCollection.userInterfaceIdiom { -// case .pad: -// keyboardHasShortcutBar.value = state != .floating -// default: -// keyboardHasShortcutBar.value = false -// } -// -// let extraMargin: CGFloat = { -// var margin = self.composeToolbarView.frame.height -// if autoCompleteInfo != nil { -// margin += ComposeViewController.minAutoCompleteVisibleHeight -// } -// return margin -// }() -// -// guard isShow, state == .dock else { -// self.tableView.contentInset.bottom = extraMargin -// self.tableView.verticalScrollIndicatorInsets.bottom = extraMargin -// -// if let superView = self.autoCompleteViewController.tableView.superview { -// let autoCompleteTableViewBottomInset: CGFloat = { -// let tableViewFrameInWindow = superView.convert(self.autoCompleteViewController.tableView.frame, to: nil) -// let padding = tableViewFrameInWindow.maxY + self.composeToolbarView.frame.height + AutoCompleteViewController.chevronViewHeight - self.view.frame.maxY -// return max(0, padding) -// }() -// self.autoCompleteViewController.tableView.contentInset.bottom = autoCompleteTableViewBottomInset -// self.autoCompleteViewController.tableView.verticalScrollIndicatorInsets.bottom = autoCompleteTableViewBottomInset -// } -// -// UIView.animate(withDuration: 0.3) { -// self.composeToolbarViewBottomLayoutConstraint.constant = self.view.safeAreaInsets.bottom -// if self.view.window != nil { -// self.view.layoutIfNeeded() -// } -// } -// return -// } -// // isShow AND dock state -// self.systemKeyboardHeight = endFrame.height -// -// // adjust inset for auto-complete -// let autoCompleteTableViewBottomInset: CGFloat = { -// guard let superview = self.autoCompleteViewController.tableView.superview else { return .zero } -// let tableViewFrameInWindow = superview.convert(self.autoCompleteViewController.tableView.frame, to: nil) -// let padding = tableViewFrameInWindow.maxY + self.composeToolbarView.frame.height + AutoCompleteViewController.chevronViewHeight - endFrame.minY -// return max(0, padding) -// }() -// self.autoCompleteViewController.tableView.contentInset.bottom = autoCompleteTableViewBottomInset -// self.autoCompleteViewController.tableView.verticalScrollIndicatorInsets.bottom = autoCompleteTableViewBottomInset -// -// // adjust inset for tableView -// let contentFrame = self.view.convert(self.tableView.frame, to: nil) -// let padding = contentFrame.maxY + extraMargin - endFrame.minY -// guard padding > 0 else { -// self.tableView.contentInset.bottom = self.view.safeAreaInsets.bottom + extraMargin -// self.tableView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin -// return -// } -// -// self.tableView.contentInset.bottom = padding - self.view.safeAreaInsets.bottom -// self.tableView.verticalScrollIndicatorInsets.bottom = padding - self.view.safeAreaInsets.bottom -// UIView.animate(withDuration: 0.3) { -// self.composeToolbarViewBottomLayoutConstraint.constant = endFrame.height -// self.view.layoutIfNeeded() -// } -// }) -// .store(in: &disposeBag) + // // // bind auto-complete // viewModel.$autoCompleteInfo diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Contents.json new file mode 100644 index 000000000..6e965652d --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Contents.json new file mode 100644 index 000000000..04f310f98 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Earth.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Earth.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Earth.pdf new file mode 100644 index 000000000..4f6b948a3 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/Earth.imageset/Earth.pdf @@ -0,0 +1,169 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.000122 2.000000 cm +0.000000 0.000000 0.000000 scn +8.945436 19.952877 m +8.950368 19.945572 l +9.295332 19.981556 9.645513 20.000000 10.000000 20.000000 c +15.522847 20.000000 20.000000 15.522847 20.000000 10.000000 c +20.000000 4.477153 15.522847 0.000000 10.000000 0.000000 c +6.790722 0.000000 3.934541 1.511787 2.104761 3.862055 c +2.102194 3.862638 l +2.102672 3.864738 l +0.784842 5.558613 0.000000 7.687653 0.000000 10.000000 c +0.000000 15.161964 3.911163 19.410429 8.931705 19.943607 c +8.945436 19.952877 l +h +10.000000 18.500000 m +9.946768 18.500000 9.893649 18.499510 9.840650 18.498537 c +9.963233 18.254343 10.094863 17.965696 10.214363 17.648212 c +10.561299 16.726484 10.880171 15.367099 10.314304 14.162127 c +9.791718 13.049316 8.889565 12.761408 8.224188 12.589492 c +8.139534 12.567652 l +7.483193 12.398458 7.230809 12.333397 7.046710 12.053902 c +6.877729 11.797358 6.903327 11.471569 7.108089 10.804317 c +7.122483 10.757413 7.138054 10.707805 7.154294 10.656069 c +7.235397 10.397685 7.333165 10.086211 7.384129 9.793275 c +7.447527 9.428862 7.465442 8.965590 7.232083 8.517794 c +7.000589 8.073575 6.693745 7.770780 6.331198 7.573263 c +5.990655 7.387735 5.637942 7.317377 5.374053 7.270582 c +5.281080 7.254177 l +4.766211 7.163565 4.519922 7.120219 4.280048 6.863250 c +4.093846 6.663777 3.973670 6.311463 3.903486 5.785102 c +3.874918 5.570853 3.857739 5.358463 3.839978 5.138891 c +3.830442 5.021761 l +3.810462 4.779471 3.785685 4.500609 3.731205 4.261164 c +3.730906 4.259850 l +5.284881 2.563602 7.518231 1.500000 10.000000 1.500000 c +11.577014 1.500000 13.053720 1.929466 14.319545 2.677820 c +14.221224 2.777969 14.114439 2.895618 14.009129 3.028202 c +13.669640 3.455608 13.224341 4.191939 13.378761 5.060995 c +13.453023 5.478927 13.677018 5.828774 13.893493 6.097116 c +14.114051 6.370518 14.380263 6.623110 14.613050 6.837366 c +14.668355 6.888268 14.721365 6.936671 14.772196 6.983084 c +14.950412 7.145808 15.101837 7.284072 15.231435 7.419845 c +15.404221 7.600864 15.441820 7.682460 15.443790 7.686735 c +15.511713 7.911400 15.428436 8.070621 15.337708 8.140779 c +15.292102 8.176043 15.230948 8.201571 15.147898 8.202232 c +15.064073 8.202900 14.928219 8.177752 14.746777 8.062835 c +14.537054 7.930006 14.232018 7.847993 13.911026 7.977239 c +13.643642 8.084899 13.495515 8.290975 13.424360 8.408617 c +13.280478 8.646499 13.199624 8.954817 13.146976 9.180877 c +13.106362 9.355261 13.067616 9.553251 13.032258 9.733932 c +13.018108 9.806237 13.004500 9.875771 12.991533 9.939910 c +12.941022 10.189741 12.898354 10.368218 12.857431 10.479053 c +12.856843 10.480482 12.851788 10.492748 12.838216 10.517543 c +12.823483 10.544457 12.802644 10.579025 12.774174 10.622349 c +12.716190 10.710581 12.640428 10.814299 12.546493 10.938749 c +12.512385 10.983936 12.475714 11.032014 12.437285 11.082394 c +12.276200 11.293579 12.084242 11.545244 11.920969 11.794048 c +11.725189 12.092388 11.503861 12.482321 11.433911 12.898157 c +11.396839 13.118542 11.397423 13.373061 11.488866 13.631610 c +11.582505 13.896370 11.753467 14.114110 11.975435 14.280597 c +12.458843 14.643174 13.168970 15.453171 13.798772 16.239641 c +14.086361 16.598770 14.343374 16.935246 14.534719 17.190622 c +13.222366 18.019987 11.667240 18.500000 10.000000 18.500000 c +h +15.727353 16.280794 m +15.529826 16.017342 15.265779 15.671862 14.969622 15.302032 c +14.367900 14.550627 13.570269 13.617192 12.920100 13.114614 c +12.945479 13.015734 13.020371 12.852727 13.175053 12.617016 c +13.306167 12.417215 13.456026 12.220543 13.614124 12.013055 c +13.656691 11.957191 13.700173 11.900127 13.743729 11.842422 c +13.916128 11.614019 14.155027 11.295321 14.264583 10.998598 c +14.350787 10.765120 14.412687 10.480006 14.461784 10.237164 c +14.479100 10.151520 14.495111 10.069643 14.510527 9.990811 c +14.536025 9.860416 14.559895 9.738358 14.585339 9.621376 c +15.187048 9.793123 15.787111 9.689411 16.255274 9.327401 c +16.863905 8.856771 17.118000 8.041076 16.879692 7.252826 c +16.770346 6.891145 16.515705 6.592863 16.316484 6.384149 c +16.147512 6.207124 15.944934 6.022339 15.761238 5.854778 c +15.715802 5.813333 15.671200 5.772646 15.628872 5.733688 c +15.398922 5.522042 15.205485 5.334450 15.060962 5.155299 c +14.912354 4.971087 14.865835 4.856014 14.855629 4.798573 c +14.816802 4.580065 14.923186 4.289124 15.183693 3.961153 c +15.301805 3.812452 15.427599 3.687178 15.525196 3.598549 c +15.536726 3.588078 15.547768 3.578207 15.558244 3.568960 c +17.360012 5.127576 18.500000 7.430659 18.500000 10.000000 c +18.500000 12.488004 17.431046 14.726340 15.727353 16.280794 c +h +1.500000 10.000000 m +1.500000 8.601643 1.837670 7.282152 2.435920 6.118621 c +2.520806 6.676047 2.697947 7.366606 3.183541 7.886808 c +3.783359 8.529375 4.519145 8.649875 4.981673 8.725623 c +5.027948 8.733203 5.071755 8.740378 5.112145 8.747540 c +5.359830 8.791461 5.503073 8.830262 5.613584 8.890469 c +5.702090 8.938686 5.801398 9.018201 5.901872 9.211002 c +5.916738 9.239530 5.944188 9.318548 5.906326 9.536173 c +5.873906 9.722527 5.813122 9.917411 5.733576 10.172447 c +5.714817 10.232594 5.694809 10.296745 5.674091 10.364261 c +5.488935 10.967622 5.193007 11.966541 5.794037 12.879015 c +6.315677 13.670959 7.154699 13.873423 7.687307 14.001944 c +7.745055 14.015879 7.799201 14.028945 7.848949 14.041800 c +8.411874 14.187244 8.732245 14.322063 8.956565 14.799735 c +9.251945 15.428725 9.124854 16.284683 8.810515 17.119806 c +8.661468 17.515793 8.486593 17.863750 8.348099 18.113476 c +8.304624 18.191868 8.265136 18.259853 8.231707 18.315813 c +4.385974 17.502075 1.500000 14.088065 1.500000 10.000000 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 5594 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000005684 00000 n +0000005707 00000 n +0000005880 00000 n +0000005954 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +6013 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/button.tint.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/button.tint.colorset/Contents.json new file mode 100644 index 000000000..9bdcecb67 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/button.tint.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x38", + "green" : "0x29", + "red" : "0x2B" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF9", + "green" : "0xF5", + "red" : "0xF5" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/Contents.json new file mode 100644 index 000000000..7ed4f66e6 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "chat.warning.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/chat.warning.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/chat.warning.pdf new file mode 100644 index 000000000..8b984cc82 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/chat.warning.imageset/chat.warning.pdf @@ -0,0 +1,101 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.000000 1.858978 cm +0.000000 0.000000 0.000000 scn +10.000000 15.641022 m +10.414213 15.641022 10.750000 15.305235 10.750000 14.891022 c +10.750000 8.641022 l +10.750000 8.226809 10.414213 7.891022 10.000000 7.891022 c +9.585787 7.891022 9.250000 8.226809 9.250000 8.641022 c +9.250000 14.891022 l +9.250000 15.305235 9.585787 15.641022 10.000000 15.641022 c +h +10.000000 4.643219 m +10.552285 4.643219 11.000000 5.090935 11.000000 5.643219 c +11.000000 6.195504 10.552285 6.643219 10.000000 6.643219 c +9.447715 6.643219 9.000000 6.195504 9.000000 5.643219 c +9.000000 5.090935 9.447715 4.643219 10.000000 4.643219 c +h +10.000000 20.141022 m +15.522848 20.141022 20.000000 15.663870 20.000000 10.141022 c +20.000000 4.618174 15.522848 0.141022 10.000000 0.141022 c +8.381707 0.141022 6.817824 0.526447 5.412859 1.253002 c +1.587041 0.185684 l +0.922123 0.000010 0.232581 0.388512 0.046906 1.053431 c +-0.014536 1.273458 -0.014506 1.506115 0.046948 1.725969 c +1.114612 5.548796 l +0.386366 6.955047 0.000000 8.520757 0.000000 10.141022 c +0.000000 15.663870 4.477152 20.141022 10.000000 20.141022 c +h +10.000000 18.641022 m +5.305580 18.641022 1.500000 14.835442 1.500000 10.141022 c +1.500000 8.671413 1.872775 7.257639 2.573033 6.003563 c +2.723677 5.733776 l +1.610960 1.749634 l +5.597552 2.861805 l +5.867086 2.711519 l +7.120057 2.012886 8.532184 1.641022 10.000000 1.641022 c +14.694420 1.641022 18.500000 5.446602 18.500000 10.141022 c +18.500000 14.835442 14.694420 18.641022 10.000000 18.641022 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1552 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001642 00000 n +0000001665 00000 n +0000001838 00000 n +0000001912 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1971 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/Contents.json new file mode 100644 index 000000000..26d6caeb6 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "emoji.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/emoji.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/emoji.pdf new file mode 100644 index 000000000..59180776b --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/emoji.imageset/emoji.pdf @@ -0,0 +1,99 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.998444 1.997925 cm +0.000000 0.000000 0.000000 scn +10.001551 20.003113 m +15.525254 20.003113 20.003101 15.525267 20.003101 10.001562 c +20.003101 4.477859 15.525254 0.000013 10.001551 0.000013 c +4.477847 0.000013 0.000000 4.477859 0.000000 10.001562 c +0.000000 15.525267 4.477847 20.003113 10.001551 20.003113 c +h +10.001551 18.503113 m +5.306274 18.503113 1.500000 14.696838 1.500000 10.001562 c +1.500000 5.306286 5.306274 1.500013 10.001551 1.500013 c +14.696827 1.500013 18.503101 5.306286 18.503101 10.001562 c +18.503101 14.696838 14.696827 18.503113 10.001551 18.503113 c +h +6.463291 7.218245 m +7.312427 6.140525 8.603443 5.499995 10.001535 5.499995 c +11.397759 5.499995 12.687231 6.138799 13.536489 7.214072 c +13.793221 7.539129 14.264852 7.594518 14.589909 7.337786 c +14.914966 7.081055 14.970354 6.609422 14.713623 6.284365 c +13.582860 4.852667 11.861678 3.999996 10.001535 3.999996 c +8.138899 3.999996 6.415668 4.854965 5.285066 6.289920 c +5.028717 6.615278 5.084659 7.086845 5.410017 7.343195 c +5.735374 7.599545 6.206941 7.543602 6.463291 7.218245 c +h +7.001998 13.250921 m +7.691962 13.250921 8.251287 12.691595 8.251287 12.001632 c +8.251287 11.311668 7.691962 10.752343 7.001998 10.752343 c +6.312035 10.752343 5.752709 11.311668 5.752709 12.001632 c +5.752709 12.691595 6.312035 13.250921 7.001998 13.250921 c +h +13.001999 13.250921 m +13.691962 13.250921 14.251287 12.691595 14.251287 12.001632 c +14.251287 11.311668 13.691962 10.752343 13.001999 10.752343 c +12.312036 10.752343 11.752709 11.311668 11.752709 12.001632 c +11.752709 12.691595 12.312036 13.250921 13.001999 13.250921 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1663 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001753 00000 n +0000001776 00000 n +0000001949 00000 n +0000002023 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2082 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/Contents.json new file mode 100644 index 000000000..aad419f8f --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "media.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/media.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/media.pdf new file mode 100644 index 000000000..91bd4fa06 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/media.imageset/media.pdf @@ -0,0 +1,111 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 3.000000 cm +0.000000 0.000000 0.000000 scn +14.750000 18.000000 m +16.544926 18.000000 18.000000 16.544926 18.000000 14.750000 c +18.000000 3.250000 l +18.000000 1.455074 16.544926 0.000000 14.750000 0.000000 c +3.250000 0.000000 l +1.455075 0.000000 0.000000 1.455074 0.000000 3.250000 c +0.000000 14.750000 l +0.000000 16.544926 1.455075 18.000000 3.250000 18.000000 c +14.750000 18.000000 l +h +15.330538 1.598593 m +9.524668 7.285182 l +9.259618 7.544744 8.850125 7.568357 8.558795 7.356009 c +8.475204 7.285225 l +2.668451 1.598949 l +2.850401 1.534863 3.046129 1.500000 3.250000 1.500000 c +14.750000 1.500000 l +14.953493 1.500000 15.148874 1.534733 15.330538 1.598593 c +9.524668 7.285182 l +15.330538 1.598593 l +h +14.750000 16.500000 m +3.250000 16.500000 l +2.283502 16.500000 1.500000 15.716498 1.500000 14.750000 c +1.500000 3.250000 l +1.500000 3.041599 1.536428 2.841706 1.603264 2.656342 c +7.425784 8.357008 l +8.258866 9.172708 9.567461 9.211498 10.445769 8.473416 c +10.574176 8.356878 l +16.396372 2.655334 l +16.463440 2.840982 16.500000 3.041222 16.500000 3.250000 c +16.500000 14.750000 l +16.500000 15.716498 15.716498 16.500000 14.750000 16.500000 c +h +12.252115 14.500000 m +13.495924 14.500000 14.504230 13.491693 14.504230 12.247885 c +14.504230 11.004076 13.495924 9.995770 12.252115 9.995770 c +11.008307 9.995770 10.000000 11.004076 10.000000 12.247885 c +10.000000 13.491693 11.008307 14.500000 12.252115 14.500000 c +h +12.252115 13.000000 m +11.836734 13.000000 11.500000 12.663266 11.500000 12.247885 c +11.500000 11.832503 11.836734 11.495770 12.252115 11.495770 c +12.667497 11.495770 13.004230 11.832503 13.004230 12.247885 c +13.004230 12.663266 12.667497 13.000000 12.252115 13.000000 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1768 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001858 00000 n +0000001881 00000 n +0000002054 00000 n +0000002128 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2187 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/Contents.json new file mode 100644 index 000000000..0840327d8 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "poll.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/poll.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/poll.pdf new file mode 100644 index 000000000..51f03cd12 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Compose/poll.imageset/poll.pdf @@ -0,0 +1,113 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.000000 1.998138 cm +0.000000 0.000000 0.000000 scn +9.751870 20.002289 m +11.271687 20.002289 12.503741 18.770235 12.503741 17.250418 c +12.503741 2.751883 l +12.503741 1.232067 11.271687 0.000013 9.751870 0.000013 c +8.232054 0.000013 7.000000 1.232067 7.000000 2.751883 c +7.000000 17.250418 l +7.000000 18.770235 8.232054 20.002289 9.751870 20.002289 c +h +16.751871 15.002289 m +18.271687 15.002289 19.503740 13.770235 19.503740 12.250419 c +19.503740 2.751883 l +19.503740 1.232067 18.271687 0.000013 16.751871 0.000013 c +15.232055 0.000013 14.000000 1.232067 14.000000 2.751883 c +14.000000 12.250419 l +14.000000 13.770235 15.232055 15.002289 16.751871 15.002289 c +h +2.751871 10.002289 m +4.271687 10.002289 5.503741 8.770235 5.503741 7.250419 c +5.503741 2.751883 l +5.503741 1.232067 4.271687 0.000013 2.751871 0.000013 c +1.232054 0.000013 0.000000 1.232067 0.000000 2.751883 c +0.000000 7.250419 l +0.000000 8.770235 1.232054 10.002289 2.751871 10.002289 c +h +9.751870 18.502289 m +9.060481 18.502289 8.500000 17.941807 8.500000 17.250418 c +8.500000 2.751883 l +8.500000 2.060493 9.060481 1.500013 9.751870 1.500013 c +10.443259 1.500013 11.003741 2.060493 11.003741 2.751883 c +11.003741 17.250418 l +11.003741 17.941807 10.443259 18.502289 9.751870 18.502289 c +h +16.751871 13.502289 m +16.060482 13.502289 15.500000 12.941808 15.500000 12.250419 c +15.500000 2.751883 l +15.500000 2.060493 16.060482 1.500013 16.751871 1.500013 c +17.443260 1.500013 18.003740 2.060493 18.003740 2.751883 c +18.003740 12.250419 l +18.003740 12.941808 17.443260 13.502289 16.751871 13.502289 c +h +2.751871 8.502289 m +2.060482 8.502289 1.500000 7.941808 1.500000 7.250419 c +1.500000 2.751883 l +1.500000 2.060493 2.060482 1.500013 2.751871 1.500013 c +3.443260 1.500013 4.003741 2.060493 4.003741 2.751883 c +4.003741 7.250419 l +4.003741 7.941808 3.443260 8.502289 2.751871 8.502289 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1919 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002009 00000 n +0000002032 00000 n +0000002205 00000 n +0000002279 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2338 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index edbf78a0b..efdc2164e 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -129,6 +129,14 @@ public enum Asset { public static let star = ImageAsset(name: "ObjectsAndTools/star") } public enum Scene { + public enum Compose { + public static let buttonTint = ColorAsset(name: "Scene/Compose/button.tint") + public static let chatWarning = ImageAsset(name: "Scene/Compose/chat.warning") + public static let earth = ImageAsset(name: "Scene/Compose/earth") + public static let emoji = ImageAsset(name: "Scene/Compose/emoji") + public static let media = ImageAsset(name: "Scene/Compose/media") + public static let poll = ImageAsset(name: "Scene/Compose/poll") + } public enum Discovery { public static let profileCardBackground = ColorAsset(name: "Scene/Discovery/profile.card.background") } diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift index 7f8a4fd4e..29ffcbeb9 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift @@ -102,7 +102,7 @@ extension Mastodon.Entity { } extension Mastodon.Entity.Status { - public enum Visibility: RawRepresentable, Codable { + public enum Visibility: RawRepresentable, Codable, Hashable { case `public` case unlisted case `private` diff --git a/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/ComposeContentViewController.swift b/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/ComposeContentViewController.swift index 4c0a71f60..51dfb3ace 100644 --- a/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/ComposeContentViewController.swift +++ b/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/ComposeContentViewController.swift @@ -9,6 +9,7 @@ import os.log import UIKit import SwiftUI import Combine +import MastodonCore public final class ComposeContentViewController: UIViewController { @@ -16,6 +17,7 @@ public final class ComposeContentViewController: UIViewController { var disposeBag = Set() public var viewModel: ComposeContentViewModel! + let composeContentToolbarViewModel = ComposeContentToolbarView.ViewModel() let tableView: ComposeTableView = { let tableView = ComposeTableView() @@ -25,6 +27,10 @@ public final class ComposeContentViewController: UIViewController { tableView.tableFooterView = UIView() return tableView }() + + lazy var composeContentToolbarView = ComposeContentToolbarView(viewModel: composeContentToolbarViewModel) + var composeContentToolbarViewBottomLayoutConstraint: NSLayoutConstraint! + let composeContentToolbarBackgroundView = UIView() deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) @@ -36,6 +42,17 @@ extension ComposeContentViewController { public override func viewDidLoad() { super.viewDidLoad() + // setup view + self.setupBackgroundColor(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: RunLoop.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupBackgroundColor(theme: theme) + } + .store(in: &disposeBag) + + // setup tableView tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ @@ -48,6 +65,110 @@ extension ComposeContentViewController { tableView.delegate = self viewModel.setupDataSource(tableView: tableView) + let toolbarHostingView = UIHostingController(rootView: composeContentToolbarView) + toolbarHostingView.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(toolbarHostingView.view) + composeContentToolbarViewBottomLayoutConstraint = view.bottomAnchor.constraint(equalTo: toolbarHostingView.view.bottomAnchor) + NSLayoutConstraint.activate([ + toolbarHostingView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + toolbarHostingView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + composeContentToolbarViewBottomLayoutConstraint, + toolbarHostingView.view.heightAnchor.constraint(equalToConstant: ComposeContentToolbarView.toolbarHeight), + ]) + toolbarHostingView.view.preservesSuperviewLayoutMargins = true + //composeToolbarView.delegate = self + + composeContentToolbarBackgroundView.translatesAutoresizingMaskIntoConstraints = false + view.insertSubview(composeContentToolbarBackgroundView, belowSubview: toolbarHostingView.view) + NSLayoutConstraint.activate([ + composeContentToolbarBackgroundView.topAnchor.constraint(equalTo: toolbarHostingView.view.topAnchor), + composeContentToolbarBackgroundView.leadingAnchor.constraint(equalTo: toolbarHostingView.view.leadingAnchor), + composeContentToolbarBackgroundView.trailingAnchor.constraint(equalTo: toolbarHostingView.view.trailingAnchor), + view.bottomAnchor.constraint(equalTo: composeContentToolbarBackgroundView.bottomAnchor), + ]) + + let keyboardHasShortcutBar = CurrentValueSubject(traitCollection.userInterfaceIdiom == .pad) // update default value later + let keyboardEventPublishers = Publishers.CombineLatest3( + KeyboardResponderService.shared.isShow, + KeyboardResponderService.shared.state, + KeyboardResponderService.shared.endFrame + ) +// Publishers.CombineLatest3( +// viewModel.$isCustomEmojiComposing, +// ) + keyboardEventPublishers + .sink(receiveValue: { [weak self] keyboardEvents in + guard let self = self else { return } + + let (isShow, state, endFrame) = keyboardEvents + +// switch self.traitCollection.userInterfaceIdiom { +// case .pad: +// keyboardHasShortcutBar.value = state != .floating +// default: +// keyboardHasShortcutBar.value = false +// } +// + let extraMargin: CGFloat = { + var margin = ComposeContentToolbarView.toolbarHeight +// if autoCompleteInfo != nil { +//// margin += ComposeViewController.minAutoCompleteVisibleHeight +// } + return margin + }() +// + guard isShow, state == .dock else { + self.tableView.contentInset.bottom = extraMargin + self.tableView.verticalScrollIndicatorInsets.bottom = extraMargin + +// if let superView = self.autoCompleteViewController.tableView.superview { +// let autoCompleteTableViewBottomInset: CGFloat = { +// let tableViewFrameInWindow = superView.convert(self.autoCompleteViewController.tableView.frame, to: nil) +// let padding = tableViewFrameInWindow.maxY + self.composeToolbarView.frame.height + AutoCompleteViewController.chevronViewHeight - self.view.frame.maxY +// return max(0, padding) +// }() +// self.autoCompleteViewController.tableView.contentInset.bottom = autoCompleteTableViewBottomInset +// self.autoCompleteViewController.tableView.verticalScrollIndicatorInsets.bottom = autoCompleteTableViewBottomInset +// } + + UIView.animate(withDuration: 0.3) { + self.composeContentToolbarViewBottomLayoutConstraint.constant = self.view.safeAreaInsets.bottom + if self.view.window != nil { + self.view.layoutIfNeeded() + } + } + return + } + // isShow AND dock state +// self.systemKeyboardHeight = endFrame.height + + // adjust inset for auto-complete +// let autoCompleteTableViewBottomInset: CGFloat = { +// guard let superview = self.autoCompleteViewController.tableView.superview else { return .zero } +// let tableViewFrameInWindow = superview.convert(self.autoCompleteViewController.tableView.frame, to: nil) +// let padding = tableViewFrameInWindow.maxY + self.composeToolbarView.frame.height + AutoCompleteViewController.chevronViewHeight - endFrame.minY +// return max(0, padding) +// }() +// self.autoCompleteViewController.tableView.contentInset.bottom = autoCompleteTableViewBottomInset +// self.autoCompleteViewController.tableView.verticalScrollIndicatorInsets.bottom = autoCompleteTableViewBottomInset + + // adjust inset for tableView + let contentFrame = self.view.convert(self.tableView.frame, to: nil) + let padding = contentFrame.maxY + extraMargin - endFrame.minY + guard padding > 0 else { + self.tableView.contentInset.bottom = self.view.safeAreaInsets.bottom + extraMargin + self.tableView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin + return + } + + self.tableView.contentInset.bottom = padding - self.view.safeAreaInsets.bottom + self.tableView.verticalScrollIndicatorInsets.bottom = padding - self.view.safeAreaInsets.bottom + UIView.animate(withDuration: 0.3) { + self.composeContentToolbarViewBottomLayoutConstraint.constant = endFrame.height + self.view.layoutIfNeeded() + } + }) + .store(in: &disposeBag) // setup snap behavior Publishers.CombineLatest( @@ -90,6 +211,20 @@ extension ComposeContentViewController { } } +extension ComposeContentViewController { + private func setupBackgroundColor(theme: Theme) { + let backgroundColor = UIColor(dynamicProvider: { traitCollection in + switch traitCollection.userInterfaceStyle { + case .light: return .systemBackground + default: return theme.systemElevatedBackgroundColor + } + }) + view.backgroundColor = backgroundColor + tableView.backgroundColor = backgroundColor + composeContentToolbarBackgroundView.backgroundColor = theme.composeToolbarBackgroundColor + } +} + // MARK: - UIScrollViewDelegate extension ComposeContentViewController { public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { diff --git a/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView+ViewModel.swift new file mode 100644 index 000000000..ed412fbea --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView+ViewModel.swift @@ -0,0 +1,57 @@ +// +// ComposeContentToolbarView.swift +// +// +// Created by MainasuK on 22/10/18. +// + +import SwiftUI +import MastodonCore +import MastodonAsset +import MastodonSDK + +extension ComposeContentToolbarView { + class ViewModel: ObservableObject { + + // input + @Published var backgroundColor = ThemeService.shared.currentTheme.value.composeToolbarBackgroundColor + @Published var visibility: Mastodon.Entity.Status.Visibility = .public + var allVisibilities: [Mastodon.Entity.Status.Visibility] { + return [.public, .private, .direct] + } + + // output + + init() { + ThemeService.shared.currentTheme + .map { $0.composeToolbarBackgroundColor } + .assign(to: &$backgroundColor) + } + + } +} + +extension ComposeContentToolbarView.ViewModel { + enum Action: CaseIterable { + case attachment + case poll + case emoji + case contentWarning + case visibility + + var image: UIImage { + switch self { + case .attachment: + return Asset.Scene.Compose.media.image + case .poll: + return Asset.Scene.Compose.poll.image + case .emoji: + return Asset.Scene.Compose.emoji.image + case .contentWarning: + return Asset.Scene.Compose.chatWarning.image + case .visibility: + return Asset.Scene.Compose.earth.image + } + } + } +} diff --git a/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView.swift b/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView.swift new file mode 100644 index 000000000..775a6f4f0 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/View/ComposeContentToolbarView.swift @@ -0,0 +1,82 @@ +// +// ComposeContentToolbarView.swift +// +// +// Created by MainasuK on 22/10/18. +// + +import SwiftUI +import MastodonAsset + +struct ComposeContentToolbarView: View { + + static var toolbarHeight: CGFloat { 48 } + + @ObservedObject var viewModel: ViewModel + + var body: some View { + HStack(spacing: .zero) { + ForEach(ComposeContentToolbarView.ViewModel.Action.allCases, id: \.self) { action in + switch action { + case .attachment: + Menu { + Button { + + } label: { + Label("Photo Library", systemImage: "photo.on.rectangle") + } + Button { + + } label: { + Label("Camera", systemImage: "camera") + } + Button { + + } label: { + Label("Browse", systemImage: "ellipsis") + } + } label: { + label(for: action) + } + .frame(width: 48, height: 48) + case .visibility: + Menu { + Picker(selection: $viewModel.visibility) { + ForEach(viewModel.allVisibilities, id: \.self) { visibility in + Label(visibility.rawValue, systemImage: "photo.on.rectangle") + } + } label: { + Text("Select Visibility") + } + } label: { + label(for: action) + } + .frame(width: 48, height: 48) + default: + Button { + + } label: { + label(for: action) + } + .frame(width: 48, height: 48) + } + } + Spacer() + Text("Hello") + } + .padding(.leading, 4) // 4 + 12 = 16 + .padding(.trailing, 16) + .frame(height: ComposeContentToolbarView.toolbarHeight) + .background(Color(viewModel.backgroundColor)) + } + +} + + +extension ComposeContentToolbarView { + func label(for action: ComposeContentToolbarView.ViewModel.Action) -> some View { + Image(uiImage: action.image.withRenderingMode(.alwaysTemplate)) + .foregroundColor(Color(Asset.Scene.Compose.buttonTint.color)) + .frame(width: 24, height: 24, alignment: .center) + } +}