Complete refactoring SFM App Source Code

This commit is contained in:
anhtunz
2024-12-15 00:59:02 +07:00
parent caa73ca43c
commit 2e27d59278
247 changed files with 18390 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'device_notification_settings_model.dart';
import '../../../product/base/bloc/base_bloc.dart';
class DeviceNotificationSettingsBloc extends BlocBase {
final listNotifications =
StreamController<List<DeviceNotificationSettings>>.broadcast();
StreamSink<List<DeviceNotificationSettings>> get sinkListNotifications =>
listNotifications.sink;
Stream<List<DeviceNotificationSettings>> get streamListNotifications =>
listNotifications.stream;
final deviceThingID = StreamController<String>.broadcast();
StreamSink<String> get sinkDeviceThingID => deviceThingID.sink;
Stream<String> get streamDeviceThingID => deviceThingID.stream;
final deviceNotificationSettingMap =
StreamController<Map<String, int>>.broadcast();
StreamSink<Map<String, int>> get sinkDeviceNotificationSettingMap =>
deviceNotificationSettingMap.sink;
Stream<Map<String, int>> get streamDeviceNotificationSettingMap =>
deviceNotificationSettingMap.stream;
final isDataChange = StreamController<bool>.broadcast();
StreamSink<bool> get sinkIsDataChange => isDataChange.sink;
Stream<bool> get streamIsDataChange => isDataChange.stream;
final iconChange = StreamController<IconData>.broadcast();
StreamSink<IconData> get sinkIconChange => iconChange.sink;
Stream<IconData> get streamIconChange => iconChange.stream;
final messageChange = StreamController<String>.broadcast();
StreamSink<String> get sinkMessageChange => messageChange.sink;
Stream<String> get streaMmessageChange => messageChange.stream;
@override
void dispose() {}
}

View File

@@ -0,0 +1,56 @@
class DeviceNotificationSettings {
String? id;
String? userId;
String? thingId;
DeviceAliasSettings? settings;
DateTime? updatedAt;
DeviceNotificationSettings({
this.id,
this.userId,
this.thingId,
this.settings,
this.updatedAt,
});
DeviceNotificationSettings.fromJson(Map<String, dynamic> json) {
id = json["id"];
userId = json["user_id"];
thingId = json["thing_id"];
settings = json["settings"] != null
? DeviceAliasSettings.fromJson(json["settings"])
: null;
updatedAt = DateTime.parse(json["updated_at"]);
}
static List<DeviceNotificationSettings> mapToList(
Map<String, DeviceNotificationSettings> map) {
return map.values.toList();
}
static Map<String, DeviceNotificationSettings> mapFromJson(
Map<String, dynamic> json) {
final Map<String, DeviceNotificationSettings> devices = {};
json.forEach((key, value) {
devices[key] = DeviceNotificationSettings.fromJson(value);
});
return devices;
}
}
class DeviceAliasSettings {
String? alias;
Map<String, int>? notifiSettings;
DeviceAliasSettings({
this.alias,
this.notifiSettings,
});
DeviceAliasSettings.fromJson(Map<String, dynamic> json) {
alias = json['alias'];
if (json['notifi_settings'] != null) {
notifiSettings = Map<String, int>.from(json['notifi_settings']);
}
}
}

View File

