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

Migrated to Hive #16

Merged
32 commits merged into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
00cb636
Improve initialization and network structure
bisgardo Nov 15, 2023
8b06c26
migrated to Hive
Nov 20, 2023
eecbdf4
Merge branch 'main' into cbw-1474/migrate-to-hive
Nov 20, 2023
8af61af
changed name
Nov 20, 2023
b3252d8
added test
Nov 20, 2023
e45fd2b
updated ci to include test
Nov 20, 2023
1a097ea
added test location and updated gitignore
Nov 20, 2023
13da4ff
adding test for all cases
Nov 20, 2023
4bf14ae
Merge branch 'main' into cbw-1474/migrate-to-hive
Nov 20, 2023
6b2e8a3
Fix merge errors
Nov 20, 2023
533d164
Update ci.yml
Nov 20, 2023
33ec8db
formatted
Nov 20, 2023
6ca5aae
Sync iOS project files
bisgardo Nov 22, 2023
8b03d58
Refactor: Split root widget
bisgardo Nov 24, 2023
6fa18ff
fix simple fixes
Nov 24, 2023
9145604
comments
Nov 24, 2023
4fb69c4
Update terms_and_conditions.dart
Nov 24, 2023
401017e
Declare fields as 'late final' instead of optional
bisgardo Nov 24, 2023
b1630c5
Address review comments
bisgardo Nov 24, 2023
2af34d4
added terms and condition repository
Nov 24, 2023
7b511df
change to repository pattern
Nov 25, 2023
1bc4804
format
Nov 25, 2023
6f66423
Merge branch 'mo/split-root-widget' into cbw-1474/migrate-to-hive
Nov 25, 2023
0b29e82
refactor to lazy box
Nov 25, 2023
f4ffbb2
format
Nov 25, 2023
77c63f4
fix missing child and format
Nov 25, 2023
9fe56a6
Merge branch 'main' into cbw-1474/migrate-to-hive
Nov 27, 2023
5d98c69
updated packages and changed type id
Nov 27, 2023
f7a43d2
updated with docs
Nov 27, 2023
ab69c28
format
Nov 27, 2023
307bb76
added a future wrapper
Nov 28, 2023
68a7f4a
add todo for error
Nov 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Analyze and format
name: CI
This conversation was marked as resolved.
Show resolved Hide resolved

on:
# Trigger the workflow on pushes to the main and feature branches as well as PRs targeting them.
Expand All @@ -14,7 +14,7 @@ env:
flutter_version: 3.13.6

jobs:
analyze-format:
analyze-format-test:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
Expand All @@ -31,3 +31,6 @@ jobs:

- name: Check format
run: dart format --output=none --set-exit-if-changed . -l 150

- name: Test
This conversation was marked as resolved.
Show resolved Hide resolved
run: flutter test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release

# Hive testing
/test/hive_storage_test
26 changes: 26 additions & 0 deletions lib/entities/accepted_terms_and_conditions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:concordium_wallet/services/wallet_proxy/model.dart';
import 'package:hive_flutter/hive_flutter.dart';

part 'accepted_terms_and_conditions.g.dart';

