added welcome page with terms of service
This commit is contained in:
parent
b92545f059
commit
c002291adf
7 changed files with 165 additions and 6 deletions
|
@ -8,6 +8,7 @@ import 'package:aves/widgets/album/collection_page.dart';
|
||||||
import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart';
|
import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart';
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
import 'package:aves/widgets/common/icons.dart';
|
||||||
import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
|
import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
|
||||||
|
import 'package:aves/widgets/welcome.dart';
|
||||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -26,9 +27,22 @@ void main() {
|
||||||
|
|
||||||
enum AppMode { main, pick, view }
|
enum AppMode { main, pick, view }
|
||||||
|
|
||||||
class AvesApp extends StatelessWidget {
|
class AvesApp extends StatefulWidget {
|
||||||
static AppMode mode = AppMode.main;
|
static AppMode mode = AppMode.main;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_AvesAppState createState() => _AvesAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AvesAppState extends State<AvesApp> {
|
||||||
|
Future<void> _appSetup;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_appSetup = settings.init();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
@ -50,7 +64,14 @@ class AvesApp extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
home: const HomePage(),
|
home: FutureBuilder(
|
||||||
|
future: _appSetup,
|
||||||
|
builder: (context, AsyncSnapshot<void> snapshot) {
|
||||||
|
if (snapshot.hasError) return const Icon(AIcons.error);
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return const SizedBox.shrink();
|
||||||
|
return settings.hasAcceptedTerms ? const HomePage() : const WelcomePage();
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +90,6 @@ class _HomePageState extends State<HomePage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
debugPrint('$runtimeType initState');
|
|
||||||
super.initState();
|
super.initState();
|
||||||
_appSetup = _setup();
|
_appSetup = _setup();
|
||||||
imageCache.maximumSizeBytes = 512 * (1 << 20);
|
imageCache.maximumSizeBytes = 512 * (1 << 20);
|
||||||
|
@ -93,8 +113,6 @@ class _HomePageState extends State<HomePage> {
|
||||||
// TODO notify when icons are ready for drawer and section header refresh
|
// TODO notify when icons are ready for drawer and section header refresh
|
||||||
await androidFileUtils.init(); // 170ms
|
await androidFileUtils.init(); // 170ms
|
||||||
|
|
||||||
await settings.init(); // <20ms
|
|
||||||
|
|
||||||
final intentData = await ViewerService.getIntentData();
|
final intentData = await ViewerService.getIntentData();
|
||||||
if (intentData != null) {
|
if (intentData != null) {
|
||||||
final action = intentData['action'];
|
final action = intentData['action'];
|
||||||
|
|
|
@ -20,6 +20,7 @@ class Settings {
|
||||||
static const collectionTileExtentKey = 'collection_tile_extent';
|
static const collectionTileExtentKey = 'collection_tile_extent';
|
||||||
static const infoMapZoomKey = 'info_map_zoom';
|
static const infoMapZoomKey = 'info_map_zoom';
|
||||||
static const catalogTimeZoneKey = 'catalog_time_zone';
|
static const catalogTimeZoneKey = 'catalog_time_zone';
|
||||||
|
static const hasAcceptedTermsKey = 'has_accepted_terms';
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
_prefs = await SharedPreferences.getInstance();
|
_prefs = await SharedPreferences.getInstance();
|
||||||
|
@ -69,6 +70,10 @@ class Settings {
|
||||||
|
|
||||||
set collectionTileExtent(double newValue) => setAndNotify(collectionTileExtentKey, newValue);
|
set collectionTileExtent(double newValue) => setAndNotify(collectionTileExtentKey, newValue);
|
||||||
|
|
||||||
|
bool get hasAcceptedTerms => getBoolOrDefault(hasAcceptedTermsKey, false);
|
||||||
|
|
||||||
|
set hasAcceptedTerms(bool newValue) => setAndNotify(hasAcceptedTermsKey, newValue);
|
||||||
|
|
||||||
// convenience methods
|
// convenience methods
|
||||||
|
|
||||||
bool getBoolOrDefault(String key, bool defaultValue) => _prefs.getKeys().contains(key) ? _prefs.getBool(key) : defaultValue;
|
bool getBoolOrDefault(String key, bool defaultValue) => _prefs.getKeys().contains(key) ? _prefs.getBool(key) : defaultValue;
|
||||||
|
|
15
lib/model/terms.dart
Normal file
15
lib/model/terms.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
const String termsAndConditions = '''
|
||||||
|
# Terms of Service
|
||||||
|
Aves is an open-source gallery and metadata explorer app allowing you to access and manage your local photos.
|
||||||
|
|
||||||
|
You must use the app for legal, authorized and acceptable purposes.
|
||||||
|
|
||||||
|
# Privacy policy
|
||||||
|
Aves does not collect any personal data in its standard use. We never have access to your photos and videos. This also means that we cannot get them back for you if you delete them without backing them up.
|
||||||
|
|
||||||
|
__We collect anonymous data to improve the app.__ We use Google Firebase for Analytics and Crash Reporting, and the anonymous analytics data are stored on their servers. Please note that those are anonymous data, there is absolutely nothing personal about those data.
|
||||||
|
|
||||||
|
## Links
|
||||||
|
[Sources](https://github.com/deckerst/aves)
|
||||||
|
''';
|
||||||
|
|
|
@ -107,6 +107,12 @@ class Constants {
|
||||||
licenseUrl: 'https://github.com/CaiJingLong/flutter_ijkplayer/blob/master/LICENSE',
|
licenseUrl: 'https://github.com/CaiJingLong/flutter_ijkplayer/blob/master/LICENSE',
|
||||||
sourceUrl: 'https://github.com/CaiJingLong/flutter_ijkplayer',
|
sourceUrl: 'https://github.com/CaiJingLong/flutter_ijkplayer',
|
||||||
),
|
),
|
||||||
|
Dependency(
|
||||||
|
name: 'Flutter Markdown',
|
||||||
|
license: 'BSD 3-Clause',
|
||||||
|
licenseUrl: 'https://github.com/flutter/flutter_markdown/blob/master/LICENSE',
|
||||||
|
sourceUrl: 'https://github.com/flutter/flutter_markdown',
|
||||||
|
),
|
||||||
Dependency(
|
Dependency(
|
||||||
name: 'Flutter Native Timezone',
|
name: 'Flutter Native Timezone',
|
||||||
license: 'Apache 2.0',
|
license: 'Apache 2.0',
|
||||||
|
|
100
lib/widgets/welcome.dart
Normal file
100
lib/widgets/welcome.dart
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import 'package:aves/main.dart';
|
||||||
|
import 'package:aves/model/settings.dart';
|
||||||
|
import 'package:aves/model/terms.dart';
|
||||||
|
import 'package:aves/widgets/common/aves_logo.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class WelcomePage extends StatefulWidget {
|
||||||
|
const WelcomePage();
|
||||||
|
|
||||||
|
@override
|
||||||
|
_WelcomePageState createState() => _WelcomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WelcomePageState extends State<WelcomePage> {
|
||||||
|
bool _hasAcceptedTerms = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final accentColor = Theme.of(context).accentColor;
|
||||||
|
return Scaffold(
|
||||||
|
body: SafeArea(
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const AvesLogo(size: 64),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Text(
|
||||||
|
'Welcome to Aves',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontFamily: 'Concourse',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Flexible(
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
color: Colors.white10,
|
||||||
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
child: MarkdownBody(
|
||||||
|
data: termsAndConditions,
|
||||||
|
onTapLink: (url) async {
|
||||||
|
if (await canLaunch(url)) {
|
||||||
|
await launch(url);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
), // const Text('Terms terms terms'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: Checkbox(
|
||||||
|
value: _hasAcceptedTerms,
|
||||||
|
onChanged: (v) => setState(() => _hasAcceptedTerms = v),
|
||||||
|
activeColor: accentColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TextSpan(
|
||||||
|
text: 'I accept the Terms of Service',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RaisedButton(
|
||||||
|
color: accentColor,
|
||||||
|
child: const Text('Continue'),
|
||||||
|
onPressed: _hasAcceptedTerms
|
||||||
|
? () {
|
||||||
|
settings.hasAcceptedTerms = true;
|
||||||
|
Navigator.pushAndRemoveUntil(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const HomePage(),
|
||||||
|
),
|
||||||
|
(route) => false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
16
pubspec.lock
16
pubspec.lock
|
@ -125,6 +125,13 @@ packages:
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.3.6"
|
version: "0.3.6"
|
||||||
|
flutter_markdown:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_markdown
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.1"
|
||||||
flutter_native_timezone:
|
flutter_native_timezone:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -212,6 +219,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.4"
|
version: "0.11.4"
|
||||||
|
markdown:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: markdown
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -555,4 +569,4 @@ packages:
|
||||||
version: "3.6.1"
|
version: "3.6.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.7.2 <3.0.0"
|
dart: ">=2.7.2 <3.0.0"
|
||||||
flutter: ">=1.16.3 <2.0.0"
|
flutter: ">=1.17.0 <2.0.0"
|
||||||
|
|
|
@ -53,6 +53,7 @@ dependencies:
|
||||||
path: ../flutter_ijkplayer
|
path: ../flutter_ijkplayer
|
||||||
# git:
|
# git:
|
||||||
# url: git://github.com/deckerst/flutter_ijkplayer.git
|
# url: git://github.com/deckerst/flutter_ijkplayer.git
|
||||||
|
flutter_markdown:
|
||||||
flutter_native_timezone:
|
flutter_native_timezone:
|
||||||
flutter_staggered_animations:
|
flutter_staggered_animations:
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
|
|
Loading…
Reference in a new issue