Skip to content

Commit

Permalink
add setup language
Browse files Browse the repository at this point in the history
  • Loading branch information
bangindong committed Nov 12, 2024
1 parent 4df4307 commit 4427d55
Show file tree
Hide file tree
Showing 20 changed files with 334 additions and 20 deletions.
6 changes: 4 additions & 2 deletions lib/_shared/data/chat_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@ final class UserDetail {
final String displayName;
final String? photoUrl;
final String uid;
final String? language;

UserDetail.fromFirebaseUser(User user)
UserDetail.fromFirebaseUser(User user, this.language)
: displayName = user.displayName ?? 'Unknown',
photoUrl = user.photoURL,
uid = user.uid;

UserDetail.fromMap(this.uid, Map<String, dynamic> map)
: displayName = map['displayName'],
language = map['language'],
photoUrl = map['photoUrl'];

Map<String, dynamic> toMap() =>
{'displayName': displayName, 'photoUrl': photoUrl};
{'displayName': displayName, 'photoUrl': photoUrl, 'language': language};
}
25 changes: 17 additions & 8 deletions lib/_shared/widgets/chat_bubble_widget.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:image_network/image_network.dart';
import 'package:public_chat/features/language_setting/constants.dart';
import 'package:public_chat/features/language_setting/ui/widgets/button_language_setting/button_language_setting.dart';
import 'package:public_chat/repository/database.dart';

import '../bloc/user_manager/user_manager_cubit.dart';

class ChatBubble extends StatelessWidget {
final bool isMine;
Expand All @@ -10,13 +16,14 @@ class ChatBubble extends StatelessWidget {

final double _iconSize = 24.0;

const ChatBubble(
{required this.isMine,
required this.message,
required this.photoUrl,
required this.displayName,
this.translations = const {},
super.key});
const ChatBubble({
required this.isMine,
required this.message,
required this.photoUrl,
required this.displayName,
this.translations = const {},
super.key,
});

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -73,7 +80,9 @@ class ChatBubble extends StatelessWidget {
if (translations.isNotEmpty)
...translations.entries
.where(
(element) => element.key != 'original',
(element) =>
element.key != 'original' &&
element.key == context.languageUser,
)
.map(
(e) => Text.rich(
Expand Down
4 changes: 4 additions & 0 deletions lib/features/chat/ui/public_chat_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import 'package:public_chat/_shared/widgets/message_box_widget.dart';
import 'package:public_chat/features/chat/bloc/chat_cubit.dart';
import 'package:public_chat/utils/locale_support.dart';

import '../../language_setting/ui/widgets/button_language_setting/button_language_setting.dart';

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

Expand All @@ -21,7 +23,9 @@ class PublicChatScreen extends StatelessWidget {
create: (context) => ChatCubit(),
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(context.locale.publicRoomTitle),
actions: const [ButtonLanguageSetting()],
),
body: Column(
children: [
Expand Down
18 changes: 18 additions & 0 deletions lib/features/language_setting/bloc/language_setting_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:public_chat/features/language_support/data/language.dart';
import 'package:public_chat/repository/database.dart';

part 'language_setting_state.dart';

class LanguageSettingCubit extends Cubit<String> {
LanguageSettingCubit(super.initialState);

void chooseLanguage(LanguageSupport dataLanguage) {
emit(dataLanguage.code ?? 'en');
}

void saveLanguage() {
Database.instance.saveLanguageUser(state);
}
}
28 changes: 28 additions & 0 deletions lib/features/language_setting/bloc/language_setting_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
part of 'language_setting_cubit.dart';

abstract class LanguageSettingState extends Equatable {
const LanguageSettingState();
}

class LanguageSettingInitial extends LanguageSettingState {
@override
List<Object> get props => [];
}

class LanguageSettingSuccess extends LanguageSettingState {
final String language;

const LanguageSettingSuccess(this.language);

@override
List<Object?> get props => [language];
}

class LanguageSettingFailed extends LanguageSettingState {
final String reason;

const LanguageSettingFailed(this.reason);

@override
List<Object?> get props => [reason];
}
25 changes: 25 additions & 0 deletions lib/features/language_setting/bloc/user_language_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'dart:async';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:public_chat/repository/database.dart';
import 'package:public_chat/utils/bloc_extensions.dart';

class UserLanguageCubit extends Cubit<String> {
StreamSubscription<String>? _userLanguageListen;
UserLanguageCubit() : super('en');

void startListen() {
_userLanguageListen = Database.instance.listenLanguageSettingUser()?.listen(
(event) {
emitSafely(event);
},
);
}

@override
Future<void> close() {
_userLanguageListen?.cancel();
_userLanguageListen = null;
return super.close();
}
}
24 changes: 24 additions & 0 deletions lib/features/language_setting/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:public_chat/features/language_setting/bloc/language_setting_cubit.dart';
import 'package:public_chat/features/language_setting/bloc/user_language_cubit.dart';
import 'package:public_chat/features/language_support/bloc/language_support_cubit.dart';
import 'package:public_chat/features/language_support/data/language.dart';

extension GetLanguageSupport on BuildContext {
LanguageSupport languageUserObject(String language) {
var languageUser = read<LanguageSupportCubit>().state.firstWhere(
(element) => element == LanguageSupport(code: language),
);
return languageUser;
}

String get languageUser {
return read<UserLanguageCubit>().state;
}

LanguageSupport get languageTempUser {
var languageTempUser = read<LanguageSettingCubit>().state;
return LanguageSupport(code: languageTempUser);
}
}
96 changes: 96 additions & 0 deletions lib/features/language_setting/ui/language_setting_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:public_chat/features/language_setting/bloc/user_language_cubit.dart';
import 'package:public_chat/features/language_support/bloc/language_support_cubit.dart';
import 'package:public_chat/utils/locale_support.dart';

import '../../language_support/data/language.dart';
import '../bloc/language_setting_cubit.dart';

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

@override
Widget build(BuildContext context) => BlocProvider<LanguageSettingCubit>(
create: (context) =>
LanguageSettingCubit(context.read<UserLanguageCubit>().state),
child: const _SettingLangeScreenBody(),
);
}

class _SettingLangeScreenBody extends StatelessWidget {
const _SettingLangeScreenBody();

@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(context.locale.settingLanguage),
),
body: BlocBuilder<LanguageSupportCubit, List<LanguageSupport>>(
builder: (context, listLanguage) {
if (listLanguage.isEmpty) {
return Container();
}
return ListView.builder(
itemBuilder: (context, index) {
var dataLanguage = listLanguage[index];
return ChildLanguage(dataLanguage);
},
itemCount: listLanguage.length,
);
},
),
bottomNavigationBar: ElevatedButton(
onPressed: () {
context.read<LanguageSettingCubit>().saveLanguage();
Navigator.pop(context);
},
style: ButtonStyle(
fixedSize: WidgetStateProperty.all(const Size.fromHeight(70)),
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
borderRadius: BorderRadius.zero)),
backgroundColor: WidgetStateProperty.all(Colors.green)),
child: const Text('OK',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 25)),
),
);
}

class ChildLanguage extends StatelessWidget {
final LanguageSupport dataLanguage;
const ChildLanguage(this.dataLanguage, {super.key});

@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => _chooseLanguage(dataLanguage, context),
child: BlocBuilder<LanguageSettingCubit, String>(
builder: (context, state) {
return RadioListTile<LanguageSupport>(
value: dataLanguage,
onChanged: (choose) => _chooseLanguage(dataLanguage, context),
title: Row(
children: [
Text(dataLanguage.nativeName ?? ''),
const SizedBox(
width: 10,
),
Text(dataLanguage.flag ?? '',
style: const TextStyle(fontSize: 24))
],
),
groupValue: LanguageSupport(code: state),
);
},
),
);
}

