blob: c9d9a7854f08934426b30a1c66048436126bf486 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:fidl_fuchsia_io/fidl_async.dart';
import 'package:fidl_fuchsia_modular/fidl_async.dart'
show
SessionShellContextProxy,
ComponentContextProxy,
FocusControllerProxy,
FocusRequestWatcherBinding,
PuppetMaster,
PuppetMasterProxy,
StoryProviderProxy,
StoryProviderWatcherBinding,
SuggestionProvider,
SuggestionProviderBinding,
SuggestionProviderProxy;
import 'package:fidl_fuchsia_shell_ermine/fidl_async.dart' show AskBarProxy;
import 'package:fidl_fuchsia_sys/fidl_async.dart'
show
ComponentControllerProxy,
LauncherProxy,
LaunchInfo,
ServiceList,
ServiceProviderBinding;
import 'package:fidl_fuchsia_ui_app/fidl_async.dart' show ViewProviderProxy;
import 'package:fidl_fuchsia_ui_views/fidl_async.dart'
show ViewToken, ViewHolderToken;
import 'package:fidl_fuchsia_ui_policy/fidl_async.dart' show PresentationProxy;
import 'package:flutter/material.dart';
import 'package:fuchsia_scenic_flutter/child_view_connection.dart'
show ChildViewConnection;
import 'package:fuchsia_services/services.dart';
import 'package:lib.widgets/model.dart' show Model;
import 'package:lib.widgets/utils.dart' show PointerEventsListener;
import 'package:zircon/zircon.dart';
import '../utils/elevations.dart';
import '../utils/key_chord_listener.dart' show KeyChordListener;
import '../utils/session_shell_services.dart' show SessionShellServices;
import 'default_proposer.dart' show DefaultProposer;
import 'ermine_service_provider.dart' show ErmineServiceProvider;
import 'package_proposer.dart' show PackageProposer;
import 'story_manager.dart'
show FocusRequestWatcherImpl, StoryManager, StoryProviderWatcherImpl;
import 'web_proposer.dart' show WebProposer;
const _kErmineAskModuleUrl =
'fuchsia-pkg://fuchsia.com/ermine_ask_module#meta/ermine_ask_module.cmx';
/// Model that manages all the application state of this session shell.
class AppModel extends Model {
final _sessionShellContext = SessionShellContextProxy();
final _componentContext = ComponentContextProxy();
final _pointerEventsListener = PointerEventsListener();
final _presentation = PresentationProxy();
final _storyProvider = StoryProviderProxy();
final _puppetMaster = PuppetMasterProxy();
final _storyProviderWatcherBinding = StoryProviderWatcherBinding();
final _focusController = FocusControllerProxy();
final _focusRequestWatcherBinding = FocusRequestWatcherBinding();
final _componentControllerProxy = ComponentControllerProxy();
final _suggestionProvider = SuggestionProviderProxy();
final _ask = AskBarProxy();
final _defaultProposer = DefaultProposer();
final _packageProposer = PackageProposer();
final _webProposer = WebProposer();
// ignore: unused_field
SessionShellServices _sessionShellServices;
final String backgroundImageUrl = 'assets/images/fuchsia.png';
final Color backgroundColor = Colors.grey[850];
final StartupContext startupContext = StartupContext.fromStartupInfo();
ValueNotifier<bool> askVisibility = ValueNotifier(false);
ValueNotifier<ChildViewConnection> askChildViewConnection =
ValueNotifier<ChildViewConnection>(null);
StoryManager storyManager;
AppModel() {
StartupContext.fromStartupInfo()
.incoming
.connectToService(_sessionShellContext);
StartupContext.fromStartupInfo()
.incoming
.connectToService(_componentContext);
StartupContext.fromStartupInfo().incoming.connectToService(_puppetMaster);
_defaultProposer.start();
_packageProposer.start();
_webProposer.start();
_sessionShellServices = SessionShellServices(
sessionShellContext: _sessionShellContext,
)..advertise();
_sessionShellContext
..getFocusController(_focusController.ctrl.request())
..getPresentation(_presentation.ctrl.request())
..getStoryProvider(_storyProvider.ctrl.request())
..getSuggestionProvider(_suggestionProvider.ctrl.request());
storyManager = StoryManager(
context: _sessionShellContext,
puppetMaster: _puppetMaster,
)
..advertise(startupContext)
..addListener(() {
_packageProposer.focusedStoryId = storyManager.focusedStoryId;
});
_storyProvider.watch(
_storyProviderWatcherBinding.wrap(StoryProviderWatcherImpl(storyManager)),
);
_focusController.watchRequest(
_focusRequestWatcherBinding.wrap(FocusRequestWatcherImpl(storyManager)),
);
KeyChordListener(
onMeta: onMeta,
onFullscreen: storyManager.toggleFullscreen,
onLogout: onLogout,
onCancel: onCancel,
).listen(_presentation);
// Load the ask bar.
_loadAskBar();
}
/// Called after runApp which initializes flutter's gesture system.
void onStarted() {
_pointerEventsListener.listen(_presentation);
// Display the Ask bar after a brief duration.
Timer(Duration(milliseconds: 500), onMeta);
}
void _loadAskBar() {
final dirProxy = DirectoryProxy();
final launcherProxy = LauncherProxy();
startupContext.incoming.connectToService(launcherProxy);
launcherProxy.createComponent(
LaunchInfo(
url: _kErmineAskModuleUrl,
directoryRequest: dirProxy.ctrl.request().passChannel(),
additionalServices: ServiceList(
names: <String>[
PuppetMaster.$serviceName,
SuggestionProvider.$serviceName
],
provider: ServiceProviderBinding().wrap(
ErmineServiceProvider()
..advertise<SuggestionProvider>(
name: SuggestionProvider.$serviceName,
service: _suggestionProvider,
binding: SuggestionProviderBinding(),
),
),
),
),
_componentControllerProxy.ctrl.request(),
);
final viewProvider = ViewProviderProxy();
Incoming(dirProxy)
..connectToService(viewProvider)
..connectToService(_ask)
..close();
// Create a token pair for the newly-created View.
final tokenPair = EventPairPair();
assert(tokenPair.status == ZX.OK);
final viewHolderToken = ViewHolderToken(value: tokenPair.first);
final viewToken = ViewToken(value: tokenPair.second);
viewProvider.createView(viewToken.value, null, null);
viewProvider.ctrl.close();
// Load the Ask mod at elevation.
_ask
..onHidden.forEach((_) => askVisibility.value = false)
..onVisible.forEach((_) => askVisibility.value = true)
..load(elevations.systemOverlayElevation);
askChildViewConnection.value = ChildViewConnection(viewHolderToken);
}
/// Shows the Ask bar and sets the focus on it.
void onMeta() => _ask.show();
/// Called when tapped behind Ask bar, quick settings, notifications or the
/// Escape key was pressed.
void onCancel() => _ask.hide();
/// Called when the user initiates logout (using keyboard or UI).
void onLogout() {
askChildViewConnection.value = null;
_sessionShellContext.logout();
storyManager.stop();
_pointerEventsListener.stop();
_defaultProposer.stop();
_packageProposer.stop();
_webProposer.stop();
_storyProviderWatcherBinding.close();
_focusRequestWatcherBinding.close();
_sessionShellContext.ctrl.close();
_componentContext.ctrl.close();
_presentation.ctrl.close();
_storyProvider.ctrl.close();
_puppetMaster.ctrl.close();
_focusController.ctrl.close();
_componentControllerProxy.ctrl.close();
_suggestionProvider.ctrl.close();
_ask.ctrl.close();
}
}