refactor: new chat page text

This commit is contained in:
cogwheel0
2025-09-16 16:24:45 +05:30
parent f1a10caafb
commit acda5a22a6
13 changed files with 164 additions and 84 deletions

View File

@@ -10,8 +10,10 @@ import 'package:flutter_animate/flutter_animate.dart';
import 'dart:io' show Platform;
import 'dart:async';
import '../../../core/providers/app_providers.dart';
import '../../../core/auth/auth_state_manager.dart';
import '../providers/chat_providers.dart';
import '../../../core/utils/debug_logger.dart';
import '../../../core/utils/user_display_name.dart';
import '../widgets/modern_chat_input.dart';
import '../widgets/user_message_bubble.dart';
@@ -847,6 +849,15 @@ class _ChatPageState extends ConsumerState<ChatPage> {
}
Widget _buildEmptyState(ThemeData theme) {
final l10n = AppLocalizations.of(context)!;
final currentUserAsync = ref.watch(currentUserProvider);
final userFromProfile = currentUserAsync.maybeWhen(
data: (user) => user,
orElse: () => null,
);
final dynamic authUser = ref.watch(authUserProvider);
final user = userFromProfile ?? authUser;
final greetingName = deriveUserDisplayName(user);
return Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(Spacing.lg),
@@ -886,7 +897,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
const SizedBox(height: Spacing.xl),
Text(
AppLocalizations.of(context)!.onboardStartTitle,
l10n.onboardStartTitle(greetingName),
style: theme.textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w600,
color: context.conduitTheme.textPrimary,
@@ -897,7 +908,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
const SizedBox(height: Spacing.sm),
Text(
AppLocalizations.of(context)!.typeBelowToBegin,
l10n.typeBelowToBegin,
style: theme.textTheme.bodyLarge?.copyWith(
color: context.conduitTheme.textSecondary,
fontWeight: FontWeight.w400,

View File

@@ -15,7 +15,7 @@ import '../../../shared/utils/ui_utils.dart';
import '../../../shared/widgets/themed_dialogs.dart';
import '../../../core/auth/auth_state_manager.dart';
import 'package:conduit/l10n/app_localizations.dart';
import '../../../core/models/user.dart' as models;
import '../../../core/utils/user_display_name.dart';
class ChatsDrawer extends ConsumerStatefulWidget {
const ChatsDrawer({super.key});
@@ -1148,43 +1148,6 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
);
final dynamic authUser = ref.watch(authUserProvider);
final user = userFromProfile ?? authUser;
String _displayName(dynamic u) {
if (u == null) return 'User';
if (u is models.User) {
return (u.name?.isNotEmpty == true ? u.name : u.username) ?? 'User';
}
if (u is Map) {
final Map m = u;
String? _asString(dynamic v) =>
v is String && v.trim().isNotEmpty ? v.trim() : null;
String? _pick(Map source) {
return _asString(source['name']) ??
_asString(source['display_name']) ??
_asString(source['preferred_username']) ??
_asString(source['username']);
}
final top = _pick(m);
if (top != null) return top;
final nestedUser = m['user'];
if (nestedUser is Map) {
final nested = _pick(nestedUser);
if (nested != null) return nested;
final nestedEmail = _asString(nestedUser['email']);
if (nestedEmail != null && nestedEmail.contains('@')) {
return nestedEmail.split('@').first;
}
}
final email = _asString(m['email']);
if (email != null && email.contains('@')) {
return email.split('@').first;
}
return 'User';
}
// Fallback to string representation if some other type
final s = u.toString();
return s.isNotEmpty ? s : 'User';
}
String _initial(String name) {
if (name.isEmpty) return 'U';
@@ -1192,7 +1155,7 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
return ch.toUpperCase();
}
final displayName = _displayName(user);
final displayName = deriveUserDisplayName(user);
final initial = _initial(displayName);
return Padding(
padding: const EdgeInsets.fromLTRB(Spacing.sm, 0, Spacing.sm, Spacing.sm),

View File

@@ -1,29 +1,44 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../../../shared/theme/theme_extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_animate/flutter_animate.dart';
import '../../../shared/widgets/sheet_handle.dart';
import 'package:conduit/l10n/app_localizations.dart';
class OnboardingSheet extends StatefulWidget {
import '../../../core/auth/auth_state_manager.dart';
import '../../../core/providers/app_providers.dart';
import '../../../core/utils/user_display_name.dart';
import '../../../shared/theme/theme_extensions.dart';
import '../../../shared/widgets/sheet_handle.dart';
class OnboardingSheet extends ConsumerStatefulWidget {
const OnboardingSheet({super.key});
@override
State<OnboardingSheet> createState() => _OnboardingSheetState();
ConsumerState<OnboardingSheet> createState() => _OnboardingSheetState();
}
class _OnboardingSheetState extends State<OnboardingSheet> {
class _OnboardingSheetState extends ConsumerState<OnboardingSheet> {
final PageController _controller = PageController();
int _index = 0;
late List<_OnboardingPage> _pages;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final l10n = AppLocalizations.of(context)!;
_pages = [
void _next(int pageCount) {
if (_index < pageCount - 1) {
_controller.nextPage(
duration: AnimationDuration.fast,
curve: AnimationCurves.easeInOut,
);
} else {
Navigator.pop(context);
}
}
List<_OnboardingPage> _buildPages(
AppLocalizations l10n,
String greetingName,
) {
return [
_OnboardingPage(
title: l10n.onboardStartTitle,
title: l10n.onboardStartTitle(greetingName),
subtitle: l10n.onboardStartSubtitle,
icon: CupertinoIcons.chat_bubble_2,
bullets: [l10n.onboardStartBullet1, l10n.onboardStartBullet2],
@@ -49,20 +64,20 @@ class _OnboardingSheetState extends State<OnboardingSheet> {
];
}
void _next() {
if (_index < _pages.length - 1) {
_controller.nextPage(
duration: AnimationDuration.fast,
curve: AnimationCurves.easeInOut,
);
} else {
Navigator.pop(context);
}
}
@override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
final l10n = AppLocalizations.of(context)!;
final currentUserAsync = ref.watch(currentUserProvider);
final userFromProfile = currentUserAsync.maybeWhen(
data: (user) => user,
orElse: () => null,
);
final dynamic authUser = ref.watch(authUserProvider);
final user = userFromProfile ?? authUser;
final greetingName = deriveUserDisplayName(user);
final pages = _buildPages(l10n, greetingName);
final pageCount = pages.length;
return Container(
height: height * 0.7,
decoration: BoxDecoration(
@@ -83,10 +98,10 @@ class _OnboardingSheetState extends State<OnboardingSheet> {
Expanded(
child: PageView.builder(
controller: _controller,
itemCount: _pages.length,
itemCount: pageCount,
onPageChanged: (i) => setState(() => _index = i),
itemBuilder: (context, i) {
final page = _pages[i];
final page = pages[i];
final content = _IllustratedPage(page: page);
// Ensure content can scroll vertically when space is tight,
// while keeping it centered when there is enough space.
@@ -111,7 +126,7 @@ class _OnboardingSheetState extends State<OnboardingSheet> {
const SizedBox(height: Spacing.md),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(_pages.length, (i) {
children: List.generate(pageCount, (i) {
final active = i == _index;
return AnimatedContainer(
duration: AnimationDuration.fast,
@@ -136,7 +151,7 @@ class _OnboardingSheetState extends State<OnboardingSheet> {
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(
AppLocalizations.of(context)!.skip,
l10n.skip,
style: TextStyle(
color: context.conduitTheme.textSecondary,
),
@@ -144,7 +159,7 @@ class _OnboardingSheetState extends State<OnboardingSheet> {
),
const Spacer(),
FilledButton(
onPressed: _next,
onPressed: () => _next(pageCount),
style: FilledButton.styleFrom(
backgroundColor: context.conduitTheme.buttonPrimary,
foregroundColor: context.conduitTheme.buttonPrimaryText,
@@ -159,9 +174,7 @@ class _OnboardingSheetState extends State<OnboardingSheet> {
),
),
child: Text(
_index == _pages.length - 1
? AppLocalizations.of(context)!.done
: AppLocalizations.of(context)!.next,
_index == pageCount - 1 ? l10n.done : l10n.next,
),
),
],