mirrored_repositories/awesome-flutter/examples/plugins/packages/shared_preferences/shared_preferences_web
// Copyright 2013 The Flutter 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 'dart:convert' show json;
import 'dart:html' as html;

import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';

/// The web implementation of [SharedPreferencesStorePlatform].
///
/// This class implements the `package:shared_preferences` functionality for the web.
class SharedPreferencesPlugin extends SharedPreferencesStorePlatform {
  /// Registers this class as the default instance of [SharedPreferencesStorePlatform].
  static void registerWith(Registrar? registrar) {
    SharedPreferencesStorePlatform.instance = SharedPreferencesPlugin();
  }

  @override
  Future<bool> clear() async {
    // IMPORTANT: Do not use html.window.localStorage.clear() as that will
    //            remove _all_ local data, not just the keys prefixed with
    //            "flutter."
    for (String key in _storedFlutterKeys) {
      html.window.localStorage.remove(key);
    }
    return true;
  }

  @override
  Future<Map<String, Object>> getAll() async {
    final Map<String, Object> allData = {};
    for (String key in _storedFlutterKeys) {
      allData[key] = _decodeValue(html.window.localStorage[key]!);
    }
    return allData;
  }

  @override
  Future<bool> remove(String key) async {
    _checkPrefix(key);
    html.window.localStorage.remove(key);
    return true;
  }

  @override
  Future<bool> setValue(String valueType, String key, Object? value) async {
    _checkPrefix(key);
    html.window.localStorage[key] = _encodeValue(value);
    return true;
  }

  void _checkPrefix(String key) {
    if (!key.startsWith('flutter.')) {
      throw FormatException(
        'Shared preferences keys must start with prefix "flutter.".',
        key,
        0,
      );
    }
  }

  Iterable<String> get _storedFlutterKeys {
    return html.window.localStorage.keys
        .where((key) => key.startsWith('flutter.'));
  }

  String _encodeValue(Object? value) {
    return json.encode(value);
  }

  Object _decodeValue(String encodedValue) {
    final Object decodedValue = json.decode(encodedValue);

    if (decodedValue is List) {
      // JSON does not preserve generics. The encode/decode roundtrip is
      // `List<String>` => JSON => `List<dynamic>`. We have to explicitly
      // restore the RTTI.
      return decodedValue.cast<String>();
    }

    return decodedValue;
  }
}
