Files
fuckKomet/lib/utils/user_id_lookup_screen.dart

264 lines
8.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:gwid/api/api_service.dart';
import 'package:gwid/models/contact.dart';
class UserIdLookupScreen extends StatefulWidget {
const UserIdLookupScreen({super.key});
@override
State<UserIdLookupScreen> createState() => _UserIdLookupScreenState();
}
class _UserIdLookupScreenState extends State<UserIdLookupScreen> {
final TextEditingController _idController = TextEditingController();
final FocusNode _idFocusNode = FocusNode();
bool _isLoading = false;
Contact? _foundContact;
bool _searchAttempted = false;
Future<void> _searchById() async {
final String idText = _idController.text.trim();
if (idText.isEmpty) {
return;
}
final int? contactId = int.tryParse(idText);
if (contactId == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Пожалуйста, введите корректный ID (только цифры)'),
),
);
return;
}
_idFocusNode.unfocus();
setState(() {
_isLoading = true;
_searchAttempted = true;
_foundContact = null;
});
try {
final List<Contact> contacts = await ApiService.instance
.fetchContactsByIds([contactId]);
if (mounted) {
setState(() {
_foundContact = contacts.isNotEmpty ? contacts.first : null;
_isLoading = false;
});
}
} catch (e) {
if (mounted) {
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Ошибка при поиске: $e')));
}
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_idFocusNode.requestFocus();
});
}
@override
Widget build(BuildContext context) {
final colors = Theme.of(context).colorScheme;
return Scaffold(
appBar: AppBar(title: const Text('Поиск по ID')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
TextField(
controller: _idController,
focusNode: _idFocusNode,
decoration: InputDecoration(
labelText: 'Введите ID пользователя',
filled: true,
fillColor: colors.surfaceContainerHighest,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
prefixIcon: const Icon(Icons.person_search_outlined),
suffixIcon: _isLoading
? const Padding(
padding: EdgeInsets.all(12.0),
child: CircularProgressIndicator(strokeWidth: 2),
)
: IconButton(
icon: const Icon(Icons.search),
onPressed: _searchById,
),
),
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onSubmitted: (_) => _searchById(),
),
const SizedBox(height: 32),
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: _isLoading
? const Center(
key: ValueKey('loading'),
child: CircularProgressIndicator(),
)
: _searchAttempted
? _foundContact != null
? _buildContactCard(_foundContact!, colors)
: _buildEmptyState(
key: const ValueKey('not_found'),
colors: colors,
icon: Icons.search_off_rounded,
title: 'Пользователь не найден',
subtitle:
'Аккаунт с ID "${_idController.text}" не существует или скрыт.',
)
: _buildEmptyState(
key: const ValueKey('initial'),
colors: colors,
icon: Icons.person_search_rounded,
title: 'Введите ID для поиска',
subtitle: 'Найдем пользователя в системе по его ID',
),
),
],
),
),
);
}
Widget _buildContactCard(Contact contact, ColorScheme colors) {
return Column(
key: const ValueKey('contact_card'),
children: [
CircleAvatar(
radius: 56,
backgroundColor: colors.primaryContainer,
backgroundImage: contact.photoBaseUrl != null
? NetworkImage(contact.photoBaseUrl!)
: null,
child: contact.photoBaseUrl == null
? Text(
contact.name.isNotEmpty ? contact.name[0].toUpperCase() : '?',
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
color: colors.onPrimaryContainer,
),
)
: null,
),
const SizedBox(height: 16),
Text(
contact.name,
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 4),
Text(
'ID: ${contact.id}',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: colors.onSurfaceVariant),
),
const SizedBox(height: 24),
Container(
decoration: BoxDecoration(
color: colors.surfaceContainer,
borderRadius: BorderRadius.circular(16),
),
child: Column(
children: [
_buildInfoTile(
colors: colors,
icon: Icons.person_outlined,
title: 'Имя',
subtitle: contact.firstName,
),
const Divider(height: 1, indent: 16, endIndent: 16),
_buildInfoTile(
colors: colors,
icon: Icons.badge_outlined,
title: 'Фамилия',
subtitle: contact.lastName,
),
const Divider(height: 1, indent: 16, endIndent: 16),
_buildInfoTile(
colors: colors,
icon: Icons.notes_rounded,
title: 'Описание',
subtitle: contact.description,
),
],
),
),
],
);
}
Widget _buildInfoTile({
required ColorScheme colors,
required IconData icon,
required String title,
String? subtitle,
}) {
final bool hasData = subtitle != null && subtitle.isNotEmpty;
return ListTile(
leading: Icon(icon, color: colors.primary),
title: Text(title),
subtitle: Text(
hasData ? subtitle : '(не указано)',
style: TextStyle(
color: hasData
? colors.onSurfaceVariant
: colors.onSurfaceVariant.withOpacity(0.7),
fontStyle: hasData ? FontStyle.normal : FontStyle.italic,
),
),
);
}
Widget _buildEmptyState({
required Key key,
required ColorScheme colors,
required IconData icon,
required String title,
required String subtitle,
}) {
return Column(
key: key,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 64, color: colors.onSurfaceVariant.withOpacity(0.5)),
const SizedBox(height: 16),
Text(
title,
style: Theme.of(
context,
).textTheme.titleLarge?.copyWith(color: colors.onSurfaceVariant),
),
const SizedBox(height: 8),
Text(
subtitle,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: colors.onSurfaceVariant.withOpacity(0.7),
),
textAlign: TextAlign.center,
),
],
);
}
}