A whole lot of stuff

This commit is contained in:
Courtney Arnold 2026-08-18 11:04:58 -05:00
parent faf319322a
commit ad850d2be6
50 changed files with 3013 additions and 213 deletions

178
lib/screens/faq_screen.dart Normal file
View file

@ -0,0 +1,178 @@
import 'package:flutter/material.dart';
class _FaqEntry {
final String question;
final String answer;
const _FaqEntry(this.question, this.answer);
}
class _FaqSection {
final String title;
final List<_FaqEntry> entries;
const _FaqSection(this.title, this.entries);
}
const _faqSections = <_FaqSection>[
_FaqSection('Missouri Motor Fuel Tax Refund', [
_FaqEntry(
'What is the Missouri Motor Fuel Tax Refund?',
'Missouri actually offers two separate fuel tax refunds — it\'s worth evaluating '
'both to see how you could benefit:\n\n'
'• Highway use — up to 12.5¢ per gallon.\n'
'• Non-highway use — up to 29.5¢ per gallon.\n\n'
"This app helps you collect and organize the receipts you'll need to claim "
"either one. This isn't tax advice — for guidance on which refund(s) fit your "
'situation, consult a tax professional. Rates and eligibility are set by '
'Missouri law, which can change at any time, so always confirm current details '
'with the Missouri Department of Revenue before filing.',
),
_FaqEntry(
'Is this app affiliated with the Missouri Department of Revenue?',
"No. This is an independent tool for organizing your own receipts — it isn't run by, "
"endorsed by, or connected to the State of Missouri. It doesn't file anything on "
'your behalf.',
),
_FaqEntry(
'How do I generate a report for my refund claim?',
"On the Reports tab, pick a date range to see your totals, then use Share or Print. "
"There's also a link to Missouri's official Motor Fuel Refund Claim form once "
"you're ready to file.",
),
]),
_FaqSection('Usage', [
_FaqEntry(
'How do I log a fuel purchase?',
"On the Receipts tab, tap the + button, snap a photo of the receipt, and the app "
'reads the date, gallons, and price automatically. Review (and correct, if '
'needed) the values before saving — every field stays editable both before and '
'after saving.',
),
_FaqEntry(
'What if the app misreads my receipt?',
'Automatic reading is usually accurate but not perfect — correct any field yourself '
'before saving, or edit it afterward from the entry\'s detail page.',
),
_FaqEntry(
"Found a receipt, VIN, or error the app couldn't handle?",
'Send it to ohbrer+ShowMeTheFuelRefund@gmail.com — example receipts or VINs that '
"didn't scan correctly, screenshots of error screens, or anything else that "
"didn't work as expected all help improve the app.",
),
_FaqEntry(
'Do I need to add a vehicle before logging a receipt?',
'Yes — every fuel entry is linked to a vehicle. Add one on the Vehicles tab first '
"(you'll need its VIN).",
),
]),
_FaqSection('Data Safety', [
_FaqEntry(
'Is my data backed up?',
'Not by default — everything you log lives only on this device until you connect a '
'cloud storage account (Settings > Data). Once connected, a copy is kept there '
'too, in storage you control.',
),
_FaqEntry(
'What cloud storage options are supported?',
'Google Drive, Dropbox, OneDrive, or your own WebDAV server (Nextcloud, ownCloud, or '
'any self-hosted WebDAV server).',
),
_FaqEntry(
"What happens if I lose my phone, or reinstall the app?",
"If you never connected cloud storage, that data is gone — it only ever lived on "
"that device. If you had connected one, reconnect the same account on the new "
"device (or after reinstalling) and your vehicles, receipts, and photos sync back "
'down automatically.',
),
_FaqEntry(
'How do I delete my data?',
'Settings > Data > Advanced has options to purge everything, or just fuel entries in '
"a specific date range. Both are permanent and can't be undone.",
),
]),
_FaqSection('Advertisements', [
_FaqEntry(
'Why do I sometimes see an ad?',
'Syncing your data to the cloud requires watching a short ad, to help support the '
"app — at most once every 5 minutes, so it won't show again if you sync "
'repeatedly in a short span.',
),
_FaqEntry(
'How do I remove ads?',
'"Remove Ads for a Year" in Settings is a one-time purchase that disables ads for a '
"year from when you buy it. It doesn't auto-renew or charge you again "
"automatically — once the year's up, ads come back until you buy again.",
),
]),
];
/// A simple, static list of common questions grouped into sections —
/// reached from [SettingsScreen] (and every tab's AppBar via
/// [FaqActionButton]), the "back up your data" reminder, and the
/// first-launch user agreement screen.
class FaqScreen extends StatelessWidget {
/// If given, that question's entry starts expanded (and the rest
/// collapsed) instead of everything starting collapsed — used when a
/// link elsewhere in the app points at one specific answer, e.g. the
/// backup reminder dialog jumping straight to the backup question rather
/// than making the user hunt for it.
final String? initiallyExpandedQuestion;
const FaqScreen({super.key, this.initiallyExpandedQuestion});
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: AppBar(title: const Text('FAQ')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
for (final section in _faqSections) ...[
Padding(
padding: const EdgeInsets.fromLTRB(4, 8, 4, 8),
child: Text(
section.title,
style: textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700),
),
),
for (final entry in section.entries)
Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Card(
child: ExpansionTile(
title: Text(entry.question, style: textTheme.titleSmall),
initiallyExpanded: entry.question == initiallyExpandedQuestion,
childrenPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
expandedCrossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(entry.answer, style: textTheme.bodyMedium),
],
),
),
),
const SizedBox(height: 8),
],
],
),
);
}
}
/// A "?" AppBar action that jumps straight to [FaqScreen] — added to every
/// tab's AppBar (Receipts, Vehicles, Reports, Settings; see [MainShell])
/// so help is reachable the same way no matter which screen the user's on.
class FaqActionButton extends StatelessWidget {
const FaqActionButton({super.key});
@override
Widget build(BuildContext context) {
return IconButton(
icon: const Icon(Icons.help_outline),
tooltip: 'FAQ',
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const FaqScreen()),
),
);
}
}