MO-Fuel-Tax-Back/lib/screens/user_agreement_screen.dart

177 lines
8.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../services/app_state.dart';
import 'faq_screen.dart';
/// The very first thing shown on a fresh install — before the onboarding
/// tour, before anything else — gating [MainShell] entirely until the user
/// taps "I Agree" (see [AppRoot] in main.dart and
/// [AppState.hasAcceptedUserAgreement]/[AppState.acceptUserAgreement]).
/// Its whole purpose is the liability section below: this app stores data
/// on the user's own device (and, optionally, their own cloud storage
/// account) with no server or backend of ours involved, so we have no
/// ability to recover anything for them if it's lost — plus the privacy
/// section, disclosing that we don't track/log anything ourselves, and
/// that AdMob (only active for users on the free, ad-supported tier) is
/// the sole source of any data collection, governed by Google's own
/// practices rather than anything this app adds.
class UserAgreementScreen extends StatelessWidget {
/// True when reached from Settings (see [SettingsScreen]) to re-read the
/// agreement/privacy policy at any time — required so this content stays
/// reachable in the app beyond the one-time first-launch gate, not just
/// something a user saw once and can never get back to. Hides the
/// Decline/I Agree actions (already answered, and "Decline" quitting the
/// app would be a bizarre side effect of just re-reading this) and shows
/// a normal back button instead of gating navigation away entirely.
final bool isReview;
const UserAgreementScreen({super.key, this.isReview = false});
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: AppBar(
title: const Text('User Agreement'),
automaticallyImplyLeading: isReview,
),
body: SafeArea(
child: Column(
children: [
Expanded(
child: ListView(
padding: const EdgeInsets.all(20),
children: [
Text(
isReview
? 'This is the agreement you accepted when you first opened Show Me '
'The Fuel Refund.'
: 'Please read and accept the following before using Show Me The Fuel '
'Refund.',
style: textTheme.bodyLarge,
),
const SizedBox(height: 20),
_Section(
title: 'Your Data Lives on Your Device',
body:
'Every vehicle, fuel receipt, and photo you log is stored locally on '
'this device. If you connect a cloud storage account (Google Drive, '
'Dropbox, OneDrive, or your own WebDAV server) in Settings, a copy is '
'also kept there — in storage you control, not on any server we run. '
"We don't operate a backend, and we don't have a copy of your data.",
),
_Section(
title: 'Privacy',
body:
"We don't track or log your data in any way — there's no analytics, no "
"crash reporting, and no server of ours receiving anything you enter. If "
'you haven\'t purchased "Remove Ads for a Year" and are using the free, '
'ad-supported version, the only data collected is whatever Google AdMob '
'itself requires to serve ads (e.g. a device advertising identifier) — '
"that collection is Google's, governed by its own privacy practices, not "
'something this app adds on top of.',
),
_Section(
title: 'We Are Not Responsible for Your Data or Any Data Loss',
body:
'The developer is not responsible for your data, or for any loss, '
'corruption, or unavailability of it, for any reason — including but '
'not limited to device loss, theft, or damage; an uninstall or app/OS '
'update; a bug in this app; or an outage or account issue with a cloud '
'storage provider you connect. Backing up your data (by connecting a '
'cloud storage account, and by keeping it connected and in good '
'standing) is entirely your responsibility. If you never connect a '
'backup, the only copy of your data is the one on this device.',
),
_Section(
title: 'Provided As-Is',
body:
'This app is provided "as is," without warranty of any kind, express or '
'implied. Fuel and gallon values are read automatically from your '
'receipt photos and may be misread — always review them before relying '
'on them, including for a refund claim.',
),
_Section(
title: 'Not Tax or Legal Advice',
body:
'This app is purely informational. Missouri actually offers two '
'separate fuel tax refunds — up to 12.5¢ per gallon for highway use, '
"and up to 29.5¢ per gallon for non-highway use — and it's worth "
"evaluating both to see how you could benefit. This app helps you "
"organize the receipts you'd need for either one.\n\n"
"Nothing here is tax or legal advice, and using this app doesn't "
'guarantee your eligibility for either refund. For guidance on your '
'specific situation, consult a tax professional. Both refunds are set '
'by Missouri law, which can change at any time — always confirm '
'current eligibility and rates with the Missouri Department of '
'Revenue before filing.',
),
Align(
alignment: Alignment.centerLeft,
child: TextButton.icon(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const FaqScreen()),
),
icon: const Icon(Icons.help_outline),
label: const Text('See the FAQ for more'),
),
),
const SizedBox(height: 8),
],
),
),
if (!isReview) ...[
const Divider(height: 1),
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => SystemNavigator.pop(),
child: const Text('Decline'),
),
),
const SizedBox(width: 12),
Expanded(
child: FilledButton(
onPressed: () => context.read<AppState>().acceptUserAgreement(),
child: const Text('I Agree'),
),
),
],
),
),
],
],
),
),
);
}
}
class _Section extends StatelessWidget {
final String title;
final String body;
const _Section({required this.title, required this.body});
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700)),
const SizedBox(height: 6),
Text(body, style: textTheme.bodyMedium),
],
),
);
}
}