_chooseLanguage(LanguageSupport dataLanguage, BuildContext context) {
context.read<LanguageSettingCubit>().chooseLanguage(dataLanguage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:public_chat/features/language_setting/bloc/user_language_cubit.dart';
import 'package:public_chat/features/language_setting/constants.dart';
import 'package:public_chat/features/language_support/data/language.dart';

import '../../language_setting_screen.dart';

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

@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SettingLanguageScreen(),
));
},
child: Padding(
padding: const EdgeInsets.only(right: 10.0),
child: BlocBuilder<UserLanguageCubit, String>(
builder: (context, state) {
LanguageSupport languageUser = context.languageUserObject(state);
return Text(
languageUser.flag ?? '',
style: const TextStyle(fontSize: 20),
);
},
),
),
);
}
}
5 changes: 3 additions & 2 deletions lib/features/login/bloc/login_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ class LoginCubit extends Cubit<LoginState> {
return;
}

database.saveUser(user);
emitSafely(LoginSuccess(user.displayName ?? 'Unknown display name'));
var userData = await database.saveUser(user);
emitSafely(LoginSuccess(user.displayName ?? 'Unknown display name',
userData.language ?? 'en'));
} on FirebaseAuthException catch (e) {
emitSafely(LoginFailed(e.toString()));
return;
Expand Down
5 changes: 3 additions & 2 deletions lib/features/login/bloc/login_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ class LoginInitial extends LoginState {

class LoginSuccess extends LoginState {
final String displayName;
final String languageCode;

const LoginSuccess(this.displayName);
const LoginSuccess(this.displayName, this.languageCode);

@override
List<Object?> get props => [displayName];
List<Object?> get props => [displayName, languageCode];
}

class LoginFailed extends LoginState {
Expand Down
2 changes: 2 additions & 0 deletions lib/features/login/ui/login_screen.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:public_chat/features/chat/ui/public_chat_screen.dart';
import 'package:public_chat/features/language_setting/bloc/user_language_cubit.dart';
import 'package:public_chat/features/login/bloc/login_cubit.dart';
import 'package:public_chat/features/login/ui/widgets/sign_in_button.dart';
import 'package:public_chat/utils/locale_support.dart';
Expand All @@ -24,6 +25,7 @@ class _LoginScreenBody extends StatelessWidget {
if (state is LoginSuccess) {
// open public chat screen
// use Navigator temporary, will be changed later
context.read<UserLanguageCubit>().startListen();
Navigator.pushReplacement(
context,
MaterialPageRoute(
Expand Down
3 changes: 2 additions & 1 deletion lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"login":"Login",
"publicRoomTitle": "Public Room"
"publicRoomTitle": "Public Room",
"settingLanguage": "Setting Language"
}
4 changes: 2 additions & 2 deletions lib/l10n/app_vi.arb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"login":"Đăng nhập",
"publicRoomTitle": "Phòng chat công cộng"

"publicRoomTitle": "Phòng chat công cộng",
"settingLanguage": "Cài đặt ngôn ngữ"
}
4 changes: 4 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:public_chat/features/genai_setting/bloc/genai_bloc.dart';
import 'package:public_chat/features/language_setting/bloc/user_language_cubit.dart';
import 'package:public_chat/features/login/ui/login_screen.dart';
import 'package:public_chat/firebase_options.dart';
import 'package:public_chat/service_locator/service_locator.dart';
Expand All @@ -25,6 +26,9 @@ void main() async {
create: (context) => LanguageSupportCubit(),
lazy: false,
),
BlocProvider(
create: (context) => UserLanguageCubit(),
),
],
child: const MainApp(),
));
Expand Down
Loading

0 comments on commit 4427d55

Please sign in to comment.