From de10bd7fb421073d961398df68e4d35a3f8cfa29 Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Mon, 15 Apr 2019 15:25:40 -0400 Subject: [PATCH] UI: Footer nav fixes - moves footer nav to the header on iPads - disables scrolling events for iPads - removes footer nav entirely on Chrome PWAs - toggles DiscourseHub iOS app status bar styling (dark/light) when opening/closing lightboxes and modals --- .../discourse/components/d-modal-body.js.es6 | 1 + .../discourse/components/footer-nav.js.es6 | 51 +++++++++++++++---- .../discourse/controllers/application.js.es6 | 8 +-- .../discourse/initializers/mobile.js.es6 | 9 ++-- .../javascripts/discourse/lib/lightbox.js.es6 | 14 +++++ .../discourse/lib/utilities.js.es6 | 10 ++-- .../discourse/widgets/footer-nav.js.es6 | 21 ++------ .../common/components/footer-nav.scss | 21 +++++++- .../common/foundation/variables.scss | 1 + 9 files changed, 90 insertions(+), 46 deletions(-) diff --git a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 index a49887519c2..f9086827e99 100644 --- a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 @@ -22,6 +22,7 @@ export default Ember.Component.extend({ this._super(...arguments); this.appEvents.off("modal-body:flash", this, "_flash"); this.appEvents.off("modal-body:clearFlash", this, "_clearFlash"); + this.appEvents.trigger("modal:body-dismissed"); }, _afterFirstRender() { diff --git a/app/assets/javascripts/discourse/components/footer-nav.js.es6 b/app/assets/javascripts/discourse/components/footer-nav.js.es6 index 56eecf2966a..0cbf317a8a5 100644 --- a/app/assets/javascripts/discourse/components/footer-nav.js.es6 +++ b/app/assets/javascripts/discourse/components/footer-nav.js.es6 @@ -2,6 +2,8 @@ import MountWidget from "discourse/components/mount-widget"; import MobileScrollDirection from "discourse/mixins/mobile-scroll-direction"; import Scrolling from "discourse/mixins/scrolling"; import { observes } from "ember-addons/ember-computed-decorators"; +import { isiPad } from "discourse/lib/utilities"; +import { isAppWebview, postRNWebviewMessage } from "discourse/lib/utilities"; const MOBILE_SCROLL_DIRECTION_CHECK_THROTTLE = 150; @@ -28,22 +30,40 @@ const FooterNavComponent = MountWidget.extend( didInsertElement() { this._super(...arguments); - this.bindScrolling({ name: "footer-nav" }); - $(window).on("resize.footer-nav-on-scroll", () => this.scrolled()); this.appEvents.on("page:changed", this, "_routeChanged"); - this.appEvents.on("composer:opened", this, "_composerOpened"); - this.appEvents.on("composer:closed", this, "_composerClosed"); - $("body").addClass("with-footer-nav"); + + if (isAppWebview()) { + this.appEvents.on("modal:body-shown", this, "_modalOn"); + this.appEvents.on("modal:body-dismissed", this, "_modalOff"); + } + + if (isiPad()) { + $("body").addClass("footer-nav-ipad"); + } else { + this.bindScrolling({ name: "footer-nav" }); + $(window).on("resize.footer-nav-on-scroll", () => this.scrolled()); + this.appEvents.on("composer:opened", this, "_composerOpened"); + this.appEvents.on("composer:closed", this, "_composerClosed"); + } }, willDestroyElement() { this._super(...arguments); - this.unbindScrolling("footer-nav"); - $(window).unbind("resize.footer-nav-on-scroll"); this.appEvents.off("page:changed", this, "_routeChanged"); - this.appEvents.off("composer:opened", this, "_composerOpened"); - this.appEvents.off("composer:closed", this, "_composerClosed"); - $("body").removeClass("with-footer-nav"); + + if (isAppWebview()) { + this.appEvents.off("modal:body-shown", this, "_modalOn"); + this.appEvents.off("modal:body-removed", this, "_modalOff"); + } + + if (isiPad()) { + $("body").removeClass("footer-nav-ipad"); + } else { + this.unbindScrolling("footer-nav"); + $(window).unbind("resize.footer-nav-on-scroll"); + this.appEvents.off("composer:opened", this, "_composerOpened"); + this.appEvents.off("composer:closed", this, "_composerClosed"); + } }, // The user has scrolled the window, or it is finished rendering and ready for processing. @@ -105,6 +125,17 @@ const FooterNavComponent = MountWidget.extend( this.set("scrollEventDisabled", false); }, + _modalOn() { + postRNWebviewMessage( + "headerBg", + $(".modal-backdrop").css("background-color") + ); + }, + + _modalOff() { + postRNWebviewMessage("headerBg", $(".d-header").css("background-color")); + }, + goBack() { this.set("currentRouteIndex", this.get("currentRouteIndex") - 1); this.backForwardClicked = true; diff --git a/app/assets/javascripts/discourse/controllers/application.js.es6 b/app/assets/javascripts/discourse/controllers/application.js.es6 index 12459fd2882..ce23c502faa 100644 --- a/app/assets/javascripts/discourse/controllers/application.js.es6 +++ b/app/assets/javascripts/discourse/controllers/application.js.es6 @@ -1,5 +1,5 @@ import computed from "ember-addons/ember-computed-decorators"; -import { isAppWebview, isiOSPWA, isChromePWA } from "discourse/lib/utilities"; +import { isAppWebview, isiOSPWA } from "discourse/lib/utilities"; export default Ember.Controller.extend({ showTop: true, @@ -21,10 +21,6 @@ export default Ember.Controller.extend({ @computed showFooterNav() { - return ( - isAppWebview() || - isiOSPWA() || - (!this.site.isMobileDevice && isChromePWA()) - ); + return isAppWebview() || isiOSPWA(); } }); diff --git a/app/assets/javascripts/discourse/initializers/mobile.js.es6 b/app/assets/javascripts/discourse/initializers/mobile.js.es6 index fa38f88dbff..a536398e94e 100644 --- a/app/assets/javascripts/discourse/initializers/mobile.js.es6 +++ b/app/assets/javascripts/discourse/initializers/mobile.js.es6 @@ -1,5 +1,6 @@ import Mobile from "discourse/lib/mobile"; import { setResolverOption } from "discourse-common/resolver"; +import { isAppWebview, postRNWebviewMessage } from "discourse/lib/utilities"; // Initializes the `Mobile` helper object. export default { @@ -15,11 +16,11 @@ export default { setResolverOption("mobileView", Mobile.mobileView); - if (window.ReactNativeWebView) { + if (isAppWebview()) { Ember.run.later(() => { - let headerBg = $(".d-header").css("background-color"); - window.ReactNativeWebView.postMessage( - JSON.stringify({ headerBg: headerBg }) + postRNWebviewMessage( + "headerBg", + $(".d-header").css("background-color") ); }, 500); } diff --git a/app/assets/javascripts/discourse/lib/lightbox.js.es6 b/app/assets/javascripts/discourse/lib/lightbox.js.es6 index 77c675e3447..ee09275263b 100644 --- a/app/assets/javascripts/discourse/lib/lightbox.js.es6 +++ b/app/assets/javascripts/discourse/lib/lightbox.js.es6 @@ -1,6 +1,7 @@ import loadScript from "discourse/lib/load-script"; import { escapeExpression } from "discourse/lib/utilities"; import { renderIcon } from "discourse-common/lib/icon-library"; +import { isAppWebview, postRNWebviewMessage } from "discourse/lib/utilities"; export default function($elem) { if (!$elem) { @@ -35,10 +36,23 @@ export default function($elem) { wrap.hasClass("mfp-force-scrollbars") ? "none" : maxHeight ); }); + + if (isAppWebview()) { + postRNWebviewMessage( + "headerBg", + $(".mfp-bg").css("background-color") + ); + } }, beforeClose() { this.wrap.off("click.pinhandler"); this.wrap.removeClass("mfp-force-scrollbars"); + if (isAppWebview()) { + postRNWebviewMessage( + "headerBg", + $(".d-header").css("background-color") + ); + } } }, diff --git a/app/assets/javascripts/discourse/lib/utilities.js.es6 b/app/assets/javascripts/discourse/lib/utilities.js.es6 index 06f6cc40812..4d5240b66f1 100644 --- a/app/assets/javascripts/discourse/lib/utilities.js.es6 +++ b/app/assets/javascripts/discourse/lib/utilities.js.es6 @@ -654,12 +654,10 @@ export function isAppWebview() { return window.ReactNativeWebView !== undefined; } -export function isChromePWA() { - // Watch out: this doesn't distinguish between mobile or desktop PWAs - return ( - window.matchMedia("(display-mode: standalone)").matches && - navigator.userAgent.match(/(Chrome)/g) - ); +export function postRNWebviewMessage(prop, value) { + if (window.ReactNativeWebView !== undefined) { + window.ReactNativeWebView.postMessage(JSON.stringify({ [prop]: value })); + } } // This prevents a mini racer crash diff --git a/app/assets/javascripts/discourse/widgets/footer-nav.js.es6 b/app/assets/javascripts/discourse/widgets/footer-nav.js.es6 index b139daaa845..92c90263dad 100644 --- a/app/assets/javascripts/discourse/widgets/footer-nav.js.es6 +++ b/app/assets/javascripts/discourse/widgets/footer-nav.js.es6 @@ -1,5 +1,5 @@ import { createWidget } from "discourse/widgets/widget"; -import { isAppWebview, isChromePWA } from "discourse/lib/utilities"; +import { isAppWebview, postRNWebviewMessage } from "discourse/lib/utilities"; createWidget("footer-nav", { tagName: "div.footer-nav-widget", @@ -43,29 +43,14 @@ createWidget("footer-nav", { ); } - if (isChromePWA()) { - buttons.push( - this.attach("flat-button", { - action: "refresh", - icon: "sync", - className: "btn-large" - }) - ); - } return buttons; }, dismiss() { - window.ReactNativeWebView.postMessage(JSON.stringify({ dismiss: true })); + postRNWebviewMessage("dismiss", true); }, share() { - window.ReactNativeWebView.postMessage( - JSON.stringify({ shareUrl: window.location.href }) - ); - }, - - refresh() { - window.location.reload(); + postRNWebviewMessage("shareUrl", window.location.href); } }); diff --git a/app/assets/stylesheets/common/components/footer-nav.scss b/app/assets/stylesheets/common/components/footer-nav.scss index 572bee0d987..3dac7339c4b 100644 --- a/app/assets/stylesheets/common/components/footer-nav.scss +++ b/app/assets/stylesheets/common/components/footer-nav.scss @@ -5,7 +5,10 @@ $footer-nav-height: 55px; body.footer-nav-visible { - padding-bottom: $footer-nav-height + 15; + #main-outlet { + padding-bottom: $footer-nav-height + 15; + } + #topic-progress-wrapper, #reply-control.draft { bottom: $footer-nav-height; @@ -48,8 +51,22 @@ body.footer-nav-visible { } @supports (-webkit-backdrop-filter: blur(10px)) { - .footer-nav { + body:not(.footer-nav-ipad) .footer-nav { background-color: rgba($header_background, 0.7); -webkit-backdrop-filter: blur(20px); } } + +body.footer-nav-ipad { + padding-top: $footer-nav-height; + .footer-nav { + bottom: auto; + top: 0px; + background-color: $header_background; + z-index: z("ipad-header-nav"); + } + + &.docked .d-header { + margin-top: $footer-nav-height; + } +} diff --git a/app/assets/stylesheets/common/foundation/variables.scss b/app/assets/stylesheets/common/foundation/variables.scss index 7d19636ac02..220432a4900 100644 --- a/app/assets/stylesheets/common/foundation/variables.scss +++ b/app/assets/stylesheets/common/foundation/variables.scss @@ -81,6 +81,7 @@ $z-layers: ( ), "fullscreen": 1150, "mobile-composer": 1100, + "ipad-header-nav": 1020, "header": 1000, "footer-nav": 900, "tooltip": 600,