zkfinger10 1.0.0+2 copy "zkfinger10: ^1.0.0+2" to clipboard
zkfinger10: ^1.0.0+2 copied to clipboard

PlatformAndroid

The zk_finger10 plugin is used for supporting fingerprint device of ZKTECO with enrolling and verification feature.

example/lib/main.dart

// ignore_for_file: prefer_const_constructors

import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:uuid/uuid.dart';

import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:zkfinger10/finger_status.dart';
import 'package:zkfinger10/finger_status_type.dart';
import 'package:zkfinger10/zk_finger.dart';
import 'package:zkfinger10_example/network_info.dart';

import 'functions.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MaterialApp(home: MyApp()));
}

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

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final GlobalKey<ScaffoldMessengerState> _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
  String? _platformVersion = 'Unknown';

  final TextEditingController _registerationCodeController =
  TextEditingController(text: "MAMASODIKOV");
  final TextEditingController _biometricController =
  TextEditingController(text: "Here will display base64 finger template");
  final TextEditingController _sendUrlController = TextEditingController();
  final TextEditingController _idleText1 =
  TextEditingController(text: "Copy base64 to verify");
  final TextEditingController _idleText2 =
  TextEditingController(text: "Copy base64 to verify");
  String sendUrl = 'https://google.com/';
  String base64Image = 'base64isNotGenerated';

  String? score;
  String? message;
  Map<String, String> users = {};

  // New state variables for enhanced features
  Map<String, String> databaseUsers = {};
  int databaseUserCount = 0;
  final TextEditingController _exportUrlController = TextEditingController(
      text: "https://68d98bdb90a75154f0daa3f8.mockapi.io/api/data"
  );
  final TextEditingController _importUrlController = TextEditingController(
      text: "https://68d98bdb90a75154f0daa3f8.mockapi.io/api/data"
  );
  bool _isLoadingFromUrl = false;
  bool _isExporting = false;
  bool _isLoadingDatabase = false;

  @override
  void dispose() {
    ZkFinger.onDestroy();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    initPlatformState();
    _refreshDatabaseInfo();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String? platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      platformVersion = await ZkFinger.platformVersion;
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }
    ZkFinger.imageStream.receiveBroadcastStream().listen(mapFingerImage);
    ZkFinger.statusChangeStream.receiveBroadcastStream().listen(updateStatus);

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  Uint8List? fingerImages;
  String statusText = '';
  String stringLengthBytes = '';

  FingerStatus? fingerStatus;
  FingerStatusType? tempStatusType;
  bool? isDeviceSupported;

  void updateStatus(dynamic value) {
    Map<dynamic, dynamic> statusMap = value as Map<dynamic, dynamic>;
    FingerStatusType statusType =
    FingerStatusType.values[statusMap['fingerStatus']];
    fingerStatus = FingerStatus(
        statusMap['message'], statusType, statusMap['id'], statusMap['data']);

    print(fingerStatus?.message);

    if (statusType == tempStatusType &&
        tempStatusType == FingerStatusType.CAPTURE_ERROR) {
      //ignore capture error when finger device get stuck
      statusText = 'CAPTURE ERROR';
    } else {
      tempStatusType = statusType;
      setState(() {
        setBiometricBase64TextField();
        statusText = statusType.toString();
      });
    }
  }

  void setBiometricBase64TextField() {
    if (fingerStatus?.statusType == FingerStatusType.ENROLL_SUCCESS) {
      resetFieldsData();
      _biometricController.text = fingerStatus?.data ?? 'null';
      message = '${fingerStatus?.id} enroll';
    } else if (fingerStatus?.statusType ==
        FingerStatusType.ENROLL_ALREADY_EXIST) {
      resetFieldsData();
      score = fingerStatus?.data;
      message = '${fingerStatus!.id} already enrolled';
    } else if (fingerStatus?.statusType == FingerStatusType.FINGER_EXTRACTED) {
      resetFieldsData();
      _biometricController.text = fingerStatus?.data ?? 'null';
      message = fingerStatus?.message;
    } else if (fingerStatus!.statusType ==
        FingerStatusType.IDENTIFIED_SUCCESS) {
      resetFieldsData();
      message = '${fingerStatus?.id} identified';
      score = fingerStatus?.data;
    } else if (fingerStatus!.statusType == FingerStatusType.IDENTIFIED_FAILED) {
      resetFieldsData();
      message = 'User identify failed';
      score = fingerStatus?.data;
    } else if (fingerStatus?.statusType == FingerStatusType.VERIFIED_SUCCESS) {
      resetFieldsData();
      message = 'Given templates are verified';
      score = fingerStatus?.data;
    } else if (fingerStatus?.statusType == FingerStatusType.VERIFIED_FAILED) {
      resetFieldsData();
      message = 'Verify failed';
      score = fingerStatus?.data;
    } else if (fingerStatus?.statusType == FingerStatusType.ENROLL_STARTED) {
      resetFieldsData();
      message = '${fingerStatus?.id} confirm';
      _biometricController.text = 'Current Confirm Index ${fingerStatus?.data}';
    } else if (fingerStatus?.statusType == FingerStatusType.ENROLL_CONFIRM) {
      resetFieldsData();
      message = '${fingerStatus?.id} confirm';
      _biometricController.text = 'Current Confirm Index ${fingerStatus?.data}';
    } else {
      resetFieldsData();
    }
    stringLengthBytes = 'Text Size: ${_biometricController.text.length} bytes';
    statusText = '$statusText$stringLengthBytes\n';
  }

  void resetFieldsData() {
    // _biometricController.text = '---';
    message = '---';
    score = '---';
  }

  String uint8ListTob64(Uint8List uint8list) {
    String base64String = base64Encode(uint8list);
    String header = "data:image/png;base64,";
    return header + base64String;
  }

  void mapFingerImage(dynamic imageBytes) {
    setState(() {
      try {
        fingerImages = imageBytes;
        base64Image = uint8ListTob64(fingerImages!);
        print('========= BASE64_IMAGE: $base64Image');
      } catch (e) {
        print(e);
      }
    });
  }

  // New methods for enhanced functionality
  Future<void> _exportAllUsers() async {
    if (_exportUrlController.text.trim().isEmpty) {
      _showMessage('Please enter a valid export URL');
      return;
    }

    setState(() {
      _isExporting = true;
    });

    try {
      // Get all users from database
      final allUsers = await ZkFinger.getAllUsers();
      final userCount = await ZkFinger.getUserCount();

      if (allUsers == null || allUsers.isEmpty) {
        if (mounted) {
          _showMessage('No users found in database to export');
        }
        return;
      }

      // Prepare export data
      final exportData = {
        'users': allUsers,
        'exportedAt': DateTime.now().toIso8601String(),
      };

      // Send POST request to export URL
      final dio = Dio();
      final response = await dio.post(
        _exportUrlController.text.trim(),
        data: exportData,
        options: Options(
          headers: {
            'Content-Type': 'application/json',
          },
        ),
      );

      print(response);

      if (response.statusCode == 200 || response.statusCode == 201) {
        if (mounted) {
          _showMessage('Successfully exported ${allUsers.length} users to URL');
          _refreshDatabaseInfo();
        }
      } else {
        if (mounted) {
          _showMessage('Failed to export data: ${response.statusCode}');
        }
      }
    } catch (e) {
      if (mounted) {
        _showMessage('Export error: $e');
      }
    } finally {
      setState(() {
        _isExporting = false;
      });
    }
  }

  Future<void> _importFromUrl() async {
    if (_importUrlController.text.trim().isEmpty) {
      if (mounted) {
        _showMessage('Please enter a valid import URL');
      }
      return;
    }

    setState(() {
      _isLoadingFromUrl = true;
    });

    try {
      final dio = Dio();
      final response = await dio.get(_importUrlController.text.trim());

      print(response.data);

      if (response.statusCode == 200) {
        final data = response.data;
        print('Response data type: ${data.runtimeType}');

        final Map<String, String> loadedUsers = {};

        // Handle different response formats
        if (data is List) {
          // Handle array format: [{"users": {...}}, {"users": {...}}]
          print('Processing array of ${data.length} items');
          for (var item in data) {
            if (item is Map && item.containsKey('users')) {
              final usersData = item['users'];
              if (usersData is Map) {
                usersData.forEach((key, value) {
                  final userId = key.toString();
                  final template = value.toString();
                  loadedUsers[userId] = template;
                });
              }
            }
          }
        } else if (data is Map && data.containsKey('users')) {
          // Handle single object format: {"users": {...}}
          print('Processing single object');
          final usersData = data['users'];
          if (usersData is Map) {
            usersData.forEach((key, value) {
              final userId = key.toString();
              final template = value.toString();
              loadedUsers[userId] = template;
            });
          }
        } else {
          print('Data validation failed:');
          print('- data is List: ${data is List}');
          print('- data is Map: ${data is Map}');
          if (data is Map) {
            print('- data contains users: ${(data as Map).containsKey('users')}');
            print('- data keys: ${(data as Map).keys.toList()}');
          }
          if (mounted) {
            _showMessage('Invalid data format. Expected array of objects or single object with "users" key');
          }
          return;
        }

        print('Total loaded users: ${loadedUsers.length}');
          
          if (loadedUsers.isNotEmpty) {
            final success = await ZkFinger.clearAndLoadDatabase(vUserList: loadedUsers);
            if (success == true) {
              if (mounted) {
                _showMessage('Successfully imported ${loadedUsers.length} users from URL');
                _refreshDatabaseInfo();
              }
            } else {
              if (mounted) {
                _showMessage('Failed to load users to database');
              }
            }
          } else {
            if (mounted) {
              _showMessage('No users found in URL response');
            }
          }

      } else {
        if (mounted) {
          _showMessage('Failed to fetch data from URL: ${response.statusCode}');
        }
      }
    } catch (e) {
      print('Import error: $e');
      if (mounted) {
        _showMessage('Import error: $e');
      }
    } finally {
      setState(() {
        _isLoadingFromUrl = false;
      });
    }
  }

  Future<void> _refreshDatabaseInfo() async {
    setState(() {
      _isLoadingDatabase = true;
    });

    try {
      final allUsers = await ZkFinger.getAllUsers();
      final userCount = await ZkFinger.getUserCount();

      setState(() {
        databaseUsers = allUsers ?? {};
        databaseUserCount = userCount ?? 0;
      });
    } catch (e) {
      print('Error refreshing database info: $e');
    } finally {
      setState(() {
        _isLoadingDatabase = false;
      });
    }
  }

  void _showDatabaseUsersDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Current Database Users'),
          content: SizedBox(
            width: double.maxFinite,
            height: 400,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'Total Users: $databaseUserCount',
                  style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
                ),
                const SizedBox(height: 5),
                const Text(
                  'User List:',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                const SizedBox(height: 8),
                Expanded(
                  child: databaseUsers.isEmpty
                      ? const Center(child: Text('No users in database'))
                      : ListView.builder(
                    itemCount: databaseUsers.length,
                    itemBuilder: (context, index) {
                      final userId = databaseUsers.keys.elementAt(index);
                      final template = databaseUsers[userId]!;
                      return Card(
                        margin: const EdgeInsets.symmetric(vertical: 2),
                        child: ListTile(
                          leading: CircleAvatar(
                            child: Text('${index + 1}'),
                          ),
                          title: Text(
                            'User ID: $userId',
                            style: const TextStyle(fontWeight: FontWeight.bold),
                          ),
                          subtitle: Text(
                            'Template: ${template.length > 50 ? '${template.substring(0, 50)}...' : template}',
                            style: const TextStyle(fontSize: 12, fontFamily: 'monospace'),
                          ),
                          trailing: IconButton(
                            icon: const Icon(Icons.copy),
                            onPressed: () {
                              Clipboard.setData(ClipboardData(text: template));
                              if (mounted) {
                                _showMessage('Template copied to clipboard');
                              }
                            },
                          ),
                        ),
                      );
                    },
                  ),
                ),
              ],
            ),
          ),
          actionsPadding: EdgeInsets.zero,
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('Close'),
            ),
            ElevatedButton(
              onPressed: () {
                final jsonData = jsonEncode({
                  'users': databaseUsers,
                  'exportedAt': DateTime.now().toIso8601String(),
                });
                Clipboard.setData(ClipboardData(text: jsonData));
                if (mounted) {
                  _showMessage('Database data copied to clipboard');
                }
              },
              child: const Text('Copy as JSON'),
            ),
          ],
        );
      },
    );
  }

  void _showMessage(String message) {
    if (mounted && _scaffoldMessengerKey.currentState != null) {
      _scaffoldMessengerKey.currentState!.showSnackBar(
        SnackBar(
          content: Text(message),
          duration: const Duration(seconds: 3),
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations([
      // DeviceOrientation.landscapeLeft,
      // DeviceOrientation.landscapeRight,
    ]);

    return MaterialApp(
      scaffoldMessengerKey: _scaffoldMessengerKey,
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.indigo,
          brightness: Brightness.light,
        ),
        cardTheme: CardThemeData(
          elevation: 4,
          shape:
          RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
        ),
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            elevation: 2,
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
            shape:
            RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
          ),
        ),
      ),
      home: Scaffold(
        resizeToAvoidBottomInset: false,
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.primary,
          foregroundColor: Theme.of(context).colorScheme.onPrimary,
          title: const Text(
            'ZKFinger10 Professional Dashboard',
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
          centerTitle: true,
          elevation: 0,
        ),
        body: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [
                Theme.of(context).colorScheme.primary.withOpacity(0.05),
                Theme.of(context).colorScheme.secondary.withOpacity(0.05),
              ],
            ),
          ),
          child: SingleChildScrollView(
            scrollDirection: Axis.vertical,
            padding: const EdgeInsets.all(8),
            child: SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: ConstrainedBox(
                constraints: BoxConstraints(
                  minWidth: MediaQuery.of(context).size.width,
                  minHeight: MediaQuery.of(context).size.height - 100,
                ),
                child: IntrinsicHeight(
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: <Widget>[
                      // Control Panel
                      SizedBox(
                          width: 180,
                          child: Card(
                              child: Padding(
                                padding: const EdgeInsets.all(12),
                                child: SingleChildScrollView(
                                  child: Column(
                                    mainAxisSize: MainAxisSize.min,
                                    crossAxisAlignment: CrossAxisAlignment.start,
                                    children: <Widget>[
                                      Text(
                                        'Device Control',
                                        style: Theme.of(context)
                                            .textTheme
                                            .titleMedium
                                            ?.copyWith(
                                          fontWeight: FontWeight.bold,
                                          color: Theme.of(context)
                                              .colorScheme
                                              .primary,
                                        ),
                                      ),
                                      const SizedBox(height: 8),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.green,
                                            foregroundColor: Colors.white,
                                            padding: const EdgeInsets.symmetric(
                                                horizontal: 8, vertical: 8),
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.openConnection();
                                          },
                                          icon: const Icon(Icons.power_settings_new,
                                              size: 16),
                                          label: const Text('Connect',
                                              style: TextStyle(fontSize: 12)),
                                        ),
                                      ),
                                      const SizedBox(height: 4),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.blue,
                                            foregroundColor: Colors.white,
                                            padding: const EdgeInsets.symmetric(
                                                horizontal: 8, vertical: 8),
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.startListen(
                                                userId: _registerationCodeController
                                                    .text);
                                          },
                                          icon: const Icon(Icons.hearing, size: 16),
                                          label: const Text('Listen',
                                              style: TextStyle(fontSize: 12)),
                                        ),
                                      ),
                                      const SizedBox(height: 4),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.orange,
                                            foregroundColor: Colors.white,
                                            padding: const EdgeInsets.symmetric(
                                                horizontal: 8, vertical: 8),
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.registerFinger(
                                                userId: _registerationCodeController
                                                    .text);
                                          },
                                          icon: const Icon(Icons.fingerprint,
                                              size: 16),
                                          label: const Text('Enroll',
                                              style: TextStyle(fontSize: 12)),
                                        ),
                                      ),
                                      const SizedBox(height: 4),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.purple,
                                            foregroundColor: Colors.white,
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.identify(
                                                userId: _registerationCodeController
                                                    .text);
                                          },
                                          icon: const Icon(Icons.search),
                                          label: const Text('Identify Finger'),
                                        ),
                                      ),
                                      const SizedBox(height: 8),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.teal,
                                            foregroundColor: Colors.white,
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.verify(
                                                finger1: _idleText1.text,
                                                finger2: _idleText2.text);
                                          },
                                          icon: const Icon(Icons.verified),
                                          label: const Text('Verify Finger'),
                                        ),
                                      ),
                                      const SizedBox(height: 16),
                                      const Divider(),
                                      const SizedBox(height: 8),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.red,
                                            foregroundColor: Colors.white,
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.clearFingerDatabase();
                                          },
                                          icon: const Icon(Icons.delete_forever),
                                          label: const Text('Clear Database'),
                                        ),
                                      ),
                                      const SizedBox(height: 8),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.grey,
                                            foregroundColor: Colors.white,
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.stopListen();
                                          },
                                          icon: const Icon(Icons.stop),
                                          label: const Text('Stop Listening'),
                                        ),
                                      ),
                                      const SizedBox(height: 8),
                                      SizedBox(
                                        width: double.infinity,
                                        child: ElevatedButton.icon(
                                          style: ElevatedButton.styleFrom(
                                            backgroundColor: Colors.red.shade700,
                                            foregroundColor: Colors.white,
                                          ),
                                          onPressed: () async {
                                            await ZkFinger.closeConnection();
                                          },
                                          icon: const Icon(Icons.power_off),
                                          label: const Text('Disconnect'),
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ))),
                      const SizedBox(width: 16),
                      // Fingerprint Display Section
                      SizedBox(
                          width: 180,
                          child: Card(
                            child: Padding(
                              padding: const EdgeInsets.all(12),
                              child: Column(
                                mainAxisSize: MainAxisSize.min,
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    'Preview',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Theme.of(context)
                                          .colorScheme
                                          .primary,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  Center(
                                    child: fingerImages != null
                                        ? Container(
                                      decoration: BoxDecoration(
                                        borderRadius:
                                        BorderRadius.circular(12),
                                        border: Border.all(
                                          color: Theme.of(context)
                                              .colorScheme
                                              .primary,
                                          width: 2,
                                        ),
                                        boxShadow: [
                                          BoxShadow(
                                            color: Colors.black
                                                .withOpacity(0.1),
                                            blurRadius: 8,
                                            offset: const Offset(0, 4),
                                          ),
                                        ],
                                      ),
                                      child: ClipRRect(
                                        borderRadius:
                                        BorderRadius.circular(10),
                                        child: Image.memory(
                                          fingerImages!,
                                          width: 150,
                                          height: 150,
                                          fit: BoxFit.fill,
                                        ),
                                      ),
                                    )
                                        : Container(
                                      width: 150,
                                      height: 150,
                                      decoration: BoxDecoration(
                                        borderRadius:
                                        BorderRadius.circular(12),
                                        border: Border.all(
                                          color: Colors.grey.shade300,
                                          width: 2,
                                        ),
                                        color: Colors.grey.shade50,
                                      ),
                                      child: Column(
                                        mainAxisAlignment:
                                        MainAxisAlignment.center,
                                        children: [
                                          Icon(
                                            Icons.fingerprint,
                                            size: 48,
                                            color: Colors.grey.shade400,
                                          ),
                                          const SizedBox(height: 8),
                                          Text(
                                            'No Image',
                                            style: TextStyle(
                                              color: Colors.grey.shade600,
                                              fontSize: 12,
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                  ),
                                  const SizedBox(height: 16),
                                  // Status Indicator
                                  Text(
                                    'Status Indicator',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  Center(
                                    child: Container(
                                      decoration: BoxDecoration(
                                        borderRadius: BorderRadius.circular(12),
                                        border: Border.all(
                                          color: Theme.of(context)
                                              .colorScheme
                                              .primary,
                                          width: 2,
                                        ),
                                        color: Colors.white,
                                      ),
                                      height: 148,
                                      width: 154,
                                      child: _getFingerStatusImage(),
                                    ),
                                  ),
                                  const SizedBox(height: 16),

                                  // Status Information
                                  Container(
                                    padding: const EdgeInsets.all(12),
                                    decoration: BoxDecoration(
                                      color: Theme.of(context)
                                          .colorScheme
                                          .surfaceVariant,
                                      borderRadius: BorderRadius.circular(8),
                                    ),
                                    child: Column(
                                      crossAxisAlignment:
                                      CrossAxisAlignment.start,
                                      children: [
                                        Text(
                                          'Status Information',
                                          style: Theme.of(context)
                                              .textTheme
                                              .titleMedium
                                              ?.copyWith(
                                            fontWeight: FontWeight.bold,
                                          ),
                                        ),
                                        const SizedBox(height: 8),
                                        Row(
                                          children: [
                                            const Icon(Icons.score, size: 16),
                                            const SizedBox(width: 4),
                                            Text('Score: $score'),
                                          ],
                                        ),
                                        const SizedBox(height: 4),
                                        Row(
                                          children: [
                                            const Icon(Icons.message, size: 16),
                                            const SizedBox(width: 4),
                                            Expanded(
                                                child:
                                                Text('Message: $message')),
                                          ],
                                        ),
                                        const SizedBox(height: 8),
                                        Text(
                                          'Device Status:',
                                          style: Theme.of(context)
                                              .textTheme
                                              .titleSmall
                                              ?.copyWith(
                                            fontWeight: FontWeight.bold,
                                          ),
                                        ),
                                        const SizedBox(height: 4),
                                        Text(
                                          statusText,
                                          style: const TextStyle(
                                              fontSize: 12,
                                              fontFamily: 'monospace'),
                                        ),
                                      ],
                                    ),
                                  )
                                ],
                              ),
                            ),
                          )),
                      const SizedBox(width: 16),
                      // Data Management Section
                      SizedBox(
                        width: 250,
                        child: Card(
                          child: Padding(
                            padding: const EdgeInsets.all(12),
                            child: SingleChildScrollView(
                              child: Column(
                                mainAxisSize: MainAxisSize.min,
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: <Widget>[
                                  Text(
                                    'Data Management',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Theme.of(context)
                                          .colorScheme
                                          .primary,
                                    ),
                                  ),
                                  const SizedBox(height: 16),
                                  TextFormField(
                                    controller: _registerationCodeController,
                                    decoration: InputDecoration(
                                      labelText: "Registration Code",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(8),
                                      ),
                                      prefixIcon: const Icon(Icons.person),
                                    ),
                                  ),
                                  const SizedBox(height: 16),
                                  Text(
                                    'Biometric Base64 Template:',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Theme.of(context)
                                          .colorScheme
                                          .primary,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  TextFormField(
                                    readOnly: true,
                                    controller: _biometricController,
                                    maxLines: 3,
                                    decoration: InputDecoration(
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(8),
                                      ),
                                      prefixIcon: const Icon(Icons.data_object),
                                    ),
                                    style: const TextStyle(
                                        fontSize: 12, fontFamily: 'monospace'),
                                  )
                                ],
                              ),
                            ),
                          ),
                        ),
                      ),
                      const SizedBox(width: 16),
                      // Verification Section
                      SizedBox(
                        width: 220,
                        child: Card(
                          child: Padding(
                            padding: const EdgeInsets.all(12),
                            child: SingleChildScrollView(
                              child: Column(
                                mainAxisSize: MainAxisSize.min,
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    'Verification',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Theme.of(context)
                                          .colorScheme
                                          .primary,
                                    ),
                                  ),
                                  const SizedBox(height: 16),

                                  // Finger 1
                                  Text(
                                    'Template 1:',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  TextFormField(
                                    decoration: InputDecoration(
                                      labelText: "Fingerprint Template 1",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(8),
                                      ),
                                      prefixIcon: const Icon(Icons.fingerprint),
                                    ),
                                    readOnly: true,
                                    controller: _idleText1,
                                    maxLines: 2,
                                    style: const TextStyle(
                                        fontSize: 12, fontFamily: 'monospace'),
                                  ),
                                  const SizedBox(height: 8),
                                  SizedBox(
                                    width: double.infinity,
                                    child: ElevatedButton.icon(
                                      onPressed: () {
                                        _idleText1.text =
                                            _biometricController.text;
                                      },
                                      style: ElevatedButton.styleFrom(
                                        backgroundColor: Theme.of(context)
                                            .colorScheme
                                            .secondary,
                                        foregroundColor: Colors.white,
                                      ),
                                      icon: const Icon(Icons.copy),
                                      label: const Text('Copy Template'),
                                    ),
                                  ),
                                  const SizedBox(height: 16),

                                  // Finger 2
                                  Text(
                                    'Template 2:',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  TextFormField(
                                    decoration: InputDecoration(
                                      labelText: "Fingerprint Template 2",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(8),
                                      ),
                                      prefixIcon: const Icon(Icons.fingerprint),
                                    ),
                                    readOnly: true,
                                    controller: _idleText2,
                                    maxLines: 2,
                                    style: const TextStyle(
                                        fontSize: 12, fontFamily: 'monospace'),
                                  ),
                                  const SizedBox(height: 8),
                                  SizedBox(
                                    width: double.infinity,
                                    child: ElevatedButton.icon(
                                      onPressed: () {
                                        _idleText2.text =
                                            _biometricController.text;
                                      },
                                      style: ElevatedButton.styleFrom(
                                        backgroundColor: Theme.of(context)
                                            .colorScheme
                                            .secondary,
                                        foregroundColor: Colors.white,
                                      ),
                                      icon: const Icon(Icons.copy),
                                      label: const Text('Copy Template'),
                                    ),
                                  ),
                                  const SizedBox(height: 16),
                                ],
                              ),
                            ),
                          ),
                        ),
                      ),
                      const SizedBox(width: 16),

                      // Database Management Section
                      SizedBox(
                        width: 280,
                        child: Card(
                          child: Padding(
                            padding: const EdgeInsets.all(12),
                            child: SingleChildScrollView(
                              child: Column(
                                mainAxisSize: MainAxisSize.min,
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    'Database Management',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Theme.of(context)
                                          .colorScheme
                                          .primary,
                                    ),
                                  ),
                                  const SizedBox(height: 16),

                                  // Current Database Info
                                  Container(
                                    padding: const EdgeInsets.all(12),
                                    decoration: BoxDecoration(
                                      color: Theme.of(context)
                                          .colorScheme
                                          .surfaceVariant,
                                      borderRadius: BorderRadius.circular(8),
                                    ),
                                    child: Column(
                                      crossAxisAlignment: CrossAxisAlignment.start,
                                      children: [
                                        Row(
                                          children: [
                                            const Icon(Icons.storage),
                                            const SizedBox(width: 8),
                                            Text(
                                              'Current Database',
                                              style: Theme.of(context)
                                                  .textTheme
                                                  .titleMedium
                                                  ?.copyWith(
                                                fontWeight: FontWeight.bold,
                                              ),
                                            ),
                                          ],
                                        ),
                                        const SizedBox(height: 8),
                                        Row(
                                          children: [
                                            const Icon(Icons.people, size: 16),
                                            const SizedBox(width: 4),
                                            Text('Users: ${_isLoadingDatabase ? "Loading..." : databaseUserCount}'),
                                          ],
                                        ),
                                        const SizedBox(height: 8),
                                        SizedBox(
                                          width: double.infinity,
                                          child: ElevatedButton.icon(
                                            onPressed: _isLoadingDatabase ? null : () {
                                              _refreshDatabaseInfo();
                                              _showDatabaseUsersDialog();
                                            },
                                            style: ElevatedButton.styleFrom(
                                              backgroundColor: Colors.blue,
                                              foregroundColor: Colors.white,
                                            ),
                                            icon: _isLoadingDatabase
                                                ? const SizedBox(
                                              width: 16,
                                              height: 16,
                                              child: CircularProgressIndicator(strokeWidth: 2),
                                            )
                                                : const Icon(Icons.list),
                                            label: const Text('View Users'),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                  const SizedBox(height: 16),
                                  const Divider(),
                                  const SizedBox(height: 16),

                                  // Export Section
                                  Text(
                                    'Export to URL',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Colors.green,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  TextField(
                                    controller: _exportUrlController,
                                    decoration: InputDecoration(
                                      labelText: "Export URL (POST)",
                                      hintText: "https://api.example.com/export",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(8),
                                      ),
                                      prefixIcon: const Icon(Icons.upload),
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  SizedBox(
                                    width: double.infinity,
                                    child: ElevatedButton.icon(
                                      onPressed: _isExporting ? null : _exportAllUsers,
                                      style: ElevatedButton.styleFrom(
                                        backgroundColor: Colors.green,
                                        foregroundColor: Colors.white,
                                      ),
                                      icon: _isExporting
                                          ? const SizedBox(
                                        width: 16,
                                        height: 16,
                                        child: CircularProgressIndicator(strokeWidth: 2),
                                      )
                                          : const Icon(Icons.cloud_upload),
                                      label: Text(_isExporting ? 'Exporting...' : 'Export All Users'),
                                    ),
                                  ),
                                  const SizedBox(height: 16),

                                  // Import Section
                                  Text(
                                    'Import from URL',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Colors.orange,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  TextField(
                                    controller: _importUrlController,
                                    decoration: InputDecoration(
                                      labelText: "Import URL (GET)",
                                      hintText: "https://api.example.com/import",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(8),
                                      ),
                                      prefixIcon: const Icon(Icons.download),
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  SizedBox(
                                    width: double.infinity,
                                    child: ElevatedButton.icon(
                                      onPressed: _isLoadingFromUrl ? null : _importFromUrl,
                                      style: ElevatedButton.styleFrom(
                                        backgroundColor: Colors.orange,
                                        foregroundColor: Colors.white,
                                      ),
                                      icon: _isLoadingFromUrl
                                          ? const SizedBox(
                                        width: 16,
                                        height: 16,
                                        child: CircularProgressIndicator(strokeWidth: 2),
                                      )
                                          : const Icon(Icons.cloud_download),
                                      label: Text(_isLoadingFromUrl ? 'Importing...' : 'Import from URL'),
                                    ),
                                  ),
                                  const SizedBox(height: 16),
                                  const Divider(),
                                  const SizedBox(height: 8),

                                  // Legacy Network Section
                                  Text(
                                    'Legacy Network Operations',
                                    style: Theme.of(context)
                                        .textTheme
                                        .titleMedium
                                        ?.copyWith(
                                      fontWeight: FontWeight.bold,
                                      color: Colors.indigo,
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  TextField(
                                    controller: _sendUrlController,
                                    onChanged: (text) {
                                      sendUrl = text;
                                    },
                                    decoration: InputDecoration(
                                      hintText:
                                      "Enter URL (http:// or https://)",
                                      border: OutlineInputBorder(
                                        borderRadius: BorderRadius.circular(8),
                                      ),
                                      prefixIcon: const Icon(Icons.link),
                                    ),
                                  ),
                                  const SizedBox(height: 8),
                                  SizedBox(
                                    width: double.infinity,
                                    child: ElevatedButton.icon(
                                      style: ElevatedButton.styleFrom(
                                        backgroundColor: Colors.indigo,
                                        foregroundColor: Colors.white,
                                      ),
                                      onPressed: () => sendText(),
                                      icon: const Icon(Icons.send),
                                      label: const Text('Send Data'),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  Future<bool> sendText() async {
    final NetworkInfo networkInfo =
    NetworkInfoImpl(InternetConnectionChecker());
    final Dio dio = Dio();

    if (await networkInfo.isConnected) {
      ///

      try {
        final response = await dio.post(sendUrl,
            options: Options(
                headers: <String, String>{'Content-Type': 'application/json'}),
            data: {"date": DateTime.now().toString(), "finger": base64Image});
        final data = response.data;
        print(data.toString());
        if (response.statusCode == 200) {
          CustomToast.showToast(data.toString());
          return true;
        } else {
          CustomToast.showToast(data.toString());
          print(data.toString());
          return false;
        }
      } on DioException catch (e) {
        print(e.error);

        if (e.type == DioExceptionType.badResponse) {
          if (e.response != null) {
            CustomToast.showToast('Server error: ${e.response!.data}');
            print('Server error: ${e.response!.data}');
          } else {
            CustomToast.showToast(e.error.toString());
          }
        } else {
          CustomToast.showToast(e.error.toString());
        }
        return false;
      }
    } else {
      CustomToast.showToast("No internet!");
      return false;
    }
  }

  Widget _getFingerStatusImage() {
    if (fingerStatus == null) {
      return SvgPicture.asset(
        'assets/finger.svg',
        colorFilter: const ColorFilter.mode(Colors.black38, BlendMode.srcIn),
        width: 70,
        height: 120,
      );
    }
    Color svgColor = Colors.black12;
    switch (fingerStatus!.statusType) {
      case FingerStatusType.FINGER_EXTRACTED:
      case FingerStatusType.STARTED_ALREADY:
      case FingerStatusType.STARTED_SUCCESS:
        svgColor = Colors.indigo;
        break;
      case FingerStatusType.VERIFIED_SUCCESS:
        svgColor = Colors.green;
        break;
      case FingerStatusType.VERIFIED_FAILED:
        svgColor = Colors.redAccent;
        break;
      case FingerStatusType.VERIFIED_ERROR:
        svgColor = Colors.red;
        break;
      case FingerStatusType.IDENTIFIED_START_FIRST:
      case FingerStatusType.IDENTIFIED_FAILED:
        svgColor = Colors.redAccent;
        break;
      case FingerStatusType.IDENTIFIED_SUCCESS:
        svgColor = Colors.blue;
        break;
      case FingerStatusType.ENROLL_ALREADY_EXIST:
      case FingerStatusType.ENROLL_CONFIRM:
      case FingerStatusType.ENROLL_STARTED:
      case FingerStatusType.ENROLL_SUCCESS:
        svgColor = Colors.green;
        break;
      case FingerStatusType.STOPPED_ALREADY:
      case FingerStatusType.STOPPED_SUCCESS:
        svgColor = Colors.red;
        break;
      case FingerStatusType.FINGER_CLEARED:
        svgColor = Colors.yellow;
        break;
      case FingerStatusType.STARTED_FAILED:
        svgColor = Colors.redAccent;
        break;
      case FingerStatusType.STARTED_ERROR:
        svgColor = Colors.red;
        break;
      case FingerStatusType.ENROLL_FAILED:
        svgColor = Colors.redAccent;
        break;
      case FingerStatusType.STOPPED_ERROR:
        svgColor = Colors.red;
        break;
      case FingerStatusType.CAPTURE_ERROR:
        svgColor = Colors.red;
        break;
      default:
        svgColor = Colors.black38;
    }

    return SvgPicture.asset(
      'assets/finger.svg',
      colorFilter: ColorFilter.mode(svgColor, BlendMode.srcIn),
      width: 70,
      height: 120,
    );
  }
}
18
likes
150
points
2
downloads

Publisher

verified publisherflutterdev.uz

Weekly Downloads

The zk_finger10 plugin is used for supporting fingerprint device of ZKTECO with enrolling and verification feature.

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, plugin_platform_interface, uuid

More

Packages that depend on zkfinger10

Packages that implement zkfinger10