/// Version of the Terms & Conditions accepted by the user.
@HiveType(typeId: 1)
class AcceptedTermsAndConditions {
static const table = "accepted_terms_and_conditions";

@HiveField(1)
This conversation was marked as resolved.
Show resolved Hide resolved
final String acceptedVersion;
This conversation was marked as resolved.
Show resolved Hide resolved
@HiveField(2)
final DateTime acceptedAt;

AcceptedTermsAndConditions({required this.acceptedVersion, required this.acceptedAt});

factory AcceptedTermsAndConditions.acceptNow(String acceptedVersion) {
return AcceptedTermsAndConditions(acceptedVersion: acceptedVersion, acceptedAt: DateTime.now());
}
This conversation was marked as resolved.
Show resolved Hide resolved

/// Whether the accepted version is valid with respect to the provided valid version.
bool isValid(TermsAndConditions tac) {
return acceptedVersion == tac.version;
}
}
41 changes: 41 additions & 0 deletions lib/entities/accepted_terms_and_conditions.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 6 additions & 7 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:concordium_wallet/screens/routes.dart';
import 'package:concordium_wallet/services/http.dart';
import 'package:concordium_wallet/services/shared_preferences/service.dart';
import 'package:concordium_wallet/providers/storage.dart';
import 'package:concordium_wallet/services/wallet_proxy/service.dart';
import 'package:concordium_wallet/state/config.dart';
import 'package:concordium_wallet/state/network.dart';
Expand All @@ -9,7 +9,6 @@ import 'package:concordium_wallet/state/terms_and_conditions.dart';
import 'package:concordium_wallet/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
runApp(const App());
Expand All @@ -33,13 +32,13 @@ Future<Config> loadConfig(HttpService http) async {
Future<ServiceRepository> bootstrap() async {
const http = HttpService();
final configFuture = loadConfig(http);
final prefsFuture = SharedPreferences.getInstance();
final storageFuture = StorageProvider.init();
final config = await configFuture;
final prefs = await prefsFuture;
final storageService = await storageFuture;
return ServiceRepository(
config: config,
http: http,
sharedPreferences: SharedPreferencesService(prefs),
storage: storageService,
);
}

Expand Down Expand Up @@ -85,8 +84,8 @@ class App extends StatelessWidget {
BlocProvider(
create: (context) {
// Initialize T&C by loading the currently accepted version from shared preferences.
final prefs = context.read<ServiceRepository>().sharedPreferences;
return TermsAndConditionAcceptance(prefs);
final prefs = context.read<ServiceRepository>().storage;
return TermsAndConditionAcceptance(prefs, networkServices.network.name);
},
),
],
Expand Down
44 changes: 44 additions & 0 deletions lib/providers/storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:concordium_wallet/entities/accepted_terms_and_conditions.dart';
import 'package:concordium_wallet/state/network.dart';
import 'package:hive_flutter/hive_flutter.dart';

/// Service for interacting with [Hive].
class StorageProvider {
final Box<AcceptedTermsAndConditions> _acceptedTermsAndConditionBox;

const StorageProvider._(this._acceptedTermsAndConditionBox);

static Future<StorageProvider> init() async {
await Hive.initFlutter();
_registerAdapters();
await _openBoxes();

return StorageProvider._(await Hive.openBox<AcceptedTermsAndConditions>(AcceptedTermsAndConditions.table));
This conversation was marked as resolved.
Show resolved Hide resolved
}

/// Register all adapters needed for typed boxes.
static void _registerAdapters() {
Hive.registerAdapter(AcceptedTermsAndConditionsAdapter());
}

/// Opens all boxes asynchronously.
static Future<void> _openBoxes() async {
orhoj marked this conversation as resolved.
Show resolved Hide resolved
final atcFuture = Hive.openBox<AcceptedTermsAndConditions>(AcceptedTermsAndConditions.table);
This conversation was marked as resolved.
Show resolved Hide resolved
await Future.wait([atcFuture]);
}

/// Reads the currently accepted T&C version.
AcceptedTermsAndConditions? getAcceptedTermsAndConditions(NetworkName networkName) {
This conversation was marked as resolved.
Show resolved Hide resolved
return _acceptedTermsAndConditionBox.get(networkName.name);
}

/// Writes the currently accepted T&C version.
Future<void> writeAcceptedTermsAndConditions(NetworkName networkName, AcceptedTermsAndConditions acceptedTermsAndConditions) {
return _acceptedTermsAndConditionBox.put(networkName.name, acceptedTermsAndConditions);
}

/// Deletes the currently accepted T&C version.
Future<void> deleteTermsAndConditionsAcceptedVersion(NetworkName networkName) {
return _acceptedTermsAndConditionBox.delete(networkName.name);
}
}
7 changes: 4 additions & 3 deletions lib/screens/home/screen.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:concordium_wallet/entities/accepted_terms_and_conditions.dart';
import 'package:concordium_wallet/screens/terms_and_conditions/screen.dart';
import 'package:concordium_wallet/services/url_launcher.dart';
import 'package:concordium_wallet/services/wallet_proxy/service.dart';
Expand Down Expand Up @@ -65,7 +66,7 @@ class _HomeScreenState extends State<HomeScreen> {
if (acceptedTac == null || !acceptedTac.isValid(validTac.termsAndConditions)) {
return TermsAndConditionsScreen(
validTermsAndConditions: validTac.termsAndConditions,
acceptedTermsAndConditionsVersion: acceptedTac?.version,
acceptedTermsAndConditionsVersion: acceptedTac?.acceptedVersion,
urlLauncher: UrlLauncher(),
);
}
Expand All @@ -74,7 +75,7 @@ class _HomeScreenState extends State<HomeScreen> {
Expanded(
child: Column(
children: [
Text('Accepted T&C version: ${tacState.accepted?.version}'),
Text('Accepted T&C version: ${tacState.accepted?.acceptedVersion}'),
Text('Valid T&C last refreshed at ${tacState.valid?.refreshedAt}.'),
],
),
Expand All @@ -92,7 +93,7 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 8),
ElevatedButton(
onPressed: () {
const tac = AcceptedTermsAndConditions(version: '1.2.3');
final tac = AcceptedTermsAndConditions.acceptNow('1.2.3');
context.read<TermsAndConditionAcceptance>().userAccepted(tac);
},
child: const Text('Set accepted T&C version to 1.2.3'),
Expand Down
5 changes: 2 additions & 3 deletions lib/screens/terms_and_conditions/screen.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:concordium_wallet/entities/accepted_terms_and_conditions.dart';
import 'package:concordium_wallet/screens/terms_and_conditions/widget.dart';
import 'package:concordium_wallet/services/url_launcher.dart';
import 'package:concordium_wallet/services/wallet_proxy/model.dart';
Expand Down Expand Up @@ -124,9 +125,7 @@ class _TermsAndConditionsScreenState extends State<TermsAndConditionsScreen> {
Function()? _onAcceptButtonPressed(BuildContext context) {
if (isAccepted) {
return () {
final tac = AcceptedTermsAndConditions(
version: widget.validTermsAndConditions.version,
);
final tac = AcceptedTermsAndConditions.acceptNow(widget.validTermsAndConditions.version);
context.read<TermsAndConditionAcceptance>().userAccepted(tac);
};
}
Expand Down
25 changes: 0 additions & 25 deletions lib/services/shared_preferences/service.dart

This file was deleted.

8 changes: 4 additions & 4 deletions lib/state/services.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:concordium_wallet/services/http.dart';
import 'package:concordium_wallet/services/shared_preferences/service.dart';
import 'package:concordium_wallet/providers/storage.dart';
import 'package:concordium_wallet/services/wallet_proxy/service.dart';
import 'package:concordium_wallet/state/config.dart';
import 'package:concordium_wallet/state/network.dart';
Expand Down Expand Up @@ -36,10 +36,10 @@ class ServiceRepository {
/// Global service for performing HTTP calls.
final HttpService http;

/// Global service for interacting with shared preferences.
final SharedPreferencesService sharedPreferences;
/// Global service for interacting with storage.
final StorageProvider storage;
This conversation was marked as resolved.
Show resolved Hide resolved

ServiceRepository({required this.config, required this.http, required this.sharedPreferences});
ServiceRepository({required this.config, required this.http, required this.storage});

/// Activate the network with the provided name.
///
Expand Down
40 changes: 15 additions & 25 deletions lib/state/terms_and_conditions.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
import 'package:concordium_wallet/services/shared_preferences/service.dart';
import 'package:concordium_wallet/entities/accepted_terms_and_conditions.dart';
import 'package:concordium_wallet/providers/storage.dart';
import 'package:concordium_wallet/services/wallet_proxy/model.dart';
import 'package:concordium_wallet/state/network.dart';
import 'package:flutter_bloc/flutter_bloc.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;
}
}

This conversation was marked as resolved.
Show resolved Hide resolved
/// Version of the Terms & Conditions that is considered valid.
///
/// The user has to have accepted this version (or more generally, a compatible version)
Expand Down Expand Up @@ -49,12 +38,13 @@ class TermsAndConditionsAcceptanceState {
/// State component of the currently accepted and valid Terms & Conditions.
class TermsAndConditionAcceptance extends Cubit<TermsAndConditionsAcceptanceState> {
/// Service used to persist the accepted T&C version.
final SharedPreferencesService _prefs;
final StorageProvider _storage;
This conversation was marked as resolved.
Show resolved Hide resolved
final NetworkName networkName;

TermsAndConditionAcceptance(this._prefs) : super(const TermsAndConditionsAcceptanceState(accepted: null, valid: null)) {
final acceptedVersion = _prefs.termsAndConditionsAcceptedVersion;
TermsAndConditionAcceptance(this._storage, this.networkName) : super(const TermsAndConditionsAcceptanceState(accepted: null, valid: null)) {
final acceptedVersion = _storage.getAcceptedTermsAndConditions(networkName);
if (acceptedVersion != null) {
userAccepted(AcceptedTermsAndConditions(version: acceptedVersion));
userAccepted(acceptedVersion);
}
}

Expand Down Expand Up @@ -101,17 +91,17 @@ class TermsAndConditionAcceptance extends Cubit<TermsAndConditionsAcceptanceStat
void onChange(Change<TermsAndConditionsAcceptanceState> change) {
super.onChange(change);

if (change.currentState == change.nextState) {
This conversation was marked as resolved.
Show resolved Hide resolved
return;
}
// TODO: Pass success/failure status to notification service.
_persistAcceptedVersionIfChanged(change.nextState.accepted?.version, change.currentState.accepted?.version);
_persistAcceptedVersionIfChanged(change.nextState.accepted);
}

Future<void> _persistAcceptedVersionIfChanged(String? nextAcceptedVersion, String? currentAcceptedVersion) {
if (nextAcceptedVersion == currentAcceptedVersion) {
return Future.value();
}
Future<void> _persistAcceptedVersionIfChanged(AcceptedTermsAndConditions? nextAcceptedVersion) {
This conversation was marked as resolved.
Show resolved Hide resolved
if (nextAcceptedVersion == null) {
return _prefs.deleteTermsAndConditionsAcceptedVersion();
return _storage.deleteTermsAndConditionsAcceptedVersion(networkName);
}
return _prefs.writeTermsAndConditionsAcceptedVersion(nextAcceptedVersion);
return _storage.writeAcceptedTermsAndConditions(networkName, nextAcceptedVersion);
}
}
Loading