@@ -0,0 +1,313 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:convert';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import '../../../product/shared/shared_snack_bar.dart';
import 'device_notification_settings_bloc.dart';
import 'device_notification_settings_model.dart';
import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart';
class DeviceNotificationSettingsScreen extends StatefulWidget {
const DeviceNotificationSettingsScreen({super.key});
@override
State<DeviceNotificationSettingsScreen> createState() =>
_DeviceNotificationSettingsScreenState();
}
class _DeviceNotificationSettingsScreenState
extends State<DeviceNotificationSettingsScreen> {
late DeviceNotificationSettingsBloc deviceNotificationSettingsBloc;
String thingID = "";
List<DeviceNotificationSettings> deviceNotifications = [];
APIServices apiServices = APIServices();
@override
void initState() {
super.initState();
deviceNotificationSettingsBloc = BlocProvider.of(context);
getNotificationSetting();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<List<DeviceNotificationSettings>>(
stream: deviceNotificationSettingsBloc.streamListNotifications,
initialData: deviceNotifications,
builder: (context, notificationSnapshot) {
return StreamBuilder<String>(
stream: deviceNotificationSettingsBloc.streamDeviceThingID,
initialData: thingID,
builder: (context, deviceThingIdSnapshot) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
appLocalization(context).profile_setting,
style: Theme.of(context).textTheme.titleLarge,
),
),
body: deviceNotifications.isEmpty
? Center(
child: CircularProgressIndicator(
value: context.mediumValue,
),
)
: Padding(
padding: context.paddingLow,
child: Column(
children: [
DropdownButtonFormField2<
DeviceNotificationSettings>(
isExpanded: true,
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(vertical: 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
hint: Text(
appLocalization(context)
.choose_device_dropdownButton,
style: const TextStyle(fontSize: 14),
),
iconStyleData: const IconStyleData(
icon: Icon(
Icons.arrow_drop_down,
),
iconSize: 24,
),
menuItemStyleData: const MenuItemStyleData(
padding: EdgeInsets.symmetric(horizontal: 16),
),
items: deviceNotifications
.map((e) => DropdownMenuItem<
DeviceNotificationSettings>(
value: e,
child: Text(e.settings!.alias!),
))
.toList(),
onChanged: (value) {
thingID = value!.thingId ?? "";
deviceNotificationSettingsBloc
.sinkDeviceThingID
.add(thingID);
},
),
if (deviceThingIdSnapshot.data! != "")
listNotificationSetting(
deviceThingIdSnapshot.data ?? thingID,
deviceNotifications)
],
),
),
);
});
});
}
void getNotificationSetting() async {
String? response = await apiServices.getAllSettingsNotificationOfDevices();
final data = jsonDecode(response);
final result = data['data'];
// log("Data ${DeviceNotificationSettings.mapFromJson(jsonDecode(data)).values.toList()}");
deviceNotifications =
DeviceNotificationSettings.mapFromJson(result).values.toList();
deviceNotificationSettingsBloc.sinkListNotifications
.add(deviceNotifications);
}
Widget listNotificationSetting(
String thingID, List<DeviceNotificationSettings> devices) {
DeviceNotificationSettings chooseDevice = DeviceNotificationSettings();
for (var device in devices) {
if (device.thingId == thingID) {
chooseDevice = device;
break;
}
}
IconData selectIcon = Icons.unpublished_outlined;
String selectMessage = appLocalization(context)
.change_profile_device_notification_deselect_all;
bool isChange = false;
bool isDataChange = false;
// Lấy notifiSettings
final notifiSettings = chooseDevice.settings?.notifiSettings ?? {};
deviceNotificationSettingsBloc.sinkDeviceNotificationSettingMap
.add(notifiSettings);
return SingleChildScrollView(
child: StreamBuilder<Map<String, int>>(
stream:
deviceNotificationSettingsBloc.streamDeviceNotificationSettingMap,
initialData: notifiSettings,
builder: (context, deviceNotificationSettingSnapshot) {
return StreamBuilder<bool>(
stream: deviceNotificationSettingsBloc.streamIsDataChange,
initialData: isDataChange,
builder: (context, isDataChangeSnapshot) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton.icon(
onPressed: () {
changeIconAndMessage(
isChange,
selectIcon,
selectMessage,
notifiSettings,
isDataChange);
isChange = !isChange;
},
icon: StreamBuilder<IconData>(
stream: deviceNotificationSettingsBloc
.streamIconChange,
initialData: selectIcon,
builder: (context, iconSnapshot) {
return Icon(
iconSnapshot.data ?? selectIcon);
}),
label: StreamBuilder<String>(
stream: deviceNotificationSettingsBloc
.streaMmessageChange,
builder: (context, messageSnapshot) {
return Text(
messageSnapshot.data ?? selectMessage);
})),
if (isDataChangeSnapshot.data ?? isDataChange)
IconButton(
onPressed: () {
updateDeviceNotification(
thingID, notifiSettings, isDataChange);
},
icon: const Icon(Icons.done))
],
),
ListView.builder(
shrinkWrap: true,
itemCount:
deviceNotificationSettingSnapshot.data?.length ??
notifiSettings.length,
itemBuilder: (context, index) {
final key = deviceNotificationSettingSnapshot
.data!.keys
.elementAt(index);
final value =
deviceNotificationSettingSnapshot.data![key];
return CheckboxListTile(
value: value == 1,
onChanged: (newValue) {
notifiSettings[key] = newValue == true ? 1 : 0;
deviceNotificationSettingsBloc
.sinkDeviceNotificationSettingMap
.add(notifiSettings);
isDataChange = true;
deviceNotificationSettingsBloc.sinkIsDataChange
.add(isDataChange);
},
title: Text(getNotificationEvent(key)),
);
},
),
if (isDataChangeSnapshot.data ?? isDataChange)
Center(
child: TextButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(
Colors.green),
foregroundColor:
MaterialStateProperty.all<Color>(
Colors.white)),
onPressed: () async {
updateDeviceNotification(
thingID, notifiSettings, isDataChange);
},
child: Text(appLocalization(context)
.update_button_content)),
)
],
);
});
}),
);
}
void changeIconAndMessage(bool isChange, IconData icon, String message,
Map<String, int> notifiSettings, bool isDataChange) {
if (isChange == false) {
icon = Icons.published_with_changes_outlined;
message = appLocalization(context)
.change_profile_device_notification_select_all;
notifiSettings.updateAll((key, value) => 0);
} else {
icon = Icons.unpublished_outlined;
message = appLocalization(context)
.change_profile_device_notification_deselect_all;
notifiSettings.updateAll((key, value) => 1);
}
isDataChange = true;
deviceNotificationSettingsBloc.sinkIsDataChange.add(isDataChange);
deviceNotificationSettingsBloc.sinkDeviceNotificationSettingMap
.add(notifiSettings);
deviceNotificationSettingsBloc.sinkIconChange.add(icon);
deviceNotificationSettingsBloc.sinkMessageChange.add(message);
}
String getNotificationEvent(String eventCode) {
String event = "";
if (eventCode == "001") {
event = "Thiết bị mất kết nối";
} else if (eventCode == "002") {
event = "Hoạt động của thiết bị";
} else if (eventCode == "003") {
event = "Cảnh báo của thiết bị";
} else if (eventCode == "004") {
event = "Thiết bị lỗi";
} else if (eventCode == "005") {
event = "Thiết bị bình thường";
} else if (eventCode == "006") {
event = "Thiết bị yếu pin";
} else if (eventCode == "101") {
event = "Người dùng tham gia nhóm";
} else if (eventCode == "102") {
event = "Người dùng rời nhóm";
} else if (eventCode == "103") {
event = "Thiết bị tham gia nhóm";
} else if (eventCode == "104") {
event = "Thiết bị bị xóa khỏi nhóm";
} else {
event = "Chưa xác định";
}
return event;
}
void updateDeviceNotification(String thingID, Map<String, int> notifiSettings,
bool isDataChange) async {
int statusCode = await apiServices.updateDeviceNotificationSettings(
thingID, notifiSettings);
if (statusCode == 200) {
showNoIconTopSnackBar(
context,
appLocalization(context).notification_update_device_settings_success,
Colors.green,
Colors.white);
} else {
showNoIconTopSnackBar(
context,
appLocalization(context).notification_update_device_settings_failed,
Colors.red,
Colors.white);
}
isDataChange = false;
deviceNotificationSettingsBloc.sinkIsDataChange.add(isDataChange);
}
}

