gvl_comments 0.9.7 copy "gvl_comments: ^0.9.7" to clipboard
gvl_comments: ^0.9.7 copied to clipboard

Add a comments section to any Flutter app (UI + managed backend). No Firebase/Supabase setup—just an install key.

example/lib/main.dart

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:gvl_comments/gvl_comments.dart';
import 'package:gvl_comments/l10n/gvl_comments_l10n.dart';
import 'package:shared_preferences/shared_preferences.dart';

// Public demo key for the example app only (bound to example package/bundle).
// You can override it at runtime with:
//   flutter run --dart-define=GVL_INSTALL_KEY="cmt_live_xxx"
const String _demoInstallKey = String.fromEnvironment(
  'GVL_INSTALL_KEY',
  defaultValue: 'cmt_live_EyuFlFVL682oiBVMealY2TfykRvJSDlF4Hbb8G2inhw',
);

// Example thread key.
// IMPORTANT: must be high-entropy in production (avoid guessable values like "post:123").
const String _demoThreadKey = 'demo:flutter.comments:5YqL4w8bQm9ZkF3R7sN2D';

/// Stable guest identity stored on the device/emulator.
const _kGuestIdKey = 'gvl_demo_guest_id';
const _kGuestNameKey = 'gvl_demo_guest_name';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await CommentsKit.initialize(installKey: _demoInstallKey);

  final user = await _loadGuestUser();

  runApp(DemoApp(user: user));
}

class DemoApp extends StatelessWidget {
  final UserProfile user;

  const DemoApp({super.key, required this.user});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'GVL Comments Demo',
      localizationsDelegates: GvlCommentsL10n.localizationsDelegates,
      supportedLocales: GvlCommentsL10n.supportedLocales,
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blueGrey,
          brightness: Brightness.light,
        ),
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blueGrey,
          brightness: Brightness.dark,
        ),
      ),
      themeMode: ThemeMode.dark,
      home: Builder(
        // IMPORTANT: this context is below MaterialApp, so Theme.of(context)
        // is the one we configured above.
        builder: (context) => DemoHome(initialUser: user),
      ),
    );
  }
}

class DemoHome extends StatefulWidget {
  final UserProfile initialUser;

  const DemoHome({super.key, required this.initialUser});

  @override
  State<DemoHome> createState() => _DemoHomeState();
}

class _DemoHomeState extends State<DemoHome> {
  late UserProfile _user = widget.initialUser;

  Future<void> _rerollGuest() async {
    final newUser = await _regenerateGuestUser();

    // Keep auth consistent when switching identities.
    CommentsKit.I().invalidateToken();
    await CommentsKit.I().identify(newUser);

    if (!mounted) return;
    setState(() => _user = newUser);
  }

  @override
  Widget build(BuildContext context) {
    final theme = GvlCommentsThemeData.bubble(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('GVL Comments · Flutter'),
        elevation: 0,
        actions: [
          IconButton(
            tooltip: 'New guest',
            icon: const Icon(Icons.casino),
            onPressed: _rerollGuest,
          ),
        ],
      ),
      body: CommentsList(
        threadKey: _demoThreadKey,
        limit: 10,
        user: _user,
        newestAtBottom: true,
        theme: theme,
      ),
    );
  }
}

Future<UserProfile> _loadGuestUser() async {
  final prefs = await SharedPreferences.getInstance();

  var id = prefs.getString(_kGuestIdKey);
  var name = prefs.getString(_kGuestNameKey);

  if (id == null || id.isEmpty || name == null || name.isEmpty) {
    final created = _createGuest();
    id = created.$1;
    name = created.$2;

    await prefs.setString(_kGuestIdKey, id);
    await prefs.setString(_kGuestNameKey, name);
  }

  return UserProfile(
    id: 'guest_$id',
    name: name,
    avatarUrl: 'https://api.dicebear.com/7.x/identicon/png?seed=$id',
  );
}

Future<UserProfile> _regenerateGuestUser() async {
  final prefs = await SharedPreferences.getInstance();

  final created = _createGuest();
  await prefs.setString(_kGuestIdKey, created.$1);
  await prefs.setString(_kGuestNameKey, created.$2);

  return UserProfile(
    id: 'guest_${created.$1}',
    name: created.$2,
    avatarUrl: 'https://api.dicebear.com/7.x/identicon/png?seed=${created.$1}',
  );
}

(String, String) _createGuest() {
  final rnd = Random();

  const animals = <String>[
    'Falcon',
    'Wolf',
    'Panther',
    'Raven',
    'Tiger',
    'Cobra',
    'Orca',
    'Lynx',
  ];

  const adjectives = <String>[
    'Swift',
    'Silent',
    'Bold',
    'Sharp',
    'Calm',
    'Fierce',
    'Brave',
    'Bright',
  ];

  final animal = animals[rnd.nextInt(animals.length)];
  final adj = adjectives[rnd.nextInt(adjectives.length)];
  final num = 10 + rnd.nextInt(90);

  final id = _randomId(10, rnd);
  final name = 'Guest $adj $animal-$num';

  return (id, name);
}

String _randomId(int len, Random rnd) {
  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  return List.generate(len, (_) => chars[rnd.nextInt(chars.length)]).join();
}
2
likes
150
points
578
downloads

Publisher

verified publishergoodvibeslab.cloud

Weekly Downloads

Add a comments section to any Flutter app (UI + managed backend). No Firebase/Supabase setup—just an install key.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

unknown (license)

Dependencies

crypto, flutter, flutter_localizations, http, intl, meta, package_info_plus, url_launcher

More

Packages that depend on gvl_comments

Packages that implement gvl_comments