From 7525bac5c09fd961e418f748de381c2f6869000f Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Mon, 3 Jun 2024 01:02:57 +0200 Subject: [PATCH] added landing page --- app/assets/landing/changelog.md | 1 + app/assets/landing/description.md | 13 +++ .../presentation/screens/browser.dart | 10 +- .../presentation/widgets/landing/action.dart | 93 +++++++++++++++++++ .../presentation/widgets/landing/content.dart | 66 +++++++++++++ app/pubspec.lock | 16 ++++ app/pubspec.yaml | 2 + 7 files changed, 197 insertions(+), 4 deletions(-) create mode 120000 app/assets/landing/changelog.md create mode 100644 app/assets/landing/description.md create mode 100644 app/lib/features/search_browser/presentation/widgets/landing/action.dart create mode 100644 app/lib/features/search_browser/presentation/widgets/landing/content.dart diff --git a/app/assets/landing/changelog.md b/app/assets/landing/changelog.md new file mode 120000 index 00000000..79b747ae --- /dev/null +++ b/app/assets/landing/changelog.md @@ -0,0 +1 @@ +../../../CHANGELOG.md \ No newline at end of file diff --git a/app/assets/landing/description.md b/app/assets/landing/description.md new file mode 100644 index 00000000..a9fe48d9 --- /dev/null +++ b/app/assets/landing/description.md @@ -0,0 +1,13 @@ +Welcome to Bang Navigator, a privacy-centric search and research browser designed to enhance your mobile search experience while ensuring your personal data and identity remains secure during research. Bang Navigator offers a seamless and intuitive interface, integrating the powerful tools of Kagi Search Engine. + +Bang Navigator is packed with a variety of features aimed at improving usability and maintaining privacy: + +- **Privacy by Default**: Incognito mode is enabled by default to keep your searches and browsing history private. +- **Full Browser Functionality**: Includes all the essential features of a basic browser to browse the web efficiently. +- **Kagi Integration**: Seamlessly integrates Kagi's search, assistant, and summarizer tools within a user-friendly interface. +- **Easy Sharing**: Share URLs or text from any app directly into Bang Navigator without the need to copy and paste, for direct use with summarizer/assistant. +- **Quick Summarization**: Long press any link on a website to get a summary via Kagi's summarizer. +- **Enhanced Text Interaction**: Custom context menu allows for easy passage of marked text to Kagi's search or assistant tools. +- **Home Widget**: Includes a home screen widget for quick actions, enhancing productivity. +- **Speech Input**: Supports voice commands for hands-free operation and accessibility. +- **PDF processing**: Open and directly summarize/prompt PDF documents. \ No newline at end of file diff --git a/app/lib/features/search_browser/presentation/screens/browser.dart b/app/lib/features/search_browser/presentation/screens/browser.dart index 688979f3..e6b53b3b 100644 --- a/app/lib/features/search_browser/presentation/screens/browser.dart +++ b/app/lib/features/search_browser/presentation/screens/browser.dart @@ -6,6 +6,7 @@ import 'package:bang_navigator/features/search_browser/domain/providers.dart'; import 'package:bang_navigator/features/search_browser/domain/services/create_tab.dart'; import 'package:bang_navigator/features/search_browser/domain/services/session.dart'; import 'package:bang_navigator/features/search_browser/presentation/widgets/app_bar_title.dart'; +import 'package:bang_navigator/features/search_browser/presentation/widgets/landing/content.dart'; import 'package:bang_navigator/features/search_browser/presentation/widgets/sheets/shared_content_sheet.dart'; import 'package:bang_navigator/features/search_browser/presentation/widgets/sheets/view_tabs_sheet.dart'; import 'package:bang_navigator/features/search_browser/presentation/widgets/tabs_action_button.dart'; @@ -306,10 +307,11 @@ class KagiScreen extends HookConsumerWidget { ), index: (activeWebView != null) ? webViews.keys - .toList() - .indexOf(activeWebView.page.value.key) - : null, - children: webViews.values.toList(), + .toList() + .indexOf(activeWebView.page.value.key) + + 1 + : 0, + children: [const LandingContent(), ...webViews.values], ), ); }, diff --git a/app/lib/features/search_browser/presentation/widgets/landing/action.dart b/app/lib/features/search_browser/presentation/widgets/landing/action.dart new file mode 100644 index 00000000..a203deec --- /dev/null +++ b/app/lib/features/search_browser/presentation/widgets/landing/action.dart @@ -0,0 +1,93 @@ +import 'package:bang_navigator/core/routing/routes.dart'; +import 'package:bang_navigator/features/search_browser/domain/entities/modes.dart'; +import 'package:bang_navigator/features/search_browser/domain/entities/sheet.dart'; +import 'package:bang_navigator/features/search_browser/domain/services/create_tab.dart'; +import 'package:bang_navigator/features/settings/data/repositories/settings_repository.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class LandingAction extends HookConsumerWidget { + const LandingAction({super.key}); + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = Theme.of(context); + + final sessionTokenAvailable = ref.watch( + settingsRepositoryProvider.select( + (value) => value.valueOrNull?.kagiSession?.isNotEmpty ?? false, + ), + ); + + return Visibility( + visible: sessionTokenAvailable, + replacement: Container( + margin: const EdgeInsets.symmetric(horizontal: 16.0), + decoration: BoxDecoration( + color: theme.colorScheme.errorContainer, + borderRadius: BorderRadius.circular(4.0), + ), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + Icons.warning, + size: 36, + color: theme.colorScheme.onErrorContainer, + ), + ), + Expanded( + child: Markdown( + shrinkWrap: true, + onTapLink: (text, href, title) async { + if (href == 'settings') { + await context.push(SettingsRoute().location); + } + }, + data: '## No Kagi Session Provided\n' + 'Please navigate to [Settings](settings) and enter your Kagi Session Token.\n' + "You must provide a valid session in order to use Kagi's features.", + ), + ), + ], + ), + ), + child: Wrap( + spacing: 8.0, + alignment: WrapAlignment.spaceEvenly, + children: [ + OutlinedButton.icon( + onPressed: () { + ref.read(createTabStreamProvider.notifier).createTab( + CreateTab(preferredTool: KagiTool.search), + ); + }, + icon: const Icon(MdiIcons.searchWeb), + label: const Text('Search'), + ), + OutlinedButton.icon( + onPressed: () { + ref.read(createTabStreamProvider.notifier).createTab( + CreateTab(preferredTool: KagiTool.assistant), + ); + }, + icon: const Icon(MdiIcons.brain), + label: const Text('Assistant'), + ), + OutlinedButton.icon( + onPressed: () { + ref.read(createTabStreamProvider.notifier).createTab( + CreateTab(preferredTool: KagiTool.summarizer), + ); + }, + icon: const Icon(MdiIcons.text), + label: const Text('Summarizer'), + ), + ], + ), + ); + } +} diff --git a/app/lib/features/search_browser/presentation/widgets/landing/content.dart b/app/lib/features/search_browser/presentation/widgets/landing/content.dart new file mode 100644 index 00000000..9f1a25dd --- /dev/null +++ b/app/lib/features/search_browser/presentation/widgets/landing/content.dart @@ -0,0 +1,66 @@ +import 'package:bang_navigator/features/search_browser/presentation/widgets/landing/action.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show rootBundle; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class LandingContent extends HookConsumerWidget { + const LandingContent({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final textTheme = Theme.of(context).textTheme; + + // ignore: discarded_futures + final descriptionAssetFuture = useMemoized( + () async => rootBundle.loadString('assets/landing/description.md'), + ); + final descriptionAsset = useFuture(descriptionAssetFuture); + + // ignore: discarded_futures + final changelogAssetFuture = useMemoized( + () async => rootBundle.loadString('assets/landing/changelog.md'), + ); + final changelogAsset = useFuture(changelogAssetFuture); + + return SingleChildScrollView( + child: Column( + children: [ + Text( + 'BangNavigator', + style: textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ), + Text( + 'A Privacy-Focused Browser for Kagi', + style: textTheme.titleMedium, + textAlign: TextAlign.center, + ), + FractionallySizedBox( + widthFactor: 0.5, + child: Image.asset('assets/icon/icon.png'), + ), + const LandingAction(), + Markdown( + data: descriptionAsset.data ?? '', + selectable: true, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + ), + Text( + 'Changelog', + style: textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ), + Markdown( + data: changelogAsset.data ?? '', + selectable: true, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + ), + ], + ), + ); + } +} diff --git a/app/pubspec.lock b/app/pubspec.lock index c7f31196..488721aa 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -406,6 +406,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.1" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f" + url: "https://pub.dev" + source: hosted + version: "0.7.1" flutter_material_design_icons: dependency: "direct main" description: @@ -651,6 +659,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + url: "https://pub.dev" + source: hosted + version: "7.2.2" matcher: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 9b9243d5..fb6788e8 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: sdk: flutter flutter_hooks: ^0.20.5 flutter_inappwebview: ^6.0.0 + flutter_markdown: ^0.7.1 flutter_material_design_icons: ^1.1.7447 flutter_pdf_text: ^0.6.0 flutter_secure_storage: ^9.0.0 @@ -57,6 +58,7 @@ flutter: uses-material-design: true assets: - assets/icon/icon.png + - assets/landing/ flutter_launcher_icons: android: "launcher_icon"