Skip to content

Commit 2c58716

Browse files
committed
feat: Buat fitur memuat user setting di halaman setting_page.dart
1 parent b3d1b14 commit 2c58716

File tree

4 files changed

+181
-46
lines changed

4 files changed

+181
-46
lines changed

assets/translations/en-US.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,5 +267,9 @@
267267
"please_set_start_time": "Please set start time",
268268
"please_set_finish_time": "Please set finish time",
269269
"title_new_update_available": "New update available",
270-
"description_new_update_available": "Click here to download latest version"
270+
"description_new_update_available": "Click here to download latest version",
271+
"screenshot_blur": "Screenshot Blur",
272+
"description_screenshot_blur_user": "Set blurred screenshots. Only super admin can change this configuration.",
273+
"refresh": "Refresh",
274+
"invalid_id_or_user_id": "Invalid ID or user ID"
271275
}

lib/feature/presentation/bloc/setting/setting_bloc.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class SettingBloc extends Bloc<SettingEvent, SettingState> {
7878

7979
FutureOr<void> _onLoadUserSettingEvent(LoadUserSettingEvent event, Emitter<SettingState> emit) async {
8080
emit(LoadingCenterSettingState());
81+
await Future.delayed(const Duration(milliseconds: 500));
8182
final (:response, :failure) = await getUserSetting(NoParams());
8283
if (response != null) {
8384
emit(SuccessLoadUserSettingState(response: response));
@@ -102,6 +103,7 @@ class SettingBloc extends Bloc<SettingEvent, SettingState> {
102103

103104
FutureOr<void> _onUpdateUserSettingEvent(UpdateUserSettingEvent event, Emitter<SettingState> emit) async {
104105
emit(LoadingButtonSettingState());
106+
await Future.delayed(const Duration(milliseconds: 500));
105107
final (:response, :failure) = await updateUserSetting(
106108
ParamsUpdateUserSetting(
107109
body: event.body,

lib/feature/presentation/page/setting/setting_page.dart

Lines changed: 166 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@ import 'package:dipantau_desktop_client/core/util/enum/global_variable.dart';
44
import 'package:dipantau_desktop_client/core/util/enum/user_role.dart';
55
import 'package:dipantau_desktop_client/core/util/helper.dart';
66
import 'package:dipantau_desktop_client/core/util/shared_preferences_manager.dart';
7+
import 'package:dipantau_desktop_client/core/util/string_extension.dart';
78
import 'package:dipantau_desktop_client/core/util/widget_helper.dart';
9+
import 'package:dipantau_desktop_client/feature/data/model/user_setting/user_setting_body.dart';
10+
import 'package:dipantau_desktop_client/feature/data/model/user_setting/user_setting_response.dart';
811
import 'package:dipantau_desktop_client/feature/presentation/bloc/appearance/appearance_bloc.dart';
12+
import 'package:dipantau_desktop_client/feature/presentation/bloc/setting/setting_bloc.dart';
913
import 'package:dipantau_desktop_client/feature/presentation/page/home/home_page.dart';
1014
import 'package:dipantau_desktop_client/feature/presentation/page/member_setting/member_setting_page.dart';
1115
import 'package:dipantau_desktop_client/feature/presentation/page/setting_discord/setting_discord_page.dart';
1216
import 'package:dipantau_desktop_client/feature/presentation/page/setup_credential/setup_credential_page.dart';
1317
import 'package:dipantau_desktop_client/feature/presentation/page/splash/splash_page.dart';
18+
import 'package:dipantau_desktop_client/feature/presentation/widget/widget_custom_circular_progress_indicator.dart';
1419
import 'package:dipantau_desktop_client/feature/presentation/widget/widget_primary_button.dart';
1520
import 'package:dipantau_desktop_client/feature/presentation/widget/widget_theme_container.dart';
1621
import 'package:dipantau_desktop_client/injection_container.dart';
@@ -34,6 +39,7 @@ class SettingPage extends StatefulWidget {
3439
}
3540

3641
class _SettingPageState extends State<SettingPage> {
42+
final settingBloc = sl<SettingBloc>();
3743
final helper = sl<Helper>();
3844
final navigationRailDestinations = <NavigationRailDestination>[];
3945
final sharedPreferencesManager = sl<SharedPreferencesManager>();
@@ -59,6 +65,7 @@ class _SettingPageState extends State<SettingPage> {
5965
var isEnableReminderTrackFri = true;
6066
var isEnableReminderTrackSat = false;
6167
var isEnableReminderTrackSun = false;
68+
UserSettingResponse? userSetting;
6269

6370
@override
6471
void setState(VoidCallback fn) {
@@ -76,6 +83,7 @@ class _SettingPageState extends State<SettingPage> {
7683
final strUserRole = sharedPreferencesManager.getString(SharedPreferencesManager.keyUserRole) ?? '';
7784
userRole = strUserRole.fromStringUserRole;
7885
prepareData();
86+
doLoadUserSetting();
7987
WidgetsBinding.instance.addPostFrameCallback((_) {
8088
setupNavigationRailDestinations();
8189
setState(() {});
@@ -85,59 +93,91 @@ class _SettingPageState extends State<SettingPage> {
8593

8694
@override
8795
Widget build(BuildContext context) {
88-
return Scaffold(
89-
body: navigationRailDestinations.isEmpty
90-
? Container()
91-
: Row(
92-
children: [
93-
Column(
96+
return BlocProvider<SettingBloc>(
97+
create: (context) => settingBloc,
98+
child: BlocListener<SettingBloc, SettingState>(
99+
listener: (context, state) {
100+
if (state is SuccessLoadUserSettingState) {
101+
userSetting = state.response;
102+
} else if (state is SuccessUpdateUserSettingState) {
103+
final newUserSetting = UserSettingResponse(
104+
id: userSetting!.id!,
105+
isEnableBlurScreenshot: !(userSetting!.isEnableBlurScreenshot!),
106+
userId: userSetting!.userId,
107+
name: userSetting!.name,
108+
);
109+
userSetting = newUserSetting;
110+
} else if (state is FailureSettingState) {
111+
final errorMessage = state.errorMessage.convertErrorMessageToHumanMessage();
112+
if (errorMessage.contains('401')) {
113+
widgetHelper.showDialog401(context);
114+
return;
115+
}
116+
widgetHelper.showSnackBar(context, errorMessage.hideResponseCode());
117+
} else if (state is FailureSnackBarSettingState) {
118+
final errorMessage = state.errorMessage.convertErrorMessageToHumanMessage();
119+
if (errorMessage.contains('401')) {
120+
widgetHelper.showDialog401(context);
121+
return;
122+
}
123+
widgetHelper.showSnackBar(context, errorMessage.hideResponseCode());
124+
}
125+
},
126+
child: Scaffold(
127+
body: navigationRailDestinations.isEmpty
128+
? Container()
129+
: Row(
94130
children: [
95-
Expanded(
96-
child: SizedBox(
97-
width: 172,
98-
child: NavigationRail(
99-
destinations: navigationRailDestinations,
100-
selectedIndex: selectedIndexNavigationRail,
101-
onDestinationSelected: (newValue) {
102-
setState(() => selectedIndexNavigationRail = newValue);
103-
},
104-
extended: true,
105-
),
106-
),
107-
),
108-
Padding(
109-
padding: const EdgeInsets.only(bottom: 16.0),
110-
child: TextButton(
111-
onPressed: () => context.pop(),
112-
child: Row(
113-
children: [
114-
const Icon(
115-
Icons.arrow_back_ios_new,
116-
size: 14,
131+
Column(
132+
children: [
133+
Expanded(
134+
child: SizedBox(
135+
width: 172,
136+
child: NavigationRail(
137+
destinations: navigationRailDestinations,
138+
selectedIndex: selectedIndexNavigationRail,
139+
onDestinationSelected: (newValue) {
140+
setState(() => selectedIndexNavigationRail = newValue);
141+
},
142+
extended: true,
117143
),
118-
const SizedBox(width: 4),
119-
Text(
120-
'back_to_main_menu'.tr(),
144+
),
145+
),
146+
Padding(
147+
padding: const EdgeInsets.only(bottom: 16.0),
148+
child: TextButton(
149+
onPressed: () => context.pop(),
150+
child: Row(
151+
children: [
152+
const Icon(
153+
Icons.arrow_back_ios_new,
154+
size: 14,
155+
),
156+
const SizedBox(width: 4),
157+
Text(
158+
'back_to_main_menu'.tr(),
159+
),
160+
],
121161
),
122-
],
162+
),
123163
),
164+
],
165+
),
166+
const VerticalDivider(
167+
thickness: 1,
168+
width: 1,
169+
),
170+
Expanded(
171+
flex: 3,
172+
child: Padding(
173+
padding: const EdgeInsets.all(8.0),
174+
child: buildWidgetBody(),
124175
),
125176
),
126177
],
127178
),
128-
const VerticalDivider(
129-
thickness: 1,
130-
width: 1,
131-
),
132-
Expanded(
133-
flex: 3,
134-
child: Padding(
135-
padding: const EdgeInsets.all(8.0),
136-
child: buildWidgetBody(),
137-
),
138-
),
139-
],
140-
),
179+
),
180+
),
141181
);
142182
}
143183

@@ -193,6 +233,8 @@ class _SettingPageState extends State<SettingPage> {
193233
const SizedBox(height: 16),
194234
buildWidgetAlwaysOnTop(),
195235
const SizedBox(height: 16),
236+
buildWidgetUserSetting(),
237+
const SizedBox(height: 16),
196238
buildWidgetChooseAppearance(),
197239
const SizedBox(height: 16),
198240
buildWidgetCheckForUpdate(),
@@ -1366,4 +1408,83 @@ class _SettingPageState extends State<SettingPage> {
13661408
}
13671409
countTimeReminderTrackInSeconds = 0;
13681410
}
1411+
1412+
Widget buildWidgetUserSetting() {
1413+
return Row(
1414+
crossAxisAlignment: CrossAxisAlignment.start,
1415+
children: [
1416+
Expanded(
1417+
child: Column(
1418+
crossAxisAlignment: CrossAxisAlignment.start,
1419+
children: [
1420+
Text(
1421+
'screenshot_blur'.tr(),
1422+
style: Theme.of(context).textTheme.bodyLarge,
1423+
),
1424+
Text(
1425+
'description_screenshot_blur_user'.tr(),
1426+
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
1427+
color: Colors.grey,
1428+
),
1429+
),
1430+
],
1431+
),
1432+
),
1433+
const SizedBox(width: 16),
1434+
BlocBuilder<SettingBloc, SettingState>(
1435+
builder: (context, state) {
1436+
if (state is LoadingCenterSettingState || state is LoadingButtonSettingState) {
1437+
return const Padding(
1438+
padding: EdgeInsets.all(8.0),
1439+
child: WidgetCustomCircularProgressIndicator(),
1440+
);
1441+
} else if ((state is FailureSettingState || state is FailureSnackBarSettingState) && userSetting == null) {
1442+
return TextButton(
1443+
onPressed: doLoadUserSetting,
1444+
child: Text('refresh'.tr()),
1445+
);
1446+
}
1447+
1448+
if (userSetting == null) {
1449+
return Container();
1450+
}
1451+
1452+
return Switch.adaptive(
1453+
value: userSetting?.isEnableBlurScreenshot ?? false,
1454+
activeColor: Theme.of(context).colorScheme.primary,
1455+
onChanged: userRole == UserRole.superAdmin
1456+
? (value) {
1457+
final id = userSetting?.id;
1458+
final userId = userSetting?.userId;
1459+
if (id == null || userId == null) {
1460+
widgetHelper.showSnackBar(context, 'invalid_id_or_user_id'.tr());
1461+
return;
1462+
}
1463+
1464+
final body = UserSettingBody(
1465+
data: [
1466+
ItemUserSettingBody(
1467+
id: userSetting!.id!,
1468+
isEnableBlurScreenshot: value,
1469+
userId: userSetting!.userId!,
1470+
),
1471+
],
1472+
);
1473+
settingBloc.add(
1474+
UpdateUserSettingEvent(
1475+
body: body,
1476+
),
1477+
);
1478+
}
1479+
: null,
1480+
);
1481+
},
1482+
),
1483+
],
1484+
);
1485+
}
1486+
1487+
void doLoadUserSetting() {
1488+
settingBloc.add(LoadUserSettingEvent());
1489+
}
13691490
}

test/feature/presentation/bloc/setting/setting_bloc_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ void main() {
261261
act: (SettingBloc bloc) {
262262
return bloc.add(tEvent);
263263
},
264+
wait: const Duration(milliseconds: 500),
264265
expect: () => [
265266
isA<LoadingCenterSettingState>(),
266267
isA<SuccessLoadUserSettingState>(),
@@ -281,6 +282,7 @@ void main() {
281282
act: (SettingBloc bloc) {
282283
return bloc.add(tEvent);
283284
},
285+
wait: const Duration(milliseconds: 500),
284286
expect: () => [
285287
isA<LoadingCenterSettingState>(),
286288
isA<FailureSettingState>(),
@@ -301,6 +303,7 @@ void main() {
301303
act: (SettingBloc bloc) {
302304
return bloc.add(tEvent);
303305
},
306+
wait: const Duration(milliseconds: 500),
304307
expect: () => [
305308
isA<LoadingCenterSettingState>(),
306309
isA<FailureSettingState>(),
@@ -321,6 +324,7 @@ void main() {
321324
act: (SettingBloc bloc) {
322325
return bloc.add(tEvent);
323326
},
327+
wait: const Duration(milliseconds: 500),
324328
expect: () => [
325329
isA<LoadingCenterSettingState>(),
326330
isA<FailureSettingState>(),
@@ -446,6 +450,7 @@ void main() {
446450
act: (SettingBloc bloc) {
447451
return bloc.add(tEvent);
448452
},
453+
wait: const Duration(milliseconds: 500),
449454
expect: () => [
450455
isA<LoadingButtonSettingState>(),
451456
isA<SuccessUpdateUserSettingState>(),
@@ -466,6 +471,7 @@ void main() {
466471
act: (SettingBloc bloc) {
467472
return bloc.add(tEvent);
468473
},
474+
wait: const Duration(milliseconds: 500),
469475
expect: () => [
470476
isA<LoadingButtonSettingState>(),
471477
isA<FailureSnackBarSettingState>(),
@@ -486,6 +492,7 @@ void main() {
486492
act: (SettingBloc bloc) {
487493
return bloc.add(tEvent);
488494
},
495+
wait: const Duration(milliseconds: 500),
489496
expect: () => [
490497
isA<LoadingButtonSettingState>(),
491498
isA<FailureSnackBarSettingState>(),
@@ -506,6 +513,7 @@ void main() {
506513
act: (SettingBloc bloc) {
507514
return bloc.add(tEvent);
508515
},
516+
wait: const Duration(milliseconds: 500),
509517
expect: () => [
510518
isA<LoadingButtonSettingState>(),
511519
isA<FailureSnackBarSettingState>(),

0 commit comments

Comments
 (0)