gestao_ponto_package 2.3.1 copy "gestao_ponto_package: ^2.3.1" to clipboard
gestao_ponto_package: ^2.3.1 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
130
points
32
downloads

Documentation

API reference

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