Skip to content

Commit 91d907a

Browse files
authored
Merge pull request #41 from flutter-news-app-full-source-code/refactor-streamline-source-language-selection
Refactor streamline source language selection
2 parents acf62ce + 0ffd856 commit 91d907a

14 files changed

+155
-40
lines changed

lib/content_management/bloc/create_source/create_source_bloc.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import 'package:core/core.dart';
33
import 'package:country_picker/country_picker.dart' as picker;
44
import 'package:data_repository/data_repository.dart';
55
import 'package:equatable/equatable.dart';
6-
import 'package:flutter/foundation.dart';
6+
import 'package:flutter/material.dart';
77
import 'package:flutter_news_app_web_dashboard_full_source_code/shared/shared.dart';
8+
import 'package:language_picker/languages.dart';
89
import 'package:uuid/uuid.dart';
910

1011
part 'create_source_event.dart';
@@ -72,7 +73,7 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
7273
CreateSourceLanguageChanged event,
7374
Emitter<CreateSourceState> emit,
7475
) {
75-
emit(state.copyWith(language: event.language));
76+
emit(state.copyWith(language: () => event.language));
7677
}
7778

7879
void _onHeadquartersChanged(
@@ -115,7 +116,7 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
115116
description: state.description,
116117
url: state.url,
117118
sourceType: state.sourceType!,
118-
language: state.language,
119+
language: adaptPackageLanguageToLanguageCode(state.language!),
119120
createdAt: now,
120121
updatedAt: now,
121122
headquarters: state.headquarters!,

lib/content_management/bloc/create_source/create_source_event.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ final class CreateSourceTypeChanged extends CreateSourceEvent {
4848
/// Event for when the source's language is changed.
4949
final class CreateSourceLanguageChanged extends CreateSourceEvent {
5050
const CreateSourceLanguageChanged(this.language);
51-
final String language;
51+
final Language? language;
5252
@override
5353
List<Object?> get props => [language];
5454
}

lib/content_management/bloc/create_source/create_source_state.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ final class CreateSourceState extends Equatable {
2727
this.description = '',
2828
this.url = '',
2929
this.sourceType,
30-
this.language = '',
30+
this.language,
3131
this.headquarters,
3232
this.contentStatus = ContentStatus.active,
3333
this.exception,
@@ -39,7 +39,7 @@ final class CreateSourceState extends Equatable {
3939
final String description;
4040
final String url;
4141
final SourceType? sourceType;
42-
final String language;
42+
final Language? language;
4343
final Country? headquarters;
4444
final ContentStatus contentStatus;
4545
final HttpException? exception;
@@ -51,7 +51,7 @@ final class CreateSourceState extends Equatable {
5151
description.isNotEmpty &&
5252
url.isNotEmpty &&
5353
sourceType != null &&
54-
language.isNotEmpty &&
54+
language != null &&
5555
headquarters != null;
5656

5757
CreateSourceState copyWith({
@@ -60,7 +60,7 @@ final class CreateSourceState extends Equatable {
6060
String? description,
6161
String? url,
6262
ValueGetter<SourceType?>? sourceType,
63-
String? language,
63+
ValueGetter<Language?>? language,
6464
ValueGetter<Country?>? headquarters,
6565
ContentStatus? contentStatus,
6666
HttpException? exception,
@@ -72,7 +72,7 @@ final class CreateSourceState extends Equatable {
7272
description: description ?? this.description,
7373
url: url ?? this.url,
7474
sourceType: sourceType != null ? sourceType() : this.sourceType,
75-
language: language ?? this.language,
75+
language: language != null ? language() : this.language,
7676
headquarters: headquarters != null ? headquarters() : this.headquarters,
7777
contentStatus: contentStatus ?? this.contentStatus,
7878
exception: exception,

lib/content_management/bloc/edit_source/edit_source_bloc.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:equatable/equatable.dart';
66
import 'package:flutter/foundation.dart';
77
import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/app_localizations.dart';
88
import 'package:flutter_news_app_web_dashboard_full_source_code/shared/shared.dart';
9+
import 'package:language_picker/languages.dart';
910

1011
part 'edit_source_event.dart';
1112
part 'edit_source_state.dart';
@@ -48,7 +49,9 @@ class EditSourceBloc extends Bloc<EditSourceEvent, EditSourceState> {
4849
description: source.description,
4950
url: source.url,
5051
sourceType: () => source.sourceType,
51-
language: source.language,
52+
language: () => adaptLanguageCodeToPackageLanguage(
53+
source.language,
54+
),
5255
headquarters: () => source.headquarters,
5356
contentStatus: source.status,
5457
),
@@ -109,7 +112,7 @@ class EditSourceBloc extends Bloc<EditSourceEvent, EditSourceState> {
109112
) {
110113
emit(
111114
state.copyWith(
112-
language: event.language,
115+
language: () => event.language,
113116
status: EditSourceStatus.initial,
114117
),
115118
);
@@ -169,7 +172,7 @@ class EditSourceBloc extends Bloc<EditSourceEvent, EditSourceState> {
169172
description: state.description,
170173
url: state.url,
171174
sourceType: state.sourceType,
172-
language: state.language,
175+
language: adaptPackageLanguageToLanguageCode(state.language!),
173176
headquarters: state.headquarters,
174177
status: state.contentStatus,
175178
updatedAt: DateTime.now(),

lib/content_management/bloc/edit_source/edit_source_event.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ final class EditSourceTypeChanged extends EditSourceEvent {
5656
/// Event triggered when the source language input changes.
5757
final class EditSourceLanguageChanged extends EditSourceEvent {
5858
const EditSourceLanguageChanged(this.language);
59-
60-
final String language;
59+
final Language? language;
6160

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

lib/content_management/bloc/edit_source/edit_source_state.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ final class EditSourceState extends Equatable {
2727
this.description = '',
2828
this.url = '',
2929
this.sourceType,
30-
this.language = '',
30+
this.language,
3131
this.headquarters,
3232
this.contentStatus = ContentStatus.active,
3333
this.exception,
@@ -40,7 +40,7 @@ final class EditSourceState extends Equatable {
4040
final String description;
4141
final String url;
4242
final SourceType? sourceType;
43-
final String language;
43+
final Language? language;
4444
final Country? headquarters;
4545
final ContentStatus contentStatus;
4646
final HttpException? exception;
@@ -52,7 +52,7 @@ final class EditSourceState extends Equatable {
5252
description.isNotEmpty &&
5353
url.isNotEmpty &&
5454
sourceType != null &&
55-
language.isNotEmpty &&
55+
language != null &&
5656
headquarters != null;
5757

5858
EditSourceState copyWith({
@@ -62,7 +62,7 @@ final class EditSourceState extends Equatable {
6262
String? description,
6363
String? url,
6464
ValueGetter<SourceType?>? sourceType,
65-
String? language,
65+
ValueGetter<Language?>? language,
6666
ValueGetter<Country?>? headquarters,
6767
ContentStatus? contentStatus,
6868
HttpException? exception,
@@ -75,7 +75,7 @@ final class EditSourceState extends Equatable {
7575
description: description ?? this.description,
7676
url: url ?? this.url,
7777
sourceType: sourceType != null ? sourceType() : this.sourceType,
78-
language: language ?? this.language,
78+
language: language != null ? language() : this.language,
7979
headquarters: headquarters != null ? headquarters() : this.headquarters,
8080
contentStatus: contentStatus ?? this.contentStatus,
8181
exception: exception,

lib/content_management/view/create_source_page.dart

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,13 @@ class _CreateSourceViewState extends State<_CreateSourceView> {
160160
.add(CreateSourceUrlChanged(value)),
161161
),
162162
const SizedBox(height: AppSpacing.lg),
163-
TextFormField(
163+
LanguagePickerFormField(
164+
labelText: l10n.language,
164165
initialValue: state.language,
165-
decoration: InputDecoration(
166-
labelText: l10n.language,
167-
border: const OutlineInputBorder(),
168-
),
169-
onChanged: (value) => context
170-
.read<CreateSourceBloc>()
171-
.add(CreateSourceLanguageChanged(value)),
166+
onChanged: (language) =>
167+
context.read<CreateSourceBloc>().add(
168+
CreateSourceLanguageChanged(language),
169+
),
172170
),
173171
const SizedBox(height: AppSpacing.lg),
174172
DropdownButtonFormField<SourceType?>(

lib/content_management/view/edit_source_page.dart

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ class _EditSourceViewState extends State<_EditSourceView> {
4545
late final TextEditingController _nameController;
4646
late final TextEditingController _descriptionController;
4747
late final TextEditingController _urlController;
48-
late final TextEditingController _languageController;
4948

5049
@override
5150
void initState() {
@@ -54,15 +53,13 @@ class _EditSourceViewState extends State<_EditSourceView> {
5453
_nameController = TextEditingController(text: state.name);
5554
_descriptionController = TextEditingController(text: state.description);
5655
_urlController = TextEditingController(text: state.url);
57-
_languageController = TextEditingController(text: state.language);
5856
}
5957

6058
@override
6159
void dispose() {
6260
_nameController.dispose();
6361
_descriptionController.dispose();
6462
_urlController.dispose();
65-
_languageController.dispose();
6663
super.dispose();
6764
}
6865

@@ -130,7 +127,6 @@ class _EditSourceViewState extends State<_EditSourceView> {
130127
_nameController.text = state.name;
131128
_descriptionController.text = state.description;
132129
_urlController.text = state.url;
133-
_languageController.text = state.language;
134130
}
135131
},
136132
builder: (context, state) {
@@ -193,15 +189,13 @@ class _EditSourceViewState extends State<_EditSourceView> {
193189
),
194190
),
195191
const SizedBox(height: AppSpacing.lg),
196-
TextFormField(
197-
controller: _languageController,
198-
decoration: InputDecoration(
199-
labelText: l10n.language,
200-
border: const OutlineInputBorder(),
201-
),
202-
onChanged: (value) => context.read<EditSourceBloc>().add(
203-
EditSourceLanguageChanged(value),
204-
),
192+
LanguagePickerFormField(
193+
labelText: l10n.language,
194+
initialValue: state.language,
195+
onChanged: (language) =>
196+
context.read<EditSourceBloc>().add(
197+
EditSourceLanguageChanged(language),
198+
),
205199
),
206200
const SizedBox(height: AppSpacing.lg),
207201
DropdownButtonFormField<SourceType?>(
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import 'package:language_picker/languages.dart';
2+
3+
/// Adapts a [Language] object from the `language_picker` package to a
4+
/// language code string (e.g., 'en', 'ar').
5+
///
6+
/// This is used to convert the selected language from the UI picker into the
7+
/// format expected by the `Source` model in the core package.
8+
String adaptPackageLanguageToLanguageCode(Language language) {
9+
return language.isoCode;
10+
}
11+
12+
/// Adapts a language code string (e.g., 'en', 'ar') to a [Language] object
13+
/// from the `language_picker` package.
14+
///
15+
/// This is used to convert the language code from a `Source` model into an
16+
/// object that can be used to set the initial value of the language picker.
17+
///
18+
/// Returns `null` if the language code is not found.
19+
Language? adaptLanguageCodeToPackageLanguage(String languageCode) {
20+
try {
21+
return Languages.defaultLanguages.firstWhere(
22+
(lang) => lang.isoCode.toLowerCase() == languageCode.toLowerCase(),
23+
);
24+
} catch (_) {
25+
// Return null if no matching language is found
26+
return null;
27+
}
28+
}

lib/shared/utils/utils.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export 'country_adapter.dart';
2+
export 'language_adapter.dart';

0 commit comments

Comments
 (0)