Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lib/core/constants/report_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
enum ReportType {
post('POST'),
comment('COMMENT'),
chatRoom('CHAT_ROOM'),
user('USER')
;

final String value;

const ReportType(this.value);
}

enum ReportReason {
swear("욕설이 많아요"),
disrespect("상대를 존중하지 않아요"),
offensive("불쾌감을 느끼는 발언을 해요"),
aggressive("공격적인 언어를 사용해요"),
discrimination("신분, 장애, 인종에 대해 차별 발언을 일삼아요"),
badName("부적절한 이름을 사용해요"),
etc("기타")
;

final String label;

const ReportReason(this.label);
}
Original file line number Diff line number Diff line change
@@ -1,56 +1,73 @@

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:ondo/core/constants/report_type.dart';
import 'package:ondo/core/design_system/app_colors.dart';
import 'package:ondo/core/design_system/app_layout.dart';
import 'package:ondo/core/design_system/app_text_styles.dart';
import 'package:ondo/core/design_system/component_variants.dart';
import 'package:ondo/core/design_system/components/custom_button.dart';
import 'package:ondo/core/design_system/components/custom_tag_card.dart';
import 'package:ondo/core/design_system/components/custom_textfield.dart';
import 'package:ondo/presentation/profile/widget/report_reason_chip.dart';
import 'package:ondo/domain/usecases/report/report_use_case.dart';

