article page

This commit is contained in:
Lea 2022-12-30 16:43:49 +01:00
parent 95c82092f8
commit 3dd315d37a
Signed by: Lea
GPG key ID: 1BAFFE8347019C42
13 changed files with 622 additions and 32 deletions

25
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "feet",
"request": "launch",
"type": "dart"
},
{
"name": "feet (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "feet (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

View file

@ -47,7 +47,7 @@ android {
applicationId "xyz.janderedev.feet"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
minSdkVersion 19
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

View file

@ -1,6 +1,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xyz.janderedev.feet">
<uses-permission android:name="android.permission.INTERNET" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
</queries>
<application
android:label="feet"
android:name="${applicationName}"

View file

@ -0,0 +1,25 @@
// Generated file.
//
// If you wish to remove Flutter's multidex support, delete this entire file.
//
// Modifications to this file should be done in a copy under a different name
// as this file may be regenerated.
package io.flutter.app;
import android.app.Application;
import android.content.Context;
import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex;
/**
* Extension of {@link android.app.Application}, adding multidex support.
*/
public class FlutterMultiDexApplication extends Application {
@Override
@CallSuper
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

117
lib/pages/article.dart Normal file
View file

@ -0,0 +1,117 @@
import 'package:feet/api/api.dart';
import 'package:feet/widgets/homepage_post.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
class ArticlePage extends StatefulWidget {
final Item article;
const ArticlePage({super.key, required this.article});
@override
State<ArticlePage> createState() => _ArticlePageState();
}
class _ArticlePageState extends State<ArticlePage> {
void showInfoDialog(bool debugInfo) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(widget.article.title),
content: Text(
// The dart formatter insists of writing this like this
'By ${widget.article.author.isEmpty ? '(Unknown author)' : widget.article.author}\nPublished on ${formatDate(widget.article.createdOnTime)}${debugInfo
? '\nID: ${widget.article.id}\n'
'Is read: ${widget.article.isRead ? 'Yes' : 'No'}\n'
'Is saved: ${widget.article.isSaved ? 'Yes' : 'No'}'
: ''}',
),
actions: debugInfo
? []
: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
showInfoDialog(true);
},
child: const Text('Debug info')),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: InkWell(
enableFeedback: false,
onTap: () => showInfoDialog(false),
child: Text(widget.article.title),
),
actions: [
IconButton(
onPressed: () {
Share.share(widget.article.url, subject: widget.article.title);
},
icon: const Icon(Icons.share),
),
PopupMenuButton(
itemBuilder: (context) => [
PopupMenuItem(
onTap: () async {
try {
if (await canLaunchUrl(Uri.parse(widget.article.url))) {
await launchUrl(
Uri.parse(widget.article.url),
mode: LaunchMode.externalApplication,
);
} else {
throw 'No application available to open URL';
}
} catch (e) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Cannot open this URL'),
content: Text(e.toString()),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
Clipboard.setData(
ClipboardData(
text: widget.article.url,
),
);
},
child: const Text('Copy URL'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Got it!'),
),
],
),
);
}
},
value: 'open_in_browser',
child: const Text('Open in browser'),
),
],
),
],
),
body: ListView(
children: [
Html(
data: widget.article.html,
),
],
),
);
}
}

View file

@ -1,3 +1,4 @@
import 'package:feet/pages/article.dart';
import 'package:flutter/material.dart';
import '../api/api.dart';
@ -25,7 +26,9 @@ class HomepagePost extends StatelessWidget {
),
child: InkWell(
onTap: () {
showDialog(context: context, builder: (context) => SimpleDialog(title: Text(post.title)));
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => ArticlePage(article: post)),
);
},
borderRadius: const BorderRadius.all(Radius.circular(15)),
child: Container(
@ -33,7 +36,9 @@ class HomepagePost extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(post.title, style: Theme.of(context).textTheme.titleMedium, overflow: TextOverflow.ellipsis),
Text(post.title,
style: Theme.of(context).textTheme.titleMedium,
overflow: TextOverflow.ellipsis),
ClipRRect(
clipBehavior: Clip.antiAlias,
child: Row(
@ -42,7 +47,8 @@ class HomepagePost extends StatelessWidget {
const Text(' \u2022 '),
post.author.isNotEmpty
? Text(post.author)
: const Text('Unknown author', style: TextStyle(fontStyle: FontStyle.italic)),
: const Text('Unknown author',
style: TextStyle(fontStyle: FontStyle.italic)),
const Text(' \u2022 '),
Text(formatDate(post.createdOnTime)),
],
@ -50,8 +56,7 @@ class HomepagePost extends StatelessWidget {
),
],
),
)
),
)),
);
}
}

View file

@ -7,9 +7,13 @@
#include "generated_plugin_registrant.h"
#include <dynamic_color/dynamic_color_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
}

View file

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color
url_launcher_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View file

@ -6,9 +6,17 @@ import FlutterMacOS
import Foundation
import dynamic_color
import path_provider_macos
import share_plus
import shared_preferences_macos
import url_launcher_macos
import wakelock_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin"))
}

View file

