import 'dart:io'; import 'package:app_review/app_review.dart'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, colorSchemeSeed: Colors.blueAccent, brightness: Brightness.light, ), darkTheme: ThemeData( useMaterial3: true, colorSchemeSeed: Colors.blueAccent, brightness: Brightness.dark, ), home: const HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({super.key}); @override State createState() => _HomePageState(); } class _HomePageState extends State { @override void initState() { super.initState(); AppReview.getAppId().then((onValue) { setState(() { appID = onValue ?? ''; }); log(onValue); }); } String appID = ""; final List _logs = []; bool _useAndroidTestMode = true; final testAppId = () { if (Platform.isAndroid) return 'com.google.android.googlequicksearchbox'; if (Platform.isIOS || Platform.isMacOS) return '640199958'; return null; }(); void log(String? message) { if (message != null) { debugPrint(message); setState(() { _logs.insert(0, message); }); } } @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ SliverAppBar.large( title: const Text('App Review'), centerTitle: true, ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (Platform.isAndroid) SwitchListTile( title: const Text('Use Android Test Mode'), subtitle: const Text('Uses FakeReviewManager'), value: _useAndroidTestMode, onChanged: (value) { setState(() { _useAndroidTestMode = value; }); }, ), _buildInfoCard( context, title: 'App ID', subtitle: appID.isEmpty ? 'Loading...' : appID, icon: Icons.info_outline, onTap: () { AppReview.getAppId().then(log); }, ), const SizedBox(height: 16), Text( 'Actions', style: Theme.of(context).textTheme.titleMedium?.copyWith( color: Theme.of(context).colorScheme.primary, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), _buildActionCard( context, title: 'View Store Page', subtitle: 'Open the app store listing for this app', icon: Icons.storefront, color: Colors.orange, onTap: () async { try { await AppReview.storeListing( appStoreId: (Platform.isIOS || Platform.isMacOS) ? testAppId : null, playStoreId: Platform.isAndroid ? testAppId : null, ); log('Opened Store Listing'); } catch (e) { log('Failed to open store listing: $e'); } }, ), const SizedBox(height: 12), _buildActionCard( context, title: 'Request Review', subtitle: 'Ask the user to rate the app', icon: Icons.star_rate_rounded, color: Colors.amber, onTap: () async { try { await AppReview.requestReview( useAndroidTestMode: _useAndroidTestMode, ); log('Requested Review'); } catch (e) { log('Request Review failed: $e'); } }, ), const SizedBox(height: 12), _buildActionCard( context, title: 'Write a New Review', subtitle: 'Navigate to the review page', icon: Icons.rate_review_outlined, color: Colors.green, onTap: () async { try { await AppReview.writeReview( appStoreId: (Platform.isIOS || Platform.isMacOS) ? testAppId : null, playStoreId: Platform.isAndroid ? testAppId : null, useAndroidTestMode: _useAndroidTestMode, ); log('Opened Write Review'); } catch (e) { log('Write Review failed: $e'); } }, ), const SizedBox(height: 24), Text( 'Log Output', style: Theme.of(context).textTheme.titleMedium?.copyWith( color: Theme.of(context).colorScheme.primary, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Container( height: 200, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: Theme.of(context).colorScheme.outlineVariant, ), ), child: _logs.isEmpty ? Center( child: Text( 'No logs yet', style: TextStyle( color: Theme.of(context).colorScheme.onSurface, ), ), ) : ListView.separated( padding: const EdgeInsets.all(8), itemCount: _logs.length, separatorBuilder: (context, index) => const Divider(height: 1), itemBuilder: (context, index) { return ListTile( dense: true, title: Text( _logs[index], style: TextStyle( fontFamily: 'monospace', fontSize: 12, color: Theme.of(context).colorScheme.onSurface, ), ), leading: const Icon(Icons.code, size: 16), ); }, ), ), ], ), ), ), ], ), ); } Widget _buildInfoCard( BuildContext context, { required String title, required String subtitle, required IconData icon, required VoidCallback onTap, }) { return Card( elevation: 0, color: Theme.of(context).colorScheme.secondaryContainer, child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ Icon( icon, color: Theme.of(context).colorScheme.onSecondaryContainer, size: 28, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: Theme.of(context).textTheme.labelLarge?.copyWith( color: Theme.of(context) .colorScheme .onSecondaryContainer .withValues(alpha: 0.8), ), ), const SizedBox(height: 4), Text( subtitle, style: Theme.of(context).textTheme.titleMedium?.copyWith( color: Theme.of(context) .colorScheme .onSecondaryContainer, fontWeight: FontWeight.bold, ), ), ], ), ), Icon( Icons.copy, size: 18, color: Theme.of(context) .colorScheme .onSecondaryContainer .withValues(alpha: 0.5), ), ], ), ), ), ); } Widget _buildActionCard( BuildContext context, { required String title, required String subtitle, required IconData icon, required Color color, required VoidCallback onTap, }) { return Card( elevation: 2, shadowColor: Colors.transparent, shape: RoundedRectangleBorder( side: BorderSide( color: Theme.of(context).colorScheme.outlineVariant, ), borderRadius: BorderRadius.circular(12), ), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: color.withValues(alpha: 0.1), shape: BoxShape.circle, ), child: Icon( icon, color: color, size: 24, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.outline, ), ), const SizedBox(height: 2), Text( subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.outline, ), ), ], ), ), Icon( Icons.chevron_right, color: Theme.of(context).colorScheme.outline, ), ], ), ), ), ); } }