gestao_ponto_package 2.2.4 copy "gestao_ponto_package: ^2.2.4" to clipboard
gestao_ponto_package: ^2.2.4 copied to clipboard

Flutter package with time tracking and attendance management features for Senior mobile apps.

example/lib/main.dart

import 'dart:convert';
import 'dart:developer';

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:gestao_ponto_package/gestao_ponto_package.dart' as gestao;
import 'package:http/http.dart' as http;
import 'package:senior_design_system/senior_design_system.dart';
import 'package:senior_design_tokens/senior_design_tokens.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'features/app/module/app_module.dart';
import 'features/app/presentation/app_widget.dart';
import 'firebase_options.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

  runApp(const LoginApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(debugShowCheckedModeBanner: false, home: const LoginScreen());
  }
}

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

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  bool _isLoading = false;
  String? _errorMessage;

  // URL options
  final List<Map<String, String>> _urlOptions = [
    {'name': 'Leaf (Cloud Leaf)', 'value': 'https://cloud-leaf.senior.com.br/t/senior.com.br/bridge/1.0/rest/'},
    {'name': 'Homologação (Platform)', 'value': 'https://platform-homologx.senior.com.br/t/senior.com.br/bridge/1.0/rest/'},
  ];

  String _selectedUrl = 'https://platform-homologx.senior.com.br/t/senior.com.br/bridge/1.0/rest/';

  // Credenciais salvas
  List<Map<String, String>> _savedCredentials = [];
  String? _selectedCredential;

  @override
  void initState() {
    super.initState();
    _loadSavedCredentials();
  }

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

    var username = _usernameController.text.trim();
    var password = _passwordController.text.trim();

    if (username.isEmpty || password.isEmpty) {
      setState(() {
        _isLoading = false;
        _errorMessage = 'Por favor, preencha todos os campos.';
      });
      return;
    }

    try {
      final url = '${_selectedUrl}platform/authentication/actions/login';
      final requestBody = {'username': username, 'password': password};

      // Log da request
      log('🔍 === REQUEST LOG ===');
      log('URL: $url');
      log('Headers: {Content-Type: application/json}');
      log('Body: ${jsonEncode(requestBody)}');
      log('Selected URL for Config: $_selectedUrl');
      log('========================');

      final response = await http.post(Uri.parse(url), headers: {'Content-Type': 'application/json'}, body: jsonEncode(requestBody));

      // Log da response
      log('📥 === RESPONSE LOG ===');
      log('Status Code: ${response.statusCode}');
      log('Headers: ${response.headers}');
      log('Body: ${response.body}');
      log('======================');

      if (response.statusCode != 200) {
        // Limita o tamanho da mensagem de erro para evitar overflow
        String errorBody = response.body;
        if (errorBody.length > 200) {
          errorBody = '${errorBody.substring(0, 200)}...';
        }
        throw Exception('Falha ao autenticar (${response.statusCode}): $errorBody');
      }

      final body = jsonDecode(response.body);
      final jsonToken = jsonDecode(body['jsonToken'] as String);

      final token = getTokenFromJson(jsonToken);

      // Salva as credenciais após sucesso no login
      await _saveCredentials(username, password);

      if (!gestao.Config.isInitialized()) {
        gestao.Config.init(_selectedUrl, token: token);
      }

      Modular.setInitialRoute('/');

      final brightness = WidgetsBinding.instance.platformDispatcher.platformBrightness;
      var theme = brightness == Brightness.dark ? SENIOR_DARK_THEME : SENIOR_LIGHT_THEME;

      runApp(
        ModularApp(
          module: AppModule(),
          child: SeniorDesignSystem(theme: theme, child: const AppWidget()),
        ),
      );
    } catch (e) {
      setState(() {
        _isLoading = false;
        _errorMessage = 'Erro ao autenticar: $e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: SeniorColors.primaryColor500,
      body: SingleChildScrollView(
        child: ConstrainedBox(
          constraints: BoxConstraints(minHeight: MediaQuery.of(context).size.height),
          child: IntrinsicHeight(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Center(
                child: Card(
                  color: SeniorColors.pureBlack,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
                  child: Padding(
                    padding: const EdgeInsets.all(24.0),
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        const Text(
                          'Exemplo Biblioteca Gestão Ponto Package',
                          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white),
                        ),
                        const SizedBox(height: 16),
                        DropdownButtonFormField<String>(
                          value: _selectedUrl,
                          decoration: const InputDecoration(
                            labelText: 'Ambiente',
                            labelStyle: TextStyle(color: Colors.white),
                            filled: true,
                            fillColor: Colors.white10,
                            border: OutlineInputBorder(),
                          ),
                          dropdownColor: Colors.grey[800],
                          style: const TextStyle(color: Colors.white),
                          items: _urlOptions.map((option) {
                            return DropdownMenuItem<String>(
                              value: option['value'],
                              child: Text(option['name']!, style: const TextStyle(color: Colors.white)),
                            );
                          }).toList(),
                          onChanged: (String? newValue) {
                            if (newValue != null) {
                              setState(() {
                                _selectedUrl = newValue;
                              });
                            }
                          },
                        ),
                        const SizedBox(height: 16),
                        if (_savedCredentials.isNotEmpty)
                          DropdownButtonFormField<String>(
                            value: _selectedCredential,
                            decoration: const InputDecoration(
                              labelText: 'Credenciais Salvas',
                              labelStyle: TextStyle(color: Colors.white),
                              filled: true,
                              fillColor: Colors.white10,
                              border: OutlineInputBorder(),
                            ),
                            dropdownColor: Colors.grey[800],
                            style: const TextStyle(color: Colors.white),
                            items: [
                              const DropdownMenuItem<String>(
                                value: null,
                                child: Text('Selecione uma credencial...', style: TextStyle(color: Colors.white70)),
                              ),
                              ..._savedCredentials.map((credential) {
                                return DropdownMenuItem<String>(
                                  value: credential['username'],
                                  child: Text(credential['displayName'] ?? credential['username'] ?? '', style: const TextStyle(color: Colors.white)),
                                );
                              }),
                            ],
                            onChanged: _selectCredential,
                          ),
                        if (_savedCredentials.isNotEmpty) const SizedBox(height: 16),
                        TextField(
                          controller: _usernameController,
                          decoration: const InputDecoration(
                            labelText: 'Usuário',
                            labelStyle: TextStyle(color: Colors.white),
                            filled: true,
                            fillColor: Colors.white10,
                            border: OutlineInputBorder(),
                          ),
                          style: const TextStyle(color: Colors.white),
                        ),
                        const SizedBox(height: 16),
                        TextField(
                          controller: _passwordController,
                          decoration: const InputDecoration(
                            labelText: 'Senha',
                            labelStyle: TextStyle(color: Colors.white),
                            filled: true,
                            fillColor: Colors.white10,
                            border: OutlineInputBorder(),
                          ),
                          obscureText: true,
                          style: const TextStyle(color: Colors.white),
                        ),
                        const SizedBox(height: 16),
                        if (_errorMessage != null)
                          Container(
                            padding: const EdgeInsets.all(12),
                            decoration: BoxDecoration(
                              color: Colors.red.withOpacity(0.1),
                              border: Border.all(color: Colors.red),
                              borderRadius: BorderRadius.circular(8),
                            ),
                            child: Text(
                              _errorMessage!,
                              style: const TextStyle(color: Colors.red, fontSize: 12),
                              textAlign: TextAlign.center,
                              softWrap: true,
                              overflow: TextOverflow.visible,
                            ),
                          ),
                        const SizedBox(height: 16),
                        _isLoading
                            ? const CircularProgressIndicator()
                            : ElevatedButton(
                                onPressed: _authenticate,
                                style: ElevatedButton.styleFrom(
                                  backgroundColor: Colors.teal,
                                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
                                ),
                                child: const Text('Entrar', style: TextStyle(color: Colors.white)),
                              ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  Future<void> _loadSavedCredentials() async {
    final prefs = await SharedPreferences.getInstance();
    final credentialsJson = prefs.getStringList('saved_credentials') ?? [];

    setState(() {
      _savedCredentials = credentialsJson.map((cred) {
        final decoded = jsonDecode(cred);
        return Map<String, String>.from(decoded);
      }).toList();
    });
  }

  Future<void> _saveCredentials(String username, String password) async {
    final prefs = await SharedPreferences.getInstance();

    // Verifica se as credenciais já existem
    final existingIndex = _savedCredentials.indexWhere((cred) => cred['username'] == username);

    final newCredential = {
      'username': username,
      'password': password,
      'displayName': username, // Pode ser customizado futuramente
    };

    if (existingIndex >= 0) {
      // Atualiza credenciais existentes
      _savedCredentials[existingIndex] = newCredential;
    } else {
      // Adiciona novas credenciais
      _savedCredentials.add(newCredential);
    }

    // Limita a 5 credenciais salvas
    if (_savedCredentials.length > 5) {
      _savedCredentials = _savedCredentials.sublist(_savedCredentials.length - 5);
    }

    final credentialsJson = _savedCredentials.map((cred) => jsonEncode(cred)).toList();
    await prefs.setStringList('saved_credentials', credentialsJson);

    setState(() {});
  }

  void _selectCredential(String? credentialJson) {
    if (credentialJson != null && credentialJson.isNotEmpty) {
      final credential = _savedCredentials.firstWhere((cred) => cred['username'] == credentialJson, orElse: () => {});

      if (credential.isNotEmpty) {
        setState(() {
          _selectedCredential = credentialJson;
          _usernameController.text = credential['username'] ?? '';
          _passwordController.text = credential['password'] ?? '';
        });
      }
    } else {
      setState(() {
        _selectedCredential = null;
        _usernameController.clear();
        _passwordController.clear();
      });
    }
  }

  gestao.Token? getTokenFromJson(Map<String, dynamic>? body) {
    if (body == null) {
      return null;
    }

    return gestao.Token(
      accessToken: gestao.tryCast<String>(body['access_token'], ''),
      expiresIn: gestao.tryCast<int>(body['expires_in'], 0),
      tokenType: gestao.tryCast<String>(body['token_type'], ''),
      refreshToken: gestao.tryCast<String>(body['refresh_token'], ''),
      username: gestao.tryCast<String>(body['username'], ''),
    );
  }
}
0
likes
0
points
32
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter package with time tracking and attendance management features for Senior mobile apps.

Repository

License

unknown (license)

Dependencies

connectivity_plus, dartz, dio, equatable, flutter, flutter_bloc, flutter_localizations, flutter_modular, font_awesome_flutter, intl, provider, senior_design_system, senior_design_tokens, shared_preferences, skeletonizer, url_launcher

More

Packages that depend on gestao_ponto_package