Compare commits
3 commits
dfc2de6e33
...
98b8e2b3bf
Author | SHA1 | Date | |
---|---|---|---|
98b8e2b3bf | |||
a28817a93d | |||
2cc099d2ae |
12 changed files with 160 additions and 53 deletions
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
A shy Gopher client made with Flutter for Android (and maybe desktop)
|
A shy Gopher client made with Flutter for Android (and maybe desktop)
|
||||||
|
|
||||||
Not even in Alpha state, it can browse text files over Gopher but it's not usable yet
|
In Alpha state, you can use it if you're tough, for more see Current Usability
|
||||||
|
|
||||||
Eventually will be on F-Droid
|
Eventually will be on F-Droid
|
||||||
|
|
||||||
|
## Current usability status: Barely usable
|
||||||
|
|
||||||
|
You can navigate GoperDirectories, read plaintext files and go back in navigation stack
|
||||||
|
|
||||||
|
List of [features and TODOs](/features.org)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
the Android process has started. This theme is visible to the user
|
the Android process has started. This theme is visible to the user
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
|
@ -23,6 +24,15 @@
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<!-- Add optional android:host to distinguish your app
|
||||||
|
from others in case of conflicting scheme name -->
|
||||||
|
<!-- <data android:scheme="sample" android:host="open.my.app" /> -->
|
||||||
|
<data android:scheme="gopher" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
|
@ -33,7 +43,6 @@
|
||||||
<!-- Required to query activities that can process text, see:
|
<!-- Required to query activities that can process text, see:
|
||||||
https://developer.android.com/training/package-visibility?hl=en and
|
https://developer.android.com/training/package-visibility?hl=en and
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||||
|
|
||||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
* Features non exhaustive list of TODOs
|
* Features non exhaustive list of TODOs
|
||||||
|
|
||||||
Some todos collected from source code, sorted roughly in the order of importance
|
Some todos collected from source code, sorted roughly in the order of importance
|
||||||
- [-] *Most important features* [0%]
|
- [-] *Most important features* [9%]
|
||||||
- [-] Navigation stack with loaded items and urls [1/3]
|
- [-] Navigation stack with loaded items and urls [1/3]
|
||||||
- [X] Capture the back key
|
- [X] Capture the back key
|
||||||
- [ ] Add buttons to go back & forth
|
- [ ] Add buttons to go back & forth
|
||||||
|
@ -10,7 +10,7 @@ Some todos collected from source code, sorted roughly in the order of importance
|
||||||
- [ ] Add toolbar with disable wrap button
|
- [ ] Add toolbar with disable wrap button
|
||||||
- [ ] Menu should be nonwrapping by default
|
- [ ] Menu should be nonwrapping by default
|
||||||
- [ ] Add option to wrap only filenames and not info items as they may be just decoration
|
- [ ] 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
|
- [X] [[https://github.com/llfbandit/app_links/blob/master/doc/README_android.md][Register to handle]] ~gopher://~ protocol
|
||||||
- [ ] Keep toolbar url up to date
|
- [ ] Keep toolbar url up to date
|
||||||
- [ ] Fix line reading from socket
|
- [ ] Fix line reading from socket
|
||||||
- [ ] Bookmarks
|
- [ ] Bookmarks
|
||||||
|
|
|
@ -21,6 +21,7 @@ class _GopherBrowserState extends State<GopherBrowser> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
print("Started with: ${widget.initialUrl}");
|
||||||
_currentItem = ParsedGopherItem.parseUrl(widget.initialUrl);
|
_currentItem = ParsedGopherItem.parseUrl(widget.initialUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,8 +169,6 @@ class ParsedGopherItem {
|
||||||
for (int i = 0; i < rcvd.length; i++) {
|
for (int i = 0; i < rcvd.length; i++) {
|
||||||
if (rcvd[i] == "\n") {
|
if (rcvd[i] == "\n") {
|
||||||
var menuLine = rcvd.substring(start, i);
|
var menuLine = rcvd.substring(start, i);
|
||||||
// TODO: Gophernicus sends .\r for some reason which doesnt seem acording to spec
|
|
||||||
// Maybe ignore when sent from menu=forced?
|
|
||||||
if (menuLine.startsWith(".")) {
|
if (menuLine.startsWith(".")) {
|
||||||
print("Received starting dot, this should be the end I guess");
|
print("Received starting dot, this should be the end I guess");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
// once it will matter
|
// once it will matter
|
||||||
// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables
|
// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'dart:io';
|
import 'package:app_links/app_links.dart';
|
||||||
|
|
||||||
import 'package:gophershy/gopher_browser.dart';
|
import 'package:gophershy/gopher_browser.dart';
|
||||||
|
|
||||||
|
@ -11,13 +13,45 @@ void main() {
|
||||||
runApp(const GopherShy());
|
runApp(const GopherShy());
|
||||||
}
|
}
|
||||||
|
|
||||||
class GopherShy extends StatelessWidget {
|
class _GopherShyState extends State<GopherShy> {
|
||||||
const GopherShy({super.key});
|
late final AppLinks _appLinks;
|
||||||
|
final _navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
StreamSubscription<Uri>? _linkSubscription;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_appLinks = AppLinks();
|
||||||
|
_initDeepLinks();
|
||||||
|
print("Launching bcs: ${widget.fromIntentLink}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_linkSubscription?.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initDeepLinks() async {
|
||||||
|
// Handle links
|
||||||
|
_linkSubscription = _appLinks.uriLinkStream.listen((uri) {
|
||||||
|
debugPrint('GopherShy: onAppLink: $uri');
|
||||||
|
_openAppLink(uri);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openAppLink(Uri uri) {
|
||||||
|
_navigatorKey.currentState?.push(MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return GopherShy(fromIntentLink: uri.toString());
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// This widget is the root of your application.
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
navigatorKey: _navigatorKey,
|
||||||
title: 'GopherShy',
|
title: 'GopherShy',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||||
|
@ -28,13 +62,22 @@ class GopherShy extends StatelessWidget {
|
||||||
appBar: PreferredSize(
|
appBar: PreferredSize(
|
||||||
preferredSize: Size.fromHeight(50),
|
preferredSize: Size.fromHeight(50),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Whoaaaaa",
|
"${widget.fromIntentLink} Whoaaaaa",
|
||||||
style: TextStyle(fontSize: 50),
|
style: TextStyle(fontSize: 50),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// In future replace with bookmark view
|
// In future replace with bookmark view
|
||||||
body: GopherBrowser(initialUrl: "gopher://treebrary.org"),
|
body: GopherBrowser( //TODO: replace default url with homepage from prefs
|
||||||
|
initialUrl: widget.fromIntentLink ?? "gopher://treebrary.org"),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GopherShy extends StatefulWidget {
|
||||||
|
const GopherShy({super.key, this.fromIntentLink});
|
||||||
|
|
||||||
|
final String? fromIntentLink;
|
||||||
|
@override
|
||||||
|
State<GopherShy> createState() => _GopherShyState();
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <gtk/gtk_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) gtk_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin");
|
||||||
|
gtk_plugin_register_with_registrar(gtk_registrar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
gtk
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|
40
pubspec.lock
40
pubspec.lock
|
@ -1,6 +1,38 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
app_links:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: app_links
|
||||||
|
sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.2"
|
||||||
|
app_links_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: app_links_linux
|
||||||
|
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
app_links_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: app_links_platform_interface
|
||||||
|
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
app_links_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: app_links_web
|
||||||
|
sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -88,6 +120,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
gtk:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: gtk
|
||||||
|
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -25,6 +25,7 @@ environment:
|
||||||
# the latest version available on pub.dev. To see which dependencies have newer
|
# the latest version available on pub.dev. To see which dependencies have newer
|
||||||
# versions available, run `flutter pub outdated`.
|
# versions available, run `flutter pub outdated`.
|
||||||
dependencies:
|
dependencies:
|
||||||
|
app_links: ^6.3.2
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <app_links/app_links_plugin_c_api.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
AppLinksPluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
app_links
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|
Loading…
Reference in a new issue