View File

@@ -0,0 +1,37 @@
class User {
String? id;
String? username;
String? role;
String? name;
String? email;
String? phone;
String? address;
String? notes;
String? latitude;
String? longitude;
User(
{this.address,
this.email,
this.id,
this.name,
this.notes,
this.phone,
this.role,
this.username,
this.latitude,
this.longitude});
User.fromJson(Map<String, dynamic> json) {
id = json['id'];
username = json['username'];
role = json['role'];
name = json['name'];
email = json['email'];
phone = json['phone'];
address = json['address'];
notes = json['notes'];
latitude = json['latitude'];
longitude = json['longitude'];
}
}

View File

@@ -0,0 +1,440 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import '../../../product/shared/shared_snack_bar.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/services/api_services.dart';
import '../settings_bloc.dart';
import '../../../product/shared/shared_input_decoration.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/services/language_services.dart';
import 'profile_model.dart';
changeUserInfomation(
BuildContext context, User user, SettingsBloc settingsBloc) {
final formKey = GlobalKey<FormState>();
String username = user.name ?? "";
String email = user.email ?? "";
String tel = user.phone ?? "";
String address = user.address ?? "";
bool isChange = false;
APIServices apiServices = APIServices();
showModalBottomSheet(
isScrollControlled: true,
useSafeArea: true,
context: context,
builder: (modalBottomSheetContext) {
return StreamBuilder<bool>(
stream: settingsBloc.streamIsChangeProfileInfomation,
initialData: isChange,
builder: (context, isChangeSnapshot) {
return Scaffold(
appBar: AppBar(
title: Text(appLocalization(context).change_profile_title),
centerTitle: true,
actions: [
isChangeSnapshot.data ?? isChange
? IconButton(
onPressed: () async {
if (formKey.currentState!.validate()) {
formKey.currentState!.save();
String latitude = user.latitude ?? "";
String longitude = user.longitude ?? "";
Map<String, dynamic> body = {
"name": username,
"email": email,
"phone": tel,
"address": address,
"latitude": latitude,
"longitude": longitude
};
int statusCode =
await apiServices.updateUserProfile(body);
if (statusCode == 200) {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_profile_success,
Colors.green,
Colors.white);
} else {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_profile_failed,
Colors.redAccent,
Colors.white);
}
Navigator.pop(modalBottomSheetContext);
}
},
icon:
IconConstants.instance.getMaterialIcon(Icons.check),
)
: const SizedBox.shrink()
],
),
body: SingleChildScrollView(
child: Form(
key: formKey,
child: Padding(
padding: context.paddingLow,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
appLocalization(context).change_profile_username,
style: context.titleMediumTextStyle,
),
Padding(
padding: context.paddingLowVertical,
child: TextFormField(
initialValue: username,
textInputAction: TextInputAction.next,
validator: (usernameValue) {
if (usernameValue == "null" ||
usernameValue!.isEmpty) {
return appLocalization(modalBottomSheetContext)
.login_account_not_empty;
}
return null;
},
onChanged: (value) {
isChange = true;
settingsBloc.sinkIsChangeProfileInfomation
.add(isChange);
},
onSaved: (newUsername) {
username = newUsername!;
},
decoration: borderRadiusTopLeftAndBottomRight(
modalBottomSheetContext,
appLocalization(modalBottomSheetContext)
.change_profile_username_hint),
),
),
Text(
appLocalization(context).change_profile_email,
style: context.titleMediumTextStyle,
),
Padding(
padding: context.paddingLowVertical,
child: TextFormField(
initialValue: email,
textInputAction: TextInputAction.next,
validator: (emailValue) {
if (emailValue == "null" || emailValue!.isEmpty) {
return appLocalization(modalBottomSheetContext)
.change_profile_email_not_empty;
}
return null;
},
onChanged: (value) {
isChange = true;
settingsBloc.sinkIsChangeProfileInfomation
.add(isChange);
},
onSaved: (newEmail) {
email = newEmail!;
},
decoration: borderRadiusTopLeftAndBottomRight(
modalBottomSheetContext,
appLocalization(modalBottomSheetContext)
.change_profile_email_hint),
),
),
Text(
appLocalization(context).change_profile_tel,
style: context.titleMediumTextStyle,
),
Padding(
padding: context.paddingLowVertical,
child: TextFormField(
initialValue: tel,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.phone,
validator: (telValue) {
if (telValue == "null" || telValue!.isEmpty) {
return appLocalization(modalBottomSheetContext)
.change_profile_tel_not_empty;
}
return null;
},
onChanged: (value) {
isChange = true;
settingsBloc.sinkIsChangeProfileInfomation
.add(isChange);
},
onSaved: (newTel) {
tel = newTel!;
},
decoration: borderRadiusTopLeftAndBottomRight(
modalBottomSheetContext,
appLocalization(modalBottomSheetContext)
.change_profile_tel_hint),
),
),
Text(
appLocalization(context).change_profile_address,
style: context.titleMediumTextStyle,
),
Padding(
padding: context.paddingLowVertical,
child: TextFormField(
initialValue: address,
textInputAction: TextInputAction.done,
onSaved: (newAddress) {
address = newAddress!;
},
onChanged: (value) {
isChange = true;
settingsBloc.sinkIsChangeProfileInfomation
.add(isChange);
},
decoration: borderRadiusTopLeftAndBottomRight(
modalBottomSheetContext,
appLocalization(modalBottomSheetContext)
.change_profile_address_hint),
),
),
SizedBox(height: context.mediumValue),
isChangeSnapshot.data ?? isChange
? Center(
child: TextButton(
onPressed: () async {
if (formKey.currentState!.validate()) {
formKey.currentState!.save();
String latitude = user.latitude ?? "";
String longitude = user.longitude ?? "";
Map<String, dynamic> body = {
"name": username,
"email": email,
"phone": tel,
"address": address,
"latitude": latitude,
"longitude": longitude
};
int statusCode = await apiServices
.updateUserProfile(body);
if (statusCode == 200) {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_profile_success,
Colors.green,
Colors.white);
} else {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_profile_failed,
Colors.redAccent,
Colors.white);
}
Navigator.pop(modalBottomSheetContext);
}
},
style: const ButtonStyle(
backgroundColor:
MaterialStatePropertyAll(Colors.blue),
foregroundColor:
MaterialStatePropertyAll(Colors.white),
),
child: Text(appLocalization(context)
.update_button_content),
),
)
: const SizedBox.shrink(),
],
),
),
),
),
);
},
);
},
);
}
changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
final formKey = GlobalKey<FormState>();
String oldPass = "";
String newPass = "";
APIServices apiServices = APIServices();
bool isChange = false;
showModalBottomSheet(
isScrollControlled: true,
useSafeArea: true,
context: context,
builder: (modalBottomSheetContext) {
return StreamBuilder<bool>(
stream: settingsBloc.streamIsChangeProfileInfomation,
initialData: isChange,
builder: (context, isChangeSnapshot) {
return Scaffold(
appBar: AppBar(
title: Text(appLocalization(context).change_profile_title),
centerTitle: true,
actions: [
isChangeSnapshot.data ?? isChange
? IconButton(
onPressed: () async {
if (formKey.currentState!.validate()) {
formKey.currentState!.save();
Map<String, dynamic> body = {
"password_old": oldPass,
"password_new": newPass,
};
int statusCode =
await apiServices.updateUserPassword(body);
if (statusCode == 200) {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_password_success,
Colors.green,
Colors.white);
} else {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_password_failed,
Colors.redAccent,
Colors.white);
}
Navigator.pop(modalBottomSheetContext);
}
},
icon:
IconConstants.instance.getMaterialIcon(Icons.check),
)
: const SizedBox.shrink()
],
),
body: SingleChildScrollView(
child: Form(
key: formKey,
child: Padding(
padding: context.paddingLow,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
appLocalization(context).change_profile_old_pass,
style: context.titleMediumTextStyle,
),
Padding(
padding: context.paddingLowVertical,
child: TextFormField(
initialValue: oldPass,
textInputAction: TextInputAction.next,
validator: (oldPassValue) {
if (oldPassValue == "null" ||
oldPassValue!.isEmpty) {
return appLocalization(modalBottomSheetContext)
.change_profile_old_pass_not_empty;
}
return null;
},
onChanged: (value) {
isChange = true;
settingsBloc.sinkIsChangeProfileInfomation
.add(isChange);
},
onSaved: (newOldPass) {
oldPass = newOldPass!;
},
decoration: borderRadiusTopLeftAndBottomRight(
modalBottomSheetContext,
appLocalization(modalBottomSheetContext)
.change_profile_old_pass_hint),
),
),
Text(
appLocalization(context).change_profile_new_pass,
style: context.titleMediumTextStyle,
),
Padding(
padding: context.paddingLowVertical,
child: TextFormField(
initialValue: newPass,
textInputAction: TextInputAction.done,
validator: (newPassValue) {
if (newPassValue == "null" ||
newPassValue!.isEmpty) {
return appLocalization(modalBottomSheetContext)
.change_profile_new_pass_not_empty;
}
return null;
},
onChanged: (value) {
isChange = true;
settingsBloc.sinkIsChangeProfileInfomation
.add(isChange);
},
onSaved: (newnewPass) {
newPass = newnewPass!;
},
decoration: borderRadiusTopLeftAndBottomRight(
modalBottomSheetContext,
appLocalization(modalBottomSheetContext)
.change_profile_new_pass_hint),
),
),
SizedBox(height: context.mediumValue),
isChangeSnapshot.data ?? isChange
? Center(
child: TextButton(
onPressed: () async {
if (formKey.currentState!.validate()) {
formKey.currentState!.save();
Map<String, dynamic> body = {
"password_old": oldPass,
"password_new": newPass,
};
int statusCode = await apiServices
.updateUserPassword(body);
if (statusCode == 200) {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_password_success,
Colors.green,
Colors.white);
} else {
showNoIconTopSnackBar(
modalBottomSheetContext,
appLocalization(context)
.notification_update_password_failed,
Colors.redAccent,
Colors.white);
}
Navigator.pop(modalBottomSheetContext);
}
},
style: const ButtonStyle(
backgroundColor:
MaterialStatePropertyAll(Colors.blue),
foregroundColor:
MaterialStatePropertyAll(Colors.white),
),
child: Text(appLocalization(context)
.update_button_content),
),
)
: const SizedBox.shrink()
],
),
),
),
),
);
},
);
},
);
}

View File

@@ -0,0 +1,25 @@
import 'dart:async';
import 'profile/profile_model.dart';
import '../../product/base/bloc/base_bloc.dart';
class SettingsBloc extends BlocBase {
// Settings Screen
final userProfile = StreamController<User>.broadcast();
StreamSink<User> get sinkUserProfile => userProfile.sink;
Stream<User> get streamUserProfile => userProfile.stream;
// Profile Screen
final isChangeProfileInfomation = StreamController<bool>.broadcast();
StreamSink<bool> get sinkIsChangeProfileInfomation =>
isChangeProfileInfomation.sink;
Stream<bool> get streamIsChangeProfileInfomation =>
isChangeProfileInfomation.stream;
@override
void dispose() {
}
}

View File

@@ -0,0 +1,153 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../../product/constant/app/app_constants.dart';
import 'profile/profile_screen.dart';
import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart';
import '../../product/services/api_services.dart';
import 'profile/profile_model.dart';
import 'settings_bloc.dart';
import '../../product/base/bloc/base_bloc.dart';
import '../../product/services/language_services.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
late SettingsBloc settingsBloc;
User user = User();
APIServices apiServices = APIServices();
@override
void initState() {
super.initState();
settingsBloc = BlocProvider.of(context);
getUserProfile();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(appLocalization(context).profile_page_title),
centerTitle: true,
),
body: StreamBuilder<User>(
stream: settingsBloc.streamUserProfile,
initialData: user,
builder: (context, userSnapshot) {
return userSnapshot.data?.id == "" || user.id == ""
? Center(
child: CircularProgressIndicator(
value: context.highValue,
),
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircleAvatar(
radius: 70,
child: CircleAvatar(
radius: 60,
child: CircleAvatar(
radius: 50,
child: Text(
getAvatarContent(
userSnapshot.data?.username ?? ""),
style: const TextStyle(
fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
SizedBox(height: context.lowValue),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
userSnapshot.data?.name ?? "User Name",
style: const TextStyle(
fontWeight: FontWeight.w900, fontSize: 26),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [Text(userSnapshot.data?.email ?? "Email")],
),
SizedBox(height: context.mediumValue),
cardContent(
Icons.account_circle_rounded,
appLocalization(context).profile_change_info,
),
SizedBox(height: context.lowValue),
cardContent(
Icons.lock_outline,
appLocalization(context).profile_change_pass,
),
SizedBox(height: context.lowValue),
cardContent(
Icons.settings_outlined,
appLocalization(context).profile_setting,
),
SizedBox(height: context.lowValue),
cardContent(
Icons.logout_outlined,
appLocalization(context).log_out,
),
],
);
}),
);
}
cardContent(IconData icon, String content) {
return GestureDetector(
onTap: () async {
if (icon == Icons.account_circle_rounded) {
changeUserInfomation(context, user, settingsBloc);
} else if (icon == Icons.lock_outline) {
changeUserPassword(context, settingsBloc);
} else if (icon == Icons.settings_outlined) {
context.push(ApplicationConstants.DEVICE_NOTIFICATIONS_SETTINGS);
} else {
await apiServices.logOut(context);
}
},
child: Card(
margin: const EdgeInsets.only(left: 35, right: 35, bottom: 10),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
child: ListTile(
leading: IconConstants.instance.getMaterialIcon(icon),
title: Text(
content,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
trailing: const Icon(
Icons.arrow_forward_ios_outlined,
),
),
),
);
}
void getUserProfile() async {
String data = await apiServices.getUserDetail();
user = User.fromJson(jsonDecode(data));
settingsBloc.sinkUserProfile.add(user);
}
String getAvatarContent(String username) {
String name = "";
if (username.isNotEmpty) {
name = username[0].toUpperCase();
}
return name;
}
}