@ -25,6 +25,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
chewie:
dependency: transitive
description:
name: chewie
sha256: "7737b1b8b1f9df3b3751abfb0dea5efbebb7060c28eccdc3b0fa4a0d638eaf9f"
url: "https://pub.dev"
source: hosted
version: "1.3.6"
chewie_audio:
dependency: transitive
description:
name: chewie_audio
sha256: f92bb4364ced21318e1a7c0eddaf249a7554e5cf27f869d58c44d926abd292a7
url: "https://pub.dev"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
@ -41,6 +57,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.17.0"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: f71079978789bc2fe78d79227f1f8cfe195b31bbd8db2399b0d15a4b96fb843b
url: "https://pub.dev"
source: hosted
version: "0.3.3+2"
crypto:
dependency: "direct main"
description:
@ -49,6 +73,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
csslib:
dependency: transitive
description:
name: csslib
sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
url: "https://pub.dev"
source: hosted
version: "0.17.2"
cupertino_icons:
dependency: "direct main"
description:
@ -94,6 +126,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_html:
dependency: "direct main"
description:
name: flutter_html
sha256: ccb810fcabfce3a7ffaca46e458323915ac7e7fc59082c7357ff848972c02230
url: "https://pub.dev"
source: hosted
version: "2.2.1"
flutter_layout_grid:
dependency: transitive
description:
name: flutter_layout_grid
sha256: "86c1b21520612edfbb93f189b3ec05058470570f3a5c08ce10c92cc76a6e814e"
url: "https://pub.dev"
source: hosted
version: "1.0.6"
flutter_lints:
dependency: "direct dev"
description:
@ -102,6 +150,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
flutter_math_fork:
dependency: transitive
description:
name: flutter_math_fork
sha256: a34205227e1a1d040a56e74a5e2e56e9397ea930540a9373bd0b3e2e4f122017
url: "https://pub.dev"
source: hosted
version: "0.5.0"
flutter_svg:
dependency: transitive
description:
name: flutter_svg
sha256: cbf529d563dd910a249041bde2a0dfc3cf62280fcc459b85f3d614b2ab73abb3
url: "https://pub.dev"
source: hosted
version: "0.23.0+1"
flutter_test:
dependency: "direct dev"
description: flutter
@ -112,6 +176,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
html:
dependency: transitive
description:
name: html
sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269
url: "https://pub.dev"
source: hosted
version: "0.15.1"
http:
dependency: "direct main"
description:
@ -168,6 +240,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.0"
mime:
dependency: transitive
description:
name: mime
sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
numerus:
dependency: transitive
description:
name: numerus
sha256: "0087ef729d63b96cb347a9c44b9c592f21cecb3605b415bbd18710aef80ce5cb"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
path:
dependency: transitive
description:
@ -176,6 +272,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.2"
path_drawing:
dependency: transitive
description:
name: path_drawing
sha256: "3bdd251dae9ffaef944450b73f168610db7e968e7b20daf0c3907f8b4aafc8a2"
url: "https://pub.dev"
source: hosted
version: "0.5.1+1"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: ee5c47c1058ad66b4a41746ec3996af9593d0858872807bcd64ac118f0700337
url: "https://pub.dev"
source: hosted
version: "0.2.1"
path_provider:
dependency: transitive
description:
name: path_provider
sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd"
url: "https://pub.dev"
source: hosted
version: "2.0.11"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
url: "https://pub.dev"
source: hosted
version: "2.0.22"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
sha256: "03d639406f5343478352433f00d3c4394d52dac8df3d847869c5e2333e0bbce8"
url: "https://pub.dev"
source: hosted
version: "2.0.11"
path_provider_linux:
dependency: transitive
description:
@ -184,6 +320,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.7"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8"
url: "https://pub.dev"
source: hosted
version: "2.0.6"
path_provider_platform_interface:
dependency: transitive
description:
@ -200,6 +344,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.3"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4"
url: "https://pub.dev"
source: hosted
version: "5.1.0"
platform:
dependency: transitive
description:
@ -224,6 +376,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.2.4"
provider:
dependency: transitive
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
url: "https://pub.dev"
source: hosted
version: "6.0.5"
quiver:
dependency: transitive
description:
name: quiver
sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
url: "https://pub.dev"
source: hosted
version: "3.2.1"
share_plus:
dependency: "direct main"
description:
name: share_plus
sha256: e387077716f80609bb979cd199331033326033ecd1c8f200a90c5f57b1c9f55e
url: "https://pub.dev"
source: hosted
version: "6.3.0"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
sha256: "82ddd4ab9260c295e6e39612d4ff00390b9a7a21f1bb1da771e2f232d80ab8a1"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
shared_preferences:
dependency: "direct main"
description:
@ -341,6 +525,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.16"
tuple:
dependency: transitive
description:
name: tuple
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
typed_data:
dependency: transitive
description:
@ -349,6 +541,78 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
sha256: "3c92b0efb5e9dcb8f846aefabf9f0f739f91682ed486b991ceda51c288e60896"
url: "https://pub.dev"
source: hosted
version: "6.1.7"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "6f91d30ce9060c204b2dbe728adb300750fa4b228e8f7ed1b961aa1ceb728799"
url: "https://pub.dev"
source: hosted
version: "6.0.22"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: "6ba7dddee26c9fae27c9203c424631109d73c8fa26cfa7bc3e35e751cb87f62e"
url: "https://pub.dev"
source: hosted
version: "6.0.17"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: "360fa359ab06bcb4f7c5cd3123a2a9a4d3364d4575d27c4b33468bd4497dd094"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: a9b3ea9043eabfaadfa3fb89de67a11210d85569086d22b3854484beab8b3978
url: "https://pub.dev"
source: hosted
version: "3.0.1"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: "5669882643b96bb6d5786637cac727c6e918a790053b09245fd4513b8a07df2a"
url: "https://pub.dev"
source: hosted
version: "2.0.13"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: e3c3b16d3104260c10eea3b0e34272aaa57921f83148b0619f74c2eced9b7ef1
url: "https://pub.dev"
source: hosted
version: "3.0.1"
uuid:
dependency: transitive
description:
name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
vector_math:
dependency: transitive
description:
@ -357,6 +621,118 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
video_player:
dependency: transitive
description:
name: video_player
sha256: "86b4fb9e30613ef4ff7e47367bfec4b080ab17205b7d969cd12bbebde49476b1"
url: "https://pub.dev"
source: hosted
version: "2.4.10"
video_player_android:
dependency: transitive
description:
name: video_player_android
sha256: "984388511230bac63feb53b2911a70e829fe0976b6b2213f5c579c4e0a882db3"
url: "https://pub.dev"
source: hosted
version: "2.3.10"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
sha256: d9f7a46d6a77680adb03ec05a381025d6e890ebe636637c6c3014cc3926b97e9
url: "https://pub.dev"
source: hosted
version: "2.3.8"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
sha256: "42bb75de5e9b79e1f20f1d95f688fac0f95beac4d89c6eb2cd421724d4432dae"
url: "https://pub.dev"
source: hosted
version: "6.0.1"
video_player_web:
dependency: transitive
description:
name: video_player_web
sha256: b649b07b8f8f553bee4a97a0a53d0fe78a70b115eafaf0105b612b32b05ddb99
url: "https://pub.dev"
source: hosted
version: "2.0.13"
wakelock:
dependency: transitive
description:
name: wakelock
sha256: "769ecf42eb2d07128407b50cb93d7c10bd2ee48f0276ef0119db1d25cc2f87db"
url: "https://pub.dev"
source: hosted
version: "0.6.2"
wakelock_macos:
dependency: transitive
description:
name: wakelock_macos
sha256: "047c6be2f88cb6b76d02553bca5a3a3b95323b15d30867eca53a19a0a319d4cd"
url: "https://pub.dev"
source: hosted
version: "0.4.0"
wakelock_platform_interface:
dependency: transitive
description:
name: wakelock_platform_interface
sha256: "1f4aeb81fb592b863da83d2d0f7b8196067451e4df91046c26b54a403f9de621"
url: "https://pub.dev"
source: hosted
version: "0.3.0"
wakelock_web:
dependency: transitive
description:
name: wakelock_web
sha256: "1b256b811ee3f0834888efddfe03da8d18d0819317f20f6193e2922b41a501b5"
url: "https://pub.dev"
source: hosted
version: "0.4.0"
wakelock_windows:
dependency: transitive
description:
name: wakelock_windows
sha256: "857f77b3fe6ae82dd045455baa626bc4b93cb9bb6c86bf3f27c182167c3a5567"
url: "https://pub.dev"
source: hosted
version: "0.2.1"
webview_flutter:
dependency: transitive
description:
name: webview_flutter
sha256: "6886b3ceef1541109df5001054aade5ee3c36b5780302e41701c78357233721c"
url: "https://pub.dev"
source: hosted
version: "2.8.0"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: "8b3b2450e98876c70bfcead876d9390573b34b9418c19e28168b74f6cb252dbd"
url: "https://pub.dev"
source: hosted
version: "2.10.4"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "812165e4e34ca677bdfbfa58c01e33b27fd03ab5fa75b70832d4b7d4ca1fa8cf"
url: "https://pub.dev"
source: hosted
version: "1.9.5"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: a5364369c758892aa487cbf59ea41d9edd10f9d9baf06a94e80f1bd1b4c7bbc0
url: "https://pub.dev"
source: hosted
version: "2.9.5"
win32:
dependency: transitive
description:
@ -373,6 +749,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.0+2"
xml:
dependency: transitive
description:
name: xml
sha256: "80d494c09849dc3f899d227a78c30c5b949b985ededf884cb3f3bcd39f4b447a"
url: "https://pub.dev"
source: hosted
version: "5.4.1"
sdks:
dart: ">=2.19.0-444.2.beta <4.0.0"
flutter: ">=3.3.0"

View file

@ -39,6 +39,9 @@ dependencies:
crypto: ^3.0.2
dynamic_color: ^1.5.4
shared_preferences: ^2.0.15
share_plus: ^6.3.0
flutter_html: ^2.2.1
url_launcher: ^6.1.7
dev_dependencies:
flutter_test:

View file

@ -7,8 +7,14 @@
#include "generated_plugin_registrant.h"
#include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
DynamicColorPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
SharePlusWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View file

@ -4,6 +4,8 @@
list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color
share_plus
url_launcher_windows
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST