real_ist_time 1.0.0 copy "real_ist_time: ^1.0.0" to clipboard
real_ist_time: ^1.0.0 copied to clipboard

Get accurate Indian Standard Time (IST) from multiple NTP servers and HTTP APIs with smart caching and automatic fallback. Independent of device clock settings.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:real_ist_time/real_ist_time.dart';
import 'dart:async';

void main() {
  runApp(const RealIstTimeExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Real IST Time Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  DateTime? _currentTime;
  String? _source;
  Duration? _latency;
  bool _fromCache = false;
  bool _isLoading = false;
  String? _errorMessage;
  Timer? _timer;
  Map<String, dynamic>? _cacheStats;

  @override
  void initState() {
    super.initState();
    _fetchTime();
    // Auto-refresh every second
    _timer = Timer.periodic(const Duration(seconds: 1), (_) {
      if (_currentTime != null && !_isLoading) {
        setState(() {
          _currentTime = _currentTime!.add(const Duration(seconds: 1));
        });
      }
    });
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  Future<void> _fetchTime() async {
    setState(() {
      _isLoading = true;
      _errorMessage = null;
    });

    try {
      final result = await RealIstTime.getIstTimeWithSource();
      setState(() {
        _currentTime = result.dateTime;
        _source = result.source;
        _latency = result.latency;
        _fromCache = result.fromCache;
        _cacheStats = RealIstTime.getCacheStatus();
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _errorMessage = e.toString();
        _isLoading = false;
      });
    }
  }

  Future<void> _testAllSources() async {
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => const Center(child: CircularProgressIndicator()),
    );

    try {
      final results = await RealIstTime.testAllSources();
      if (!mounted) return;

      Navigator.pop(context);

      showDialog(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('All Sources Test Results'),
          content: SizedBox(
            width: double.maxFinite,
            child: ListView.builder(
              shrinkWrap: true,
              itemCount: results.length,
              itemBuilder: (context, index) {
                final result = results[index];
                return ListTile(
                  leading: const Icon(Icons.check_circle, color: Colors.green),
                  title: Text(result.source),
                  subtitle: Text(
                    'Latency: ${result.latency.inMilliseconds}ms\n'
                    'Time: ${result.dateTime}',
                  ),
                );
              },
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Close'),
            ),
          ],
        ),
      );
    } catch (e) {
      if (!mounted) return;
      Navigator.pop(context);

      ScaffoldMessenger.of(
        context,
      ).showSnackBar(SnackBar(content: Text('Error: $e')));
    }
  }

  void _showConfigDialog() {
    showDialog(context: context, builder: (context) => const ConfigDialog());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Real IST Time'),
        actions: [
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: _showConfigDialog,
            tooltip: 'Configuration',
          ),
        ],
      ),
      body: Center(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // Main Time Display
              if (_isLoading)
                const CircularProgressIndicator()
              else if (_errorMessage != null)
                Column(
                  children: [
                    const Icon(Icons.error, color: Colors.red, size: 64),
                    const SizedBox(height: 16),
                    Text(
                      'Error',
                      style: Theme.of(context).textTheme.headlineSmall,
                    ),
                    const SizedBox(height: 8),
                    Text(
                      _errorMessage!,
                      textAlign: TextAlign.center,
                      style: const TextStyle(color: Colors.red),
                    ),
                  ],
                )
              else if (_currentTime != null)
                Column(
                  children: [
                    // Time Display
                    Container(
                      padding: const EdgeInsets.all(32),
                      decoration: BoxDecoration(
                        gradient: LinearGradient(
                          colors: [
                            Colors.deepPurple.shade700,
                            Colors.deepPurple.shade900,
                          ],
                        ),
                        borderRadius: BorderRadius.circular(24),
                        boxShadow: [
                          BoxShadow(
                            color: Colors.deepPurple.withValues(alpha: 0.3),
                            blurRadius: 20,
                            spreadRadius: 5,
                          ),
                        ],
                      ),
                      child: Column(
                        children: [
                          Text(
                            _formatTime(_currentTime!),
                            style: const TextStyle(
                              fontSize: 56,
                              fontWeight: FontWeight.bold,
                              letterSpacing: 2,
                            ),
                          ),
                          const SizedBox(height: 8),
                          Text(
                            _formatDate(_currentTime!),
                            style: TextStyle(
                              fontSize: 20,
                              color: Colors.white.withValues(alpha: 0.8),
                            ),
                          ),
                        ],
                      ),
                    ),

                    const SizedBox(height: 32),

                    // Source Info
                    Card(
                      child: Padding(
                        padding: const EdgeInsets.all(16),
                        child: Column(
                          children: [
                            _InfoRow(
                              icon: Icons.source,
                              label: 'Source',
                              value: _source ?? 'Unknown',
                            ),
                            const Divider(),
                            _InfoRow(
                              icon: Icons.speed,
                              label: 'Latency',
                              value: '${_latency?.inMilliseconds ?? 0}ms',
                            ),
                            const Divider(),
                            _InfoRow(
                              icon: Icons.cached,
                              label: 'From Cache',
                              value: _fromCache ? 'Yes' : 'No',
                            ),
                          ],
                        ),
                      ),
                    ),

                    // Cache Stats
                    if (_cacheStats != null) ...[
                      const SizedBox(height: 16),
                      Card(
                        child: Padding(
                          padding: const EdgeInsets.all(16),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'Cache Status',
                                style: Theme.of(context).textTheme.titleMedium,
                              ),
                              const SizedBox(height: 8),
                              Text('Valid: ${_cacheStats!['isValid']}'),
                              Text(
                                'Age: ${_cacheStats!['ageSeconds']} seconds',
                              ),
                            ],
                          ),
                        ),
                      ),
                    ],
                  ],
                ),

              const SizedBox(height: 32),

              // Action Buttons
              Wrap(
                spacing: 12,
                runSpacing: 12,
                alignment: WrapAlignment.center,
                children: [
                  ElevatedButton.icon(
                    onPressed: _isLoading ? null : _fetchTime,
                    icon: const Icon(Icons.refresh),
                    label: const Text('Refresh'),
                  ),
                  ElevatedButton.icon(
                    onPressed: _isLoading
                        ? null
                        : () {
                            RealIstTime.clearCache();
                            ScaffoldMessenger.of(context).showSnackBar(
                              const SnackBar(content: Text('Cache cleared')),
                            );
                            _fetchTime();
                          },
                    icon: const Icon(Icons.clear),
                    label: const Text('Clear Cache'),
                  ),
                  ElevatedButton.icon(
                    onPressed: _isLoading ? null : _testAllSources,
                    icon: const Icon(Icons.science),
                    label: const Text('Test All Sources'),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

  String _formatTime(DateTime time) {
    return '${time.hour.toString().padLeft(2, '0')}:'
        '${time.minute.toString().padLeft(2, '0')}:'
        '${time.second.toString().padLeft(2, '0')}';
  }

  String _formatDate(DateTime time) {
    const months = [
      'Jan',
      'Feb',
      'Mar',
      'Apr',
      'May',
      'Jun',
      'Jul',
      'Aug',
      'Sep',
      'Oct',
      'Nov',
      'Dec',
    ];
    return '${time.day} ${months[time.month - 1]} ${time.year}';
  }
}

class _InfoRow extends StatelessWidget {
  final IconData icon;
  final String label;
  final String value;

  const _InfoRow({
    required this.icon,
    required this.label,
    required this.value,
  });

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Icon(icon, size: 20),
        const SizedBox(width: 12),
        Text(label, style: const TextStyle(fontWeight: FontWeight.w500)),
        const Spacer(),
        Text(
          value,
          style: TextStyle(color: Colors.white.withValues(alpha: 0.7)),
        ),
      ],
    );
  }
}

class ConfigDialog extends StatefulWidget {
  const ConfigDialog({super.key});

  @override
  State<ConfigDialog> createState() => _ConfigDialogState();
}

class _ConfigDialogState extends State<ConfigDialog> {
  late bool _useNtp;
  late bool _useHttp;
  late bool _useCache;
  late int _cacheDuration;

  @override
  void initState() {
    super.initState();
    final config = RealIstTime.getConfig();
    _useNtp = config.useNtp;
    _useHttp = config.useHttp;
    _useCache = config.useCache;
    _cacheDuration = config.cacheDurationSeconds;
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text('Configuration'),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SwitchListTile(
            title: const Text('Use NTP'),
            subtitle: const Text('Google, Cloudflare, etc.'),
            value: _useNtp,
            onChanged: (value) => setState(() => _useNtp = value),
          ),
          SwitchListTile(
            title: const Text('Use HTTP APIs'),
            subtitle: const Text('timeapi.io, worldtimeapi.org'),
            value: _useHttp,
            onChanged: (value) => setState(() => _useHttp = value),
          ),
          SwitchListTile(
            title: const Text('Use Cache'),
            value: _useCache,
            onChanged: (value) => setState(() => _useCache = value),
          ),
          ListTile(
            title: const Text('Cache Duration'),
            subtitle: Slider(
              value: _cacheDuration.toDouble(),
              min: 10,
              max: 300,
              divisions: 29,
              label: '$_cacheDuration seconds',
              onChanged: (value) =>
                  setState(() => _cacheDuration = value.toInt()),
            ),
          ),
        ],
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: () {
            RealIstTime.configure(
              IstTimeConfig(
                useNtp: _useNtp,
                useHttp: _useHttp,
                useCache: _useCache,
                cacheDurationSeconds: _cacheDuration,
              ),
            );
            Navigator.pop(context);
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Configuration updated')),
            );
          },
          child: const Text('Apply'),
        ),
      ],
    );
  }
}
2
likes
160
points
3
downloads

Publisher

unverified uploader

Weekly Downloads

Get accurate Indian Standard Time (IST) from multiple NTP servers and HTTP APIs with smart caching and automatic fallback. Independent of device clock settings.

Repository (GitHub)
View/report issues

Topics

#time #ntp #ist #indian-time #timezone

Documentation

API reference

License

MIT (license)

Dependencies

http, ntp

More

Packages that depend on real_ist_time