Skip to main content

daybook_feedback 0.1.0 copy "daybook_feedback: ^0.1.0" to clipboard
daybook_feedback: ^0.1.0 copied to clipboard

In-app feedback for Flutter: shake, screenshot, a button or a two-finger long press opens a composer with a screenshot you can pin. Only for people approved in Daybook.

example/lib/main.dart

import 'package:daybook_feedback/daybook_feedback.dart';
import 'package:flutter/material.dart';

/// A small shop with Daybook feedback in it.
///
/// Run against your own project:
///   flutter run --dart-define=DAYBOOK_KEY=pmi_... --dart-define=DAYBOOK_EMAIL=you@example.com
/// and, for a local API, --dart-define=DAYBOOK_API=http://localhost:5099
///
/// The first run lands in the project's Reporters queue as Pending and shows nothing. Approve the
/// request in Daybook, restart, and the triggers the key has on start working.
const _key = String.fromEnvironment('DAYBOOK_KEY');
const _api = String.fromEnvironment('DAYBOOK_API', defaultValue: kDefaultApiUrl);
const _email = String.fromEnvironment('DAYBOOK_EMAIL', defaultValue: 'tester@example.com');

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await startFeedback();
  runApp(DaybookFeedback.wrap(const ShopApp()));
}

/// Kept separate so the integration test can start the same way.
Future<void> startFeedback() async {
  await DaybookFeedback.init(ingestKey: _key, apiUrl: _api, appVersion: '1.0.0');

  // In a real app: once you know who is signed in.
  await DaybookFeedback.identify(FeedbackIdentity(externalId: 'example:$_email', email: _email, name: 'Example tester'));
}

class ShopApp extends StatelessWidget {
  const ShopApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'Daybook feedback example',
        navigatorObservers: [DaybookFeedback.navigatorObserver],
        initialRoute: '/cart',
        routes: {
          '/cart': (_) => const CartPage(),
          '/profile': (_) => const ProfilePage(),
        },
      );
}

class CartPage extends StatelessWidget {
  const CartPage({super.key});

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Cart'), actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () => Navigator.of(context).pushNamed('/profile'),
          ),
        ]),
        body: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            const ListTile(title: Text('Blue mug'), trailing: Text('€12.00')),
            const ListTile(title: Text('Notebook'), trailing: Text('€8.50')),
            const Divider(),
            const ListTile(title: Text('Total'), trailing: Text('€20.50', key: ValueKey('total'))),
            const SizedBox(height: 16),
            KeyedSubtree(
              key: const ValueKey('pay-button'),
              child: FilledButton(onPressed: () {}, child: const Text('Pay now')),
            ),
            const SizedBox(height: 32),
            const _FeedbackStatus(),
          ],
        ),
      );
}

/// What the SDK thinks, for this demo. A real app would not show this to its users.
class _FeedbackStatus extends StatelessWidget {
  const _FeedbackStatus();

  @override
  Widget build(BuildContext context) => ValueListenableBuilder<HandshakeResult?>(
        valueListenable: DaybookFeedback.state,
        builder: (context, state, _) {
          final text = switch (state?.status) {
            null => 'Feedback: not connected',
            ReporterStatus.approved => 'Feedback: on (${state!.triggers.map((t) => t.wire).join(', ')})',
            ReporterStatus.pending => 'Feedback: waiting for approval in Daybook',
            ReporterStatus.blocked => 'Feedback: blocked',
            ReporterStatus.unknown => 'Feedback: unknown',
          };

          return Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
            Text(text, key: const ValueKey('feedback-status'), style: Theme.of(context).textTheme.bodySmall),
            if (state?.isActive ?? false)
              TextButton(
                key: const ValueKey('open-feedback'),
                onPressed: () => DaybookFeedback.open(),
                child: const Text('Send feedback'),
              ),
          ]);
        },
      );
}

class ProfilePage extends StatelessWidget {
  const ProfilePage({super.key});

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Profile')),
        body: const Center(child: Text('Streak: 40 days')),
      );
}
0
likes
0
points
491
downloads

Publisher

verified publisherdaybook.team

Weekly Downloads

In-app feedback for Flutter: shake, screenshot, a button or a two-finger long press opens a composer with a screenshot you can pin. Only for people approved in Daybook.

Homepage
Repository (GitLab)
View/report issues

License

unknown (license)

Dependencies

device_info_plus, flutter, http, package_info_plus, sensors_plus, shared_preferences

More

Packages that depend on daybook_feedback

Packages that implement daybook_feedback