Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve issue 359 #413

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2781ab4
+ Extension for hive with the application dir
Sarath191181208 Jun 15, 2024
8632ef1
+ file_picker, shared_prefs for hive app folder
Sarath191181208 Jun 15, 2024
ff1ad1f
updated hive services to use new extension
Sarath191181208 Jun 15, 2024
3b08a27
+ localprefs for hive dir selector
Sarath191181208 Jun 15, 2024
a417d2d
+ HiveDirectorySelector compoenet
Sarath191181208 Jun 15, 2024
1dc2e40
+ used HiveDirectorySelector in main
Sarath191181208 Jun 15, 2024
5164dce
+Fix broken test due to change in `openBoxes` fn
Sarath191181208 Jun 15, 2024
3be3f74
+ test for hive_storage_folder_model pref
Sarath191181208 Jun 15, 2024
b457622
rm useless comment
Sarath191181208 Jun 15, 2024
a29c473
rm useless code
Sarath191181208 Jun 16, 2024
f8d56d5
refactored component to use DI for ease in testing
Sarath191181208 Jun 16, 2024
597414b
added await in test
Sarath191181208 Jun 16, 2024
21c5009
put the help text in main
Sarath191181208 Jun 16, 2024
f1ddf7a
tests for hive_directory_selector widget
Sarath191181208 Jun 16, 2024
172de14
moved the hive_directory_selector to widgets/
Sarath191181208 Jun 16, 2024
0493f7b
folder change import updated
Sarath191181208 Jun 16, 2024
f56c322
Merge `main` with `save_app_folder`
Sarath191181208 Jun 16, 2024
c64fbf0
fixed pubspec.lock
Sarath191181208 Jun 16, 2024
c82763d
Merge branch 'main' into resolve-issue-359-hivefolderpicker
Sarath191181208 Jun 16, 2024
1b719d7
rm useless comments
Sarath191181208 Jun 16, 2024
a0fcb2a
`file_selector` pkg & used rm useless pkgs
Sarath191181208 Jun 26, 2024
ed2b222
Merge pull request #1 from Sarath191181208/save_app_folder
Sarath191181208 Jun 26, 2024
7f92210
Merge branch 'main' into resolve-issue-359-hivefolderpicker
ashitaprasad Jul 6, 2024
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
17 changes: 17 additions & 0 deletions lib/extensions/load_hive_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:path/path.dart';

/// Flutter extensions for Hive.
extension HiveWithFolder on HiveInterface {
/// Initializes Hive with the path from [appDir].
///
/// You can provide a [subDir] where the boxes should be stored.
Future<void> initHiveWithRootFolder(String appDir, [String? subDir]) async {
WidgetsFlutterBinding.ensureInitialized();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WidgetsFlutterBinding.ensureInitialized(); should not be hidden in this function. It should be in main() as it is currently.

if (kIsWeb) return;

init(join(appDir, subDir));
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this extension. This task can be done by a hive utility function.

12 changes: 9 additions & 3 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:apidash/widgets/hive_directory_selector.dart';
import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
Expand All @@ -8,17 +10,21 @@ import 'app.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
GoogleFonts.config.allowRuntimeFetching = false;
await openBoxes();
if (kIsLinux) {
await setupInitialWindow();
}
if (kIsMacOS || kIsWindows) {
var win = getInitialSize();
await setupWindow(sz: win.$1, off: win.$2);
}


runApp(
const ProviderScope(
child: DashApp(),
const HiveDirectorySelector(
getDirectoryPath: getDirectoryPath,
child: ProviderScope(
child: DashApp(),
),
),
);
}
30 changes: 30 additions & 0 deletions lib/models/hive_storage_folder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Store hive save folder path.
Copy link
Member

@ashitaprasad ashitaprasad Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not models. They are shared_preferences utility functions.

// SharedPreferences dynamicall changes saving folder based on platform, which isn't null.
// Contrary to this hive stores the data in `getApplicationDocumentsDirectory()` given by
// the path_provider package. Which is platform dependent and could be null.
// See this issue for more details:
// - https://github.com/foss42/apidash/issues/359

import 'package:shared_preferences/shared_preferences.dart';

// The key to store the folder path in shared preferences.
const String kHiveSaveFolder = 'hive_save_folder';

Future<String?> getHiveSaveFolder() async {
// Retrieves the folder path where hive stores data.
// Which is stored in shared preferences.

// Getting the shared preferences instance.
final prefs = await SharedPreferences.getInstance();
// Getting the folder path.
return prefs.getString(kHiveSaveFolder);
}

Future<void> setHiveSaveFolder(String folder) async {
// Sets the folder path where hive stores data.

// Getting the shared preferences instance.
final prefs = await SharedPreferences.getInstance();
// Setting the folder path.
await prefs.setString(kHiveSaveFolder, folder);
}
5 changes: 3 additions & 2 deletions lib/services/hive_services.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:apidash/extensions/load_hive_extension.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';

Expand All @@ -8,8 +9,8 @@ const String kKeyEnvironmentBoxIds = "environmentIds";

const String kSettingsBox = "apidash-settings";

Future<void> openBoxes() async {
await Hive.initFlutter();
Future<void> openBoxes(String hiveSaveFolder) async {
await Hive.initHiveWithRootFolder(hiveSaveFolder);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will get changed according to the comment above

await Hive.openBox(kDataBox);
await Hive.openBox(kSettingsBox);
await Hive.openBox(kEnvironmentBox);
Expand Down
63 changes: 63 additions & 0 deletions lib/widgets/hive_directory_selector.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:apidash/models/hive_storage_folder.dart';
import 'package:apidash/services/hive_services.dart';
import 'package:flutter/material.dart';

class HiveDirectorySelector extends StatefulWidget {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it require a Stateful Widget or Stateless can work?

final Widget child;
final Future<String?> Function() getDirectoryPath;
const HiveDirectorySelector({super.key, required this.child, required this.getDirectoryPath});

@override
HiveDirectorySelectorState createState() => HiveDirectorySelectorState();
}

class HiveDirectorySelectorState extends State<HiveDirectorySelector> {
void selectFolder() async {
// Show the folder selection menu
String? selectedDirectory = await widget.getDirectoryPath();
// TODO: check if can write in current folder
// If the selected selectedDirectory isn't null save it as hive save folder
if (selectedDirectory != null) setHiveSaveFolder(selectedDirectory);
// Changing the state of application
setState(() {});
}

@override
Widget build(BuildContext context) {
const circularLoader = MaterialApp(
home: Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
),
);

return FutureBuilder<String?>(
future: getHiveSaveFolder(),
builder: (BuildContext context, AsyncSnapshot<String?> snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return circularLoader;
}

// If there isn't hive selected folder choose it
if (snapshot.data == null) {
selectFolder();
return circularLoader;
}

// Once _hiveSaveFolder is set, display DashApp after hive init
return FutureBuilder<void>(
future: openBoxes(snapshot.data!),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
// if loading show circularLoader
if (snapshot.connectionState != ConnectionState.done) {
return circularLoader;
}
// Display widget
return widget.child;
},
);
},
);
}
}
56 changes: 56 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.3.8"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
url: "https://pub.dev"
source: hosted
version: "2.2.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shelf:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ dependencies:
flex_color_scheme: ^7.3.1
data_table_2: ^2.5.15
file_selector: ^1.0.3
shared_preferences: ^2.2.3
hooks_riverpod: ^2.5.1
flutter_hooks: ^0.20.5
flutter_portal: ^1.1.4
Expand Down
20 changes: 20 additions & 0 deletions test/models/hive_storage_folder_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'dart:io';

import 'package:apidash/models/hive_storage_folder.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:test/test.dart';

void main() async{
Directory tempDir =
await Directory.systemTemp.createTemp('save_folder_path');

test('Load Hive directory', () async {
SharedPreferences.setMockInitialValues({kHiveSaveFolder: tempDir.path});
expect(await getHiveSaveFolder(), tempDir.path);
});

test('Saving Hive directory', () async {
await setHiveSaveFolder(tempDir.path);
expect(await getHiveSaveFolder(), tempDir.path);
});
}
16 changes: 3 additions & 13 deletions test/providers/ui_providers_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,9 @@ void main() {
TestWidgetsFlutterBinding.ensureInitialized();

setUp(() async {
const MethodChannel channel =
MethodChannel('plugins.flutter.io/path_provider');
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
if (methodCall.method == 'getApplicationDocumentsDirectory') {
// Create a mock app doc directory for testing
Directory tempDir =
await Directory.systemTemp.createTemp('mock_app_doc_dir');
return tempDir.path; // Return the path to the mock directory
}
return null;
});
await openBoxes();
Directory tempDir =
await Directory.systemTemp.createTemp('mock_app_doc_dir');
await openBoxes(tempDir.path);
});

group('Testing navRailIndexStateProvider', () {
Expand Down
62 changes: 62 additions & 0 deletions test/widgets/hive_directory_selector_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'dart:io';

import 'package:apidash/widgets/hive_directory_selector.dart';
import 'package:apidash/models/hive_storage_folder.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
Directory tempDir = await Directory.systemTemp.createTemp('hive_dir_temp');

testWidgets('Given valid path, Then load the child component', (widgetTester) async {
await widgetTester.runAsync(() async {
// Set the hive save folder
SharedPreferences.setMockInitialValues({});
await setHiveSaveFolder(tempDir.path);

// Rendering the widgets
await widgetTester.pumpWidget(
HiveDirectorySelector(
getDirectoryPath: () async => tempDir.path,
child: Container(),
),
);

// Find the container widget in the tree
expect(find.byType(Container), findsOneWidget);
});
});

testWidgets('Given when no path is set, Then set hive save folder',
(widgetTester) async {
await widgetTester.runAsync(() async {
// Checking inital hive save folder to be null
SharedPreferences.setMockInitialValues({});
expect(await getHiveSaveFolder(), null);

// rendering the widgets
await widgetTester.pumpWidget(
HiveDirectorySelector(
getDirectoryPath: () async => tempDir.path,
child: Container(),
),
);

// making a pump to render the widgets
await widgetTester.pump();

// check if CircularProgressIndicator is shown
expect(find.byType(CircularProgressIndicator), findsOneWidget);

// check if the function `selectFolder` is called
final state = widgetTester.state(find.byType(HiveDirectorySelector))
as HiveDirectorySelectorState;
expect(state.selectFolder, isNotNull,
reason: "The function selectFolder isn't rechable.");

// check if the hive save folder is set
expect(await getHiveSaveFolder(), tempDir.path);
});
});
}