mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-11-26 12:34:55 +00:00
code changes
This commit is contained in:
@ -167,24 +167,8 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveName(
|
//============================ fitch devise info and status =======================
|
||||||
SaveNameEvent event, Emitter<SixSceneState> emit) async {
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
if (_validateInputs()) return;
|
|
||||||
try {
|
|
||||||
add(const ChangeNameEvent(value: false));
|
|
||||||
isSaving = true;
|
|
||||||
emit(SixSceneLoadingState());
|
|
||||||
var response = await DevicesAPI.putDeviceName(
|
|
||||||
deviceId: sixSceneId, deviceName: nameController.text);
|
|
||||||
add(const SixSceneInitialInfo());
|
|
||||||
CustomSnackBar.displaySnackBar('Save Successfully');
|
|
||||||
emit(SaveState());
|
|
||||||
} catch (e) {
|
|
||||||
emit(SixSceneFailedState(errorMessage: e.toString()));
|
|
||||||
} finally {
|
|
||||||
isSaving = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future fetchDeviceInfo(
|
Future fetchDeviceInfo(
|
||||||
SixSceneInitialInfo event, Emitter<SixSceneState> emit) async {
|
SixSceneInitialInfo event, Emitter<SixSceneState> emit) async {
|
||||||
@ -219,6 +203,9 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================ assign Scene =======================
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
String selectedFormApiSceneId = '';
|
String selectedFormApiSceneId = '';
|
||||||
|
|
||||||
void getSceneByName(
|
void getSceneByName(
|
||||||
@ -332,44 +319,6 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
|||||||
DeviceReport recordGroups =
|
DeviceReport recordGroups =
|
||||||
DeviceReport(startTime: '0', endTime: '0', data: []);
|
DeviceReport(startTime: '0', endTime: '0', data: []);
|
||||||
|
|
||||||
final List<SixSceneQuestionModel> faqQuestions = [
|
|
||||||
SixSceneQuestionModel(
|
|
||||||
id: 1,
|
|
||||||
question: 'How does an SOS emergency button work?',
|
|
||||||
answer:
|
|
||||||
'The SOS emergency button sends an alert to your contacts when pressed.',
|
|
||||||
),
|
|
||||||
SixSceneQuestionModel(
|
|
||||||
id: 2,
|
|
||||||
question: 'How long will an SOS alarm persist?',
|
|
||||||
answer:
|
|
||||||
'The SOS alarm will persist until it is manually turned off or after a set time.',
|
|
||||||
),
|
|
||||||
SixSceneQuestionModel(
|
|
||||||
id: 3,
|
|
||||||
question: 'What should I do if the SOS button is unresponsive?',
|
|
||||||
answer: 'Try restarting the device. If it persists, contact support.',
|
|
||||||
),
|
|
||||||
SixSceneQuestionModel(
|
|
||||||
id: 4,
|
|
||||||
question: 'Can I use the SOS feature without a network connection?',
|
|
||||||
answer:
|
|
||||||
'No, a network connection is required to send the alert to your contacts.',
|
|
||||||
),
|
|
||||||
SixSceneQuestionModel(
|
|
||||||
id: 5,
|
|
||||||
question: 'How often should I check the SOS battery?',
|
|
||||||
answer:
|
|
||||||
'Check the SOS battery at least once a month to ensure it is operational.',
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
Future<void> _onSixSceneInitial(
|
|
||||||
SixSceneInitialQuestion event, Emitter<SixSceneState> emit) async {
|
|
||||||
emit(SixSceneLoadingState());
|
|
||||||
emit(FaqLoadedState(filteredFaqQuestions: faqQuestions));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DeviceModel> allDevices = [];
|
List<DeviceModel> allDevices = [];
|
||||||
|
|
||||||
bool switchStatus = true;
|
bool switchStatus = true;
|
||||||
@ -430,7 +379,7 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
|||||||
filteredScenes = event.query.isEmpty
|
filteredScenes = event.query.isEmpty
|
||||||
? allScenes
|
? allScenes
|
||||||
: allScenes.where((scene) {
|
: allScenes.where((scene) {
|
||||||
final sceneName = scene.name?.toLowerCase() ?? '';
|
final sceneName = scene.name.toLowerCase() ?? '';
|
||||||
return sceneName.contains(event.query.toLowerCase());
|
return sceneName.contains(event.query.toLowerCase());
|
||||||
}).toList();
|
}).toList();
|
||||||
emit(SearchResultsState());
|
emit(SearchResultsState());
|
||||||
@ -456,6 +405,7 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================= group settings =================================
|
||||||
//addDevicesIcon
|
//addDevicesIcon
|
||||||
List<GroupDevicesModel> groupDevices = [
|
List<GroupDevicesModel> groupDevices = [
|
||||||
GroupDevicesModel(
|
GroupDevicesModel(
|
||||||
@ -488,6 +438,97 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
|||||||
emit(UpdateStateList(groupDevices: groupDevices, devices: devices));
|
emit(UpdateStateList(groupDevices: groupDevices, devices: devices));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//======================= update device functions ============================
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool enableUpdate = false;
|
||||||
|
|
||||||
|
void _toggleUpdate(
|
||||||
|
ToggleUpdateEvent event, Emitter<SixSceneState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(SixSceneLoadingState());
|
||||||
|
enableUpdate = event.isUpdateEnabled!;
|
||||||
|
emit(SaveState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(const SixSceneFailedState(errorMessage: 'Something went wrong'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//======================= q&a and questions ====================================
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool isHelpful = false;
|
||||||
|
|
||||||
|
void _toggleHelpful(
|
||||||
|
ToggleHelpfulEvent event, Emitter<SixSceneState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(SixSceneLoadingState());
|
||||||
|
isHelpful = event.isHelpful!;
|
||||||
|
emit(SaveState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(const SixSceneFailedState(errorMessage: 'Something went wrong'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<SixSceneQuestionModel> faqQuestions = [
|
||||||
|
SixSceneQuestionModel(
|
||||||
|
id: 1,
|
||||||
|
question: 'How does an SOS emergency button work?',
|
||||||
|
answer:
|
||||||
|
'The SOS emergency button sends an alert to your contacts when pressed.',
|
||||||
|
),
|
||||||
|
SixSceneQuestionModel(
|
||||||
|
id: 2,
|
||||||
|
question: 'How long will an SOS alarm persist?',
|
||||||
|
answer:
|
||||||
|
'The SOS alarm will persist until it is manually turned off or after a set time.',
|
||||||
|
),
|
||||||
|
SixSceneQuestionModel(
|
||||||
|
id: 3,
|
||||||
|
question: 'What should I do if the SOS button is unresponsive?',
|
||||||
|
answer: 'Try restarting the device. If it persists, contact support.',
|
||||||
|
),
|
||||||
|
SixSceneQuestionModel(
|
||||||
|
id: 4,
|
||||||
|
question: 'Can I use the SOS feature without a network connection?',
|
||||||
|
answer:
|
||||||
|
'No, a network connection is required to send the alert to your contacts.',
|
||||||
|
),
|
||||||
|
SixSceneQuestionModel(
|
||||||
|
id: 5,
|
||||||
|
question: 'How often should I check the SOS battery?',
|
||||||
|
answer:
|
||||||
|
'Check the SOS battery at least once a month to ensure it is operational.',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
Future<void> _onSixSceneInitial(
|
||||||
|
SixSceneInitialQuestion event, Emitter<SixSceneState> emit) async {
|
||||||
|
emit(SixSceneLoadingState());
|
||||||
|
emit(FaqLoadedState(filteredFaqQuestions: faqQuestions));
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================== name setting ===================================
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Future<void> saveName(
|
||||||
|
SaveNameEvent event, Emitter<SixSceneState> emit) async {
|
||||||
|
if (_validateInputs()) return;
|
||||||
|
try {
|
||||||
|
add(const ChangeNameEvent(value: false));
|
||||||
|
isSaving = true;
|
||||||
|
emit(SixSceneLoadingState());
|
||||||
|
var response = await DevicesAPI.putDeviceName(
|
||||||
|
deviceId: sixSceneId, deviceName: nameController.text);
|
||||||
|
add(const SixSceneInitialInfo());
|
||||||
|
CustomSnackBar.displaySnackBar('Save Successfully');
|
||||||
|
emit(SaveState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(SixSceneFailedState(errorMessage: e.toString()));
|
||||||
|
} finally {
|
||||||
|
isSaving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool _validateInputs() {
|
bool _validateInputs() {
|
||||||
final nameError = fullNameValidator(nameController.text);
|
final nameError = fullNameValidator(nameController.text);
|
||||||
if (nameError != null) {
|
if (nameError != null) {
|
||||||
@ -508,30 +549,4 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool enableUpdate = false;
|
|
||||||
|
|
||||||
void _toggleUpdate(
|
|
||||||
ToggleUpdateEvent event, Emitter<SixSceneState> emit) async {
|
|
||||||
try {
|
|
||||||
emit(SixSceneLoadingState());
|
|
||||||
enableUpdate = event.isUpdateEnabled!;
|
|
||||||
emit(SaveState());
|
|
||||||
} catch (e) {
|
|
||||||
emit(const SixSceneFailedState(errorMessage: 'Something went wrong'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isHelpful = false;
|
|
||||||
|
|
||||||
void _toggleHelpful(
|
|
||||||
ToggleHelpfulEvent event, Emitter<SixSceneState> emit) async {
|
|
||||||
try {
|
|
||||||
emit(SixSceneLoadingState());
|
|
||||||
isHelpful = event.isHelpful!;
|
|
||||||
emit(SaveState());
|
|
||||||
} catch (e) {
|
|
||||||
emit(const SixSceneFailedState(errorMessage: 'Something went wrong'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,21 +10,6 @@ abstract class SixSceneEvent extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class SixSceneLoading extends SixSceneEvent {}
|
|
||||||
|
|
||||||
class SixSceneSwitch extends SixSceneEvent {
|
|
||||||
final String switchD;
|
|
||||||
final String deviceId;
|
|
||||||
final String productId;
|
|
||||||
const SixSceneSwitch(
|
|
||||||
{required this.switchD, this.deviceId = '', this.productId = ''});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [switchD, deviceId, productId];
|
|
||||||
}
|
|
||||||
|
|
||||||
class SixSceneUpdated extends SixSceneEvent {}
|
|
||||||
|
|
||||||
class GetSceneBySwitchName extends SixSceneEvent {
|
class GetSceneBySwitchName extends SixSceneEvent {
|
||||||
final String? switchName;
|
final String? switchName;
|
||||||
|
|
||||||
@ -47,19 +32,6 @@ class SexSceneSwitchInitial extends SixSceneEvent {
|
|||||||
const SexSceneSwitchInitial();
|
const SexSceneSwitchInitial();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReportLogsInitial extends SixSceneEvent {
|
|
||||||
const ReportLogsInitial();
|
|
||||||
}
|
|
||||||
|
|
||||||
class SixSceneChangeStatus extends SixSceneEvent {}
|
|
||||||
|
|
||||||
class GetCounterEvent extends SixSceneEvent {
|
|
||||||
final String deviceCode;
|
|
||||||
const GetCounterEvent({required this.deviceCode});
|
|
||||||
@override
|
|
||||||
List<Object> get props => [deviceCode];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ToggleEnableAlarmEvent extends SixSceneEvent {
|
class ToggleEnableAlarmEvent extends SixSceneEvent {
|
||||||
final bool isLowBatteryEnabled;
|
final bool isLowBatteryEnabled;
|
||||||
|
|
||||||
@ -78,44 +50,6 @@ class ToggleNotificationEvent extends SixSceneEvent {
|
|||||||
List<Object> get props => [isClosingEnabled];
|
List<Object> get props => [isClosingEnabled];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ToggleSixSceneAlarmEvent extends SixSceneEvent {
|
|
||||||
final bool isSixSceneAlarmEnabled;
|
|
||||||
|
|
||||||
const ToggleSixSceneAlarmEvent(this.isSixSceneAlarmEnabled);
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [isSixSceneAlarmEnabled];
|
|
||||||
}
|
|
||||||
|
|
||||||
class SetCounterValue extends SixSceneEvent {
|
|
||||||
final Duration duration;
|
|
||||||
final String deviceCode;
|
|
||||||
const SetCounterValue({required this.duration, required this.deviceCode});
|
|
||||||
@override
|
|
||||||
List<Object> get props => [duration, deviceCode];
|
|
||||||
}
|
|
||||||
|
|
||||||
class StartTimer extends SixSceneEvent {
|
|
||||||
final int duration;
|
|
||||||
|
|
||||||
const StartTimer(this.duration);
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [duration];
|
|
||||||
}
|
|
||||||
|
|
||||||
class TickTimer extends SixSceneEvent {
|
|
||||||
final int remainingTime;
|
|
||||||
|
|
||||||
const TickTimer(this.remainingTime);
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [remainingTime];
|
|
||||||
}
|
|
||||||
|
|
||||||
class StopTimer extends SixSceneEvent {}
|
|
||||||
|
|
||||||
class OnClose extends SixSceneEvent {}
|
|
||||||
class DeleteDeviceEvent extends SixSceneEvent {}
|
class DeleteDeviceEvent extends SixSceneEvent {}
|
||||||
|
|
||||||
class ChangeNameEvent extends SixSceneEvent {
|
class ChangeNameEvent extends SixSceneEvent {
|
||||||
@ -182,14 +116,14 @@ class SelectOptionEvent extends SixSceneEvent {
|
|||||||
class AddDeviceToGroup extends SixSceneEvent {
|
class AddDeviceToGroup extends SixSceneEvent {
|
||||||
final GroupDevicesModel device;
|
final GroupDevicesModel device;
|
||||||
final String icon;
|
final String icon;
|
||||||
AddDeviceToGroup(this.device, this.icon);
|
const AddDeviceToGroup(this.device, this.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemoveDeviceFromGroup extends SixSceneEvent {
|
class RemoveDeviceFromGroup extends SixSceneEvent {
|
||||||
final GroupDevicesModel device;
|
final GroupDevicesModel device;
|
||||||
final String icon;
|
final String icon;
|
||||||
|
|
||||||
RemoveDeviceFromGroup(this.device, this.icon);
|
const RemoveDeviceFromGroup(this.device, this.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssignDeviceScene extends SixSceneEvent {
|
class AssignDeviceScene extends SixSceneEvent {
|
||||||
@ -203,7 +137,6 @@ class AssignDeviceScene extends SixSceneEvent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AssignRoomEvent extends SixSceneEvent {
|
class AssignRoomEvent extends SixSceneEvent {
|
||||||
final String roomId;
|
final String roomId;
|
||||||
final SpaceModel unit;
|
final SpaceModel unit;
|
||||||
@ -223,14 +156,11 @@ class AssignRoomEvent extends SixSceneEvent {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ToggleUpdateEvent extends SixSceneEvent {
|
class ToggleUpdateEvent extends SixSceneEvent {
|
||||||
final bool? isUpdateEnabled;
|
final bool? isUpdateEnabled;
|
||||||
const ToggleUpdateEvent({this.isUpdateEnabled});
|
const ToggleUpdateEvent({this.isUpdateEnabled});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ToggleHelpfulEvent extends SixSceneEvent {
|
class ToggleHelpfulEvent extends SixSceneEvent {
|
||||||
final bool? isHelpful;
|
final bool? isHelpful;
|
||||||
const ToggleHelpfulEvent({this.isHelpful});
|
const ToggleHelpfulEvent({this.isHelpful});
|
||||||
|
|||||||
@ -14,12 +14,9 @@ class SixSceneState extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class SixSceneInitialState extends SixSceneState {}
|
|
||||||
|
|
||||||
class SixSceneLoadingState extends SixSceneState {}
|
class SixSceneLoadingState extends SixSceneState {}
|
||||||
class SaveState extends SixSceneState {}
|
|
||||||
|
|
||||||
class SixSceState extends SixSceneState {}
|
class SaveState extends SixSceneState {}
|
||||||
|
|
||||||
class UpdateStateList extends SixSceneState {
|
class UpdateStateList extends SixSceneState {
|
||||||
final List<GroupDevicesModel> groupDevices;
|
final List<GroupDevicesModel> groupDevices;
|
||||||
@ -55,13 +52,13 @@ class LoadingNewSate extends SixSceneState {
|
|||||||
class NameEditingState extends SixSceneState {
|
class NameEditingState extends SixSceneState {
|
||||||
final bool editName;
|
final bool editName;
|
||||||
|
|
||||||
NameEditingState({required this.editName});
|
const NameEditingState({required this.editName});
|
||||||
}
|
}
|
||||||
|
|
||||||
class FaqLoadedState extends SixSceneState {
|
class FaqLoadedState extends SixSceneState {
|
||||||
final List<SixSceneQuestionModel> filteredFaqQuestions;
|
final List<SixSceneQuestionModel> filteredFaqQuestions;
|
||||||
|
|
||||||
FaqLoadedState({this.filteredFaqQuestions = const []});
|
const FaqLoadedState({this.filteredFaqQuestions = const []});
|
||||||
}
|
}
|
||||||
|
|
||||||
class FaqSearchState extends SixSceneState {
|
class FaqSearchState extends SixSceneState {
|
||||||
@ -95,8 +92,6 @@ class SceneLoaded extends SixSceneState {
|
|||||||
{this.loadingSceneId, this.loadingStates = const {}});
|
{this.loadingSceneId, this.loadingStates = const {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
class SelectedSceneState extends SixSceneState {}
|
|
||||||
|
|
||||||
class SearchResultsState extends SixSceneState {}
|
class SearchResultsState extends SixSceneState {}
|
||||||
|
|
||||||
class SaveSelectionSuccessState extends SixSceneState {}
|
class SaveSelectionSuccessState extends SixSceneState {}
|
||||||
@ -105,7 +100,7 @@ class OptionSelectedState extends SixSceneState {
|
|||||||
final String selectedOption;
|
final String selectedOption;
|
||||||
final bool hasSelectionChanged;
|
final bool hasSelectionChanged;
|
||||||
|
|
||||||
OptionSelectedState({
|
const OptionSelectedState({
|
||||||
required this.selectedOption,
|
required this.selectedOption,
|
||||||
required this.hasSelectionChanged,
|
required this.hasSelectionChanged,
|
||||||
});
|
});
|
||||||
@ -117,7 +112,7 @@ class OptionSelectedState extends SixSceneState {
|
|||||||
class SceneSelectionUpdatedState extends SixSceneState {
|
class SceneSelectionUpdatedState extends SixSceneState {
|
||||||
final String selectedSceneId;
|
final String selectedSceneId;
|
||||||
|
|
||||||
SceneSelectionUpdatedState({required this.selectedSceneId});
|
const SceneSelectionUpdatedState({required this.selectedSceneId});
|
||||||
}
|
}
|
||||||
|
|
||||||
class LoadingDeviceInfo extends SixSceneState {
|
class LoadingDeviceInfo extends SixSceneState {
|
||||||
|
|||||||
@ -110,7 +110,7 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
//============================ get Scene and assign scene =====================
|
//============================ get Scene and assign scene =======================
|
||||||
String selectedFormApiSceneId = '';
|
String selectedFormApiSceneId = '';
|
||||||
String selectedSceneId = '';
|
String selectedSceneId = '';
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import 'package:intl/intl.dart';
|
|||||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||||
|
|
||||||
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user