Compare commits
No commits in common. "26dd27a435a0752b4fcd363a453adc88bfde80ab" and "dfc2de6e331cef7ecc058498bdb8e5b2ab662f94" have entirely different histories.
26dd27a435
...
dfc2de6e33
12 changed files with 54 additions and 167 deletions
14
README.md
14
README.md
|
@ -2,18 +2,6 @@
|
|||
|
||||
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
|
||||
|
||||
## Current usability status: kinda usable
|
||||
|
||||
You can navigate GoperDirectories, read plaintext files and go back in navigation stack.
|
||||
App starts when you click on ``gopher://`` link.
|
||||
|
||||
List of [features and TODOs](/features.org)
|
||||
|
||||
[Link to test gopher page](gopher://treebrary.org/Directory/) because it's hard to find gopher link on the web these days for some
|
||||
reason.
|
||||
[Link to test page with type inference](gopher://treebrary.org/0/Directory/)
|
||||
|
||||
|
|
|
@ -1,53 +1,44 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="gophershy"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
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
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</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>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
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>
|
||||
<application
|
||||
android:label="gophershy"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
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>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
* Features non exhaustive list of TODOs
|
||||
|
||||
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]
|
||||
- [X] Capture the back key
|
||||
- [ ] 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
|
||||
- [ ] Menu should be nonwrapping by default
|
||||
- [ ] 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
|
||||
- [ ] Fix line reading from socket
|
||||
- [ ] Bookmarks
|
||||
|
|
|
@ -21,7 +21,6 @@ class _GopherBrowserState extends State<GopherBrowser> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
print("Started with: ${widget.initialUrl}");
|
||||
_currentItem = ParsedGopherItem.parseUrl(widget.initialUrl);
|
||||
}
|
||||
|
||||
|
|
|
@ -169,6 +169,8 @@ class ParsedGopherItem {
|
|||
for (int i = 0; i < rcvd.length; i++) {
|
||||
if (rcvd[i] == "\n") {
|
||||
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(".")) {
|
||||
print("Received starting dot, this should be the end I guess");
|
||||
return;
|
||||
|
@ -178,7 +180,7 @@ class ParsedGopherItem {
|
|||
start = i + 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
await subscription.asFuture<void>();
|
||||
sock.close();
|
||||
return LoadedGopherItem(
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
// once it will matter
|
||||
// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:app_links/app_links.dart';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:gophershy/gopher_browser.dart';
|
||||
|
||||
|
@ -13,45 +11,13 @@ void main() {
|
|||
runApp(const GopherShy());
|
||||
}
|
||||
|
||||
class _GopherShyState extends State<GopherShy> {
|
||||
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());
|
||||
},
|
||||
));
|
||||
}
|
||||
class GopherShy extends StatelessWidget {
|
||||
const GopherShy({super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
navigatorKey: _navigatorKey,
|
||||
title: 'GopherShy',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
|
@ -62,22 +28,13 @@ class _GopherShyState extends State<GopherShy> {
|
|||
appBar: PreferredSize(
|
||||
preferredSize: Size.fromHeight(50),
|
||||
child: Text(
|
||||
"${widget.fromIntentLink} Whoaaaaa",
|
||||
"Whoaaaaa",
|
||||
style: TextStyle(fontSize: 50),
|
||||
),
|
||||
),
|
||||
// In future replace with bookmark view
|
||||
body: GopherBrowser( //TODO: replace default url with homepage from prefs
|
||||
initialUrl: widget.fromIntentLink ?? "gopher://treebrary.org"),
|
||||
body: GopherBrowser(initialUrl: "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 <gtk/gtk_plugin.h>
|
||||
|
||||
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
|
||||
gtk
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
40
pubspec.lock
40
pubspec.lock
|
@ -1,38 +1,6 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -120,14 +88,6 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
gtk:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: gtk
|
||||
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -25,7 +25,6 @@ environment:
|
|||
# the latest version available on pub.dev. To see which dependencies have newer
|
||||
# versions available, run `flutter pub outdated`.
|
||||
dependencies:
|
||||
app_links: ^6.3.2
|
||||
flutter:
|
||||
sdk: flutter
|
||||
shared_preferences: ^2.2.3
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <app_links/app_links_plugin_c_api.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
AppLinksPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
app_links
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
Loading…
Reference in a new issue