class PostReportDialog extends StatefulWidget {
const PostReportDialog({
class CustomReportDialog extends StatefulWidget {
const CustomReportDialog({
super.key,
required this.type,
required this.targetId,
});

final ReportType type;
final String targetId;

@override
State<PostReportDialog> createState() => _PostReportDialogState();
State<CustomReportDialog> createState() => _CustomReportDialogState();
}

class _PostReportDialogState extends State<PostReportDialog> {
class _CustomReportDialogState extends State<CustomReportDialog> {
final TextEditingController controller = TextEditingController();

final List<String> _reasons = [
"욕설이 많아요",
"상대를 존중하지 않아요",
"불쾌감을 느끼는 발언을 해요",
"공격적인 언어를 사용해요",
"신분, 장애, 인종에 대해 차별 발언을 일삼아요",
"부적절한 이름을 사용해요",
"기타",
];
final Set<ReportReason> _selectedReasons = {};

final Set<String> _selectedReasons = {};
String get _title => switch (widget.type) {
ReportType.post => '게시물 신고',
ReportType.comment => '댓글 신고',
ReportType.chatRoom => '채팅방 신고',
ReportType.user => '유저 신고',
};

bool get _isValid =>
_selectedReasons.isNotEmpty || controller.text.trim().isNotEmpty;

void _toggleReason(String reason) {
setState(() {
if (_selectedReasons.contains(reason)) {
_selectedReasons.remove(reason);
} else {
_selectedReasons.add(reason);
}
});
}

Future<void> _submitReport() async {
if (!_isValid) return;
final description = [
if (_selectedReasons.isNotEmpty) ...[
'tags',
..._selectedReasons.map((e) => e.label),
],
if (controller.text.trim().isNotEmpty) ...[
'detail',
controller.text.trim(),
],
].join('\n');
Comment thread
eum018 marked this conversation as resolved.

await Get.find<ReportUseCase>()(
targetType: widget.type,
targetId: widget.targetId,
description: description,
);

if (!mounted) return;
Navigator.pop(context);
}

@override
void dispose() {
controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Dialog(
Expand All @@ -68,20 +85,28 @@ class _PostReportDialogState extends State<PostReportDialog> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(child: Text("게시물 신고", style: AppTextStyles.titleBold20())),
Center(child: Text(_title, style: AppTextStyles.titleBold20())),
AppGap.v16,
SizedBox(
width: MediaQuery.of(context).size.width,
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.start,
spacing: AppSpacing.s12,
runSpacing: AppSpacing.s12,
children: _reasons.map(
(e) {
return ReportReasonChip(
label: e,
isSelected: _selectedReasons.contains(e),
onTap: () => _toggleReason(e),
children: ReportReason.values.map(
(r) {
return CustomTagCard(
label: r.label,
isSelected: _selectedReasons.contains(r),
onTap: (isSelect) {
setState(() {
if (isSelect) {
_selectedReasons.add(r);
} else {
_selectedReasons.remove(r);
}
});
},
);
},
).toList(),
Comment thread
eum018 marked this conversation as resolved.
Expand Down
61 changes: 27 additions & 34 deletions lib/core/design_system/components/custom_tag_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,41 @@ import 'package:ondo/core/design_system/app_colors.dart';
import 'package:ondo/core/design_system/app_layout.dart';
import 'package:ondo/core/design_system/app_text_styles.dart';

typedef SelectTag = void Function(bool isSelect);

class CustomTagCard extends StatelessWidget {
final String tag;
final Color? color;
final void Function(bool isSelect)? onTap;
final ValueNotifier<bool> isSelect;
final String label;
final bool isSelected;
final SelectTag? onTap;

CustomTagCard({
const CustomTagCard({
super.key,
required this.tag,
this.color,
required this.label,
this.isSelected = false,
this.onTap,
bool isSelect = false,
}) : isSelect = ValueNotifier(isSelect);
});

@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: isSelect,
builder: (context, value, child) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
isSelect.value = !isSelect.value;
onTap?.call(isSelect.value);
},
child: Container(
padding: AppPadding.chip,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: isSelect.value
? AppColors.primary
: color ?? AppColors.white,
),
child: Text(
tag,
style: AppTextStyles.textMedium(
textColor: isSelect.value ? AppColors.white : AppColors.gray90,
),
),
final foregroundColor = isSelected ? AppColors.white : AppColors.gray90;
final backgroundColor = isSelected ? AppColors.primary : AppColors.gray20;

return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => onTap?.call(!isSelected),
child: Container(
padding: AppPadding.chip,
decoration: BoxDecoration(
borderRadius: AppRadius.baseRadius,
color: backgroundColor,
),
child: Text(
label,
style: AppTextStyles.textMedium(
textColor: foregroundColor,
),
);
},
),
),
);
}
}
4 changes: 3 additions & 1 deletion lib/core/router/bindings/navigation_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:ondo/core/router/bindings/home_binding.dart';
import 'package:ondo/core/router/bindings/notification_binding.dart';
import 'package:ondo/core/router/bindings/post_binding.dart';
import 'package:ondo/core/router/bindings/profile_binding.dart';
import 'package:ondo/core/router/bindings/report_binding.dart';
import 'package:ondo/core/router/bindings/user_binding.dart';
import 'package:ondo/data/datasource/auth/auth_local_datasource_impl.dart';
import 'package:ondo/data/datasource/auth/auth_remote_datasource.dart';
Expand Down Expand Up @@ -38,8 +39,9 @@ class NavigationBinding extends Bindings {

/// 전 화면 공통 controller 등록
Get.lazyPut<NavigationController>(() => NavigationController());
NotificationBinding().dependencies();

NotificationBinding().dependencies();
ReportBinding().dependencies();
UserBinding().dependencies();
PostBinding().dependencies();

Expand Down
2 changes: 0 additions & 2 deletions lib/core/router/bindings/post_view_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class PostViewBinding extends Bindings {

@override
void dependencies() {

// Post UseCases
Get.lazyPut<GetPostDetailUseCase>(
() => GetPostDetailUseCase(
Expand All @@ -56,7 +55,6 @@ class PostViewBinding extends Bindings {
),
);


// Comment DataSource
Get.lazyPut<CommentRemoteDataSource>(
() => CommentRemoteDataSourceImpl(
Expand Down
23 changes: 23 additions & 0 deletions lib/core/router/bindings/report_binding.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:get/get.dart';
import 'package:ondo/data/datasource/report/report_remote_datasource.dart';
import 'package:ondo/data/network/clients/auth_client.dart';
import 'package:ondo/data/repositories/report/report_repository_impl.dart';
import 'package:ondo/domain/repositories/report/report_repository.dart';
import 'package:ondo/domain/usecases/report/report_use_case.dart';

class ReportBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(
() => ReportRemoteDatasource(Get.find<AuthClient>()),
);

Get.lazyPut<ReportRepository>(
() => ReportRepositoryImpl(Get.find<ReportRemoteDatasource>()),
);

Get.lazyPut(
() => ReportUseCase(Get.find<ReportRepository>()),
);
}
}
2 changes: 1 addition & 1 deletion lib/data/datasource/post/post_remote_datasource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class PostRemoteDatasource {
final res = await _client.get(Uri.parse("${ApiConstants.post}/popular"));

final body = jsonDecode(res.body);
log.serverLog(body, stausCode: res.statusCode);
log.serverLog(body, statusCode: res.statusCode);

if (res.statusCode == 200 && body["success"] == true) {
return body["data"];
Expand Down
37 changes: 37 additions & 0 deletions lib/data/datasource/report/report_remote_datasource.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'dart:convert';

import 'package:http/http.dart';
import 'package:ondo/data/models/report/request/report_request_model.dart';
import 'package:ondo/data/network/constants/api_constants.dart';

class ReportRemoteDatasource {
final BaseClient _client;

ReportRemoteDatasource(this._client);

Future<bool> report(ReportRequestModel model) async {
final log = ApiConstants(logName: '신고 접수 서버');

try {
final res = await _client.post(
Uri.parse(ApiConstants.report),
headers: ApiConstants.baseHeader,
body: jsonEncode(model.toJson()),
);

final body = jsonDecode(res.body);

log.successLog(body['success']);
log.messageLog(body['message']);

if (res.statusCode == 200 && body['success'] == true) {
return true;
}
log.statusLog(res.statusCode);
} catch (e) {
log.errorLog(e);
}

return false;
}
}
19 changes: 19 additions & 0 deletions lib/data/models/report/request/report_request_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:ondo/core/constants/report_type.dart';

class ReportRequestModel {
final ReportType targetType;
final String targetId;
final String description;

ReportRequestModel({
required this.targetType,
required this.targetId,
required this.description,
});

Map<String, dynamic> toJson() => {
'targetType': targetType.value,
'targetId': targetId,
'description': description,
};
}
8 changes: 5 additions & 3 deletions lib/data/network/constants/api_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ class ApiConstants {

static String get comment => "${Env.apiBaseUrl}/comments";

static String get report => "${Env.apiBaseUrl}/reports";

static const baseHeader = {"Content-Type": "application/json"};

//TODO : 임시 로그인 데이터
static String get loginId => Env.loginId;

static String get loginPassword => Env.loginPassword;

void serverLog(Map body, {int? stausCode}) {
if (stausCode != null) {
statusLog(stausCode);
void serverLog(Map body, {int? statusCode}) {
if (statusCode != null) {
statusLog(statusCode);
}
successLog(body["success"]);
messageLog(body["message"]);
Expand Down
Loading
Loading