Improved onboarding
This commit is contained in:
4
lib/constants/urls.dart
Normal file
4
lib/constants/urls.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
class Urls {
|
||||
static const linkdingInstallationInstructions =
|
||||
"https://github.com/sissbruecker/linkding?tab=readme-ov-file#installation";
|
||||
}
|
||||
@@ -4,7 +4,9 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
import 'package:my_linkding/screens/onboarding/provider/onboarding.provider.dart';
|
||||
|
||||
import 'package:my_linkding/constants/urls.dart';
|
||||
import 'package:my_linkding/i18n/strings.g.dart';
|
||||
import 'package:my_linkding/utils/open_url.dart';
|
||||
|
||||
class OnboardingServerRequired extends ConsumerWidget {
|
||||
const OnboardingServerRequired({Key? key}) : super(key: key);
|
||||
@@ -18,22 +20,14 @@ class OnboardingServerRequired extends ConsumerWidget {
|
||||
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,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
const SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _Header(),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
t.onboarding.serverRequired,
|
||||
style: const TextStyle(fontSize: 28),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SliverList.list(
|
||||
children: [
|
||||
Text(
|
||||
t.onboarding.serverRequiredDescription,
|
||||
style: TextStyle(
|
||||
@@ -41,12 +35,10 @@ class OnboardingServerRequired extends ConsumerWidget {
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(height: 24),
|
||||
const SizedBox(height: 16),
|
||||
Card(
|
||||
child: InkWell(
|
||||
onTap: () => {},
|
||||
onTap: () => openUrl(Urls.linkdingInstallationInstructions),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
@@ -74,14 +66,9 @@ class OnboardingServerRequired extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
ListTile(
|
||||
contentPadding: const EdgeInsets.all(8),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
leading: Checkbox(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
@@ -95,7 +82,12 @@ class OnboardingServerRequired extends ConsumerWidget {
|
||||
),
|
||||
onTap: () => ref.read(onboardingProvider.notifier).confirmServerRunning(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@@ -125,8 +117,72 @@ class OnboardingServerRequired extends ConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const _minExent = 50.0;
|
||||
const _maxExent = 130.0;
|
||||
|
||||
const _iconMaxSize = 50;
|
||||
const _iconMinSize = 30;
|
||||
|
||||
const _textMaxSize = 28;
|
||||
const _textMinSize = 22;
|
||||
|
||||
const _textMaxTopPosition = 70;
|
||||
const _textMinTopPosition = 0;
|
||||
|
||||
const _textMaxLeftPosition = 0;
|
||||
const _textMinLeftPosition = 44;
|
||||
|
||||
class _Header extends SliverPersistentHeaderDelegate {
|
||||
const _Header();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
final iconPercentage = shrinkOffset.clamp(0, _maxExent - _minExent) / (_maxExent - _minExent);
|
||||
final textPercentage = shrinkOffset.clamp(0, _maxExent - _minExent) / (_maxExent - _minExent);
|
||||
|
||||
final iconSize = _iconMinSize + (_iconMaxSize - _iconMinSize) * (1 - iconPercentage);
|
||||
final textSize = _textMinSize + (_textMaxSize - _textMinSize) * (1 - textPercentage);
|
||||
final textTopPosition = _textMinTopPosition + (_textMaxTopPosition - _textMinTopPosition) * (1 - textPercentage);
|
||||
final textLeftPosition =
|
||||
_textMinLeftPosition + (_textMaxLeftPosition - _textMinLeftPosition) * (1 - textPercentage);
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
top: 0,
|
||||
child: Icon(
|
||||
Icons.dns_rounded,
|
||||
size: iconSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: textTopPosition,
|
||||
left: textLeftPosition,
|
||||
child: Text(
|
||||
t.onboarding.serverRequired,
|
||||
style: TextStyle(fontSize: textSize),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
double get maxExtent => _maxExent;
|
||||
|
||||
@override
|
||||
double get minExtent => _minExent;
|
||||
|
||||
@override
|
||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class OnboardingWelcome extends ConsumerWidget {
|
||||
t.onboarding.title,
|
||||
style: const TextStyle(fontSize: 28),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
t.onboarding.subtitle,
|
||||
style: TextStyle(
|
||||
|
||||
31
lib/utils/open_url.dart
Normal file
31
lib/utils/open_url.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart' as flutter_custom_tabs;
|
||||
import 'package:url_launcher/url_launcher.dart' as url_launcher;
|
||||
|
||||
void openUrl(String url) async {
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
try {
|
||||
await flutter_custom_tabs.launchUrl(
|
||||
Uri.parse(url),
|
||||
customTabsOptions: const flutter_custom_tabs.CustomTabsOptions(
|
||||
shareState: flutter_custom_tabs.CustomTabsShareState.browserDefault,
|
||||
urlBarHidingEnabled: true,
|
||||
showTitle: true,
|
||||
),
|
||||
safariVCOptions: const flutter_custom_tabs.SafariViewControllerOptions(
|
||||
barCollapsingEnabled: true,
|
||||
dismissButtonStyle: flutter_custom_tabs.SafariViewControllerDismissButtonStyle.close,
|
||||
),
|
||||
);
|
||||
} catch (e, stackTrace) {
|
||||
// Sentry.captureException(e, stackTrace: stackTrace);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
url_launcher.launchUrl(Uri.parse(url));
|
||||
} catch (e, stackTrace) {
|
||||
// Sentry.captureException(e, stackTrace: stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
pubspec.lock
40
pubspec.lock
@@ -294,6 +294,46 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_custom_tabs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_custom_tabs
|
||||
sha256: "961fe962ae55e9e41097c34e68c6d7d2de10e9a71034f83834919e31a891e728"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0+1"
|
||||
flutter_custom_tabs_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_custom_tabs_android
|
||||
sha256: "5701a3e38117dfc59e5fa9e84a29eea9203e0062de7be56d1f775845c34456d9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0+1"
|
||||
flutter_custom_tabs_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_custom_tabs_ios
|
||||
sha256: b29f687f7f366159d37347f888369fcd1259adac8ca6c7f07d356a80b091e08a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
flutter_custom_tabs_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_custom_tabs_platform_interface
|
||||
sha256: "13531a743486695d87b462b151801e11476b1b5a15274caec092420cc1943064"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
flutter_custom_tabs_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_custom_tabs_web
|
||||
sha256: "3114b511d3942ed42c502cc57ad47eaef9622ac06dd036e2b21b19d8876f6498"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
||||
@@ -46,6 +46,7 @@ dependencies:
|
||||
slang: ^3.29.0
|
||||
slang_flutter: ^3.29.0
|
||||
flutter_svg: ^2.0.9
|
||||
flutter_custom_tabs: ^2.0.0+1
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.8
|
||||
|
||||
Reference in New Issue
Block a user