diff --git a/features.org b/features.org index fd19a01..cf82e85 100644 --- a/features.org +++ b/features.org @@ -1,13 +1,17 @@ -- [ ] Most important features [0%] - - [ ] Navigation stack with loaded items and urls - - Capture the back key - - Add buttons to go back & forth - - Figure out a way to exit with back arrow - - Maybe go with back arrow until the begginging of navigation stack and then double click? - - [ ] [[https://github.com/llfbandit/app_links/blob/master/doc/README_android.md][Register to handle]] ~gopher://~ protocol - - [ ] Line wrap togglable for text files and menus +* Features non exhaustive list of TODOs + +Some todos collected from source code, sorted roughly in the order of importance +- [-] *Most important features* [0%] + - [-] Navigation stack with loaded items and urls [1/3] + - [X] Capture the back key + - [ ] Add buttons to go back & forth + - [ ] Show toast at the end of history and exit after double click on back arrow + - [ ] Line wrap togglable for text files and menus [0/3] + - [ ] Add toolbar with disable wrap button - [ ] Menu should be nonwrapping by default - [ ] Add option to wrap only filenames and not info items as they may be just decoration + - [ ] [[https://github.com/llfbandit/app_links/blob/master/doc/README_android.md][Register to handle]] ~gopher://~ protocol + - [ ] Keep toolbar url up to date - [ ] Fix line reading from socket - [ ] Bookmarks - [ ] Picture view with option to save to file @@ -15,7 +19,9 @@ - [ ] Option to "Open in app" for all files that we don't know how to handle (pdf, exec binaries, sound files) - [ ] Homepage or custom homepage - [ ] Working user input -- [ ] Nice to haves +- [ ] *Configuration options* + - [ ] Option to select whether back arrow goes Up directory tree ro back in navigation stack +- [ ] *Nice to haves* [0%] - [ ] Icon - [ ] Preferences for navigation stack depth (both loaded & url stacks) - [ ] Preferences for diff --git a/lib/gopher_browser.dart b/lib/gopher_browser.dart index 7272a82..7fd495f 100644 --- a/lib/gopher_browser.dart +++ b/lib/gopher_browser.dart @@ -7,16 +7,31 @@ class _GopherBrowserState extends State { // TODO: We must have button: Menu! to attempt to render any text file as menu // Because when we visit from direct url we don't know what file type we get // Other detection methods could be applied later + // This may not be the most common use case so maybe hide it in some hayburger menu String currentUrl = "gopher://treebrary.org"; // Directory listing doesn't have to end with / so we can never // be sure whether we're visiting menu or not. // When true, we try to parse anything as menu bool forceMenu = false; + /// Only links to session history, will be much bigger than [_loadedStack] + // Probably remove from here + final List _urlStack = List.empty(growable: true); + + @override + void initState() { + super.initState(); + _currentItem = ParsedGopherItem.parseUrl(widget.initialUrl); + } + + late ParsedGopherItem _currentItem; void gotoUrl(String link) { + print("GoTo: $link from: $currentUrl"); if (link == currentUrl) return; setState(() { - print("prev: $currentUrl Submitted: $link"); + print("prev: Submitted: $link"); + _currentItem = ParsedGopherItem.parseUrl(link); + _urlStack.add(_currentItem); currentUrl = link; }); } @@ -24,17 +39,21 @@ class _GopherBrowserState extends State { @override Widget build(BuildContext context) { print("GopherBrowseState: $currentUrl"); - return Column( - children: [ - TextField(onSubmitted: gotoUrl), - Expanded( + return Builder(builder: (context) { + return Column( + children: [ + TextField( + onSubmitted: gotoUrl, + ), + Expanded( child: GopherLoader( - key: ValueKey(currentUrl), - forceMenu: forceMenu, - parsedGopherItem: ParsedGopherItem.parseUrl(currentUrl), - )), - ], - ); + key: ValueKey(currentUrl), + forceMenu: forceMenu, + parsedGopherItem: _currentItem, + )), + ], + ); + }); } } @@ -49,57 +68,85 @@ class GopherBrowser extends StatefulWidget { class _GopherLoaderState extends State { Future? _data; + final List _loadedHistory = + List.empty(growable: true); + @override void initState() { super.initState(); - _data = widget.parsedGopherItem.load(forceMenu: widget.forceMenu); - print("Reiniterd"); + _data = widget.parsedGopherItem.load(forceMenu: widget.forceMenu).then( + (value) { + print("Pushed beacuse of initState"); + return _onLoadFinished(value); + }, + ); + print("Reinitred GopherLoaderState"); } - @override - void didChangeDependencies() { - super.didChangeDependencies(); - print("did:change: _data $_data"); - setState(() { - _data = widget.parsedGopherItem.load(forceMenu: widget.forceMenu); - }); - - print('didChangeDependencies, mounted: ${1} done? '); - print("$_data"); + LoadedGopherItem _onLoadFinished(LoadedGopherItem data) { + _loadedHistory.add(data); + print("Added to histor: ${_loadedHistory.length}"); + return data; } - void goToNext(ParsedGopherItem item) { + void _goToNext(ParsedGopherItem item, {String? why}) { + print("Going to next: $why"); setState(() { print("requesting view of: ${item.url} ${item.documentType}"); - _data = item.load(forceMenu: false); + _data = item.load(forceMenu: false).then( + (value) { + print("Pushed beacuse of gotoNext"); + return _onLoadFinished(value); + }, + ); }); } + void _onBackButton(bool popable, object) { + print("Gonna pop i guess"); + // TODO: toast if at the end of history, make time stamp and quit if pressed back button quickly again + // TODO: Setting on whether back button goes up a directory or back in navigation stack -> may be the same but might not be + if (_loadedHistory.length > 1) { + _loadedHistory.removeLast(); + setState(() { + _data = Future.delayed( + Duration.zero, () => _loadedHistory.last); + }); + } else { + // TODO: Toast here + print("At the end of stack"); + } + } + @override Widget build(BuildContext context) { - return Center( - child: FutureBuilder( - future: _data, - builder: (cont, snap) { - print("${snap.connectionState}"); - if (snap.connectionState != ConnectionState.done) { - return const CircularProgressIndicator(); + return PopScope( + canPop: false, + onPopInvokedWithResult: _onBackButton, + child: FutureBuilder( + future: _data, + builder: (cont, snap) { + print("${snap.connectionState}"); + if (snap.connectionState != ConnectionState.done) { + return const CircularProgressIndicator(); + } else { + if (snap.hasData) { + print( + "data & doctype: ${snap.data!}, ${snap.data!.parsed.documentType}"); + return switch (snap.data!.parsed.documentType) { + DocumentType.TextFile => GopherText(snap.data!), + DocumentType.Directory => GopherDirectory( + parsedDirectory: snap.data!, + onItemClick: _goToNext, + ), + _ => Container(color: Colors.yellow), + }; } else { - if (snap.hasData) { - print("data & doctype: ${snap.data!}, ${snap.data!.parsed.documentType}, "); - return switch (snap.data!.parsed.documentType) { - DocumentType.TextFile => GopherText(snap.data!), - DocumentType.Directory => GopherDirectory( - parsedDirectory: snap.data!, - onItemClick: goToNext, - ), - _ => Container(color: Colors.yellow), - }; - } else { - return const Text("Errored"); - } + return Text("Errored ${snap.error}"); } - })); + } + }), + ); } }