Compare commits
No commits in common. "98b8e2b3bf7a0d413ac367bb47fc1cd5b54d3331" and "dfc2de6e331cef7ecc058498bdb8e5b2ab662f94" have entirely different histories.
98b8e2b3bf
...
dfc2de6e33
12 changed files with 53 additions and 160 deletions
|
@ -2,12 +2,6 @@
|
||||||
|
|
||||||
A shy Gopher client made with Flutter for Android (and maybe desktop)
|
A shy Gopher client made with Flutter for Android (and maybe desktop)
|
||||||
|
|
||||||
In Alpha state, you can use it if you're tough, for more see Current Usability
|
Not even in Alpha state, it can browse text files over Gopher but it's not usable yet
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
|
@ -1,53 +1,44 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<application
|
<application
|
||||||
android:label="gophershy"
|
android:label="gophershy"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
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
|
to determine the Window background behind the Flutter UI. -->
|
||||||
to determine the Window background behind the Flutter UI. -->
|
<meta-data
|
||||||
<meta-data
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
android:resource="@style/NormalTheme"
|
||||||
android:resource="@style/NormalTheme"
|
/>
|
||||||
/>
|
<intent-filter>
|
||||||
<intent-filter>
|
<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>
|
</activity>
|
||||||
<intent-filter>
|
<!-- Don't delete the meta-data below.
|
||||||
<action android:name="android.intent.action.VIEW" />
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<meta-data
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
android:name="flutterEmbedding"
|
||||||
<!-- Add optional android:host to distinguish your app
|
android:value="2" />
|
||||||
from others in case of conflicting scheme name -->
|
</application>
|
||||||
<!-- <data android:scheme="sample" android:host="open.my.app" /> -->
|
<!-- Required to query activities that can process text, see:
|
||||||
<data android:scheme="gopher" />
|
https://developer.android.com/training/package-visibility?hl=en and
|
||||||
</intent-filter>
|
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||||
</activity>
|
|
||||||
<!-- Don't delete the meta-data below.
|
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
<queries>
|
||||||
<meta-data
|
<intent>
|
||||||
android:name="flutterEmbedding"
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
android:value="2" />
|
<data android:mimeType="text/plain"/>
|
||||||
</application>
|
</intent>
|
||||||
<!-- Required to query activities that can process text, see:
|
</queries>
|
||||||
https://developer.android.com/training/package-visibility?hl=en and
|
|
||||||
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. -->
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
|
||||||
<data android:mimeType="text/plain"/>
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -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* [9%]
|
- [-] *Most important features* [0%]
|
||||||
- [-] 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
|
||||||
- [X] [[https://github.com/llfbandit/app_links/blob/master/doc/README_android.md][Register to handle]] ~gopher://~ protocol
|
- [ ] [[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,7 +21,6 @@ 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,6 +169,8 @@ 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,10 +2,8 @@
|
||||||
// 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 'package:app_links/app_links.dart';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:gophershy/gopher_browser.dart';
|
import 'package:gophershy/gopher_browser.dart';
|
||||||
|
|
||||||
|
@ -13,45 +11,13 @@ void main() {
|
||||||
runApp(const GopherShy());
|
runApp(const GopherShy());
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GopherShyState extends State<GopherShy> {
|
class GopherShy extends StatelessWidget {
|
||||||
late final AppLinks _appLinks;
|
const GopherShy({super.key});
|
||||||
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),
|
||||||
|
@ -62,22 +28,13 @@ class _GopherShyState extends State<GopherShy> {
|
||||||
appBar: PreferredSize(
|
appBar: PreferredSize(
|
||||||
preferredSize: Size.fromHeight(50),
|
preferredSize: Size.fromHeight(50),
|
||||||
child: Text(
|
child: Text(
|
||||||
"${widget.fromIntentLink} Whoaaaaa",
|
"Whoaaaaa",
|
||||||
style: TextStyle(fontSize: 50),
|
style: TextStyle(fontSize: 50),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// In future replace with bookmark view
|
// In future replace with bookmark view
|
||||||
body: GopherBrowser( //TODO: replace default url with homepage from prefs
|
body: GopherBrowser(initialUrl: "gopher://treebrary.org"),
|
||||||
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,10 +6,6 @@
|
||||||
|
|
||||||
#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,7 +3,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
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,38 +1,6 @@
|
||||||
# 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:
|
||||||
|
@ -120,14 +88,6 @@ 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,7 +25,6 @@ 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,9 +6,6 @@
|
||||||
|
|
||||||
#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,7 +3,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
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