Skip to content
This repository has been archived by the owner on Feb 9, 2024. It is now read-only.

Commit

Permalink
Add doc comments
Browse files Browse the repository at this point in the history
  • Loading branch information
bisgardo committed Oct 27, 2023
1 parent 057f9b7 commit c8f68ba
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 20 deletions.
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class App extends StatelessWidget {
child: MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => SelectedNetwork(config.availableNetworks[NetworkName.testnet]!),
create: (context) => ActiveNetwork(config.availableNetworks[NetworkName.testnet]!),
),
ChangeNotifierProvider(
create: (context) {
Expand Down
6 changes: 3 additions & 3 deletions lib/screens/home/screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ class _HomeScreenState extends State<HomeScreen> {

// Fetch currently valid T&C version unconditionally when initializing the widget.
final tacAcceptance = context.read<TermsAndConditionAcceptance>();
final network = context.read<SelectedNetwork>();
final services = context.read<ServiceRepository>().networkServices[network.selected]!;
final network = context.read<ActiveNetwork>();
final services = context.read<ServiceRepository>().networkServices[network.active]!;
_updateValidTac(services.walletProxy, tacAcceptance);
}

static Future<void> _updateValidTac(WalletProxyService walletProxy, TermsAndConditionAcceptance tacAcceptance) async {
final tac = await walletProxy.getTermsAndConditions();
final tac = await walletProxy.fetchTermsAndConditions();
tacAcceptance.validVersionUpdated(ValidTermsAndConditions.refreshedNow(termsAndConditions: tac));
}

Expand Down
5 changes: 4 additions & 1 deletion lib/services/http.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import 'package:http/http.dart' as http;

/// Service for performing HTTP requests.
///
/// The service is intended to take care of retry logic, cookie management, etc.
class HttpService {
const HttpService();

/// Performs an HTTP request asynchronously.
Future<http.Response> get(Uri url) async {
// TODO: Implement retry logic.
return http.get(url);
}
}
7 changes: 6 additions & 1 deletion lib/services/shared_preferences/service.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import 'package:shared_preferences/shared_preferences.dart';

/// Service for interacting with [SharedPreferences].
class SharedPreferencesService {
/// String key associated with the persisted accepted T&C version.
static const _tacAcceptedVersionKey = 'tac:accepted_version';

/// Wrapped instance.
final SharedPreferences _prefs;

const SharedPreferencesService(this._prefs);

/// Currently accepted shared preferences.
String? get termsAndConditionsAcceptedVersion => _prefs.getString(_tacAcceptedVersionKey);

void setTermsAndConditionsAcceptedVersion(String? v) {
/// Sets or deletes the currently accepted shared preferences.
void updateTermsAndConditionsAcceptedVersion(String? v) {
if (v == null) {
_prefs.remove(_tacAcceptedVersionKey);
} else {
Expand Down
4 changes: 4 additions & 0 deletions lib/services/wallet_proxy/model.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import 'package:concordium_wallet/services/wallet_proxy/service.dart';
import 'package:json_annotation/json_annotation.dart';

part 'model.g.dart';

/// Response from endpoint [WalletProxyEndpoint.termsAndConditionsVersion].
@JsonSerializable()
class TermsAndConditions {
/// URL of the T&C text.
final Uri url;
/// T&C version.
final String version;

const TermsAndConditions(this.url, this.version);
Expand Down
16 changes: 12 additions & 4 deletions lib/services/wallet_proxy/service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ import 'dart:convert';
import 'package:concordium_wallet/services/http.dart';
import 'package:concordium_wallet/services/wallet_proxy/model.dart';

/// Paths of the wallet-proxy endpoints.
enum WalletProxyEndpoint {
tacVersion('v0/termsAndConditionsVersion'),
termsAndConditionsVersion('v0/termsAndConditionsVersion'),
;

final String path;

const WalletProxyEndpoint(this.path);
}

/// Configuration to control the interaction with a wallet-proxy instance.
class WalletProxyConfig {
/// Base URL of the instance.
///
/// Endpoint URLs are constructed by simple concatenation of this value and the endpoint path.
final String baseUrl;

const WalletProxyConfig({required this.baseUrl});
Expand All @@ -24,15 +29,18 @@ class WalletProxyConfig {
}
}

/// Service for interacting with a wallet-proxy instance.
class WalletProxyService {
/// Configuration of the instance.
final WalletProxyConfig config;
/// HTTP service used to send requests to the instance.
final HttpService httpService;

const WalletProxyService({required this.config, required this.httpService});

/// Retrieves the terms and conditions from the wallet-proxy.
Future<TermsAndConditions> getTermsAndConditions() async {
final url = config.urlOf(WalletProxyEndpoint.tacVersion);
/// Fetches the currently valid T&C.
Future<TermsAndConditions> fetchTermsAndConditions() async {
final url = config.urlOf(WalletProxyEndpoint.termsAndConditionsVersion);
final response = await httpService.get(url);
final jsonResponse = jsonDecode(response.body);
return TermsAndConditions.fromJson(jsonResponse);
Expand Down
19 changes: 18 additions & 1 deletion lib/state/config.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
import 'package:concordium_wallet/state/network.dart';

/// Global configuration of the app.
///
/// For now, the configuration is hardcoded and only contains the network configuration of each available network.
///
/// The intent is that it should be loaded from a predefined location that is set with a build parameter
/// and include all necessary information for setting up the services used by the app.
/// This means things like where to find IP info, T&C, forced upgrade config, news, marketplace apps, etc.
///
/// Custom configuration exposed to the user is not intended to live in this object.
class Config {
/// All available networks in the app.
/// All available networks and their configuration.
///
/// It will eventually be possible for the user to manage the set of available networks
/// at which point the source of truth will live somewhere else (with this value being the default).
///
/// At some other point we'll introduce a notion of "enabled" networks,
/// i.e. the list of networks to be included in the user's network selector.
/// That list will be a subset of the available networks.
/// The purpose of describing the concept here already is to allow other doc comments to reference it early.
final Map<NetworkName, Network> availableNetworks;

const Config({required this.availableNetworks});
Expand Down
21 changes: 16 additions & 5 deletions lib/state/network.dart
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
import 'package:concordium_wallet/state/config.dart';
import 'package:concordium_wallet/services/wallet_proxy/service.dart';
import 'package:flutter/foundation.dart';

/// Name of a network.
class NetworkName {
final String name;

const NetworkName(this.name);

/// Standard name of the testnet network.
static const NetworkName testnet = NetworkName('testnet');
/// Standard name of the mainnet network.
static const NetworkName mainnet = NetworkName('mainnet');
}

/// Configuration of all services of a specific network.
class Network {
/// Name of the network.
final NetworkName name;
/// Configuration of the Wallet Proxy service belonging to the network.
final WalletProxyConfig walletProxyConfig;

const Network({required this.name, required this.walletProxyConfig});
}

class SelectedNetwork extends ChangeNotifier {
Network selected;
/// State component acting as the source of truth for what network is currently active in the app.
class ActiveNetwork extends ChangeNotifier {
/// Currently active network.
///
/// The network is guaranteed to be one of the "enabled" networks (as defined in [Config.availableNetworks]).
Network active;

SelectedNetwork(this.selected);
ActiveNetwork(this.active);

void setSelected(Network n) {
selected = n;
void setActive(Network n) {
active = n;
notifyListeners();
}
}
6 changes: 6 additions & 0 deletions lib/state/services.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import 'package:concordium_wallet/services/http.dart';
import 'package:concordium_wallet/services/shared_preferences/service.dart';
import 'package:concordium_wallet/services/wallet_proxy/service.dart';
import 'package:concordium_wallet/state/config.dart';
import 'package:concordium_wallet/state/network.dart';

/// Collection of all services of a network.
class NetworkServices {
/// The Wallet Proxy service on the network.
final WalletProxyService walletProxy;

const NetworkServices({required this.walletProxy});
Expand All @@ -18,8 +21,11 @@ class NetworkServices {
}
}

/// Collection of all services available to the app.
class ServiceRepository {
/// Service collections for all "enabled" networks (as defined in [Config.availableNetworks]).
final Map<Network, NetworkServices> networkServices;
/// Global service for interacting with shared preferences.
final SharedPreferencesService sharedPreferences;

const ServiceRepository({required this.networkServices, required this.sharedPreferences});
Expand Down
34 changes: 30 additions & 4 deletions lib/state/terms_and_conditions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,47 @@ import 'package:concordium_wallet/services/shared_preferences/service.dart';
import 'package:concordium_wallet/services/wallet_proxy/model.dart';
import 'package:flutter/foundation.dart';

/// Version of the Terms & Conditions accepted by the user.
class AcceptedTermsAndConditions {
/// Accepted version.
final String version;

const AcceptedTermsAndConditions({required this.version});

/// Whether the accepted version is valid with respect to the provided valid version.
bool isValid(TermsAndConditions tac) {
return version == tac.version;
}
}

/// Version of the Terms & Conditions that is considered valid.
///
/// The user has to have accepted this version (or more generally, a compatible version)
/// for the acceptance to be valid.
class ValidTermsAndConditions {
/// T&C configuration fetched from an external endpoint.
final TermsAndConditions termsAndConditions;
final DateTime? refreshedAt;
/// Latest time at which [termsAndConditions] is known to be valid.
final DateTime refreshedAt;

const ValidTermsAndConditions({required this.termsAndConditions, required this.refreshedAt});

/// Constructs an instance for the provided [TermsAndConditions] with a refresh time of the current time.
factory ValidTermsAndConditions.refreshedNow({required TermsAndConditions termsAndConditions}) {
return ValidTermsAndConditions(termsAndConditions: termsAndConditions, refreshedAt: DateTime.now());
}
}

/// State component of the currently accepted and valid Terms & Conditions.
class TermsAndConditionAcceptance extends ChangeNotifier {
/// Service used to persist the accepted T&C version.
final SharedPreferencesService _prefs;

/// Currently accepted T&C.
///
/// The accepted version is persisted into shared preferences.
AcceptedTermsAndConditions? accepted;
/// Currently valid T&C.
ValidTermsAndConditions? valid;

TermsAndConditionAcceptance(this._prefs) {
Expand All @@ -36,29 +52,39 @@ class TermsAndConditionAcceptance extends ChangeNotifier {
}
}

/// Update the currently accepted T&C and persist the new value.
///
/// Use [resetAccepted] to revoke acceptance.
void userAccepted(AcceptedTermsAndConditions tac) {
accepted = tac;
_prefs.setTermsAndConditionsAcceptedVersion(tac.version);
_prefs.updateTermsAndConditionsAcceptedVersion(tac.version);
notifyListeners();
}

/// Updates the currently valid T&C.
void validVersionUpdated(ValidTermsAndConditions tac) {
valid = tac;
notifyListeners();
}

/// Revokes T&C acceptance and delete it from persistence.
void resetAccepted() {
accepted = null;
_prefs.setTermsAndConditionsAcceptedVersion(null);
_prefs.updateTermsAndConditionsAcceptedVersion(null);
notifyListeners();
}

/// Resets the valid T&C.
///
/// This should trigger a reload and re-verification of the validity of the acceptance.
void resetValid() {
valid = null;
notifyListeners();
}

// Temporary - for testing.
/// Resets the update time of the currently valid T&C (if present).
///
/// This method is not likely to have any uses besides maybe testing.
void testResetValidTime() {
final valid = this.valid;
if (valid != null) {
Expand Down

0 comments on commit c8f68ba

Please sign in to comment.