Skip to content

Commit

Permalink
iwa: Implement GetMetadataScreen installer UI
Browse files Browse the repository at this point in the history
This isn't currently hooked up to the Command to get the metadata yet.

Bug: 1479140
Change-Id: Id941f1ff9523b0d37c978a005f0aed58d6d2e651
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4944693
Commit-Queue: Robbie McElrath <rmcelrath@chromium.org>
Reviewed-by: Zelin Liu <zelin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1212900}
  • Loading branch information
robbiemc authored and Chromium LUCI CQ committed Oct 20, 2023
1 parent aa93665 commit 3afcd96
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 40 deletions.
14 changes: 14 additions & 0 deletions chrome/app/generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -16248,6 +16248,20 @@ Please help our engineers fix this problem. Tell us what happened right before y
<message name="IDS_PROMISE_APP_ACCESSIBLE_LABEL_INSTALLING" desc="Accessibility label for a promise icon in the Launcher or Shelf to indicate that the app is currently downloading or installing">
<ph name="APP_NAME">$1<ex>Gmail</ex></ph>, installing
</message>

<!-- Isolated Web App installer. -->
<message name="IDS_IWA_INSTALLER_VERIFICATION_TITLE" desc="Title of the verification step of the IWA installation">
Chrome is verifying the installation bundle
</message>
<message name="IDS_IWA_INSTALLER_VERIFICATION_SUBTITLE" desc="Subtitle of the verification step of the IWA installation">
Please wait while verification is in progress
</message>
<message name="IDS_IWA_INSTALLER_VERIFICATION_STATUS" desc="Text below a progress bar describing the operation being performed and a time remaining estimate">
{MINUTES, plural,
=0 {Checking public key and integrity block... Less than 1 minute remaining}
=1 {Checking public key and integrity block... 1 minute remaining}
other {Checking public key and integrity block... # minutes remaining}}
</message>
</messages>
</release>
</grit>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9a1a4e1467fab9711d271f062fff815c40070272
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9cd1341fe1f3fdeeae715f9778940274c6727a74
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d8f5b9daf9334d4409afd67c965d783f463699e8
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ IsolatedWebAppInstallerCoordinator::~IsolatedWebAppInstallerCoordinator() =

void IsolatedWebAppInstallerCoordinator::Show(
base::OnceCallback<void(absl::optional<webapps::AppId>)> callback) {
// TODO(crbug.com/1479140): Switch to "not enabled" if the pref isn't set
model_->SetStep(IsolatedWebAppInstallerModel::Step::kGetMetadata);

controller_->Show(
base::BindOnce(&IsolatedWebAppInstallerCoordinator::OnDialogClosed,
base::Unretained(this), std::move(callback)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,133 @@

#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_view.h"

#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_model.h"
#include <memory>
#include <string>

#include "base/memory/raw_ptr.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h"
#include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_metadata.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/progress_bar.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/style/typography.h"

namespace web_app {

namespace {

std::unique_ptr<views::Label> CreateLabel(int text_id) {
return std::make_unique<views::Label>(l10n_util::GetStringUTF16(text_id));
constexpr int kIconSize = 32;
constexpr int kProgressViewHorizontalPadding = 45;

void ConfigureBoxLayoutView(views::BoxLayoutView* view) {
views::LayoutProvider* provider = views::LayoutProvider::Get();
view->SetOrientation(views::BoxLayout::Orientation::kVertical);
view->SetBetweenChildSpacing(
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL));
view->SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kCenter);
}

std::unique_ptr<views::Label> CreateLabelWithContextAndStyle(
const std::u16string& text,
views::style::TextContext text_context = views::style::CONTEXT_LABEL,
views::style::TextStyle text_style = views::style::STYLE_PRIMARY) {
auto label = std::make_unique<views::Label>(text, text_context, text_style);
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetCollapseWhenHidden(true);
label->SetMultiLine(true);
return label;
}

class GetMetadataView : public views::BoxLayoutView {
} // namespace

// Base class for all installer screens that handles common UI elements like
// icons, title, and subtitle.
class InstallerScreenView : public views::BoxLayoutView {
public:
METADATA_HEADER(GetMetadataView);
METADATA_HEADER(InstallerScreenView);

InstallerScreenView(const ui::ImageModel& icon_model,
const std::u16string& title,
const std::u16string& subtitle) {
ConfigureBoxLayoutView(this);

auto* icon = AddChildView(std::make_unique<NonAccessibleImageView>());
icon->SetImage(icon_model);
icon->SetHorizontalAlignment(views::ImageView::Alignment::kLeading);

AddChildView(CreateLabelWithContextAndStyle(
title, views::style::CONTEXT_DIALOG_TITLE,
views::style::STYLE_PRIMARY));
AddChildView(CreateLabelWithContextAndStyle(
subtitle, views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY));
}

GetMetadataView() {
views::LayoutProvider* provider = views::LayoutProvider::Get();
SetOrientation(views::BoxLayout::Orientation::kVertical);
SetBetweenChildSpacing(
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL));
virtual void SetProgress(double percent, int minutes_remaining) {}

// TODO(crbug.com/1479140): Use the correct string here
AddChildView(CreateLabel(IDS_PROMISE_STATUS_INSTALLING));
protected:
void SetContentsView(std::unique_ptr<views::View> contents) {
CHECK(!contents_);
contents_ = AddChildView(std::move(contents));
SetFlexForView(contents_, 1);
}

private:
raw_ptr<views::View> contents_;
};
BEGIN_METADATA(GetMetadataView, views::BoxLayoutView)
BEGIN_METADATA(InstallerScreenView, views::BoxLayoutView)
END_METADATA

} // namespace
class GetMetadataScreen : public InstallerScreenView {
public:
METADATA_HEADER(GetMetadataScreen);

GetMetadataScreen()
: InstallerScreenView(
ui::ImageModel::FromVectorIcon(kFingerprintIcon,
ui::kColorAccent,
kIconSize),
l10n_util::GetStringUTF16(IDS_IWA_INSTALLER_VERIFICATION_TITLE),
l10n_util::GetStringUTF16(
IDS_IWA_INSTALLER_VERIFICATION_SUBTITLE)) {
SetContentsView(CreateContentsView());
}

void SetProgress(double percent, int minutes_remaining) override {
progress_bar_->SetValue(percent / 100.0);
}

private:
std::unique_ptr<views::View> CreateContentsView() {
auto progress_view = std::make_unique<views::BoxLayoutView>();
ConfigureBoxLayoutView(progress_view.get());
progress_view->SetInsideBorderInsets(
gfx::Insets::VH(0, kProgressViewHorizontalPadding));

progress_bar_ =
progress_view->AddChildView(std::make_unique<views::ProgressBar>());
progress_view->AddChildView(CreateLabelWithContextAndStyle(
l10n_util::GetPluralStringFUTF16(IDS_IWA_INSTALLER_VERIFICATION_STATUS,
0),
views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY));
return progress_view;
}

raw_ptr<views::ProgressBar> progress_bar_;
};
BEGIN_METADATA(GetMetadataScreen, InstallerScreenView)
END_METADATA

IsolatedWebAppInstallerView::IsolatedWebAppInstallerView(Delegate* delegate)
: delegate_(delegate), active_view_(nullptr) {
: delegate_(delegate), screen_(nullptr) {
views::LayoutProvider* provider = views::LayoutProvider::Get();
SetInsideBorderInsets(
provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG));
Expand All @@ -56,11 +143,14 @@ void IsolatedWebAppInstallerView::ShowDisabledScreen() {
}

void IsolatedWebAppInstallerView::ShowGetMetadataScreen() {
SetActiveView(std::make_unique<GetMetadataView>());
ShowScreen(std::make_unique<GetMetadataScreen>());
}

void IsolatedWebAppInstallerView::UpdateGetMetadataProgress(double percent) {
// TODO(crbug.com/1479140): Implement
void IsolatedWebAppInstallerView::UpdateGetMetadataProgress(
double percent,
int minutes_remaining) {
CHECK(screen_);
screen_->SetProgress(percent, minutes_remaining);
}

void IsolatedWebAppInstallerView::ShowMetadataScreen(
Expand All @@ -73,7 +163,8 @@ void IsolatedWebAppInstallerView::ShowInstallScreen(
// TODO(crbug.com/1479140): Implement
}

void IsolatedWebAppInstallerView::UpdateInstallProgress(double percent) {
void IsolatedWebAppInstallerView::UpdateInstallProgress(double percent,
int minutes_remaining) {
// TODO(crbug.com/1479140): Implement
}

Expand All @@ -82,12 +173,12 @@ void IsolatedWebAppInstallerView::ShowInstallSuccessScreen(
// TODO(crbug.com/1479140): Implement
}

void IsolatedWebAppInstallerView::SetActiveView(std::unique_ptr<View> view) {
if (active_view_) {
RemoveChildView(active_view_);
void IsolatedWebAppInstallerView::ShowScreen(
std::unique_ptr<InstallerScreenView> screen) {
if (screen_) {
RemoveChildView(screen_);
}
active_view_ = AddChildView(std::move(view));
InvalidateLayout();
screen_ = AddChildView(std::move(screen));
}

BEGIN_METADATA(IsolatedWebAppInstallerView, views::BoxLayoutView)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_ISOLATED_WEB_APPS_ISOLATED_WEB_APP_INSTALLER_VIEW_H_

#include "base/memory/raw_ptr.h"
#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_model.h"
#include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_metadata.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/view.h"

namespace web_app {

class InstallerScreenView;
class SignedWebBundleMetadata;

// Responsible for displaying the contents section of the installation dialog:
Expand Down Expand Up @@ -44,20 +43,20 @@ class IsolatedWebAppInstallerView : public views::BoxLayoutView {
void ShowDisabledScreen();

void ShowGetMetadataScreen();
void UpdateGetMetadataProgress(double percent);
void UpdateGetMetadataProgress(double percent, int minutes_remaining);

void ShowMetadataScreen(const SignedWebBundleMetadata& bundle_metadata);

void ShowInstallScreen(const SignedWebBundleMetadata& bundle_metadata);
void UpdateInstallProgress(double percent);
void UpdateInstallProgress(double percent, int minutes_remaining);

void ShowInstallSuccessScreen(const SignedWebBundleMetadata& bundle_metadata);

private:
void SetActiveView(std::unique_ptr<View> view);
void ShowScreen(std::unique_ptr<InstallerScreenView> screen);

raw_ptr<Delegate> delegate_;
raw_ptr<View> active_view_;
raw_ptr<InstallerScreenView> screen_;
};

} // namespace web_app
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_view.h"

#include <string>

#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/test/pixel_test_configuration_mixin.h"
#include "chrome/browser/ui/test/test_browser_dialog.h"
#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_model.h"
#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_view_controller.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"

namespace web_app {

using Step = IsolatedWebAppInstallerModel::Step;

struct TestParam {
std::string test_suffix;
Step step;
bool use_dark_theme = false;
bool use_right_to_left_language = false;
};

// To be passed as 4th argument to `INSTANTIATE_TEST_SUITE_P()`, allows the test
// to be named like `<TestClassName>.InvokeUi_default/<TestSuffix>` instead
// of using the index of the param in `TestParam` as suffix.
std::string ParamToTestSuffix(const ::testing::TestParamInfo<TestParam>& info) {
return info.param.test_suffix;
}

const TestParam kTestParam[] = {
{.test_suffix = "GetMetadata", .step = Step::kGetMetadata},
};

class IsolatedWebAppInstallerViewUiPixelTest
: public TestBrowserDialog,
public MixinBasedInProcessBrowserTest,
public testing::WithParamInterface<TestParam> {
public:
IsolatedWebAppInstallerViewUiPixelTest()
: pixel_test_mixin_(&mixin_host_,
GetParam().use_dark_theme,
GetParam().use_right_to_left_language) {}

~IsolatedWebAppInstallerViewUiPixelTest() override = default;

// `TestBrowserDialog`:
void ShowUi(const std::string& name) override {
IsolatedWebAppInstallerModel model{base::FilePath()};
model.SetStep(GetParam().step);

IsolatedWebAppInstallerViewController controller{
WebAppProvider::GetForWebApps(browser()->profile()), &model};
controller.Show(base::DoNothing());
}

private:
base::test::ScopedFeatureList feature_list_{features::kIsolatedWebApps};
PixelTestConfigurationMixin pixel_test_mixin_;
};

IN_PROC_BROWSER_TEST_P(IsolatedWebAppInstallerViewUiPixelTest,
InvokeUi_default) {
ShowAndVerifyUi();
}

INSTANTIATE_TEST_SUITE_P(,
IsolatedWebAppInstallerViewUiPixelTest,
testing::ValuesIn(kTestParam),
&ParamToTestSuffix);

} // namespace web_app

0 comments on commit 3afcd96

Please sign in to comment.