Created onboarding

This commit is contained in:
Juan Gilsanz Polo
2024-02-22 02:11:10 +01:00
parent d9a82ec1fa
commit 36f9332f61
23 changed files with 538 additions and 43 deletions

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z" /></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M3,20.5V3.5C3,2.91 3.34,2.39 3.84,2.15L13.69,12L3.84,21.85C3.34,21.6 3,21.09 3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08 20.75,11.5 20.75,12C20.75,12.5 20.53,12.9 20.18,13.18L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z" /></svg>

After

Width:  |  Height:  |  Size: 588 B

View File

@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 2
/// Strings: 8 (4 per locale)
/// Strings: 30 (15 per locale)
///
/// Built on 2024-02-21 at 23:50 UTC
/// Built on 2024-02-22 at 01:09 UTC
// coverage:ignore-file
// ignore_for_file: type=lint
@@ -148,8 +148,28 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
late final Translations _root = this; // ignore: unused_field
// Translations
late final _StringsOnboardingEn onboarding = _StringsOnboardingEn._(_root);
late final _StringsConnectEn connect = _StringsConnectEn._(_root);
late final _StringsLinksEn links = _StringsLinksEn._(_root);
late final _StringsSettingsEn settings = _StringsSettingsEn._(_root);
}
// Path: onboarding
class _StringsOnboardingEn {
_StringsOnboardingEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get title => 'Welcome to My Linkding';
String get subtitle => 'An application to manage your bookmarks.';
String get start => 'Start';
String get next => 'Next';
String get previous => 'Previous';
String get serverRequired => 'Servidor requerido';
String get serverRequiredDescription => 'My Linkding it\'s not an standalone app, it requires the Linkding server to work.\nIn order to use this application, you must deploy Linkding on your home server, VPS or any other computer.';
String get installationInstructions => 'Check the installation instructions on the official GitHub repository.';
String get serverRunningConfirmation => 'I confirm that I have an instance of the Linkding server already running.';
}
// Path: connect
@@ -174,6 +194,17 @@ class _StringsLinksEn {
String get links => 'Links';
}
// Path: settings
class _StringsSettingsEn {
_StringsSettingsEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get settings => 'Settings';
String get disconnectFromServer => 'Disconnect from server';
}
// Path: <root>
class _StringsEs implements Translations {
/// You can call this constructor and build your own translation instance of this locale.
@@ -198,8 +229,28 @@ class _StringsEs implements Translations {
@override late final _StringsEs _root = this; // ignore: unused_field
// Translations
@override late final _StringsOnboardingEs onboarding = _StringsOnboardingEs._(_root);
@override late final _StringsConnectEs connect = _StringsConnectEs._(_root);
@override late final _StringsLinksEs links = _StringsLinksEs._(_root);
@override late final _StringsSettingsEs settings = _StringsSettingsEs._(_root);
}
// Path: onboarding
class _StringsOnboardingEs implements _StringsOnboardingEn {
_StringsOnboardingEs._(this._root);
@override final _StringsEs _root; // ignore: unused_field
// Translations
@override String get title => 'Bienvenido a My Linkding';
@override String get subtitle => 'Una aplicación para gestionar tus enlaces favoritos.';
@override String get start => 'Comenzar';
@override String get next => 'Siguiente';
@override String get previous => 'Anterior';
@override String get serverRequired => 'Servidor requerido';
@override String get serverRequiredDescription => 'My Linkding no es una aplicación independiente, requiere el servidor Linkding para funcionar.\nPara utilizar esta aplicación, debe instalar Linkding en su servidor doméstico, VPS o cualquier otro ordenador.';
@override String get installationInstructions => 'Mira las instrucciones de instalación en el repositorio oficial en GitHub.';
@override String get serverRunningConfirmation => 'Confirmo que tengo una instancia del servidor Linkding ya en funcionamiento.';
}
// Path: connect
@@ -224,16 +275,38 @@ class _StringsLinksEs implements _StringsLinksEn {
@override String get links => 'Enlaces';
}
// Path: settings
class _StringsSettingsEs implements _StringsSettingsEn {
_StringsSettingsEs._(this._root);
@override final _StringsEs _root; // ignore: unused_field
// Translations
@override String get settings => 'Ajustes';
@override String get disconnectFromServer => 'Desconectar del servidor';
}
/// Flat map(s) containing all translations.
/// Only for edge cases! For simple maps, use the map function of this library.
extension on Translations {
dynamic _flatMapFunction(String path) {
switch (path) {
case 'onboarding.title': return 'Welcome to My Linkding';
case 'onboarding.subtitle': return 'An application to manage your bookmarks.';
case 'onboarding.start': return 'Start';
case 'onboarding.next': return 'Next';
case 'onboarding.previous': return 'Previous';
case 'onboarding.serverRequired': return 'Servidor requerido';
case 'onboarding.serverRequiredDescription': return 'My Linkding it\'s not an standalone app, it requires the Linkding server to work.\nIn order to use this application, you must deploy Linkding on your home server, VPS or any other computer.';
case 'onboarding.installationInstructions': return 'Check the installation instructions on the official GitHub repository.';
case 'onboarding.serverRunningConfirmation': return 'I confirm that I have an instance of the Linkding server already running.';
case 'connect.connect': return 'Connect';
case 'connect.connecting': return 'Connecting...';
case 'connect.cannotConnectToServer': return 'Cannot connect to the server.';
case 'links.links': return 'Links';
case 'settings.settings': return 'Settings';
case 'settings.disconnectFromServer': return 'Disconnect from server';
default: return null;
}
}
@@ -242,10 +315,21 @@ extension on Translations {
extension on _StringsEs {
dynamic _flatMapFunction(String path) {
switch (path) {
case 'onboarding.title': return 'Bienvenido a My Linkding';
case 'onboarding.subtitle': return 'Una aplicación para gestionar tus enlaces favoritos.';
case 'onboarding.start': return 'Comenzar';
case 'onboarding.next': return 'Siguiente';
case 'onboarding.previous': return 'Anterior';
case 'onboarding.serverRequired': return 'Servidor requerido';
case 'onboarding.serverRequiredDescription': return 'My Linkding no es una aplicación independiente, requiere el servidor Linkding para funcionar.\nPara utilizar esta aplicación, debe instalar Linkding en su servidor doméstico, VPS o cualquier otro ordenador.';
case 'onboarding.installationInstructions': return 'Mira las instrucciones de instalación en el repositorio oficial en GitHub.';
case 'onboarding.serverRunningConfirmation': return 'Confirmo que tengo una instancia del servidor Linkding ya en funcionamiento.';
case 'connect.connect': return 'Conectar';
case 'connect.connecting': return 'Conectando...';
case 'connect.cannotConnectToServer': return 'No se puede conectar con el servidor.';
case 'links.links': return 'Enlaces';
case 'settings.settings': return 'Ajustes';
case 'settings.disconnectFromServer': return 'Desconectar del servidor';
default: return null;
}
}

View File

@@ -1,4 +1,15 @@
{
"onboarding": {
"title": "Welcome to My Linkding",
"subtitle": "An application to manage your bookmarks.",
"start": "Start",
"next": "Next",
"previous": "Previous",
"serverRequired": "Servidor requerido",
"serverRequiredDescription": "My Linkding it's not an standalone app, it requires the Linkding server to work.\nIn order to use this application, you must deploy Linkding on your home server, VPS or any other computer.",
"installationInstructions": "Check the installation instructions on the official GitHub repository.",
"serverRunningConfirmation": "I confirm that I have an instance of the Linkding server already running."
},
"connect": {
"connect": "Connect",
"connecting": "Connecting...",
@@ -6,5 +17,9 @@
},
"links": {
"links": "Links"
},
"settings": {
"settings": "Settings",
"disconnectFromServer": "Disconnect from server"
}
}

View File

@@ -1,4 +1,15 @@
{
"onboarding": {
"title": "Bienvenido a My Linkding",
"subtitle": "Una aplicación para gestionar tus enlaces favoritos.",
"start": "Comenzar",
"next": "Siguiente",
"previous": "Anterior",
"serverRequired": "Servidor requerido",
"serverRequiredDescription": "My Linkding no es una aplicación independiente, requiere el servidor Linkding para funcionar.\nPara utilizar esta aplicación, debe instalar Linkding en su servidor doméstico, VPS o cualquier otro ordenador.",
"installationInstructions": "Mira las instrucciones de instalación en el repositorio oficial en GitHub.",
"serverRunningConfirmation": "Confirmo que tengo una instancia del servidor Linkding ya en funcionamiento."
},
"connect": {
"connect": "Conectar",
"connecting": "Conectando...",
@@ -6,5 +17,9 @@
},
"links": {
"links": "Enlaces"
},
"settings": {
"settings": "Ajustes",
"disconnectFromServer": "Desconectar del servidor"
}
}

View File

@@ -18,4 +18,9 @@ class ApiClientProvider extends _$ApiClientProvider {
void setApiClient(ApiClient client) {
state = client;
}
void disconnectApiClient() {
state = null;
ref.read(serverInstancesProvider.notifier).removeServerInstances();
}
}

View File

@@ -6,7 +6,7 @@ part of 'api_client_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$apiClientProviderHash() => r'eff6aeacbfe369f2204d77f4884cc9d78ecf1e27';
String _$apiClientProviderHash() => r'8c44873c4e0758acfcd64b181134b80a43327f46';
/// See also [ApiClientProvider].
@ProviderFor(ApiClientProvider)

View File

@@ -12,7 +12,7 @@ GoRouter router(RouterRef ref) {
return GoRouter(
redirect: (context, state) {
if (ref.watch(apiClientProviderProvider) == null) {
return RoutesPaths.connect;
return RoutesPaths.onboarding;
}
return null;
},

View File

@@ -6,7 +6,7 @@ part of 'router_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$routerHash() => r'47e3f3d747dcb7b2543c73209f8a2f5561eb6ff7';
String _$routerHash() => r'78eb4c32cddebb29e3029e0eeaeb0f4c40d77012';
/// See also [router].
@ProviderFor(router)

View File

@@ -4,8 +4,6 @@ import 'package:my_linkding/config/shared_preferences_keys.dart';
import 'package:my_linkding/providers/shared_preferences_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:my_linkding/services/api_client.dart';
import 'package:my_linkding/providers/api_client_provider.dart';
import 'package:my_linkding/models/server_instance.dart';
part 'server_instances_provider.g.dart';
@@ -45,4 +43,9 @@ class ServerInstances extends _$ServerInstances {
final stringList = instances.map((i) => jsonEncode(i.toJson())).toList();
ref.read(sharedPreferencesProvider).setStringList(SharedPreferencesKeys.serversInstances, stringList);
}
void removeServerInstances() {
state = [];
ref.read(sharedPreferencesProvider).remove(SharedPreferencesKeys.serversInstances);
}
}

View File

@@ -6,7 +6,7 @@ part of 'server_instances_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$serverInstancesHash() => r'82b7d3367afbe5c19ad0238977e5df35fac3499b';
String _$serverInstancesHash() => r'ee41f5a717b9f779aa4319cc711b479a47c1c9ef';
/// See also [ServerInstances].
@ProviderFor(ServerInstances)

View File

@@ -1,5 +1,5 @@
class RoutesPaths {
static const connect = "/connect";
static const onboarding = "/onboarding";
static const links = "/links";
static const search = "/search";
static const settings = "/settings";

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:my_linkding/screens/connect/ui/connect.dart';
import 'package:my_linkding/screens/links/ui/links.dart';
import 'package:my_linkding/screens/onboarding/ui/onboarding.dart';
import 'package:my_linkding/screens/search/ui/search.dart';
import 'package:my_linkding/screens/settings/ui/settings.dart';
import 'package:my_linkding/widgets/layout.dart';
@@ -16,8 +16,8 @@ final settingsNavigatorKey = GlobalKey<NavigatorState>();
final List<RouteBase> appRoutes = [
GoRoute(
path: RoutesPaths.connect,
builder: (context, state) => const Connect(),
path: RoutesPaths.onboarding,
builder: (context, state) => const Onboarding(),
),
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) => Layout(

View File

@@ -6,7 +6,7 @@ part of 'connect_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$connectToServerHash() => r'af66fee9a4bf26aba08b27ff5a7fe4643215117a';
String _$connectToServerHash() => r'c40898fd5dd6dd7507140c7a69a6f336a56e30c0';
/// See also [connectToServer].
@ProviderFor(connectToServer)

View File

@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
class OnboardingModel {
final PageController pageController;
final bool confirmServerRunning;
OnboardingModel({
required this.pageController,
required this.confirmServerRunning,
});
OnboardingModel toggleConfirmServerRunning(bool newValue) => OnboardingModel(
pageController: pageController,
confirmServerRunning: newValue,
);
}

View File

@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:my_linkding/screens/onboarding/model/onboarding.model.dart';
part 'onboarding.provider.g.dart';
@riverpod
class Onboarding extends _$Onboarding {
@override
OnboardingModel build() {
return OnboardingModel(
pageController: PageController(),
confirmServerRunning: false,
);
}
void nextPage() {
state.pageController.nextPage(
duration: const Duration(milliseconds: 200),
curve: Curves.ease,
);
}
void previousPage() {
state.pageController.previousPage(
duration: const Duration(milliseconds: 200),
curve: Curves.ease,
);
}
void confirmServerRunning() {
state = state.toggleConfirmServerRunning(!state.confirmServerRunning);
}
}

View File

@@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'onboarding.provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$onboardingHash() => r'5c876d53acbca92ab15630516099700609aa4f89';
/// See also [Onboarding].
@ProviderFor(Onboarding)
final onboardingProvider =
AutoDisposeNotifierProvider<Onboarding, OnboardingModel>.internal(
Onboarding.new,
name: r'onboardingProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$onboardingHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$Onboarding = AutoDisposeNotifier<OnboardingModel>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:my_linkding/screens/onboarding/provider/onboarding.provider.dart';
import 'package:my_linkding/screens/onboarding/ui/server_required.dart';
import 'package:my_linkding/screens/onboarding/ui/welcome.dart';
import 'package:my_linkding/widgets/system_overlay_style.dart';
class Onboarding extends ConsumerWidget {
const Onboarding({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return OverlayStyle(
child: Scaffold(
body: SafeArea(
child: PageView(
controller: ref.watch(onboardingProvider).pageController,
physics: const NeverScrollableScrollPhysics(),
children: const [
OnboardingWelcome(),
OnboardingServerRequired(),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:my_linkding/screens/onboarding/provider/onboarding.provider.dart';
import 'package:my_linkding/i18n/strings.g.dart';
class OnboardingServerRequired extends ConsumerWidget {
const OnboardingServerRequired({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: ListView(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.dns_rounded,
size: 50,
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(height: 24),
Text(
t.onboarding.serverRequired,
style: const TextStyle(fontSize: 28),
),
const SizedBox(height: 8),
Text(
t.onboarding.serverRequiredDescription,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
Container(height: 24),
Card(
child: InkWell(
onTap: () => {},
borderRadius: BorderRadius.circular(10),
child: Padding(
padding: const EdgeInsets.all(24),
child: Row(
children: [
SvgPicture.asset(
'assets/resources/github.svg',
color: Theme.of(context).colorScheme.primary,
width: 40,
height: 40,
),
const SizedBox(width: 24),
Flexible(
child: Text(
t.onboarding.installationInstructions,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
),
),
const SizedBox(height: 8),
],
),
),
Column(
children: [
ListTile(
contentPadding: const EdgeInsets.all(8),
leading: Checkbox(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
value: ref.watch(onboardingProvider).confirmServerRunning,
onChanged: (_) => ref.read(onboardingProvider.notifier).confirmServerRunning(),
),
title: Text(
t.onboarding.serverRunningConfirmation,
style: const TextStyle(fontSize: 14),
),
onTap: () => ref.read(onboardingProvider.notifier).confirmServerRunning(),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
FilledButton(
onPressed: () => ref.read(onboardingProvider.notifier).previousPage(),
child: Row(
children: [
const Icon(Icons.arrow_back_rounded),
const SizedBox(width: 8),
Text(t.onboarding.previous),
],
),
),
FilledButton(
onPressed: ref.watch(onboardingProvider).confirmServerRunning == true
? () => ref.read(onboardingProvider.notifier).nextPage()
: null,
child: Row(
children: [
Text(t.onboarding.next),
const SizedBox(width: 8),
const Icon(Icons.arrow_forward_rounded),
],
),
),
],
),
],
),
],
),
);
}
}

View File

@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:my_linkding/i18n/strings.g.dart';
import 'package:my_linkding/screens/onboarding/provider/onboarding.provider.dart';
class OnboardingWelcome extends ConsumerWidget {
const OnboardingWelcome({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final iconSize = width > height ? height : width;
return Padding(
padding: const EdgeInsets.all(24),
child: Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 50,
height: 50,
color: Colors.red,
),
const SizedBox(height: 24),
Text(
t.onboarding.title,
style: const TextStyle(fontSize: 28),
),
const SizedBox(height: 8),
Text(
t.onboarding.subtitle,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(),
FilledButton(
onPressed: () => ref.read(onboardingProvider.notifier).nextPage(),
child: Row(
children: [
Text(t.onboarding.start),
const SizedBox(width: 8),
const Icon(Icons.arrow_forward_rounded),
],
),
),
],
),
],
),
Center(
child: Transform.rotate(
angle: 0.7,
child: Icon(
Icons.link_rounded,
size: iconSize - 48,
color: Theme.of(context).colorScheme.secondary.withOpacity(0.2),
),
),
),
],
),
);
}
}

View File

@@ -1,38 +1,28 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class Settings extends StatelessWidget {
import 'package:my_linkding/i18n/strings.g.dart';
import 'package:my_linkding/providers/api_client_provider.dart';
class Settings extends ConsumerWidget {
const Settings({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar.large(
pinned: true,
floating: true,
centerTitle: false,
forceElevated: innerBoxIsScrolled,
title: Text("Settings"),
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: Text(t.settings.settings),
),
body: ListView(
children: [
FilledButton.icon(
onPressed: () => ref.read(apiClientProviderProvider.notifier).disconnectApiClient(),
icon: const Icon(Icons.clear_rounded),
label: Text(
t.settings.disconnectFromServer,
),
),
],
body: SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
],
),
),
),
),
);
}

View File

@@ -315,6 +315,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.10"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
url: "https://pub.dev"
source: hosted
version: "2.0.10+1"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -373,6 +381,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.2.0"
http:
dependency: transitive
description:
name: http
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
url: "https://pub.dev"
source: hosted
version: "1.2.0"
http_multi_server:
dependency: transitive
description:
@@ -493,6 +509,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.3"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
url: "https://pub.dev"
source: hosted
version: "1.0.1"
path_provider_linux:
dependency: transitive
description:
@@ -517,6 +541,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "6.0.2"
platform:
dependency: transitive
description:
@@ -882,6 +914,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.3.3"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_math:
dependency: transitive
description:
@@ -938,6 +994,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
yaml:
dependency: transitive
description:

View File

@@ -45,6 +45,7 @@ dependencies:
uuid: ^4.3.3
slang: ^3.29.0
slang_flutter: ^3.29.0
flutter_svg: ^2.0.9
dev_dependencies:
build_runner: ^2.4.8
@@ -64,9 +65,9 @@ flutter:
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/resources/github.svg
- assets/resources/google-play.svg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware