Skip to content

Commit

Permalink
fix tab view and browser, add settings support
Browse files Browse the repository at this point in the history
  • Loading branch information
Sivan22 committed Feb 6, 2024
1 parent d98c665 commit cb1e679
Show file tree
Hide file tree
Showing 10 changed files with 592 additions and 228 deletions.
13 changes: 5 additions & 8 deletions TODO.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
V add multi tabs support
V save tab state
close the current tab
V change markdown loading to async
V add book title search
move tabView to be home page
add setting screen
add option for styling the markdown
up folder in brwser
use html2markdown
add option for themes for the markdown
add search in markdown content
add PDF support
add search for reference
deploy with msix for sharing
להוסיף את הרמה האחרונה של כותרת לכל הרמות מעל 4
להחזיר ספרים שנמחקו

1 change: 1 addition & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extensions:
239 changes: 239 additions & 0 deletions lib/book_tabs_viewer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import 'package:flutter_settings_screen_ex/flutter_settings_screen_ex.dart';
import 'package:universal_io/io.dart';
import 'package:flutter/material.dart';
import 'package:markdown_widget/markdown_widget.dart';
import 'custom_node.dart';
import 'main.dart';
import 'dart:math';

class MarkdownTabView extends StatefulWidget {


const MarkdownTabView({Key? key,})
: super(key: key);

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

class MarkdownTabViewState extends State<MarkdownTabView> with TickerProviderStateMixin{
int selectedIndex = 0;
List<File> openedFiles = [];
late TabController tabController;


@override
void initState() {
super.initState();
tabController = TabController(length: openedFiles.length, vsync:this);

}


void enlargeText() {
setState(() {
Settings.setValue<double>( 'key-font-size',min(Settings.getValue<double>('key-font-size')!+5,50.0));

});

}

void enSmallText() {
setState(() {
Settings.setValue<double>( 'key-font-size',max(Settings.getValue<double>('key-font-size')!-5,15.0));

});

}

void closelastTab() {
setState(() {
if (openedFiles.isNotEmpty) {
openedFiles.removeAt(tabController.index);

tabController = TabController(length: openedFiles.length, vsync:this,initialIndex: max(0,tabController.index-1));
}
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text('אוצריא')),
actions: [

IconButton(
icon: const Icon(
Icons.font_download_outlined,

),
tooltip: 'הגדל טקסט',
onPressed: enlargeText,
),
IconButton(
icon: const Icon(
Icons.font_download_off_outlined,

),
tooltip: 'הקטן טקסט',
onPressed: enSmallText,
),
IconButton(
icon: const Icon(Icons.close),
tooltip: 'סגור ספר פתוח',
onPressed: closelastTab,
),
],
bottom: TabBar(
controller: tabController,
tabs: openedFiles
.map((file) => Tab(text: file.path.split('/').last))
.toList(),
),
),
body: Row(children: [
NavigationRail(
labelType: NavigationRailLabelType.all,
destinations: const [
NavigationRailDestination(
icon: Icon(Icons.library_books),
label: Text('ספריה'),
),
NavigationRailDestination(
icon: Icon(Icons.search),
label: Text('חיפוש'),
),
NavigationRailDestination(
icon: Icon(Icons.settings),
label: Text('הגדרות'),
),
],
selectedIndex: selectedIndex,
onDestinationSelected: (int index) {
setState(() {
selectedIndex = index;
switch (index) {
case 0:
_openSelectedFile('browser');
case 1:
_openSelectedFile('search');
case 2:
Navigator.pushNamed(context, '/settings');
}
});
}),
Expanded(
child: TabBarView(
controller: tabController,
children: openedFiles.map((file) {
return BookViewer(
file: file,
);
}).toList()),
),
]),
);
}

void _openSelectedFile(String how) async {
File? selectedFile;

if (how == 'browser') {
selectedFile = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DirectoryBrowser(
directory: Directory('./אוצריא'),
)),
);
} else if (how == 'search') {
selectedFile = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => BookSearchScreen()),
);
}
if (selectedFile != null) {
setState(() {
openedFiles.add(selectedFile!);
tabController = TabController(length: openedFiles.length, vsync:this,initialIndex: openedFiles.length-1);
});
}
}
}


class BookViewer extends StatefulWidget {
final File file;
late Future<String> data;

BookViewer({Key? key, required this.file}) : super(key: key) {
data = file.readAsString();
}

@override
State<BookViewer> createState() => _BookViewerState();
}

class _BookViewerState extends State<BookViewer> with AutomaticKeepAliveClientMixin<BookViewer> {
//use value notifier

ValueNotifier textFontSize = ValueNotifier(Settings.getValue('key-font-size'));


@override
void initState() {
super.initState();
}
final tocController = TocController();

Widget buildTocWidget() => TocWidget(controller: tocController);

Widget buildMarkdown() => FutureBuilder(
future: widget.data.then((value) => value),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}

if (snapshot.hasData) {
return ValueListenableBuilder(
key: PageStorageKey<String>(widget.key.toString()),
valueListenable: textFontSize,
builder: (context, value, child) =>
MarkdownWidget(
padding: const EdgeInsets.all(50),
data: snapshot.data!,
tocController: tocController,
config: MarkdownConfig(configs: [
PConfig(
textStyle: TextStyle(
fontSize: Settings.getValue('key-font-size'),
fontFamily: Settings.getValue('key-font-family'),

)),
]),
markdownGenerator: MarkdownGenerator(
textGenerator: (node, config, visitor) =>
CustomTextNode(node.textContent, config, visitor))));
}
}
return const Center(child: CircularProgressIndicator(
));
});

@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(child: buildTocWidget()),
appBar: AppBar(
actions: [],
title: Text('${widget.file.path.split('/').last}'),
),
body: buildMarkdown(),
);
}
@override
bool get wantKeepAlive => true;
}
105 changes: 105 additions & 0 deletions lib/cache_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_settings_screen_ex/flutter_settings_screen_ex.dart';


/// A cache access provider class for shared preferences using Hive library
class HiveCache extends CacheProvider {
Box? _preferences;
final String keyName = 'app_preferences';

@override
Future<void> init() async {
WidgetsFlutterBinding.ensureInitialized();
if (!kIsWeb) {
final defaultDirectory = await getApplicationDocumentsDirectory();
Hive.init(defaultDirectory.path);
}
if (Hive.isBoxOpen(keyName)) {
_preferences = Hive.box(keyName);
} else {
_preferences = await Hive.openBox(keyName);
}
}

Set get keys => getKeys();

@override
bool? getBool(String key, {bool? defaultValue}) {
return _preferences?.get(key);
}

@override
double? getDouble(String key, {double? defaultValue}) {
return _preferences?.get(key);
}

@override
int? getInt(String key, {int? defaultValue}) {
return _preferences?.get(key);
}

@override
String? getString(String key, {String? defaultValue}) {
return _preferences?.get(key);
}

@override
Future<void> setBool(String key, bool? value) async {
await _preferences?.put(key, value);
}

@override
Future<void> setDouble(String key, double? value) async {
await _preferences?.put(key, value);
}

@override
Future<void> setInt(String key, int? value) async {
await _preferences?.put(key, value);
}

@override
Future<void> setString(String key, String? value) async {
await _preferences?.put(key, value);
}

@override
Future<void> setObject<T>(String key, T? value) async {
await _preferences?.put(key, value);
}

@override
bool containsKey(String key) {
return _preferences?.containsKey(key) ?? false;
}

@override
Set getKeys() {
return _preferences?.keys.toSet() ?? {};
}

@override
Future<void> remove(String key) async {
if (containsKey(key)) {
await _preferences?.delete(key);
}
}

@override
Future<void> removeAll() async {
final keys = getKeys();
await _preferences?.deleteAll(keys);
}

@override
T? getValue<T>(String key, {T? defaultValue}) {
var value = _preferences?.get(key);
if (value is T) {
return value;
}
return defaultValue;
}
}
Loading

0 comments on commit cb1e679

Please sign in to comment.