[settings] copies deprecated settings deps from topaz

This CL copies the deprecated setting mods' dependency (lib.settings) into the
experiences repo.

Deprecated settings code is being migrated to experiences so it can be removed
from the topaz repo (and eventually removed from experiences once new settings
feature parity is met).

Bug: 45550

This is 2 of 4 CLs that need to be submitted in order:
1. [fxr/381099] add SDK visibility to experiences/settings
2. => [fxr/380992] copy lib.settings into experiences
3. [fxr/381113] delete lib.settings from topaz
4. [fxr/381106] remove SDK visibility from topaz

The set of CLs has been vaildated with:

        fx make-integration-patch

Change-Id: I56dfb3029d093a52a4ea3c902da5a7910d6c8b87
Reviewed-on: https://fuchsia-review.googlesource.com/c/experiences/+/380992
Reviewed-by: Sanjay Chouksey <sanjayc@google.com>
Testability-Review: Chase Latta <chaselatta@google.com>
Commit-Queue: Jason Campbell <jasoncampbell@google.com>
diff --git a/session_shells/ermine/login_shell/BUILD.gn b/session_shells/ermine/login_shell/BUILD.gn
index a044972..d2212c1 100644
--- a/session_shells/ermine/login_shell/BUILD.gn
+++ b/session_shells/ermine/login_shell/BUILD.gn
@@ -40,6 +40,7 @@
 
   deps = [
     "//src/experiences/session_shells/ermine/device",
+    "//src/experiences/settings/lib/settings",
     "//sdk/fidl/fuchsia.modular",
     "//sdk/fidl/fuchsia.modular.auth",
     "//sdk/fidl/fuchsia.netstack",
@@ -47,7 +48,6 @@
     "//sdk/fidl/fuchsia.ui.views",
     "//third_party/dart-pkg/git/flutter/packages/flutter",
     "//third_party/dart-pkg/pub/http",
-    "//topaz/lib/settings:lib.settings",
     "//topaz/public/dart/fuchsia_logger",
     "//topaz/public/dart/fuchsia_scenic_flutter",
     "//topaz/public/dart/widgets:lib.widgets",
diff --git a/settings/bluetooth/BUILD.gn b/settings/bluetooth/BUILD.gn
index 4568278..eb314bf 100644
--- a/settings/bluetooth/BUILD.gn
+++ b/settings/bluetooth/BUILD.gn
@@ -23,12 +23,12 @@
   ]
 
   deps = [
+    "//src/experiences/settings/lib/settings",
     "//sdk/fidl/fuchsia.bluetooth",
     "//sdk/fidl/fuchsia.bluetooth.control",
     "//sdk/fidl/fuchsia.bluetooth.gatt",
     "//sdk/fidl/fuchsia.bluetooth.le",
     "//third_party/dart-pkg/git/flutter/packages/flutter",
-    "//topaz/lib/settings:lib.settings",
     "//topaz/public/dart/fuchsia_logger",
     "//topaz/public/dart/fuchsia_services",
     "//topaz/public/dart/widgets:lib.widgets",
diff --git a/settings/build/settings_app.gni b/settings/build/settings_app.gni
index 5bf8a9f..5c27ca7 100644
--- a/settings/build/settings_app.gni
+++ b/settings/build/settings_app.gni
@@ -21,13 +21,13 @@
   ]
 
   base_deps = [
+    "//src/experiences/settings/lib/settings",
     "//sdk/fidl/fuchsia.deprecatedtimezone",
     "//sdk/fidl/fuchsia.ui.views",
     "//sdk/fidl/fuchsia.wlan.service",
     "//third_party/dart-pkg/git/flutter/packages/flutter",
     "//third_party/dart-pkg/git/flutter/packages/flutter_test",
     "//third_party/dart-pkg/pub/meta",
-    "//topaz/lib/settings:lib.settings",
     "//topaz/public/dart/fuchsia_logger",
     "//topaz/public/dart/fuchsia_scenic_flutter",
     "//topaz/public/dart/fuchsia_services",
diff --git a/settings/datetime/BUILD.gn b/settings/datetime/BUILD.gn
index 6b5de4d..54f0c06 100644
--- a/settings/datetime/BUILD.gn
+++ b/settings/datetime/BUILD.gn
@@ -20,9 +20,9 @@
   ]
 
   deps = [
+    "//src/experiences/settings/lib/settings",
     "//sdk/fidl/fuchsia.deprecatedtimezone",
     "//third_party/dart-pkg/git/flutter/packages/flutter",
-    "//topaz/lib/settings:lib.settings",
     "//topaz/public/dart/fuchsia_logger",
     "//topaz/public/dart/fuchsia_services",
     "//topaz/public/dart/widgets:lib.widgets"
diff --git a/settings/lib/settings/BUILD.gn b/settings/lib/settings/BUILD.gn
new file mode 100644
index 0000000..ad68648
--- /dev/null
+++ b/settings/lib/settings/BUILD.gn
@@ -0,0 +1,24 @@
+# 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("//build/dart/dart_library.gni")
+
+dart_library("settings") {
+  package_name = "lib.settings"
+
+  sources = [
+    "device_info.dart",
+    "timezone_picker.dart",
+    "widgets.dart",
+    "debug.dart",
+  ]
+
+  deps = [
+    "//sdk/fidl/fuchsia.devicesettings",
+    "//third_party/dart-pkg/git/flutter/packages/flutter",
+    "//topaz/public/dart/fuchsia_logger",
+    "//topaz/public/dart/fuchsia_services",
+    "//topaz/public/dart/widgets:lib.widgets",
+  ]
+}
diff --git a/settings/lib/settings/OWNERS b/settings/lib/settings/OWNERS
new file mode 100644
index 0000000..f4ebede
--- /dev/null
+++ b/settings/lib/settings/OWNERS
@@ -0,0 +1,5 @@
+ejia@google.com
+brycelee@google.com
+spqchan@google.com
+wxyz@google.com
+cfukuhara@google.com
\ No newline at end of file
diff --git a/settings/lib/settings/analysis_options.yaml b/settings/lib/settings/analysis_options.yaml
new file mode 100644
index 0000000..4a9fd4d
--- /dev/null
+++ b/settings/lib/settings/analysis_options.yaml
@@ -0,0 +1,6 @@
+# Copyright 2017 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.
+
+include: ../../../analysis_options.yaml
+
diff --git a/settings/lib/settings/lib/debug.dart b/settings/lib/settings/lib/debug.dart
new file mode 100644
index 0000000..8c958bc
--- /dev/null
+++ b/settings/lib/settings/lib/debug.dart
@@ -0,0 +1,74 @@
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:fuchsia_logger/logger.dart';
+import 'package:lib.widgets/utils.dart';
+
+/// Key/value store used to display debug state using a [DebugStatusWidget].
+class DebugStatus extends ChangeNotifier {
+  final ChangeNotifierMap<String, String> _output =
+      ChangeNotifierMap<String, String>();
+  final ChangeNotifierMap<String, Timer> _timers =
+      ChangeNotifierMap<String, Timer>();
+
+  DebugStatus() {
+    _output.addListener(notifyListeners);
+    _timers.addListener(notifyListeners);
+  }
+
+  /// Writes
+  void write(String key, String value) {
+    log.fine('$key: $value');
+
+    if (_output[key] != value) {
+      _timers[key] = Timer(Duration(seconds: 5), () {
+        _timers[key] = null;
+      });
+      _output[key] = value;
+    }
+  }
+
+  void timestamp(String key) {
+    write(key, '${DateTime.now()}');
+  }
+}
+
+class DebugStatusWidget extends StatelessWidget {
+  static final _unchangedStyle = TextStyle(color: Colors.black, fontSize: 10.0);
+  static final _changedStyle =
+      _unchangedStyle.merge(TextStyle(color: Colors.red));
+
+  final DebugStatus debugStatus;
+
+  const DebugStatusWidget(this.debugStatus);
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: _debugText(),
+    );
+  }
+
+  List<Widget> _debugText() {
+    final output = <Widget>[];
+
+    for (String key in debugStatus._output.keys.toList()..sort()) {
+      output.add(debugStatus._timers[key] != null
+          ? _changed(key, debugStatus._output[key])
+          : _unchanged(key, debugStatus._output[key]));
+    }
+    return output;
+  }
+
+  static Widget _changed(String key, String text) => Text(
+        '$key: $text',
+        style: _changedStyle,
+      );
+  static Widget _unchanged(String key, String text) => Text(
+        '$key: $text',
+        style: _unchangedStyle,
+      );
+}
diff --git a/settings/lib/settings/lib/device_info.dart b/settings/lib/settings/lib/device_info.dart
new file mode 100644
index 0000000..013e32a
--- /dev/null
+++ b/settings/lib/settings/lib/device_info.dart
@@ -0,0 +1,57 @@
+import 'dart:async';
+import 'dart:io';
+import 'package:fidl_fuchsia_devicesettings/fidl_async.dart';
+import 'package:fuchsia_logger/logger.dart';
+import 'package:fuchsia_services/services.dart';
+import 'package:meta/meta.dart';
+
+// If a release build, will show the build tag. Otherwise defaults to last built date.
+const String _buildTagFilePath = '/config/build-info/version';
+const String _lastUpdateFilePath = '/config/build-info/latest-commit-date';
+const String _factoryResetKey = 'FactoryReset';
+
+/// Class to provide device-specific details, such as build information.
+class DeviceInfo {
+  DateTime _sourceTimeStamp;
+  DateTime get sourceTimeStamp => _sourceTimeStamp;
+
+  /// Returns the build tag if available, or the date the source code was last updated.
+  static String get buildTag {
+    final File updateFile = File(_buildTagFilePath);
+
+    if (updateFile.existsSync()) {
+      return updateFile.readAsStringSync();
+    }
+    log.warning('Update file not present');
+    return null;
+  }
+
+  /// Returns the date the source code was last updated.
+  static String get sourceDate {
+    final File updateFile = File(_lastUpdateFilePath);
+
+    if (updateFile.existsSync()) {
+      return updateFile.readAsStringSync();
+    }
+    log.warning('Update file not present');
+    return null;
+  }
+
+  /// Sets a flag to determine whether the device should be reset to factory
+  /// settings or not.
+  ///
+  /// [shouldReset] specifies whether the flag should be set or not. Will
+  /// complete with true if the flag was set successfully and false otherwise.
+  static Future<bool> setFactoryResetFlag({@required bool shouldReset}) async {
+    final resetFlagValue = shouldReset ? 1 : 0;
+    final deviceSettingsManagerProxy = DeviceSettingsManagerProxy();
+
+    StartupContext.fromStartupInfo()
+        .incoming
+        .connectToService(deviceSettingsManagerProxy);
+    final success = await deviceSettingsManagerProxy.setInteger(
+        _factoryResetKey, resetFlagValue);
+    deviceSettingsManagerProxy.ctrl.close();
+    return success;
+  }
+}
diff --git a/settings/lib/settings/lib/timezone_picker.dart b/settings/lib/settings/lib/timezone_picker.dart
new file mode 100644
index 0000000..ccb5a65
--- /dev/null
+++ b/settings/lib/settings/lib/timezone_picker.dart
@@ -0,0 +1,619 @@
+// Copyright 2017 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 'package:flutter/material.dart';
+
+class _Timezone {
+  /// The ICU standard zone ID.
+  final String zoneId;
+
+  const _Timezone({this.zoneId});
+}
+
+// Note: these timezones were generated from a script using ICU data.
+// These should ideally be loaded ad hoc or stored somewhere.
+const List<_Timezone> _kTimeZones = <_Timezone>[
+  _Timezone(zoneId: 'US/Eastern'),
+  _Timezone(zoneId: 'US/Pacific'),
+  _Timezone(zoneId: 'Europe/Paris'),
+  _Timezone(zoneId: 'Africa/Abidjan'),
+  _Timezone(zoneId: 'Africa/Accra'),
+  _Timezone(zoneId: 'Africa/Addis_Ababa'),
+  _Timezone(zoneId: 'Africa/Algiers'),
+  _Timezone(zoneId: 'Africa/Asmara'),
+  _Timezone(zoneId: 'Africa/Asmera'),
+  _Timezone(zoneId: 'Africa/Bamako'),
+  _Timezone(zoneId: 'Africa/Bangui'),
+  _Timezone(zoneId: 'Africa/Banjul'),
+  _Timezone(zoneId: 'Africa/Bissau'),
+  _Timezone(zoneId: 'Africa/Blantyre'),
+  _Timezone(zoneId: 'Africa/Brazzaville'),
+  _Timezone(zoneId: 'Africa/Bujumbura'),
+  _Timezone(zoneId: 'Africa/Cairo'),
+  _Timezone(zoneId: 'Africa/Casablanca'),
+  _Timezone(zoneId: 'Africa/Ceuta'),
+  _Timezone(zoneId: 'Africa/Conakry'),
+  _Timezone(zoneId: 'Africa/Dakar'),
+  _Timezone(zoneId: 'Africa/Dar_es_Salaam'),
+  _Timezone(zoneId: 'Africa/Djibouti'),
+  _Timezone(zoneId: 'Africa/Douala'),
+  _Timezone(zoneId: 'Africa/El_Aaiun'),
+  _Timezone(zoneId: 'Africa/Freetown'),
+  _Timezone(zoneId: 'Africa/Gaborone'),
+  _Timezone(zoneId: 'Africa/Harare'),
+  _Timezone(zoneId: 'Africa/Johannesburg'),
+  _Timezone(zoneId: 'Africa/Kampala'),
+  _Timezone(zoneId: 'Africa/Khartoum'),
+  _Timezone(zoneId: 'Africa/Kigali'),
+  _Timezone(zoneId: 'Africa/Kinshasa'),
+  _Timezone(zoneId: 'Africa/Lagos'),
+  _Timezone(zoneId: 'Africa/Libreville'),
+  _Timezone(zoneId: 'Africa/Lome'),
+  _Timezone(zoneId: 'Africa/Luanda'),
+  _Timezone(zoneId: 'Africa/Lubumbashi'),
+  _Timezone(zoneId: 'Africa/Lusaka'),
+  _Timezone(zoneId: 'Africa/Malabo'),
+  _Timezone(zoneId: 'Africa/Maputo'),
+  _Timezone(zoneId: 'Africa/Maseru'),
+  _Timezone(zoneId: 'Africa/Mbabane'),
+  _Timezone(zoneId: 'Africa/Mogadishu'),
+  _Timezone(zoneId: 'Africa/Monrovia'),
+  _Timezone(zoneId: 'Africa/Nairobi'),
+  _Timezone(zoneId: 'Africa/Ndjamena'),
+  _Timezone(zoneId: 'Africa/Niamey'),
+  _Timezone(zoneId: 'Africa/Nouakchott'),
+  _Timezone(zoneId: 'Africa/Ouagadougou'),
+  _Timezone(zoneId: 'Africa/Porto-Novo'),
+  _Timezone(zoneId: 'Africa/Sao_Tome'),
+  _Timezone(zoneId: 'Africa/Timbuktu'),
+  _Timezone(zoneId: 'Africa/Tripoli'),
+  _Timezone(zoneId: 'Africa/Tunis'),
+  _Timezone(zoneId: 'Africa/Windhoek'),
+  _Timezone(zoneId: 'America/Adak'),
+  _Timezone(zoneId: 'America/Anchorage'),
+  _Timezone(zoneId: 'America/Anguilla'),
+  _Timezone(zoneId: 'America/Antigua'),
+  _Timezone(zoneId: 'America/Araguaina'),
+  _Timezone(zoneId: 'America/Argentina/Buenos_Aires'),
+  _Timezone(zoneId: 'America/Argentina/Catamarca'),
+  _Timezone(zoneId: 'America/Argentina/ComodRivadavia'),
+  _Timezone(zoneId: 'America/Argentina/Cordoba'),
+  _Timezone(zoneId: 'America/Argentina/Jujuy'),
+  _Timezone(zoneId: 'America/Argentina/La_Rioja'),
+  _Timezone(zoneId: 'America/Argentina/Mendoza'),
+  _Timezone(zoneId: 'America/Argentina/Rio_Gallegos'),
+  _Timezone(zoneId: 'America/Argentina/San_Juan'),
+  _Timezone(zoneId: 'America/Argentina/Tucuman'),
+  _Timezone(zoneId: 'America/Argentina/Ushuaia'),
+  _Timezone(zoneId: 'America/Aruba'),
+  _Timezone(zoneId: 'America/Asuncion'),
+  _Timezone(zoneId: 'America/Atikokan'),
+  _Timezone(zoneId: 'America/Atka'),
+  _Timezone(zoneId: 'America/Bahia'),
+  _Timezone(zoneId: 'America/Barbados'),
+  _Timezone(zoneId: 'America/Belem'),
+  _Timezone(zoneId: 'America/Belize'),
+  _Timezone(zoneId: 'America/Blanc-Sablon'),
+  _Timezone(zoneId: 'America/Boa_Vista'),
+  _Timezone(zoneId: 'America/Bogota'),
+  _Timezone(zoneId: 'America/Boise'),
+  _Timezone(zoneId: 'America/Buenos_Aires'),
+  _Timezone(zoneId: 'America/Cambridge_Bay'),
+  _Timezone(zoneId: 'America/Campo_Grande'),
+  _Timezone(zoneId: 'America/Cancun'),
+  _Timezone(zoneId: 'America/Caracas'),
+  _Timezone(zoneId: 'America/Catamarca'),
+  _Timezone(zoneId: 'America/Cayenne'),
+  _Timezone(zoneId: 'America/Cayman'),
+  _Timezone(zoneId: 'America/Chicago'),
+  _Timezone(zoneId: 'America/Chihuahua'),
+  _Timezone(zoneId: 'America/Coral_Harbour'),
+  _Timezone(zoneId: 'America/Cordoba'),
+  _Timezone(zoneId: 'America/Costa_Rica'),
+  _Timezone(zoneId: 'America/Cuiaba'),
+  _Timezone(zoneId: 'America/Curacao'),
+  _Timezone(zoneId: 'America/Danmarkshavn'),
+  _Timezone(zoneId: 'America/Dawson'),
+  _Timezone(zoneId: 'America/Dawson_Creek'),
+  _Timezone(zoneId: 'America/Denver'),
+  _Timezone(zoneId: 'America/Detroit'),
+  _Timezone(zoneId: 'America/Dominica'),
+  _Timezone(zoneId: 'America/Edmonton'),
+  _Timezone(zoneId: 'America/Eirunepe'),
+  _Timezone(zoneId: 'America/El_Salvador'),
+  _Timezone(zoneId: 'America/Ensenada'),
+  _Timezone(zoneId: 'America/Fort_Wayne'),
+  _Timezone(zoneId: 'America/Fortaleza'),
+  _Timezone(zoneId: 'America/Glace_Bay'),
+  _Timezone(zoneId: 'America/Godthab'),
+  _Timezone(zoneId: 'America/Goose_Bay'),
+  _Timezone(zoneId: 'America/Grand_Turk'),
+  _Timezone(zoneId: 'America/Grenada'),
+  _Timezone(zoneId: 'America/Guadeloupe'),
+  _Timezone(zoneId: 'America/Guatemala'),
+  _Timezone(zoneId: 'America/Guayaquil'),
+  _Timezone(zoneId: 'America/Guyana'),
+  _Timezone(zoneId: 'America/Halifax'),
+  _Timezone(zoneId: 'America/Havana'),
+  _Timezone(zoneId: 'America/Hermosillo'),
+  _Timezone(zoneId: 'America/Indiana/Indianapolis'),
+  _Timezone(zoneId: 'America/Indiana/Knox'),
+  _Timezone(zoneId: 'America/Indiana/Marengo'),
+  _Timezone(zoneId: 'America/Indiana/Petersburg'),
+  _Timezone(zoneId: 'America/Indiana/Tell_City'),
+  _Timezone(zoneId: 'America/Indiana/Vevay'),
+  _Timezone(zoneId: 'America/Indiana/Vincennes'),
+  _Timezone(zoneId: 'America/Indiana/Winamac'),
+  _Timezone(zoneId: 'America/Indianapolis'),
+  _Timezone(zoneId: 'America/Inuvik'),
+  _Timezone(zoneId: 'America/Iqaluit'),
+  _Timezone(zoneId: 'America/Jamaica'),
+  _Timezone(zoneId: 'America/Jujuy'),
+  _Timezone(zoneId: 'America/Juneau'),
+  _Timezone(zoneId: 'America/Kentucky/Louisville'),
+  _Timezone(zoneId: 'America/Kentucky/Monticello'),
+  _Timezone(zoneId: 'America/Knox_IN'),
+  _Timezone(zoneId: 'America/La_Paz'),
+  _Timezone(zoneId: 'America/Lima'),
+  _Timezone(zoneId: 'America/Los_Angeles'),
+  _Timezone(zoneId: 'America/Louisville'),
+  _Timezone(zoneId: 'America/Maceio'),
+  _Timezone(zoneId: 'America/Managua'),
+  _Timezone(zoneId: 'America/Manaus'),
+  _Timezone(zoneId: 'America/Marigot'),
+  _Timezone(zoneId: 'America/Martinique'),
+  _Timezone(zoneId: 'America/Mazatlan'),
+  _Timezone(zoneId: 'America/Mendoza'),
+  _Timezone(zoneId: 'America/Menominee'),
+  _Timezone(zoneId: 'America/Merida'),
+  _Timezone(zoneId: 'America/Mexico_City'),
+  _Timezone(zoneId: 'America/Miquelon'),
+  _Timezone(zoneId: 'America/Moncton'),
+  _Timezone(zoneId: 'America/Monterrey'),
+  _Timezone(zoneId: 'America/Montevideo'),
+  _Timezone(zoneId: 'America/Montreal'),
+  _Timezone(zoneId: 'America/Montserrat'),
+  _Timezone(zoneId: 'America/Nassau'),
+  _Timezone(zoneId: 'America/New_York'),
+  _Timezone(zoneId: 'America/Nipigon'),
+  _Timezone(zoneId: 'America/Nome'),
+  _Timezone(zoneId: 'America/Noronha'),
+  _Timezone(zoneId: 'America/North_Dakota/Center'),
+  _Timezone(zoneId: 'America/North_Dakota/New_Salem'),
+  _Timezone(zoneId: 'America/Panama'),
+  _Timezone(zoneId: 'America/Pangnirtung'),
+  _Timezone(zoneId: 'America/Paramaribo'),
+  _Timezone(zoneId: 'America/Phoenix'),
+  _Timezone(zoneId: 'America/Port-au-Prince'),
+  _Timezone(zoneId: 'America/Port_of_Spain'),
+  _Timezone(zoneId: 'America/Porto_Acre'),
+  _Timezone(zoneId: 'America/Porto_Velho'),
+  _Timezone(zoneId: 'America/Puerto_Rico'),
+  _Timezone(zoneId: 'America/Rainy_River'),
+  _Timezone(zoneId: 'America/Rankin_Inlet'),
+  _Timezone(zoneId: 'America/Recife'),
+  _Timezone(zoneId: 'America/Regina'),
+  _Timezone(zoneId: 'America/Resolute'),
+  _Timezone(zoneId: 'America/Rio_Branco'),
+  _Timezone(zoneId: 'America/Rosario'),
+  _Timezone(zoneId: 'America/Santiago'),
+  _Timezone(zoneId: 'America/Santo_Domingo'),
+  _Timezone(zoneId: 'America/Sao_Paulo'),
+  _Timezone(zoneId: 'America/Scoresbysund'),
+  _Timezone(zoneId: 'America/Shiprock'),
+  _Timezone(zoneId: 'America/St_Barthelemy'),
+  _Timezone(zoneId: 'America/St_Johns'),
+  _Timezone(zoneId: 'America/St_Kitts'),
+  _Timezone(zoneId: 'America/St_Lucia'),
+  _Timezone(zoneId: 'America/St_Thomas'),
+  _Timezone(zoneId: 'America/St_Vincent'),
+  _Timezone(zoneId: 'America/Swift_Current'),
+  _Timezone(zoneId: 'America/Tegucigalpa'),
+  _Timezone(zoneId: 'America/Thule'),
+  _Timezone(zoneId: 'America/Thunder_Bay'),
+  _Timezone(zoneId: 'America/Tijuana'),
+  _Timezone(zoneId: 'America/Toronto'),
+  _Timezone(zoneId: 'America/Tortola'),
+  _Timezone(zoneId: 'America/Vancouver'),
+  _Timezone(zoneId: 'America/Virgin'),
+  _Timezone(zoneId: 'America/Whitehorse'),
+  _Timezone(zoneId: 'America/Winnipeg'),
+  _Timezone(zoneId: 'America/Yakutat'),
+  _Timezone(zoneId: 'America/Yellowknife'),
+  _Timezone(zoneId: 'Antarctica/Casey'),
+  _Timezone(zoneId: 'Antarctica/Davis'),
+  _Timezone(zoneId: 'Antarctica/DumontDUrville'),
+  _Timezone(zoneId: 'Antarctica/Mawson'),
+  _Timezone(zoneId: 'Antarctica/McMurdo'),
+  _Timezone(zoneId: 'Antarctica/Palmer'),
+  _Timezone(zoneId: 'Antarctica/Rothera'),
+  _Timezone(zoneId: 'Antarctica/South_Pole'),
+  _Timezone(zoneId: 'Antarctica/Syowa'),
+  _Timezone(zoneId: 'Antarctica/Vostok'),
+  _Timezone(zoneId: 'Arctic/Longyearbyen'),
+  _Timezone(zoneId: 'Asia/Aden'),
+  _Timezone(zoneId: 'Asia/Almaty'),
+  _Timezone(zoneId: 'Asia/Amman'),
+  _Timezone(zoneId: 'Asia/Anadyr'),
+  _Timezone(zoneId: 'Asia/Aqtau'),
+  _Timezone(zoneId: 'Asia/Aqtobe'),
+  _Timezone(zoneId: 'Asia/Ashgabat'),
+  _Timezone(zoneId: 'Asia/Ashkhabad'),
+  _Timezone(zoneId: 'Asia/Baghdad'),
+  _Timezone(zoneId: 'Asia/Bahrain'),
+  _Timezone(zoneId: 'Asia/Baku'),
+  _Timezone(zoneId: 'Asia/Bangkok'),
+  _Timezone(zoneId: 'Asia/Beirut'),
+  _Timezone(zoneId: 'Asia/Bishkek'),
+  _Timezone(zoneId: 'Asia/Brunei'),
+  _Timezone(zoneId: 'Asia/Calcutta'),
+  _Timezone(zoneId: 'Asia/Choibalsan'),
+  _Timezone(zoneId: 'Asia/Chongqing'),
+  _Timezone(zoneId: 'Asia/Chungking'),
+  _Timezone(zoneId: 'Asia/Colombo'),
+  _Timezone(zoneId: 'Asia/Dacca'),
+  _Timezone(zoneId: 'Asia/Damascus'),
+  _Timezone(zoneId: 'Asia/Dhaka'),
+  _Timezone(zoneId: 'Asia/Dili'),
+  _Timezone(zoneId: 'Asia/Dubai'),
+  _Timezone(zoneId: 'Asia/Dushanbe'),
+  _Timezone(zoneId: 'Asia/Gaza'),
+  _Timezone(zoneId: 'Asia/Harbin'),
+  _Timezone(zoneId: 'Asia/Hong_Kong'),
+  _Timezone(zoneId: 'Asia/Hovd'),
+  _Timezone(zoneId: 'Asia/Irkutsk'),
+  _Timezone(zoneId: 'Asia/Istanbul'),
+  _Timezone(zoneId: 'Asia/Jakarta'),
+  _Timezone(zoneId: 'Asia/Jayapura'),
+  _Timezone(zoneId: 'Asia/Jerusalem'),
+  _Timezone(zoneId: 'Asia/Kabul'),
+  _Timezone(zoneId: 'Asia/Kamchatka'),
+  _Timezone(zoneId: 'Asia/Karachi'),
+  _Timezone(zoneId: 'Asia/Kashgar'),
+  _Timezone(zoneId: 'Asia/Katmandu'),
+  _Timezone(zoneId: 'Asia/Krasnoyarsk'),
+  _Timezone(zoneId: 'Asia/Kuala_Lumpur'),
+  _Timezone(zoneId: 'Asia/Kuching'),
+  _Timezone(zoneId: 'Asia/Kuwait'),
+  _Timezone(zoneId: 'Asia/Macao'),
+  _Timezone(zoneId: 'Asia/Macau'),
+  _Timezone(zoneId: 'Asia/Magadan'),
+  _Timezone(zoneId: 'Asia/Makassar'),
+  _Timezone(zoneId: 'Asia/Manila'),
+  _Timezone(zoneId: 'Asia/Muscat'),
+  _Timezone(zoneId: 'Asia/Nicosia'),
+  _Timezone(zoneId: 'Asia/Novosibirsk'),
+  _Timezone(zoneId: 'Asia/Omsk'),
+  _Timezone(zoneId: 'Asia/Oral'),
+  _Timezone(zoneId: 'Asia/Phnom_Penh'),
+  _Timezone(zoneId: 'Asia/Pontianak'),
+  _Timezone(zoneId: 'Asia/Pyongyang'),
+  _Timezone(zoneId: 'Asia/Qatar'),
+  _Timezone(zoneId: 'Asia/Qyzylorda'),
+  _Timezone(zoneId: 'Asia/Rangoon'),
+  _Timezone(zoneId: 'Asia/Riyadh'),
+  _Timezone(zoneId: 'Asia/Riyadh87'),
+  _Timezone(zoneId: 'Asia/Riyadh88'),
+  _Timezone(zoneId: 'Asia/Riyadh89'),
+  _Timezone(zoneId: 'Asia/Saigon'),
+  _Timezone(zoneId: 'Asia/Sakhalin'),
+  _Timezone(zoneId: 'Asia/Samarkand'),
+  _Timezone(zoneId: 'Asia/Seoul'),
+  _Timezone(zoneId: 'Asia/Shanghai'),
+  _Timezone(zoneId: 'Asia/Singapore'),
+  _Timezone(zoneId: 'Asia/Taipei'),
+  _Timezone(zoneId: 'Asia/Tashkent'),
+  _Timezone(zoneId: 'Asia/Tbilisi'),
+  _Timezone(zoneId: 'Asia/Tehran'),
+  _Timezone(zoneId: 'Asia/Tel_Aviv'),
+  _Timezone(zoneId: 'Asia/Thimbu'),
+  _Timezone(zoneId: 'Asia/Thimphu'),
+  _Timezone(zoneId: 'Asia/Tokyo'),
+  _Timezone(zoneId: 'Asia/Ujung_Pandang'),
+  _Timezone(zoneId: 'Asia/Ulaanbaatar'),
+  _Timezone(zoneId: 'Asia/Ulan_Bator'),
+  _Timezone(zoneId: 'Asia/Urumqi'),
+  _Timezone(zoneId: 'Asia/Vientiane'),
+  _Timezone(zoneId: 'Asia/Vladivostok'),
+  _Timezone(zoneId: 'Asia/Yakutsk'),
+  _Timezone(zoneId: 'Asia/Yekaterinburg'),
+  _Timezone(zoneId: 'Asia/Yerevan'),
+  _Timezone(zoneId: 'Atlantic/Azores'),
+  _Timezone(zoneId: 'Atlantic/Bermuda'),
+  _Timezone(zoneId: 'Atlantic/Canary'),
+  _Timezone(zoneId: 'Atlantic/Cape_Verde'),
+  _Timezone(zoneId: 'Atlantic/Faeroe'),
+  _Timezone(zoneId: 'Atlantic/Faroe'),
+  _Timezone(zoneId: 'Atlantic/Jan_Mayen'),
+  _Timezone(zoneId: 'Atlantic/Madeira'),
+  _Timezone(zoneId: 'Atlantic/Reykjavik'),
+  _Timezone(zoneId: 'Atlantic/South_Georgia'),
+  _Timezone(zoneId: 'Atlantic/St_Helena'),
+  _Timezone(zoneId: 'Atlantic/Stanley'),
+  _Timezone(zoneId: 'Australia/ACT'),
+  _Timezone(zoneId: 'Australia/Adelaide'),
+  _Timezone(zoneId: 'Australia/Brisbane'),
+  _Timezone(zoneId: 'Australia/Broken_Hill'),
+  _Timezone(zoneId: 'Australia/Canberra'),
+  _Timezone(zoneId: 'Australia/Currie'),
+  _Timezone(zoneId: 'Australia/Darwin'),
+  _Timezone(zoneId: 'Australia/Eucla'),
+  _Timezone(zoneId: 'Australia/Hobart'),
+  _Timezone(zoneId: 'Australia/LHI'),
+  _Timezone(zoneId: 'Australia/Lindeman'),
+  _Timezone(zoneId: 'Australia/Lord_Howe'),
+  _Timezone(zoneId: 'Australia/Melbourne'),
+  _Timezone(zoneId: 'Australia/NSW'),
+  _Timezone(zoneId: 'Australia/North'),
+  _Timezone(zoneId: 'Australia/Perth'),
+  _Timezone(zoneId: 'Australia/Queensland'),
+  _Timezone(zoneId: 'Australia/South'),
+  _Timezone(zoneId: 'Australia/Sydney'),
+  _Timezone(zoneId: 'Australia/Tasmania'),
+  _Timezone(zoneId: 'Australia/Victoria'),
+  _Timezone(zoneId: 'Australia/West'),
+  _Timezone(zoneId: 'Australia/Yancowinna'),
+  _Timezone(zoneId: 'Brazil/Acre'),
+  _Timezone(zoneId: 'Brazil/DeNoronha'),
+  _Timezone(zoneId: 'Brazil/East'),
+  _Timezone(zoneId: 'Brazil/West'),
+  _Timezone(zoneId: 'CET'),
+  _Timezone(zoneId: 'CST6CDT'),
+  _Timezone(zoneId: 'Canada/Atlantic'),
+  _Timezone(zoneId: 'Canada/Central'),
+  _Timezone(zoneId: 'Canada/East-Saskatchewan'),
+  _Timezone(zoneId: 'Canada/Eastern'),
+  _Timezone(zoneId: 'Canada/Mountain'),
+  _Timezone(zoneId: 'Canada/Newfoundland'),
+  _Timezone(zoneId: 'Canada/Pacific'),
+  _Timezone(zoneId: 'Canada/Saskatchewan'),
+  _Timezone(zoneId: 'Canada/Yukon'),
+  _Timezone(zoneId: 'Chile/Continental'),
+  _Timezone(zoneId: 'Chile/EasterIsland'),
+  _Timezone(zoneId: 'Cuba'),
+  _Timezone(zoneId: 'EET'),
+  _Timezone(zoneId: 'EST'),
+  _Timezone(zoneId: 'EST5EDT'),
+  _Timezone(zoneId: 'Egypt'),
+  _Timezone(zoneId: 'Eire'),
+  _Timezone(zoneId: 'Etc/GMT'),
+  _Timezone(zoneId: 'Etc/GMT+0'),
+  _Timezone(zoneId: 'Etc/GMT+1'),
+  _Timezone(zoneId: 'Etc/GMT+10'),
+  _Timezone(zoneId: 'Etc/GMT+11'),
+  _Timezone(zoneId: 'Etc/GMT+12'),
+  _Timezone(zoneId: 'Etc/GMT+2'),
+  _Timezone(zoneId: 'Etc/GMT+3'),
+  _Timezone(zoneId: 'Etc/GMT+4'),
+  _Timezone(zoneId: 'Etc/GMT+5'),
+  _Timezone(zoneId: 'Etc/GMT+6'),
+  _Timezone(zoneId: 'Etc/GMT+7'),
+  _Timezone(zoneId: 'Etc/GMT+8'),
+  _Timezone(zoneId: 'Etc/GMT+9'),
+  _Timezone(zoneId: 'Etc/GMT-0'),
+  _Timezone(zoneId: 'Etc/GMT-1'),
+  _Timezone(zoneId: 'Etc/GMT-10'),
+  _Timezone(zoneId: 'Etc/GMT-11'),
+  _Timezone(zoneId: 'Etc/GMT-12'),
+  _Timezone(zoneId: 'Etc/GMT-13'),
+  _Timezone(zoneId: 'Etc/GMT-14'),
+  _Timezone(zoneId: 'Etc/GMT-2'),
+  _Timezone(zoneId: 'Etc/GMT-3'),
+  _Timezone(zoneId: 'Etc/GMT-4'),
+  _Timezone(zoneId: 'Etc/GMT-5'),
+  _Timezone(zoneId: 'Etc/GMT-6'),
+  _Timezone(zoneId: 'Etc/GMT-7'),
+  _Timezone(zoneId: 'Etc/GMT-8'),
+  _Timezone(zoneId: 'Etc/GMT-9'),
+  _Timezone(zoneId: 'Etc/GMT0'),
+  _Timezone(zoneId: 'Etc/Greenwich'),
+  _Timezone(zoneId: 'Etc/UCT'),
+  _Timezone(zoneId: 'Etc/UTC'),
+  _Timezone(zoneId: 'Etc/Universal'),
+  _Timezone(zoneId: 'Etc/Zulu'),
+  _Timezone(zoneId: 'Europe/Amsterdam'),
+  _Timezone(zoneId: 'Europe/Andorra'),
+  _Timezone(zoneId: 'Europe/Athens'),
+  _Timezone(zoneId: 'Europe/Belfast'),
+  _Timezone(zoneId: 'Europe/Belgrade'),
+  _Timezone(zoneId: 'Europe/Berlin'),
+  _Timezone(zoneId: 'Europe/Bratislava'),
+  _Timezone(zoneId: 'Europe/Brussels'),
+  _Timezone(zoneId: 'Europe/Bucharest'),
+  _Timezone(zoneId: 'Europe/Budapest'),
+  _Timezone(zoneId: 'Europe/Chisinau'),
+  _Timezone(zoneId: 'Europe/Copenhagen'),
+  _Timezone(zoneId: 'Europe/Dublin'),
+  _Timezone(zoneId: 'Europe/Gibraltar'),
+  _Timezone(zoneId: 'Europe/Guernsey'),
+  _Timezone(zoneId: 'Europe/Helsinki'),
+  _Timezone(zoneId: 'Europe/Isle_of_Man'),
+  _Timezone(zoneId: 'Europe/Istanbul'),
+  _Timezone(zoneId: 'Europe/Jersey'),
+  _Timezone(zoneId: 'Europe/Kaliningrad'),
+  _Timezone(zoneId: 'Europe/Kiev'),
+  _Timezone(zoneId: 'Europe/Lisbon'),
+  _Timezone(zoneId: 'Europe/Ljubljana'),
+  _Timezone(zoneId: 'Europe/London'),
+  _Timezone(zoneId: 'Europe/Luxembourg'),
+  _Timezone(zoneId: 'Europe/Madrid'),
+  _Timezone(zoneId: 'Europe/Malta'),
+  _Timezone(zoneId: 'Europe/Mariehamn'),
+  _Timezone(zoneId: 'Europe/Minsk'),
+  _Timezone(zoneId: 'Europe/Monaco'),
+  _Timezone(zoneId: 'Europe/Moscow'),
+  _Timezone(zoneId: 'Europe/Nicosia'),
+  _Timezone(zoneId: 'Europe/Oslo'),
+  _Timezone(zoneId: 'Europe/Podgorica'),
+  _Timezone(zoneId: 'Europe/Prague'),
+  _Timezone(zoneId: 'Europe/Riga'),
+  _Timezone(zoneId: 'Europe/Rome'),
+  _Timezone(zoneId: 'Europe/Samara'),
+  _Timezone(zoneId: 'Europe/San_Marino'),
+  _Timezone(zoneId: 'Europe/Sarajevo'),
+  _Timezone(zoneId: 'Europe/Simferopol'),
+  _Timezone(zoneId: 'Europe/Skopje'),
+  _Timezone(zoneId: 'Europe/Sofia'),
+  _Timezone(zoneId: 'Europe/Stockholm'),
+  _Timezone(zoneId: 'Europe/Tallinn'),
+  _Timezone(zoneId: 'Europe/Tirane'),
+  _Timezone(zoneId: 'Europe/Tiraspol'),
+  _Timezone(zoneId: 'Europe/Uzhgorod'),
+  _Timezone(zoneId: 'Europe/Vaduz'),
+  _Timezone(zoneId: 'Europe/Vatican'),
+  _Timezone(zoneId: 'Europe/Vienna'),
+  _Timezone(zoneId: 'Europe/Vilnius'),
+  _Timezone(zoneId: 'Europe/Volgograd'),
+  _Timezone(zoneId: 'Europe/Warsaw'),
+  _Timezone(zoneId: 'Europe/Zagreb'),
+  _Timezone(zoneId: 'Europe/Zaporozhye'),
+  _Timezone(zoneId: 'Europe/Zurich'),
+  _Timezone(zoneId: 'Factory'),
+  _Timezone(zoneId: 'GB'),
+  _Timezone(zoneId: 'GB-Eire'),
+  _Timezone(zoneId: 'GMT'),
+  _Timezone(zoneId: 'GMT+0'),
+  _Timezone(zoneId: 'GMT-0'),
+  _Timezone(zoneId: 'GMT0'),
+  _Timezone(zoneId: 'Greenwich'),
+  _Timezone(zoneId: 'HST'),
+  _Timezone(zoneId: 'Hongkong'),
+  _Timezone(zoneId: 'Iceland'),
+  _Timezone(zoneId: 'Indian/Antananarivo'),
+  _Timezone(zoneId: 'Indian/Chagos'),
+  _Timezone(zoneId: 'Indian/Christmas'),
+  _Timezone(zoneId: 'Indian/Cocos'),
+  _Timezone(zoneId: 'Indian/Comoro'),
+  _Timezone(zoneId: 'Indian/Kerguelen'),
+  _Timezone(zoneId: 'Indian/Mahe'),
+  _Timezone(zoneId: 'Indian/Maldives'),
+  _Timezone(zoneId: 'Indian/Mauritius'),
+  _Timezone(zoneId: 'Indian/Mayotte'),
+  _Timezone(zoneId: 'Indian/Reunion'),
+  _Timezone(zoneId: 'Iran'),
+  _Timezone(zoneId: 'Israel'),
+  _Timezone(zoneId: 'Jamaica'),
+  _Timezone(zoneId: 'Japan'),
+  _Timezone(zoneId: 'Kwajalein'),
+  _Timezone(zoneId: 'Libya'),
+  _Timezone(zoneId: 'MET'),
+  _Timezone(zoneId: 'MST'),
+  _Timezone(zoneId: 'MST7MDT'),
+  _Timezone(zoneId: 'Mexico/BajaNorte'),
+  _Timezone(zoneId: 'Mexico/BajaSur'),
+  _Timezone(zoneId: 'Mexico/General'),
+  _Timezone(zoneId: 'Mideast/Riyadh87'),
+  _Timezone(zoneId: 'Mideast/Riyadh88'),
+  _Timezone(zoneId: 'Mideast/Riyadh89'),
+  _Timezone(zoneId: 'NZ'),
+  _Timezone(zoneId: 'NZ-CHAT'),
+  _Timezone(zoneId: 'Navajo'),
+  _Timezone(zoneId: 'PRC'),
+  _Timezone(zoneId: 'PST8PDT'),
+  _Timezone(zoneId: 'Pacific/Apia'),
+  _Timezone(zoneId: 'Pacific/Auckland'),
+  _Timezone(zoneId: 'Pacific/Chatham'),
+  _Timezone(zoneId: 'Pacific/Easter'),
+  _Timezone(zoneId: 'Pacific/Efate'),
+  _Timezone(zoneId: 'Pacific/Enderbury'),
+  _Timezone(zoneId: 'Pacific/Fakaofo'),
+  _Timezone(zoneId: 'Pacific/Fiji'),
+  _Timezone(zoneId: 'Pacific/Funafuti'),
+  _Timezone(zoneId: 'Pacific/Galapagos'),
+  _Timezone(zoneId: 'Pacific/Gambier'),
+  _Timezone(zoneId: 'Pacific/Guadalcanal'),
+  _Timezone(zoneId: 'Pacific/Guam'),
+  _Timezone(zoneId: 'Pacific/Honolulu'),
+  _Timezone(zoneId: 'Pacific/Johnston'),
+  _Timezone(zoneId: 'Pacific/Kiritimati'),
+  _Timezone(zoneId: 'Pacific/Kosrae'),
+  _Timezone(zoneId: 'Pacific/Kwajalein'),
+  _Timezone(zoneId: 'Pacific/Majuro'),
+  _Timezone(zoneId: 'Pacific/Marquesas'),
+  _Timezone(zoneId: 'Pacific/Midway'),
+  _Timezone(zoneId: 'Pacific/Nauru'),
+  _Timezone(zoneId: 'Pacific/Niue'),
+  _Timezone(zoneId: 'Pacific/Norfolk'),
+  _Timezone(zoneId: 'Pacific/Noumea'),
+  _Timezone(zoneId: 'Pacific/Pago_Pago'),
+  _Timezone(zoneId: 'Pacific/Palau'),
+  _Timezone(zoneId: 'Pacific/Pitcairn'),
+  _Timezone(zoneId: 'Pacific/Ponape'),
+  _Timezone(zoneId: 'Pacific/Port_Moresby'),
+  _Timezone(zoneId: 'Pacific/Rarotonga'),
+  _Timezone(zoneId: 'Pacific/Saipan'),
+  _Timezone(zoneId: 'Pacific/Samoa'),
+  _Timezone(zoneId: 'Pacific/Tahiti'),
+  _Timezone(zoneId: 'Pacific/Tarawa'),
+  _Timezone(zoneId: 'Pacific/Tongatapu'),
+  _Timezone(zoneId: 'Pacific/Truk'),
+  _Timezone(zoneId: 'Pacific/Wake'),
+  _Timezone(zoneId: 'Pacific/Wallis'),
+  _Timezone(zoneId: 'Pacific/Yap'),
+  _Timezone(zoneId: 'Poland'),
+  _Timezone(zoneId: 'Portugal'),
+  _Timezone(zoneId: 'ROC'),
+  _Timezone(zoneId: 'ROK'),
+  _Timezone(zoneId: 'Singapore'),
+  _Timezone(zoneId: 'Turkey'),
+  _Timezone(zoneId: 'UCT'),
+  _Timezone(zoneId: 'US/Alaska'),
+  _Timezone(zoneId: 'US/Aleutian'),
+  _Timezone(zoneId: 'US/Arizona'),
+  _Timezone(zoneId: 'US/Central'),
+  _Timezone(zoneId: 'US/East-Indiana'),
+  _Timezone(zoneId: 'US/Hawaii'),
+  _Timezone(zoneId: 'US/Indiana-Starke'),
+  _Timezone(zoneId: 'US/Michigan'),
+  _Timezone(zoneId: 'US/Mountain'),
+  _Timezone(zoneId: 'US/Pacific'),
+  _Timezone(zoneId: 'US/Pacific-New'),
+  _Timezone(zoneId: 'US/Samoa'),
+  _Timezone(zoneId: 'UTC'),
+  _Timezone(zoneId: 'Universal'),
+  _Timezone(zoneId: 'W-SU'),
+  _Timezone(zoneId: 'WET'),
+  _Timezone(zoneId: 'Zulu'),
+];
+
+/// Callback when user picks a timezone.
+typedef OnTimezoneTap = void Function(String timeZoneId);
+
+/// Calback when the user taps outside the timezone picker, usually dismissing
+/// the picker.
+typedef OnTapOutside = void Function();
+
+/// Allows the selection of timezone.
+class TimezonePicker extends StatelessWidget {
+  final String _currentTimezoneId;
+  final OnTimezoneTap _onTap;
+
+  /// Creates a new TimezonePicker widget
+  const TimezonePicker({String currentTimezoneId, OnTimezoneTap onTap})
+      : _currentTimezoneId = currentTimezoneId,
+        _onTap = onTap;
+
+  @override
+  Widget build(BuildContext context) => ListView.builder(
+        physics: BouncingScrollPhysics(),
+        itemCount: _kTimeZones.length,
+        itemBuilder: (BuildContext context, int index) => Material(
+              color: _currentTimezoneId == _kTimeZones[index].zoneId
+                  ? Colors.grey[500]
+                  : Colors.transparent,
+              child: InkWell(
+                onTap: () {
+                  _onTap?.call(_kTimeZones[index].zoneId);
+                },
+                child: Padding(
+                  padding: EdgeInsets.all(8.0),
+                  child: Text(
+                    '${_kTimeZones[index].zoneId}',
+                    style: TextStyle(color: Colors.black),
+                  ),
+                ),
+              ),
+            ),
+      );
+}
diff --git a/settings/lib/settings/lib/widgets.dart b/settings/lib/settings/lib/widgets.dart
new file mode 100644
index 0000000..df6dd5c
--- /dev/null
+++ b/settings/lib/settings/lib/widgets.dart
@@ -0,0 +1,349 @@
+// 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 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:lib.widgets/widgets.dart';
+
+TextStyle _textStyle(double scale) => TextStyle(
+      color: Colors.grey[900],
+      fontSize: 24.0 * scale,
+      fontWeight: FontWeight.w200,
+    );
+
+TextStyle _titleTextStyle(double scale) => TextStyle(
+      color: Colors.grey[900],
+      fontSize: 48.0 * scale,
+      fontWeight: FontWeight.w200,
+    );
+
+// Padding that is used as an edge inset for settings lists.
+const double _listPadding = 28.0;
+
+Widget _applyStartPadding({@required Widget child, @required double scale}) {
+  return Container(
+    padding: EdgeInsets.only(left: _listPadding * scale),
+    child: child,
+  );
+}
+
+/// A settings item should have a flexible width but height as specified
+abstract class SettingsItem extends StatelessWidget {
+  static const double _unscaledHeight = 48.0;
+
+  /// Scaling factor to render widget
+  final double scale;
+
+  /// Builds a new settings item with the specified scale.
+  const SettingsItem(this.scale);
+
+  /// Total height of a single settings item.
+  double get height => _unscaledHeight * scale;
+}
+
+/// A list of items such as devices or toggles.
+class SettingsItemList extends StatelessWidget {
+  /// A list of child items in a settings item
+  final Iterable<SettingsItem> items;
+
+  final CrossAxisAlignment crossAxisAlignment;
+
+  /// Constructs a new list with the settings items
+  const SettingsItemList(
+      {@required this.items,
+      this.crossAxisAlignment = CrossAxisAlignment.center});
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+        mainAxisSize: MainAxisSize.min,
+        children: items.toList(),
+        crossAxisAlignment: crossAxisAlignment);
+  }
+}
+
+/// A single page displayed in a settings app.
+class SettingsPage extends StatelessWidget {
+  /// Whether or not to display a spinner
+  final bool isLoading;
+
+  /// The label to be shown for the entire page
+  final String title;
+
+  /// The subsections of the settings page
+  final List<SettingsSection> sections;
+
+  /// The scale at which to render the text
+  final double scale;
+
+  /// Constructor.
+  const SettingsPage({
+    @required this.scale,
+    this.isLoading = false,
+    this.title,
+    this.sections,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final List<Widget> children = [];
+
+    final verticalInsets = EdgeInsets.only(
+        top: _listPadding * scale, bottom: _listPadding * scale);
+
+    if (title != null) {
+      children.add(SettingsSection(
+        title: title,
+        scale: scale,
+        child: Offstage(offstage: true),
+      ));
+    }
+
+    if (isLoading) {
+      children.add(Expanded(
+        child: Center(
+            child: Container(
+          width: 64.0,
+          height: 64.0,
+          child: FuchsiaSpinner(),
+        )),
+      ));
+      return Container(
+        padding: verticalInsets,
+        child: Column(children: children),
+      );
+    } else {
+      return ListView(
+          physics: BouncingScrollPhysics(),
+          padding: verticalInsets,
+          children: children..addAll(sections));
+    }
+  }
+}
+
+/// Widget that displays a popup which is dismissable by tapping outside of the
+/// child widget.
+///
+/// The child widget should  therefore be smaller than the full size of the screen.
+class SettingsPopup extends StatelessWidget {
+  /// The child should leave some space for the user to dismiss the popup.
+  final Widget child;
+
+  /// Called when user taps outside of displayed popup
+  final VoidCallback onDismiss;
+
+  /// Constructor.
+  const SettingsPopup({@required this.child, @required this.onDismiss});
+
+  @override
+  Widget build(BuildContext context) {
+    Widget overlayCancel = Opacity(
+        opacity: 0.4,
+        child: Material(
+            color: Colors.grey[900],
+            child: GestureDetector(
+              behavior: HitTestBehavior.opaque,
+              onTap: onDismiss,
+            )));
+
+    return Stack(children: [
+      overlayCancel,
+      Center(child: child),
+    ]);
+  }
+}
+
+/// A subsection of a settings page, with an optional title.
+///
+/// All subsections should be fixed height widgets.
+class SettingsSection extends StatelessWidget {
+  static const SettingsSection _emptySection =
+      SettingsSection(scale: 1.0, child: Offstage(offstage: true));
+
+  /// String displayed at the top of the section
+  final String title;
+
+  /// Contents of the section
+  final Widget child;
+
+  /// Scale at which to render the text
+  final double scale;
+
+  /// Whether we are the top section
+  final bool topSection;
+
+  const SettingsSection({
+    @required this.child,
+    @required this.scale,
+    this.title,
+    this.topSection = true,
+  });
+
+  /// Returns an empty section with no title.
+  factory SettingsSection.empty() => _emptySection;
+
+  /// Returns a section with just some text describing why the section
+  /// has an error.
+  ///
+  /// Used when the underlying settings are unavailable or not operational.
+  factory SettingsSection.error({
+    @required double scale,
+    @required String description,
+    String title,
+  }) {
+    return SettingsSection(
+      scale: scale,
+      title: title,
+      child: SettingsTile(scale: scale, text: description),
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    if (title != null) {
+      return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
+        Container(
+            padding: EdgeInsets.only(
+                top: topSection ? 0.0 : _listPadding * scale,
+                left: _listPadding * scale,
+                right: _listPadding * scale),
+            child: Text(title, style: _titleTextStyle(scale))),
+        child
+      ]);
+    }
+    return child;
+  }
+}
+
+/// Function called when a settings switch tile is toggled.
+typedef OnSwitch = void Function(bool value);
+
+/// A settings item containing a switch with some description.
+///
+/// Can be used for all on and off settings.
+class SettingsSwitchTile extends SettingsItem {
+  static const double maxSwitchWidth = 600.0;
+
+  /// Whether the switch is on or off.
+  final bool state;
+
+  final String text;
+
+  /// Function called when user toggles the switch.
+  final OnSwitch onSwitch;
+
+  const SettingsSwitchTile(
+      {@required double scale, this.state, this.text, this.onSwitch})
+      : super(scale);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+        constraints:
+            BoxConstraints(minHeight: height, maxWidth: maxSwitchWidth),
+        child: SwitchListTile(
+          title: SettingsText(text: text, scale: scale),
+          value: state,
+          onChanged: onSwitch,
+        ));
+  }
+}
+
+/// Simple text based button shown in settings
+class SettingsButton extends SettingsItem {
+  /// Label the button is displayed with
+  final String text;
+
+  /// Action taken when button is pressed
+  final VoidCallback onTap;
+
+  /// Constructor.
+  const SettingsButton(
+      {@required this.text, @required this.onTap, @required double scale})
+      : super(scale);
+
+  @override
+  Widget build(BuildContext context) {
+    return SettingsTile(
+      text: text,
+      scale: scale,
+      onTap: onTap,
+    );
+  }
+}
+
+/// Text with style consistent for the body of a settings page.
+class SettingsText extends SettingsItem {
+  final String text;
+
+  const SettingsText({@required double scale, this.text}) : super(scale);
+
+  @override
+  Widget build(BuildContext context) => _applyStartPadding(
+      child: Text(text, style: _textStyle(scale)), scale: scale);
+}
+
+/// A tile that can be used to display a setting with icon, text, and optional
+/// description.
+class SettingsTile extends SettingsItem {
+  /// The asset to be displayed
+  ///
+  /// Only should be set if [iconData] is not
+  final String assetUrl;
+
+  /// The icon to be displayed.
+  ///
+  /// Only should be set if [assetUrl] is not
+  final IconData iconData;
+
+  /// The label to display next to the icon
+  final String text;
+
+  /// A string displaying the status, errors, or
+  /// other secondary text.
+  final String description;
+
+  /// Callback to run when the network is tapped
+  final VoidCallback onTap;
+
+  /// Constructs a new settings item
+  const SettingsTile({
+    @required this.text,
+    @required double scale,
+    this.assetUrl,
+    this.iconData,
+    this.description,
+    this.onTap,
+  }) : super(scale);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+        constraints: BoxConstraints(minHeight: height),
+        child: ListTile(
+            leading: _buildLogo(),
+            title: _title(),
+            subtitle: description != null ? _subTitle() : null,
+            onTap: onTap));
+  }
+
+  Widget _buildLogo() {
+    if (assetUrl == null && iconData == null) {
+      return null; // No logo to show.
+    }
+
+    Widget logo = iconData != null
+        ? Icon(iconData, size: height, color: Colors.grey[900])
+        : Image.asset(
+            assetUrl,
+            height: height,
+            width: height,
+          );
+    return _applyStartPadding(child: logo, scale: scale);
+  }
+
+  Widget _subTitle() => SettingsText(text: description, scale: scale);
+
+  Widget _title() => SettingsText(text: text, scale: scale);
+}
diff --git a/settings/lib/settings/pubspec.yaml b/settings/lib/settings/pubspec.yaml
new file mode 100644
index 0000000..cc9163e
--- /dev/null
+++ b/settings/lib/settings/pubspec.yaml
@@ -0,0 +1,8 @@
+# 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.
+
+name: settings
+dependencies:
+  flutter:
+    sdk: flutter
\ No newline at end of file
diff --git a/settings/wifi/BUILD.gn b/settings/wifi/BUILD.gn
index 583fc17..ef4b6b3 100644
--- a/settings/wifi/BUILD.gn
+++ b/settings/wifi/BUILD.gn
@@ -24,10 +24,10 @@
   ]
 
   deps = [
+    "//src/experiences/settings/lib/settings",
     "//sdk/fidl/fuchsia.netstack",
     "//sdk/fidl/fuchsia.wlan.service",
     "//third_party/dart-pkg/git/flutter/packages/flutter",
-    "//topaz/lib/settings:lib.settings",
     "//topaz/public/dart/fuchsia_logger",
     "//topaz/public/dart/fuchsia_services",
     "//topaz/public/dart/widgets:lib.widgets"