Settings finalizadas

This commit is contained in:
2026-03-18 20:03:32 +00:00
parent 6322e8d798
commit 1794208143
7 changed files with 399 additions and 401 deletions

View File

@@ -1,19 +1,31 @@
import 'package:flutter/material.dart';
enum AppLanguage { pt, en, es }
class AppStrings {
static AppLanguage _currentLanguage = AppLanguage.pt;
static final ValueNotifier<AppLanguage> languageNotifier = ValueNotifier(AppLanguage.pt);
static AppLanguage get currentLanguage => languageNotifier.value;
static void setLanguage(String language) {
if (language == 'English') {
_currentLanguage = AppLanguage.en;
languageNotifier.value = AppLanguage.en;
} else if (language == 'Español') {
_currentLanguage = AppLanguage.es;
languageNotifier.value = AppLanguage.es;
} else {
_currentLanguage = AppLanguage.pt;
languageNotifier.value = AppLanguage.pt;
}
}
static String get _lang => _currentLanguage.name;
static String get currentLanguageName {
switch (languageNotifier.value) {
case AppLanguage.en: return 'English';
case AppLanguage.es: return 'Español';
case AppLanguage.pt: return 'Português';
}
}
static String get _lang => languageNotifier.value.name;
static String _get(Map<String, String> values) => values[_lang] ?? values['pt']!;
@@ -162,6 +174,7 @@ class AppStrings {
static String get btnOk => _get({'pt': "OK", 'en': "OK", 'es': "OK"});
static String get btnCancel => _get({'pt': "Cancelar", 'en': "Cancel", 'es': "Cancelar"});
static String get btnDefine => _get({'pt': "DEFINIR", 'en': "DEFINE", 'es': "DEFINIR"});
static String get profileUpdated => _get({'pt': "Perfil atualizado!", 'en': "Profile updated!", 'es': "¡Perfil actualizado!"});
// Logado Screen
static String get defineDailyGoal => _get({'pt': "Definir Meta Diária", 'en': "Set Daily Goal", 'es': "Definir Meta Diaria"});

View File

@@ -15,33 +15,22 @@ void main() async {
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<AppLanguage>(
valueListenable: AppStrings.languageNotifier,
builder: (context, language, child) {
return MaterialApp(
title: AppStrings.appTitle,
debugShowCheckedModeBanner: false,
theme: ThemeData(
// This is the theme of your application.
//
// TRY THIS: Try running your application with "flutter run". You'll see
// the application has a purple toolbar. Then, without quitting the app,
// try changing the seedColor in the colorScheme below to Colors.green
// and then invoke "hot reload" (save your changes or press the "hot
// reload" button in a Flutter-supported IDE, or press "r" if you used
// the command line to start the app).
//
// Notice that the counter didn't reset back to zero; the application
// state is not lost during the reload. To reset the state, use hot
// restart instead.
//
// This works for code too, not just values: Most code changes can be
// tested with just a hot reload.
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.white.withValues(alpha: 0.1),
),
),
home: const InicialScreen(),
);
},
);
}
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../constants/app_colors.dart';
import '../constants/app_strings.dart';
import '../services/supabase_service.dart';
@@ -16,10 +17,10 @@ class LogadoScreen extends StatefulWidget {
class _LogadoScreenState extends State<LogadoScreen> {
// Estado dinâmico do utilizador
double _dailyGoal = 0.0; // 0.0 significa que ainda não foi definida
double _dailyGoal = 0.0;
double _currentDistance = 0.0;
double _bestDistance = 12.4; // Exemplo de recorde
double _bestSpeed = 16.8; // Exemplo de recorde
double _bestDistance = 12.4;
double _bestSpeed = 16.8;
int _steps = 0;
int _totalTimeMinutes = 0;
@@ -32,15 +33,38 @@ class _LogadoScreenState extends State<LogadoScreen> {
}
Future<void> _loadUserData() async {
// No futuro, aqui buscaríamos os dados reais do Supabase ou Local Storage
final prefs = await SharedPreferences.getInstance();
final lastGoalDate = prefs.getString('last_goal_date');
final today = DateTime.now().toIso8601String().split('T')[0];
setState(() {
// Simulação de dados carregados
_currentDistance = 0.0; // Começa o dia a zero
// Reset meta se o dia mudou
if (lastGoalDate != today) {
_dailyGoal = 0.0;
prefs.remove('daily_goal');
} else {
_dailyGoal = prefs.getDouble('daily_goal') ?? 0.0;
}
// No futuro, estes viriam do Supabase ou histórico local
_currentDistance = 0.0;
_steps = 0;
_totalTimeMinutes = 0;
});
}
Future<void> _saveGoal(double goal) async {
final prefs = await SharedPreferences.getInstance();
final today = DateTime.now().toIso8601String().split('T')[0];
await prefs.setDouble('daily_goal', goal);
await prefs.setString('last_goal_date', today);
setState(() {
_dailyGoal = goal;
});
}
void _showGoalDialog() {
showDialog(
context: context,
@@ -54,9 +78,7 @@ class _LogadoScreenState extends State<LogadoScreen> {
...[5, 10, 15, 20].map((km) => ListTile(
title: Text("$km ${AppStrings.kmUnit}", style: const TextStyle(color: Colors.white)),
onTap: () {
setState(() {
_dailyGoal = km.toDouble();
});
_saveGoal(km.toDouble());
Navigator.pop(context);
},
)),
@@ -107,9 +129,7 @@ class _LogadoScreenState extends State<LogadoScreen> {
onPressed: () {
final value = double.tryParse(controller.text);
if (value != null && value > 0) {
setState(() {
_dailyGoal = value;
});
_saveGoal(value);
Navigator.pop(context);
}
},
@@ -126,6 +146,9 @@ class _LogadoScreenState extends State<LogadoScreen> {
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<AppLanguage>(
valueListenable: AppStrings.languageNotifier,
builder: (context, language, child) {
final user = SupabaseService.currentUser;
final userName = user?.userMetadata?['name'] ?? user?.email?.split('@')[0] ?? AppStrings.userPlaceholder;
@@ -133,7 +156,6 @@ class _LogadoScreenState extends State<LogadoScreen> {
backgroundColor: AppColors.background,
body: Stack(
children: [
// Background Gradient
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
@@ -149,7 +171,6 @@ class _LogadoScreenState extends State<LogadoScreen> {
SafeArea(
child: Column(
children: [
// Header Bar
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Row(
@@ -203,13 +224,8 @@ class _LogadoScreenState extends State<LogadoScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
// Main Tracking Card (Meta Diária)
_buildMainTrackingCard(),
const SizedBox(height: 30),
// Personal Bests Section
Text(
AppStrings.personalRecords,
style: const TextStyle(
@@ -243,10 +259,7 @@ class _LogadoScreenState extends State<LogadoScreen> {
),
],
),
const SizedBox(height: 25),
// Steps Section (Atividade Geral)
Text(
AppStrings.generalActivity,
style: const TextStyle(
@@ -264,8 +277,7 @@ class _LogadoScreenState extends State<LogadoScreen> {
Icons.directions_walk_rounded,
AppColors.success,
),
const SizedBox(height: 120), // Espaço para o botão inferior
const SizedBox(height: 120),
],
),
),
@@ -274,7 +286,6 @@ class _LogadoScreenState extends State<LogadoScreen> {
),
),
// Bottom Action Button
Positioned(
bottom: 30,
left: 50,
@@ -315,6 +326,8 @@ class _LogadoScreenState extends State<LogadoScreen> {
],
),
);
},
);
}
Widget _buildIconButton(IconData icon, VoidCallback onTap) {
@@ -352,10 +365,26 @@ class _LogadoScreenState extends State<LogadoScreen> {
style: const TextStyle(color: Colors.white54, fontWeight: FontWeight.bold, letterSpacing: 1),
),
if (_dailyGoal > 0)
GestureDetector(
onTap: _showGoalDialog,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: AppColors.coral.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: [
Text(
"${(_progress * 100).toInt()}%",
style: const TextStyle(color: AppColors.coral, fontWeight: FontWeight.w900),
),
const SizedBox(width: 5),
const Icon(Icons.edit_rounded, color: AppColors.coral, size: 14),
],
),
),
),
],
),
const SizedBox(height: 20),

View File

@@ -11,9 +11,13 @@ class SettingsScreen extends StatefulWidget {
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _isNightMode = true;
bool _notificationsEnabled = true;
String _selectedLanguage = 'Português';
late String _selectedLanguage;
@override
void initState() {
super.initState();
_selectedLanguage = AppStrings.currentLanguageName;
}
@override
Widget build(BuildContext context) {
@@ -93,12 +97,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
IconButton(
icon: const Icon(Icons.edit, color: AppColors.buttonColor),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppStrings.editProfile),
backgroundColor: AppColors.buttonColor,
),
);
_showEditProfileDialog(context, userName, userEmail);
},
),
],
@@ -115,28 +114,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
child: Column(
children: [
_buildSettingsItem(
icon: Icons.schedule,
title: AppStrings.adjustDateTime,
onTap: () {
_showDatePicker(context);
},
),
_buildDivider(),
_buildSettingsItem(
icon: Icons.dark_mode,
title: AppStrings.nightMode,
trailing: Switch(
value: _isNightMode,
activeThumbColor: AppColors.buttonColor,
onChanged: (value) {
setState(() {
_isNightMode = value;
});
},
),
),
_buildDivider(),
_buildSettingsItem(
icon: Icons.language,
title: AppStrings.language,
@@ -152,59 +129,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
},
),
_buildDivider(),
_buildSettingsItem(
icon: Icons.accessibility,
title: AppStrings.accessibility,
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppStrings.accessibility),
backgroundColor: AppColors.buttonColor,
),
);
},
),
_buildDivider(),
_buildSettingsItem(
icon: Icons.notifications,
title: AppStrings.notifications,
trailing: Switch(
value: _notificationsEnabled,
onChanged: (value) {
setState(() {
_notificationsEnabled = value;
});
},
activeThumbColor: AppColors.buttonColor,
),
),
_buildDivider(),
_buildSettingsItem(
icon: Icons.privacy_tip,
title: AppStrings.privacySecurity,
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppStrings.privacySecurity),
backgroundColor: AppColors.buttonColor,
),
);
},
),
_buildDivider(),
_buildSettingsItem(
icon: Icons.description,
title: AppStrings.termsOfUse,
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppStrings.termsOfUse),
backgroundColor: AppColors.buttonColor,
),
);
},
),
_buildDivider(),
_buildSettingsItem(
icon: Icons.info,
title: AppStrings.about,
@@ -278,28 +202,88 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
void _showDatePicker(BuildContext context) {
showDatePicker(
void _showEditProfileDialog(BuildContext context, String currentName, String currentEmail) {
final nameController = TextEditingController(text: currentName);
final emailController = TextEditingController(text: currentEmail);
showDialog(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2020),
lastDate: DateTime(2025),
).then((date) {
if (date != null && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${AppStrings.dateSelected}: ${date.toString().split(' ')[0]}'),
backgroundColor: AppColors.buttonColor,
builder: (context) => AlertDialog(
backgroundColor: AppColors.backgroundGrey,
title: Text(
AppStrings.editProfile,
style: const TextStyle(color: Colors.white),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: nameController,
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: AppStrings.labelName,
labelStyle: const TextStyle(color: Colors.white70),
enabledBorder: const UnderlineInputBorder(borderSide: BorderSide(color: Colors.white24)),
focusedBorder: const UnderlineInputBorder(borderSide: BorderSide(color: AppColors.buttonColor)),
),
),
const SizedBox(height: 16),
TextField(
controller: emailController,
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: AppStrings.labelEmail,
labelStyle: const TextStyle(color: Colors.white70),
enabledBorder: const UnderlineInputBorder(borderSide: BorderSide(color: Colors.white24)),
focusedBorder: const UnderlineInputBorder(borderSide: BorderSide(color: AppColors.buttonColor)),
),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(
AppStrings.btnCancel,
style: const TextStyle(color: Colors.white54),
),
),
ElevatedButton(
onPressed: () async {
try {
await SupabaseService.updateProfile(
name: nameController.text.trim(),
email: emailController.text.trim(),
);
if (context.mounted) {
Navigator.pop(context);
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Perfil atualizado!'), backgroundColor: Colors.green),
);
}
});
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(e.toString()), backgroundColor: Colors.red),
);
}
}
},
style: ElevatedButton.styleFrom(backgroundColor: AppColors.buttonColor),
child: Text(AppStrings.btnDefine),
),
],
),
);
}
void _showLanguageSelector(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
builder: (context) => StatefulBuilder(
builder: (context, setDialogState) {
return AlertDialog(
backgroundColor: AppColors.backgroundGrey,
title: Text(
AppStrings.selectLanguage,
@@ -308,9 +292,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildLanguageOption('Português'),
_buildLanguageOption('English'),
_buildLanguageOption('Español'),
_buildLanguageOption(context, setDialogState, 'Português'),
_buildLanguageOption(context, setDialogState, 'English'),
_buildLanguageOption(context, setDialogState, 'Español'),
],
),
actions: [
@@ -322,11 +306,13 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
),
],
);
}
),
);
}
Widget _buildLanguageOption(String language) {
Widget _buildLanguageOption(BuildContext context, StateSetter setDialogState, String language) {
return ListTile(
title: Text(language, style: const TextStyle(color: Colors.white)),
trailing: Radio<String>(
@@ -334,26 +320,24 @@ class _SettingsScreenState extends State<SettingsScreen> {
groupValue: _selectedLanguage,
onChanged: (value) {
if (value != null) {
setState(() {
_selectedLanguage = value;
AppStrings.setLanguage(value);
});
_updateLanguage(value);
Navigator.pop(context);
// Force rebuild of current screen to apply changes
setState(() {});
}
},
fillColor: WidgetStateProperty.all(AppColors.buttonColor),
),
onTap: () {
_updateLanguage(language);
Navigator.pop(context);
},
);
}
void _updateLanguage(String language) {
setState(() {
_selectedLanguage = language;
AppStrings.setLanguage(language);
});
Navigator.pop(context);
setState(() {});
},
);
}
void _showAboutDialog(BuildContext context) {

View File

@@ -2,16 +2,12 @@ import 'package:supabase_flutter/supabase_flutter.dart';
import '../constants/app_constants.dart';
class SupabaseService {
static final SupabaseClient _supabase = Supabase.instance.client;
static SupabaseClient get _supabase => Supabase.instance.client;
// Initialize Supabase
static Future<void> initialize() async {
try {
print('DEBUG: Inicializando Supabase...');
print('DEBUG: URL: ${AppConstants.supabaseUrl}');
print(
'DEBUG: AnonKey: ${AppConstants.supabaseAnonKey.substring(0, 10)}...',
);
await Supabase.initialize(
url: AppConstants.supabaseUrl,
@@ -19,10 +15,6 @@ class SupabaseService {
);
print('DEBUG: Supabase inicializado com sucesso!');
// Test connection
final currentUser = _supabase.auth.currentUser;
print('DEBUG: Usuário atual: ${currentUser?.email ?? 'null'}');
} catch (e) {
print('DEBUG: Erro ao inicializar Supabase: $e');
rethrow;
@@ -39,26 +31,18 @@ class SupabaseService {
required String name,
}) async {
try {
print('DEBUG: Criando conta - Email: $email, Name: $name');
final response = await _supabase.auth.signUp(
email: email,
password: password,
data: {'name': name},
);
print('DEBUG: Conta criada! User ID: ${response.user?.id}');
// Check if user was created successfully
if (response.user != null) {
print('DEBUG: Usuário criado com sucesso!');
return response;
} else {
print('DEBUG: Falha ao criar usuário - response.user é null');
throw Exception('Falha ao criar usuário. Tente novamente.');
throw Exception('Falha ao criar usuário.');
}
} catch (e) {
print('DEBUG: Erro no signUp: $e');
throw Exception('Erro ao criar conta: $e');
}
}
@@ -69,17 +53,11 @@ class SupabaseService {
required String password,
}) async {
try {
print('DEBUG: Fazendo login - Email: $email');
final response = await _supabase.auth.signInWithPassword(
return await _supabase.auth.signInWithPassword(
email: email,
password: password,
);
print('DEBUG: Login realizado! User ID: ${response.user?.id}');
return response;
} catch (e) {
print('DEBUG: Erro no signIn: $e');
throw Exception('Erro ao fazer login: $e');
}
}
@@ -88,9 +66,7 @@ class SupabaseService {
static Future<void> signOut() async {
try {
await _supabase.auth.signOut();
print('DEBUG: Logout realizado');
} catch (e) {
print('DEBUG: Erro no signOut: $e');
throw Exception('Erro ao sair: $e');
}
}
@@ -99,27 +75,34 @@ class SupabaseService {
static Future<void> resetPassword(String email) async {
try {
await _supabase.auth.resetPasswordForEmail(email);
print('DEBUG: Email de reset enviado para: $email');
} catch (e) {
print('DEBUG: Erro no resetPassword: $e');
throw Exception('Erro ao redefinir senha: $e');
}
}
// Update user profile
static Future<void> updateProfile({String? name, String? email}) async {
try {
final updates = <String, dynamic>{};
if (name != null) updates['name'] = name;
final userAttributes = UserAttributes(
data: updates.isNotEmpty ? updates : null,
email: email,
);
await _supabase.auth.updateUser(userAttributes);
} catch (e) {
throw Exception('Erro ao atualizar perfil: $e');
}
}
// Test connection to Supabase
static Future<bool> testConnection() async {
try {
print('DEBUG: Testando conexão com Supabase...');
// Test with auth service instead of database
final session = _supabase.auth.currentSession;
print('DEBUG: Sessão atual: ${session != null ? 'ativa' : 'null'}');
// Try to get auth settings (this should work even without tables)
print('DEBUG: Conexão básica funcionando!');
return true;
} catch (e) {
print('DEBUG: Erro na conexão: $e');
return false;
}
}

View File

@@ -33,7 +33,7 @@ class _EntrarSheetState extends State<EntrarSheet> {
// Show success message above the sheet
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
SnackBar(
content: Text(AppStrings.loginSuccess),
backgroundColor: Colors.green,
),
@@ -66,7 +66,7 @@ class _EntrarSheetState extends State<EntrarSheet> {
final email = _emailController.text.trim();
if (email.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
SnackBar(
content: Text(AppStrings.validatorEmailEmpty),
backgroundColor: Colors.orange,
),
@@ -82,7 +82,7 @@ class _EntrarSheetState extends State<EntrarSheet> {
// Show success message above the sheet
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
SnackBar(
content: Text(AppStrings.resetPasswordEmailSent),
backgroundColor: Colors.green,
),
@@ -115,7 +115,7 @@ class _EntrarSheetState extends State<EntrarSheet> {
minChildSize: 0.4, // 40% minimum
maxChildSize: 0.9, // 90% maximum
snap: true, // Enable snap points
snapSizes: [0.6, 0.9], // Snap to 60% or 90%
snapSizes: const [0.6, 0.9], // Snap to 60% or 90%
builder: (context, scrollController) {
return Container(
decoration: BoxDecoration(
@@ -151,9 +151,9 @@ class _EntrarSheetState extends State<EntrarSheet> {
const SizedBox(height: 24),
// Title
const Text(
Text(
AppStrings.loginTitle,
style: TextStyle(
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
@@ -162,9 +162,9 @@ class _EntrarSheetState extends State<EntrarSheet> {
const SizedBox(height: 32),
// Email field
const Text(
Text(
AppStrings.labelEmail,
style: TextStyle(fontSize: 16, color: Colors.white70),
style: const TextStyle(fontSize: 16, color: Colors.white70),
),
const SizedBox(height: 8),
Form(
@@ -196,9 +196,9 @@ class _EntrarSheetState extends State<EntrarSheet> {
const SizedBox(height: 20),
// Password field
const Text(
Text(
AppStrings.labelPassword,
style: TextStyle(fontSize: 16, color: Colors.white70),
style: const TextStyle(fontSize: 16, color: Colors.white70),
),
const SizedBox(height: 8),
TextFormField(
@@ -245,9 +245,9 @@ class _EntrarSheetState extends State<EntrarSheet> {
? const CircularProgressIndicator(
color: Colors.white,
)
: const Text(
: Text(
AppStrings.btnLogin,
style: TextStyle(
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
@@ -260,9 +260,9 @@ class _EntrarSheetState extends State<EntrarSheet> {
Center(
child: TextButton(
onPressed: _handlePasswordReset,
child: const Text(
child: Text(
AppStrings.forgotPassword,
style: TextStyle(color: Colors.white70, fontSize: 16),
style: const TextStyle(color: Colors.white70, fontSize: 16),
),
),
),

View File

@@ -85,10 +85,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.4.1"
clock:
dependency: transitive
description:
@@ -548,18 +548,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
url: "https://pub.dev"
source: hosted
version: "0.12.17"
version: "0.12.19"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
version: "0.13.0"
meta:
dependency: transitive
description:
@@ -945,10 +945,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
url: "https://pub.dev"
source: hosted
version: "0.7.7"
version: "0.7.10"
typed_data:
dependency: transitive
description: