diff --git a/assets/image/icons_not_design_sys/Info.png b/assets/image/icons_not_design_sys/Info.png new file mode 100644 index 00000000..f5d15c7d Binary files /dev/null and b/assets/image/icons_not_design_sys/Info.png differ diff --git a/lib/core/component/image/images.dart b/lib/core/component/image/images.dart index 34a126dd..b5c3a714 100644 --- a/lib/core/component/image/images.dart +++ b/lib/core/component/image/images.dart @@ -77,6 +77,8 @@ class Images { 'assets/image/icons_not_design_sys/today_excersize_complete_icon.png'; static const String iconsNotDesignSysWakatimeIcon = 'assets/image/icons_not_design_sys/wakatime_icon.png'; + static const String iconsNotDesignSysInfoIcon = + 'assets/image/icons_not_design_sys/Info.png'; static const String iconsPickle = 'assets/image/icons/pickle.png'; static const String iconsPickleFilled = 'assets/image/icons/pickle-filled.png'; diff --git a/lib/core/component/image_widget.dart b/lib/core/component/image_widget.dart index 389cb543..ba2ff35a 100644 --- a/lib/core/component/image_widget.dart +++ b/lib/core/component/image_widget.dart @@ -1,8 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -enum ImageType { svg, svgNetwork, png, pngNetwork } +enum ImageType { png, pngNetwork } class ImageWidget extends StatelessWidget { final double? width, height, imageWidth, imageHeight, radiusCircular; @@ -61,22 +60,6 @@ class ImageWidget extends StatelessWidget { height: imageHeight, fit: BoxFit.cover, ); - case ImageType.svg: - return SvgPicture.asset( - image, - color: color, - width: imageWidth, - height: imageHeight, - fit: BoxFit.cover, - ); - case ImageType.svgNetwork: - return SvgPicture.network( - image, - color: color, - width: imageWidth, - height: imageHeight, - fit: BoxFit.cover, - ); } }, ), diff --git a/lib/core/component/pose/presentation/view/pose_main_tab_body.dart b/lib/core/component/pose/presentation/view/pose_main_tab_body.dart index 94a7ca67..744c43e9 100644 --- a/lib/core/component/pose/presentation/view/pose_main_tab_body.dart +++ b/lib/core/component/pose/presentation/view/pose_main_tab_body.dart @@ -27,7 +27,7 @@ class PoseMainTabBody extends ConsumerWidget { child: Builder( builder: (context) { if (tabBodyData[ref.watch(poseTabController)] == "추천") { - return const PoseMainTabBodyRecommendScreen(); + return PoseMainTabBodyRecommendScreen(useNavigator: useNavigator,); } else { return PoseMainTabBodyPartScreen( tabName: tabBodyData[ref.watch(poseTabController)], diff --git a/lib/core/component/pose/presentation/widget/tab_body/pose_main_tab_body_recommend_screen.dart b/lib/core/component/pose/presentation/widget/tab_body/pose_main_tab_body_recommend_screen.dart index 34edf906..cabf9da4 100644 --- a/lib/core/component/pose/presentation/widget/tab_body/pose_main_tab_body_recommend_screen.dart +++ b/lib/core/component/pose/presentation/widget/tab_body/pose_main_tab_body_recommend_screen.dart @@ -3,13 +3,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/core/component/pose/presentation/provider/pose_recommend_provider.dart'; -import '../../../../../../pose/presentation/widget/pose_data.dart'; - /// Widget import 'recommend/pose_recommend_widget.dart'; class PoseMainTabBodyRecommendScreen extends ConsumerWidget { - const PoseMainTabBodyRecommendScreen({super.key}); + final bool useNavigator; + const PoseMainTabBodyRecommendScreen({super.key, required this.useNavigator}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -24,6 +23,7 @@ class PoseMainTabBodyRecommendScreen extends ConsumerWidget { recommendPoseData: poseRecommend .poses![poseRecommend.poses!.keys.toList()[index]]!, titleText: poseRecommend.poses!.keys.toList()[index], + useNavigator: useNavigator, ); }, ), diff --git a/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget.dart b/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget.dart index f6072cad..84ed69a9 100644 --- a/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget.dart +++ b/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget.dart @@ -10,9 +10,12 @@ class PoseRecommendWidget extends StatelessWidget { final String titleText; + final bool useNavigator; + const PoseRecommendWidget({ required this.recommendPoseData, required this.titleText, + required this.useNavigator, super.key, }); @@ -31,7 +34,7 @@ class PoseRecommendWidget extends StatelessWidget { ), /// ~ 운동 하단 - PoseRecommendWidgetBottom(recommendPoseData: recommendPoseData), + PoseRecommendWidgetBottom(recommendPoseData: recommendPoseData, useNavigator: useNavigator), ], ), ); diff --git a/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget_bottom.dart b/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget_bottom.dart index 69e27e8d..caf6fec4 100644 --- a/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget_bottom.dart +++ b/lib/core/component/pose/presentation/widget/tab_body/recommend/pose_recommend_widget_bottom.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; import 'package:maeum_ga_gym_flutter/core/component/pose/domain/model/pose_data_model.dart'; -import 'package:maeum_ga_gym_flutter/core/component/pose/domain/model/pose_recommend_model.dart'; -import 'package:maeum_ga_gym_flutter/pose/presentation/provider/pose_detail_provider.dart'; +import 'package:maeum_ga_gym_flutter/core/component/routine/domain/model/exercise_info_edit_routine_pose_model.dart'; +import 'package:maeum_ga_gym_flutter/self_care/presentation/provider/my_routine/self_care_my_routine_pose_list_provider.dart'; import '../../../../../../../config/maeumgagym_color.dart'; import '../../../../../../../pose/presentation/view/pose_detail_screen.dart'; @@ -11,10 +11,12 @@ import '../../../../../text/pretendard/ptd_text_widget.dart'; class PoseRecommendWidgetBottom extends ConsumerWidget { final List recommendPoseData; + final bool useNavigator; const PoseRecommendWidgetBottom({ super.key, required this.recommendPoseData, + required this.useNavigator, }); @override @@ -31,15 +33,34 @@ class PoseRecommendWidgetBottom extends ConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ GestureDetector( - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PoseDetailScreen( - id: poseData.id!, - poseData: poseData, - ), - ), - ), + onTap: () { + if (useNavigator == true) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PoseDetailScreen( + id: poseData.id!, + poseData: poseData, + ), + ), + ); + } else { + ref.read(selfCareMyRoutinePostListProvider.notifier).insert( + ExerciseInfoEditRoutinePoseModel( + poseModel: PoseDataModel( + id: recommendPoseData[index].id, + thumbnail: recommendPoseData[index].thumbnail, + name: recommendPoseData[index].name, + needMachine: recommendPoseData[index].needMachine, + simplePart: recommendPoseData[index].simplePart, + exactPart: recommendPoseData[index].exactPart), + repetitionsController: TextEditingController(text: "10"), + setsController: TextEditingController(text: "1"), + ), + ); + Navigator.pop(context); + } + }, child: Padding( padding: const EdgeInsets.only(right: 12), child: ImageWidget( diff --git a/lib/core/component/routine/data/datasource/remote/routine_remote_data_source.dart b/lib/core/component/routine/data/datasource/remote/routine_remote_data_source.dart index 57083920..be7b012c 100644 --- a/lib/core/component/routine/data/datasource/remote/routine_remote_data_source.dart +++ b/lib/core/component/routine/data/datasource/remote/routine_remote_data_source.dart @@ -5,7 +5,6 @@ import 'package:maeum_ga_gym_flutter/core/di/dio_di.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/exercise_info_request_model.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/domain/model/routine_and_user_info_model.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_history_model.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_response_model.dart'; class RoutineRemoteDataSource { Future> addRoutine({ @@ -75,38 +74,6 @@ class RoutineRemoteDataSource { } } - Future getTodayRoutine({ - required String accessToken, - }) async { - try { - return await dio - .get( - "/routines/today", - options: Options( - headers: { - "Content-Type": "application/json", - "Authorization": accessToken, - }, - ), - ) - .then((response) { - return RoutineResponseModel.fromJson( - response.data, - response.statusCode!, - ); - }); - } catch (err) { - return RoutineResponseModel( - statusCode: AsyncError(err, StackTrace.empty), - id: null, - routineName: null, - exerciseInfoResponseList: [], - dayOfWeeks: [], - routineStatus: null, - ); - } - } - Future> deleteRoutine({ required String accessToken, required int routineId, diff --git a/lib/core/component/routine/data/repositoryImpl/routine_repository_impl.dart b/lib/core/component/routine/data/repositoryImpl/routine_repository_impl.dart index e27a32a0..74ed5ea6 100644 --- a/lib/core/component/routine/data/repositoryImpl/routine_repository_impl.dart +++ b/lib/core/component/routine/data/repositoryImpl/routine_repository_impl.dart @@ -3,21 +3,11 @@ import 'package:maeum_ga_gym_flutter/core/component/routine/data/datasource/remo import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/exercise_info_request_model.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/domain/model/routine_and_user_info_model.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_history_model.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_response_model.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/domain/repository/routine_repository.dart'; class RoutineRepositoryImpl implements RoutineRepository { final RoutineRemoteDataSource _remoteDataSource = RoutineRemoteDataSource(); - @override - Future getTodayRoutine({ - required String accessToken, - }) async { - return await _remoteDataSource.getTodayRoutine( - accessToken: accessToken, - ); - } - @override Future getMyRoutine({ required String accessToken, diff --git a/lib/core/component/routine/domain/model/routine_and_user_info_model.dart b/lib/core/component/routine/domain/model/routine_and_user_info_model.dart index cd1b848c..bc7fc9a0 100644 --- a/lib/core/component/routine/domain/model/routine_and_user_info_model.dart +++ b/lib/core/component/routine/domain/model/routine_and_user_info_model.dart @@ -1,11 +1,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_response_model.dart'; +import 'package:maeum_ga_gym_flutter/core/model/routine/maeumgagym_routine_list_model.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_user_info_model.dart'; class RoutineAndUserInfoModel { final AsyncValue statusCode; final RoutineUserInfoModel? userInfo; - List routineList = []; + List routineList = []; RoutineAndUserInfoModel({ required this.statusCode, @@ -20,16 +20,14 @@ class RoutineAndUserInfoModel { return RoutineAndUserInfoModel( statusCode: AsyncData(statusCode), userInfo: RoutineUserInfoModel.fromJson(json['user_info']), - routineList: (json['routine_list'] as List) - .map((routineJson) => RoutineResponseModel.fromJson(routineJson, statusCode)) - .toList(), + routineList: json['routine_list'].map((data) => RoutineModel.fromJson(data)).toList() ); } RoutineAndUserInfoModel copyWith({ AsyncValue? statusCode, RoutineUserInfoModel? userInfo, - List? routineList, + List? routineList, }) { return RoutineAndUserInfoModel( statusCode: statusCode ?? this.statusCode, diff --git a/lib/core/component/routine/domain/repository/routine_repository.dart b/lib/core/component/routine/domain/repository/routine_repository.dart index b26ec5d2..d36542a5 100644 --- a/lib/core/component/routine/domain/repository/routine_repository.dart +++ b/lib/core/component/routine/domain/repository/routine_repository.dart @@ -2,7 +2,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/exercise_info_request_model.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/domain/model/routine_and_user_info_model.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_history_model.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_response_model.dart'; abstract class RoutineRepository { Future> addRoutine({ @@ -19,10 +18,6 @@ abstract class RoutineRepository { required int index, }); - Future getTodayRoutine({ - required String accessToken, - }); - Future> deleteRoutine({ required String accessToken, required int routineId, diff --git a/lib/core/component/routine/domain/usecase/routine_usecase.dart b/lib/core/component/routine/domain/usecase/routine_usecase.dart index 48890739..4ee0fa41 100644 --- a/lib/core/component/routine/domain/usecase/routine_usecase.dart +++ b/lib/core/component/routine/domain/usecase/routine_usecase.dart @@ -2,7 +2,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/exercise_info_request_model.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/domain/model/routine_and_user_info_model.dart'; import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_history_model.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_response_model.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/domain/repository/routine_repository.dart'; class RoutineUseCase { @@ -38,14 +37,6 @@ class RoutineUseCase { ); } - Future getTodayRoutine({ - required String accessToken, - }) async { - return await _repository.getTodayRoutine( - accessToken: accessToken, - ); - } - Future> deleteRoutine({ required String accessToken, required int routineId, diff --git a/lib/core/component/timer_sound_component.dart b/lib/core/component/timer_sound_component.dart new file mode 100644 index 00000000..0cd71359 --- /dev/null +++ b/lib/core/component/timer_sound_component.dart @@ -0,0 +1,9 @@ +import 'package:audioplayers/audioplayers.dart'; + +final _audioPlayer = AudioPlayer(); + +class TimerSoundComponent { + static void timerPlay(){ + _audioPlayer.play(AssetSource('sounds/timer/timer_end_sound.wav')); + } +} \ No newline at end of file diff --git a/lib/home/domain/model/home_today_routines_model.dart b/lib/core/model/routine/maeumgagym_routine_list_model.dart similarity index 60% rename from lib/home/domain/model/home_today_routines_model.dart rename to lib/core/model/routine/maeumgagym_routine_list_model.dart index 6588ed2f..39cf35fa 100644 --- a/lib/home/domain/model/home_today_routines_model.dart +++ b/lib/core/model/routine/maeumgagym_routine_list_model.dart @@ -1,46 +1,46 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/core/component/pose/domain/model/pose_data_model.dart'; -class HomeTodayRoutineListModel { - final List routineList; +class MaeumgagymRoutineListModel { + final List routineList; final AsyncValue statusCode; - HomeTodayRoutineListModel({ + MaeumgagymRoutineListModel({ required this.routineList, required this.statusCode, }); - factory HomeTodayRoutineListModel.fromJson( + factory MaeumgagymRoutineListModel.fromJson( Map json, int? statusCode) { - return HomeTodayRoutineListModel( + return MaeumgagymRoutineListModel( routineList: json['routine_list'] - .map( - (data) => HomeTodayRoutineModel.fromJson(data)) + .map( + (data) => RoutineModel.fromJson(data)) .toList(), statusCode: AsyncData(statusCode!), ); } - HomeTodayRoutineListModel copyWith({ - List? routineList, + MaeumgagymRoutineListModel copyWith({ + List? routineList, AsyncValue? statusCode, }) { - return HomeTodayRoutineListModel( + return MaeumgagymRoutineListModel( routineList: routineList ?? this.routineList, statusCode: statusCode ?? this.statusCode, ); } } -class HomeTodayRoutineModel { - final int? id; - final String? routineName; - final List? exerciseInfoResponseList; - final List? dayOfWeeks; - final RoutineStatus? routineStatus; +class RoutineModel { + final int id; + final String routineName; + final List exerciseInfoResponseList; + final List dayOfWeeks; + final RoutineStatus routineStatus; final bool? isCompleted; - HomeTodayRoutineModel({ + RoutineModel({ required this.id, required this.routineName, required this.exerciseInfoResponseList, @@ -49,8 +49,8 @@ class HomeTodayRoutineModel { required this.isCompleted, }); - factory HomeTodayRoutineModel.fromJson(Map json) { - return HomeTodayRoutineModel( + factory RoutineModel.fromJson(Map json) { + return RoutineModel( id: json['id'], routineName: json['routine_name'], exerciseInfoResponseList: json['exercise_info_response_list'] @@ -62,7 +62,7 @@ class HomeTodayRoutineModel { ); } - HomeTodayRoutineModel copyWith({ + RoutineModel copyWith({ int? id, String? routineName, List? exerciseInfoResponseList, @@ -71,7 +71,7 @@ class HomeTodayRoutineModel { bool? isCompleted, AsyncValue? statusCode, }) { - return HomeTodayRoutineModel( + return RoutineModel( id: id ?? this.id, routineName: routineName ?? this.routineName, exerciseInfoResponseList: @@ -85,8 +85,8 @@ class HomeTodayRoutineModel { class ExerciseInfoList { final PoseDataModel pose; - final int? repetitions; - final int? sets; + final int repetitions; + final int sets; ExerciseInfoList({ required this.pose, @@ -118,33 +118,11 @@ class RoutineStatus { isShared: json['is_shared'], ); } -} -// class PoseData { -// final int? id; -// final bool? needMachine; -// final String? name; -// final List? simplePart; -// final List? exactPart; -// final String? thumbnail; -// -// PoseData({ -// required this.id, -// required this.needMachine, -// required this.name, -// required this.simplePart, -// required this.exactPart, -// required this.thumbnail, -// }); -// -// factory PoseData.fromJson(Map json) { -// return PoseData( -// id: json['id'], -// needMachine: json['need_machine'], -// name: json['name'], -// simplePart: List.from(json['simple_part']), -// exactPart: List.from(json['exact_part']), -// thumbnail: json['thumbnail'], -// ); -// } -// } + RoutineStatus copyWith({required bool? isArchived, required bool? isShared}){ + return RoutineStatus( + isArchived: isArchived ?? this.isArchived, + isShared: isShared ?? this.isShared, + ); + } +} \ No newline at end of file diff --git a/lib/home/data/data_source/remote/home_today_routines_remote_data_source.dart b/lib/home/data/data_source/remote/home_today_routines_remote_data_source.dart index 4f67f807..ebf769a3 100644 --- a/lib/home/data/data_source/remote/home_today_routines_remote_data_source.dart +++ b/lib/home/data/data_source/remote/home_today_routines_remote_data_source.dart @@ -4,10 +4,10 @@ import 'package:intl/intl.dart'; import 'package:maeum_ga_gym_flutter/core/di/dio_di.dart'; import '../../../../core/di/token_secure_storage_di.dart'; -import '../../../domain/model/home_today_routines_model.dart'; +import '../../../../core/model/routine/maeumgagym_routine_list_model.dart'; class HomeTodayRoutinesRemoteDataSource { - Future getTodayRoutines() async { + Future getTodayRoutines() async { final accessToken = await TokenSecureStorageDi.readLoginAccessToken(); Map headers = { 'Content-Type': 'application/json', @@ -18,13 +18,13 @@ class HomeTodayRoutinesRemoteDataSource { return await dio .get('/routines/today', options: Options(headers: headers)) .then( - (response) => HomeTodayRoutineListModel.fromJson( + (response) => MaeumgagymRoutineListModel.fromJson( response.data, response.statusCode, ), ); } catch (err) { - return HomeTodayRoutineListModel( + return MaeumgagymRoutineListModel( routineList: [], statusCode: AsyncError(err, StackTrace.empty), ); diff --git a/lib/home/data/repositoryImpl/home_today_routines_repository_impl.dart b/lib/home/data/repositoryImpl/home_today_routines_repository_impl.dart index db748ca2..04cb43fb 100644 --- a/lib/home/data/repositoryImpl/home_today_routines_repository_impl.dart +++ b/lib/home/data/repositoryImpl/home_today_routines_repository_impl.dart @@ -1,6 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/home/data/data_source/remote/home_today_routines_remote_data_source.dart'; -import 'package:maeum_ga_gym_flutter/home/domain/model/home_today_routines_model.dart'; +import 'package:maeum_ga_gym_flutter/core/model/routine/maeumgagym_routine_list_model.dart'; import 'package:maeum_ga_gym_flutter/home/domain/repository/home_today_routines_repository.dart'; class HomeTodayRoutinesRepositoryImpl implements HomeTodayRoutinesRepository { @@ -8,7 +8,7 @@ class HomeTodayRoutinesRepositoryImpl implements HomeTodayRoutinesRepository { HomeTodayRoutinesRemoteDataSource(); @override - Future getTodayRoutines() async { + Future getTodayRoutines() async { return await _dataSource.getTodayRoutines(); } diff --git a/lib/home/domain/repository/home_today_routines_repository.dart b/lib/home/domain/repository/home_today_routines_repository.dart index 93e55878..74141174 100644 --- a/lib/home/domain/repository/home_today_routines_repository.dart +++ b/lib/home/domain/repository/home_today_routines_repository.dart @@ -1,8 +1,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:maeum_ga_gym_flutter/home/domain/model/home_today_routines_model.dart'; +import 'package:maeum_ga_gym_flutter/core/model/routine/maeumgagym_routine_list_model.dart'; abstract class HomeTodayRoutinesRepository { - Future getTodayRoutines(); + Future getTodayRoutines(); Future> completeTodayRoutines(int id); diff --git a/lib/home/domain/usecase/home_today_routines_usecase.dart b/lib/home/domain/usecase/home_today_routines_usecase.dart index eff074c4..f5631c5f 100644 --- a/lib/home/domain/usecase/home_today_routines_usecase.dart +++ b/lib/home/domain/usecase/home_today_routines_usecase.dart @@ -2,13 +2,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/home/domain/repository/home_today_routines_repository.dart'; import '../../../core/di/init.dart'; -import '../model/home_today_routines_model.dart'; +import '../../../core/model/routine/maeumgagym_routine_list_model.dart'; class HomeTodayRoutinesUseCase { final HomeTodayRoutinesRepository _repository = locator(); - Future getTodayRoutines() async { + Future getTodayRoutines() async { return await _repository.getTodayRoutines(); } diff --git a/lib/home/presentation/providers/home_timer_state_provider.dart b/lib/home/presentation/providers/home_timer_state_provider.dart index b9cc254d..30c96e32 100644 --- a/lib/home/presentation/providers/home_timer_state_provider.dart +++ b/lib/home/presentation/providers/home_timer_state_provider.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/home/presentation/models/timers.dart'; import 'package:maeum_ga_gym_flutter/home/presentation/widget/timer/widget/home_timer_alert_widget.dart'; +import '../../../core/component/timer_sound_component.dart'; import '../../domain/model/local_timer_model.dart'; late OverlayEntry? timerOverlay; @@ -23,10 +24,8 @@ final homeTimersProvider = class TimersNotifier extends StateNotifier> { final List?> _subscriptions = [null, null]; - final _audioPlayer = AudioPlayer(); // 이거 나중ㅇ ㅔ고쳐야됨 - TimersNotifier() : super([]); Future initAddTimer(List list) async { @@ -85,27 +84,29 @@ class TimersNotifier extends StateNotifier> { _subscriptions.add(null); } - void setTimerOverlay(BuildContext context) { + void setTimerOverlay(OverlayState context) { timerOverlay = OverlayEntry( builder: (_) => HomeTimerAlertWidget( - receivedContext: context, + overlayState: context, finishedTimers: finishedTimers, ), ); } - void showTimerOverlay(BuildContext context, int timerId) async { + void showTimerOverlay(OverlayState overlayState, int timerId) async { finishedTimers.add(timerId); if (timerOverlayMounted) { timerOverlay?.remove(); timerOverlay = null; - setTimerOverlay(context); - Navigator.of(context).overlay!.insert(timerOverlay!); + setTimerOverlay(overlayState); + overlayState.insert(timerOverlay!); + // Navigator.of(context).overlay!.insert(timerOverlay!); + } else { - setTimerOverlay(context); - Navigator.of(context).overlay!.insert(timerOverlay!); + setTimerOverlay(overlayState); + overlayState.insert(timerOverlay!); } timerOverlayMounted = true; @@ -118,7 +119,7 @@ class TimersNotifier extends StateNotifier> { timerOverlay = null; } - void onTick(int timerId, BuildContext context) { + void onTick(int timerId, OverlayState overlayState) { state = state.map((timer) { if (timer.timerId == timerId && timer.timerState == TimerState.started) { if (timer.currentTime > const Duration(milliseconds: 20)) { @@ -126,9 +127,9 @@ class TimersNotifier extends StateNotifier> { currentTime: timer.currentTime - const Duration(milliseconds: 20), ); } else { - _audioPlayer.play(AssetSource('sounds/timer/timer_end_sound.wav')); + TimerSoundComponent.timerPlay(); _subscriptions[timerId - 1]?.cancel(); - showTimerOverlay(context, timerId); + showTimerOverlay(overlayState, timerId); return timer.copyWith( currentTime: timer.initialTime, timerState: TimerState.initial, @@ -139,27 +140,27 @@ class TimersNotifier extends StateNotifier> { }).toList(); } - void onStarted(int timerId, BuildContext context) { + void onStarted(int timerId, OverlayState overlayState) { state = state.map((timer) { if (timer.timerId == timerId && timer.timerState != TimerState.started) { _subscriptions[timerId - 1]?.cancel(); _subscriptions[timerId - 1] = Stream.periodic(const Duration(milliseconds: 20), (x) => x) - .listen((_) => onTick(timerId, context)); + .listen((_) => onTick(timerId, overlayState)); return timer.copyWith(timerState: TimerState.started); } return timer; }).toList(); } - void onStartedUseSet(Set timerId, BuildContext context) { + void onStartedUseSet(Set timerId, OverlayState overlayState) { state = state.map((timer) { if (timerId.contains(timer.timerId) && timer.timerState != TimerState.started) { _subscriptions[timer.timerId - 1]?.cancel(); _subscriptions[timer.timerId - 1] = Stream.periodic(const Duration(milliseconds: 20), (x) => x) - .listen((_) => onTick(timer.timerId, context)); + .listen((_) => onTick(timer.timerId, overlayState)); return timer.copyWith(timerState: TimerState.started); } return timer; diff --git a/lib/home/presentation/providers/home_today_routines_provider.dart b/lib/home/presentation/providers/home_today_routines_provider.dart index b8aa4b06..d59c4bde 100644 --- a/lib/home/presentation/providers/home_today_routines_provider.dart +++ b/lib/home/presentation/providers/home_today_routines_provider.dart @@ -1,16 +1,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:maeum_ga_gym_flutter/home/domain/model/home_today_routines_model.dart'; +import 'package:maeum_ga_gym_flutter/core/model/routine/maeumgagym_routine_list_model.dart'; import 'package:maeum_ga_gym_flutter/home/domain/usecase/home_today_routines_usecase.dart'; final homeTodayRoutineController = StateNotifierProvider< - HomeTodayRoutineStateNotifier, HomeTodayRoutineListModel>((ref) { + HomeTodayRoutineStateNotifier, MaeumgagymRoutineListModel>((ref) { return HomeTodayRoutineStateNotifier(); }); class HomeTodayRoutineStateNotifier - extends StateNotifier { + extends StateNotifier { HomeTodayRoutineStateNotifier() - : super(HomeTodayRoutineListModel( + : super(MaeumgagymRoutineListModel( routineList: [], statusCode: const AsyncData(500), )); diff --git a/lib/home/presentation/view/home_main_screen.dart b/lib/home/presentation/view/home_main_screen.dart index 22675a5e..ef5cc097 100644 --- a/lib/home/presentation/view/home_main_screen.dart +++ b/lib/home/presentation/view/home_main_screen.dart @@ -73,7 +73,7 @@ class _HomeMainScreenState extends ConsumerState { const SizedBox(height: 20), const HomeMainQuotesContainer(), const SizedBox(height: 24), - const HomeMainWalkContainer(), + // const HomeMainWalkContainer(), const SizedBox(height: 24), const HomeMainRoutineContainer(), const SizedBox(height: 24), diff --git a/lib/home/presentation/view/home_today_routine_screen.dart b/lib/home/presentation/view/home_today_routine_screen.dart index eeb41aeb..3456ffe5 100644 --- a/lib/home/presentation/view/home_today_routine_screen.dart +++ b/lib/home/presentation/view/home_today_routine_screen.dart @@ -121,6 +121,7 @@ class HomeTodayRoutineScreen extends ConsumerWidget { bottomSheet: HomeTodayRoutineButton( isCompleted: todayRoutine.isCompleted!, routineId: todayRoutine.id!, + routineList: todayRoutine.exerciseInfoResponseList!, ), ); } diff --git a/lib/home/presentation/widget/main/container/home_main_routine_container.dart b/lib/home/presentation/widget/main/container/home_main_routine_container.dart index 04737fed..ead6ff8e 100644 --- a/lib/home/presentation/widget/main/container/home_main_routine_container.dart +++ b/lib/home/presentation/widget/main/container/home_main_routine_container.dart @@ -30,6 +30,10 @@ class _HomeMainRoutineContainerState routineContainerPageController = PageController( initialPage: 0, ); + + WidgetsBinding.instance.addPostFrameCallback((_) { + ref.read(homeRoutinePageIndexProvider.notifier).state = 0; + }); } @override diff --git a/lib/home/presentation/widget/main/widget/home_main_timer_widget.dart b/lib/home/presentation/widget/main/widget/home_main_timer_widget.dart index 42734453..99e486bf 100644 --- a/lib/home/presentation/widget/main/widget/home_main_timer_widget.dart +++ b/lib/home/presentation/widget/main/widget/home_main_timer_widget.dart @@ -69,7 +69,7 @@ class _MainTimerWidgetState extends ConsumerState { timerList[index].timerState == TimerState.initial) { ref.read(homeTimersProvider.notifier).onStarted( - timerList[index].timerId, context); + timerList[index].timerId, Overlay.of(context)); } else { ref .read(homeTimersProvider.notifier) diff --git a/lib/home/presentation/widget/timer/container/home_timer_func_button_list_container.dart b/lib/home/presentation/widget/timer/container/home_timer_func_button_list_container.dart index ee071884..b75c711c 100644 --- a/lib/home/presentation/widget/timer/container/home_timer_func_button_list_container.dart +++ b/lib/home/presentation/widget/timer/container/home_timer_func_button_list_container.dart @@ -38,12 +38,12 @@ class HomeTimerFuncButtonListContainer extends ConsumerWidget { if (timerState[timerIndex].timerState != TimerState.started) { timerNotifier.onStarted( - timerState[timerIndex].timerId, context); + timerState[timerIndex].timerId, Overlay.of(context)); timerNotifier.onPaused(timerState[timerIndex].timerId); } else { timerNotifier.onPaused(timerState[timerIndex].timerId); timerNotifier.onStarted( - timerState[timerIndex].timerId, context); + timerState[timerIndex].timerId, Overlay.of(context)); } } else { showTopSnackBar( @@ -71,7 +71,7 @@ class HomeTimerFuncButtonListContainer extends ConsumerWidget { if (timerState[timerIndex].timerState != TimerState.started) { timerNotifier.onStarted( - timerState[timerIndex].timerId, context); + timerState[timerIndex].timerId, Overlay.of(context)); } else { timerNotifier.onPaused(timerState[timerIndex].timerId); } diff --git a/lib/home/presentation/widget/timer/widget/home_timer_alert_widget.dart b/lib/home/presentation/widget/timer/widget/home_timer_alert_widget.dart index 88d41df5..eeeb9f8c 100644 --- a/lib/home/presentation/widget/timer/widget/home_timer_alert_widget.dart +++ b/lib/home/presentation/widget/timer/widget/home_timer_alert_widget.dart @@ -9,12 +9,12 @@ import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_wid import 'package:maeum_ga_gym_flutter/home/presentation/providers/home_timer_state_provider.dart'; class HomeTimerAlertWidget extends ConsumerStatefulWidget { - final BuildContext receivedContext; + final OverlayState overlayState; final Set finishedTimers; const HomeTimerAlertWidget({ super.key, - required this.receivedContext, + required this.overlayState, required this.finishedTimers, }); @@ -72,22 +72,22 @@ class _HomeTimerAlertWidgetState extends ConsumerState padding: const EdgeInsets.only(top: 24), child: SlideTransition( position: _animation, - child: Material( - child: Container( - padding: - const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - width: MediaQuery.of(context).size.width - 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - boxShadow: const [ - BoxShadow( - color: Color(0x4C000000), - blurRadius: 6, - offset: Offset(0, 0), - ), - ], - ), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + width: MediaQuery.of(context).size.width - 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: const [ + BoxShadow( + color: Color(0x4C000000), + blurRadius: 6, + offset: Offset(0, 0), + ), + ], + ), + child: Material( + color: MaeumgagymColor.white, child: Column( verticalDirection: VerticalDirection.down, mainAxisSize: MainAxisSize.min, @@ -147,7 +147,7 @@ class _HomeTimerAlertWidgetState extends ConsumerState onTap: () { timersNotifier.onStartedUseSet( widget.finishedTimers, - widget.receivedContext, + widget.overlayState, ); timersNotifier.removeTimerOverlay(); diff --git a/lib/home/presentation/widget/timer/widget/home_timer_app_bar.dart b/lib/home/presentation/widget/timer/widget/home_timer_app_bar.dart index f4c1ca74..4852c1f4 100644 --- a/lib/home/presentation/widget/timer/widget/home_timer_app_bar.dart +++ b/lib/home/presentation/widget/timer/widget/home_timer_app_bar.dart @@ -65,11 +65,11 @@ class HomeTimerAppBar extends ConsumerWidget implements PreferredSizeWidget { ), ), const SizedBox(width: 12), - const ImageWidget( - image: Images.iconsDotsVertical, - width: 32, - height: 32, - ), + // const ImageWidget( + // image: Images.iconsDotsVertical, + // width: 32, + // height: 32, + // ), ], ), ], diff --git a/lib/home/presentation/widget/today_routine/home_today_routine_app_bar.dart b/lib/home/presentation/widget/today_routine/home_today_routine_app_bar.dart index 01b34e23..7148eb03 100644 --- a/lib/home/presentation/widget/today_routine/home_today_routine_app_bar.dart +++ b/lib/home/presentation/widget/today_routine/home_today_routine_app_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; import '../../../../config/maeumgagym_color.dart'; @@ -23,8 +24,7 @@ class HomeTodayRoutineAppBar extends StatelessWidget GestureDetector( onTap: () => Navigator.pop(context), child: ImageWidget( - image: "assets/image/core_icon/left_arrow_icon.svg", - imageType: ImageType.svg, + image: Images.arrowLeft, width: 28, height: 28, color: MaeumgagymColor.black, diff --git a/lib/home/presentation/widget/today_routine/home_today_routine_button.dart b/lib/home/presentation/widget/today_routine/home_today_routine_button.dart index 4b120268..a785d7cc 100644 --- a/lib/home/presentation/widget/today_routine/home_today_routine_button.dart +++ b/lib/home/presentation/widget/today_routine/home_today_routine_button.dart @@ -1,62 +1,91 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:maeum_ga_gym_flutter/home/presentation/providers/home_today_routines_provider.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/provider/routine_start_page_view_provider.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/view/routine_start_main_screen.dart'; import '../../../../config/maeumgagym_color.dart'; import '../../../../core/component/text/pretendard/ptd_text_widget.dart'; +import '../../../../core/model/routine/maeumgagym_routine_list_model.dart'; class HomeTodayRoutineButton extends ConsumerWidget { final int routineId; final bool isCompleted; + final List routineList; - const HomeTodayRoutineButton({super.key, required this.isCompleted, required this.routineId}); + const HomeTodayRoutineButton({ + super.key, + required this.isCompleted, + required this.routineId, + required this.routineList, + }); @override Widget build(BuildContext context, WidgetRef ref) { - return GestureDetector( - onTap: () async { - if (!ref.watch(homeTodayRoutineController).statusCode.isLoading) { - if(isCompleted){ - await ref - .read(homeTodayRoutineController.notifier) - .incompleteTodayRoutines(routineId); - } - - if(!isCompleted){ - await ref - .read(homeTodayRoutineController.notifier) - .completeTodayRoutines(routineId); - } + return Container( + width: MediaQuery.of(context).size.width, + height: 98, + alignment: Alignment.center, + decoration: BoxDecoration( + color: MaeumgagymColor.white, + border: Border.all(color: MaeumgagymColor.gray50), + ), + child: Padding( + padding: const EdgeInsets.all(20), + child: Builder( + builder: (context) { + if (isCompleted) { + return Container( + decoration: BoxDecoration( + color: MaeumgagymColor.gray100, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: PtdTextWidget.labelLarge( + "루틴 완료함", + MaeumgagymColor.gray300, + ), + ), + ); + } else { + return GestureDetector( + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => RoutineStartMainScreen( + routineId: routineId, + routineList: routineList + ), + ), + ); - await ref - .read(homeTodayRoutineController.notifier) - .getTodayRoutines(); - } - }, - child: Container( - width: MediaQuery.of(context).size.width, - height: 98, - alignment: Alignment.center, - decoration: BoxDecoration( - color: MaeumgagymColor.white, - border: Border.all(color: MaeumgagymColor.gray50), - ), - child: Padding( - padding: const EdgeInsets.all(20), - child: Container( - decoration: BoxDecoration( - color: isCompleted - ? MaeumgagymColor.blue50 - : MaeumgagymColor.blue500, - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: PtdTextWidget.bodyLarge( - isCompleted ? '루틴 완료 취소하기' : '루틴 완료하기', - isCompleted ? MaeumgagymColor.blue500 : MaeumgagymColor.white, - ), - ), - ), + ref.read(routineStartPageViewProvider.notifier).state = 0; + }, + child: Container( + decoration: BoxDecoration( + color: MaeumgagymColor.blue500, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ImageWidget( + width: 24, + image: Images.mediaPlayFilled, + color: MaeumgagymColor.white, + ), + const SizedBox(width: 8), + PtdTextWidget.labelLarge("루틴 시작하기", MaeumgagymColor.white) + ], + ), + ), + ), + ); + } + }, ), ), ); diff --git a/lib/home/presentation/widget/today_routine/home_today_routine_list_widget.dart b/lib/home/presentation/widget/today_routine/home_today_routine_list_widget.dart index 47d0d708..cc6fc56b 100644 --- a/lib/home/presentation/widget/today_routine/home_today_routine_list_widget.dart +++ b/lib/home/presentation/widget/today_routine/home_today_routine_list_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/pose/domain/model/pose_data_model.dart'; import '../../../../config/maeumgagym_color.dart'; @@ -66,11 +67,11 @@ class HomeTodayRoutineListWidget extends ConsumerWidget { ), ], ), - const ImageWidget( - image: 'assets/image/core_icon/right_arrow_icon.svg', - imageType: ImageType.svg, + ImageWidget( + image: Images.chevronRight, width: 24, height: 24, + color: MaeumgagymColor.gray200, ), ], ), diff --git a/lib/page_manager/presentation/view/animated_indexed_stack_screen.dart b/lib/page_manager/presentation/view/animated_indexed_stack_screen.dart deleted file mode 100644 index 58d31aa4..00000000 --- a/lib/page_manager/presentation/view/animated_indexed_stack_screen.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; - -class AnimatedIndexedStack extends StatefulWidget { - final int index; - final List children; - final Duration duration; - - const AnimatedIndexedStack({ - super.key, - required this.index, - required this.children, - this.duration = const Duration(milliseconds: 200), - }); - - @override - State createState() => _AnimatedIndexedStackState(); -} - -class _AnimatedIndexedStackState extends State - with SingleTickerProviderStateMixin { - late AnimationController _controller; - double _position = 1.0; - late double initPosition; - - @override - void didUpdateWidget(oldWidget) { - if (widget.index != oldWidget.index) { - bool isRightScreen = widget.index > oldWidget.index; - setState(() { - _position = isRightScreen ? initPosition : -initPosition; - }); - _controller.forward(from: 0.0); - } - super.didUpdateWidget(oldWidget); - } - - @override - void initState() { - initPosition = 1.0; - - _controller = AnimationController( - vsync: this, - duration: widget.duration, - ); - _controller.forward(); - super.initState(); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return FadeTransition( - opacity: _controller, - child: SlideTransition( - position: Tween( - begin: Offset(_position, 0.0), - end: Offset.zero, - ).animate(_controller), - child: IndexedStack( - index: widget.index, - children: widget.children, - ), - ), - ); - } -} diff --git a/lib/page_manager/presentation/view/bottom_navigation_item.dart b/lib/page_manager/presentation/view/bottom_navigation_item.dart index a99cc297..ba30ef8d 100644 --- a/lib/page_manager/presentation/view/bottom_navigation_item.dart +++ b/lib/page_manager/presentation/view/bottom_navigation_item.dart @@ -10,6 +10,7 @@ class BottomNavigationItem extends ConsumerWidget { final int clickState; final String label; final String selectedImage, image; + final PageController pageController; const BottomNavigationItem({ super.key, @@ -17,6 +18,7 @@ class BottomNavigationItem extends ConsumerWidget { required this.image, required this.selectedImage, required this.clickState, + required this.pageController, }); @override @@ -25,7 +27,14 @@ class BottomNavigationItem extends ConsumerWidget { final bool isSelected = ref.watch(pageControllerProvider) == clickState; return GestureDetector( - onTap: () => pageControllerNotifier.state = clickState, + onTap: () { + pageController.animateToPage( + clickState, + duration: const Duration(milliseconds: 300), + curve: Curves.ease, + ); + pageControllerNotifier.state = clickState; + }, child: SizedBox( height: 64, child: FittedBox( diff --git a/lib/page_manager/presentation/view/page_manager_screen.dart b/lib/page_manager/presentation/view/page_manager_screen.dart index 141413de..f2dce006 100644 --- a/lib/page_manager/presentation/view/page_manager_screen.dart +++ b/lib/page_manager/presentation/view/page_manager_screen.dart @@ -4,18 +4,16 @@ import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/empty_view/view/empty_view_screen.dart'; import 'package:maeum_ga_gym_flutter/home/presentation/view/home_main_screen.dart'; -import 'package:maeum_ga_gym_flutter/page_manager/presentation/view/animated_indexed_stack_screen.dart'; import 'package:maeum_ga_gym_flutter/page_manager/presentation/view/bottom_navigation_item.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/view/self_care_main_screen.dart'; import '../../../pose/presentation/view/pose_main_screen.dart'; -import '../provider/page_manager_controller.dart'; class PageManagerScreen extends ConsumerWidget { const PageManagerScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final pageControllerIndex = ref.watch(pageControllerProvider); + final PageController pageController = PageController(); final List screenData = [ const HomeMainScreen(), @@ -26,41 +24,47 @@ class PageManagerScreen extends ConsumerWidget { ]; return Scaffold( - body: AnimatedIndexedStack( - index: pageControllerIndex, + body: PageView( + physics: const NeverScrollableScrollPhysics(), + controller: pageController, children: screenData, ), bottomNavigationBar: Container( height: 64, color: MaeumgagymColor.white, - child: const Row( + child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ BottomNavigationItem( + pageController: pageController, label: "홈", clickState: 0, selectedImage: Images.iconsHouseFilled, image: Images.iconsHouse, ), BottomNavigationItem( + pageController: pageController, label: "자세", clickState: 1, selectedImage: Images.iconsPoseFilled, image: Images.iconsPose, ), BottomNavigationItem( + pageController: pageController, label: "샵", clickState: 2, selectedImage: Images.iconsCartFilled, image: Images.iconsCart, ), BottomNavigationItem( + pageController: pageController, label: "피클", clickState: 3, selectedImage: Images.iconsPickleFilled, image: Images.iconsPickle, ), BottomNavigationItem( + pageController: pageController, label: "자기관리", clickState: 4, selectedImage: Images.iconsArmFilled, diff --git a/lib/pose/presentation/view/pose_add_routine_detail_screen.dart b/lib/pose/presentation/view/pose_add_routine_detail_screen.dart index 297206b1..5730ede5 100644 --- a/lib/pose/presentation/view/pose_add_routine_detail_screen.dart +++ b/lib/pose/presentation/view/pose_add_routine_detail_screen.dart @@ -12,9 +12,9 @@ import '../../../core/component/routine/presentation/provider/routine_my_routine import '../../../core/component/routine/presentation/provider/routine_my_routine_my_routine_provider.dart'; import '../../../core/component/routine/domain/model/exercise_info_edit_routine_pose_model.dart'; import '../../../core/component/routine/presentation/widget/routine_my_routine_item_count_widget.dart'; +import '../../../core/model/routine/maeumgagym_routine_list_model.dart'; import '../../../home/presentation/providers/home_today_routines_provider.dart'; import '../../../self_care/domain/model/my_routine/exercise_info_request_model.dart'; -import '../../../self_care/domain/model/my_routine/routine_response_model.dart'; class PoseAddRoutineDetailScreen extends ConsumerStatefulWidget { final int routineIndex; @@ -38,7 +38,7 @@ class PoseAddRoutineDetailScreen extends ConsumerStatefulWidget { class _PoseAddRoutineDetailScreenState extends ConsumerState { - late final RoutineResponseModel item; + late final RoutineModel item; late List routineEditList; late final TextEditingController poseRepetitionsTextController; late final TextEditingController poseSetTextController; @@ -58,18 +58,17 @@ class _PoseAddRoutineDetailScreenState /// 화면이 빌드되었을 때 init WidgetsBinding.instance.addPostFrameCallback((_) { - item = - ref.watch(routineMyRoutinesProvider).routineList[widget.routineIndex]; + item = ref.watch(routineMyRoutinesProvider).routineList[widget.routineIndex]; routineEditList = List.generate( item.exerciseInfoResponseList.length, (index) => ExerciseInfoEditRoutinePoseModel( poseModel: PoseDataModel( - id: item.exerciseInfoResponseList[index].pose!.id, - thumbnail: item.exerciseInfoResponseList[index].pose!.thumbnail, - name: item.exerciseInfoResponseList[index].pose!.name, - needMachine: item.exerciseInfoResponseList[index].pose!.needMachine, - simplePart: item.exerciseInfoResponseList[index].pose!.simplePart, - exactPart: item.exerciseInfoResponseList[index].pose!.exactPart, + id: item.exerciseInfoResponseList[index].pose.id, + thumbnail: item.exerciseInfoResponseList[index].pose.thumbnail, + name: item.exerciseInfoResponseList[index].pose.name, + needMachine: item.exerciseInfoResponseList[index].pose.needMachine, + simplePart: item.exerciseInfoResponseList[index].pose.simplePart, + exactPart: item.exerciseInfoResponseList[index].pose.exactPart, ), repetitionsController: TextEditingController( text: @@ -195,8 +194,8 @@ class _PoseAddRoutineDetailScreenState await editPoseListNotifier.editRoutine( routineName: widget.routineName, - isArchived: item.routineStatus!.isArchived!, - isShared: item.routineStatus!.isShared!, + isArchived: item.routineStatus.isArchived, + isShared: item.routineStatus.isShared, exerciseInfoRequestList: List.generate( routineEditList.length, @@ -217,7 +216,7 @@ class _PoseAddRoutineDetailScreenState ), ), dayOfWeeks: item.dayOfWeeks, - routineId: item.id!, + routineId: item.id, ); await ref diff --git a/lib/pose/presentation/view/pose_detail_screen.dart b/lib/pose/presentation/view/pose_detail_screen.dart index b0f4e5fc..2999402a 100644 --- a/lib/pose/presentation/view/pose_detail_screen.dart +++ b/lib/pose/presentation/view/pose_detail_screen.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; -import 'package:maeum_ga_gym_flutter/core/re_issue/presentation/maeumgagym_re_issue_provider.dart'; import 'package:maeum_ga_gym_flutter/pose/presentation/provider/pose_detail_provider.dart'; import 'package:maeum_ga_gym_flutter/pose/presentation/widget/detail/pose_detail_app_bar.dart'; import '../../../core/component/pose/domain/model/pose_data_model.dart'; @@ -46,8 +45,7 @@ class _PoseDetailScreenState extends ConsumerState { Widget build(BuildContext context) { final poseDetail = ref.read(poseDetailController); - if (ref.watch(poseDetailController).statusCode.hasValue && - ref.watch(maeumgagymReIssueController).stateus.hasValue) { + if (ref.watch(poseDetailController).statusCode.hasValue) { return Scaffold( backgroundColor: MaeumgagymColor.white, appBar: PoseDetailAppBar( diff --git a/lib/pose/presentation/widget/add_routine/pose_routine_item_widget.dart b/lib/pose/presentation/widget/add_routine/pose_routine_item_widget.dart index b5d46367..5520257a 100644 --- a/lib/pose/presentation/widget/add_routine/pose_routine_item_widget.dart +++ b/lib/pose/presentation/widget/add_routine/pose_routine_item_widget.dart @@ -43,17 +43,17 @@ class _PoseRoutineItemWidgetState extends ConsumerState { ), const SizedBox(height: 4), PtdTextWidget.bodySmall( - (item.routineStatus!.isArchived! ? "보관중" : "사용중") + + (item.routineStatus.isArchived ? "보관중" : "사용중") + (item.dayOfWeeks.isNotEmpty ? " | ${item.dayOfWeeks.map((str) => str[0]).join(", ")}" : ""), - item.routineStatus!.isArchived! + item.routineStatus.isArchived ? MaeumgagymColor.gray400 : MaeumgagymColor.blue500, ), ], ), - item.routineStatus!.isShared! + item.routineStatus.isShared ? const RoutineMyRoutineSharedWidget() : const SizedBox(), ], diff --git a/lib/routine_start/domain/model/routine_start_model.dart b/lib/routine_start/domain/model/routine_start_model.dart new file mode 100644 index 00000000..c63ff58d --- /dev/null +++ b/lib/routine_start/domain/model/routine_start_model.dart @@ -0,0 +1,84 @@ +import '../../../core/model/routine/maeumgagym_routine_list_model.dart'; + +class RoutineStartModel { + int routineId; + RestTimer restTimer; + List exercises; + + RoutineStartModel({ + required this.routineId, + required this.restTimer, + required this.exercises, + }); + + factory RoutineStartModel.fromModel(int routineId, RestTimer restTimer,List list){ + return RoutineStartModel( + routineId: routineId, + restTimer: restTimer, + exercises: list.map((e) => ExerciseModel.fromModel(e)).toList(), + ); + } +} + +class ExerciseModel { + final String? name; + final int? id; + final String? thumbnail; + final int? sets; + final int? repetitions; + List? completes; + + ExerciseModel({ + required this.name, + required this.id, + required this.thumbnail, + required this.sets, + required this.repetitions, + required this.completes, + }); + + factory ExerciseModel.fromModel(ExerciseInfoList exerciseInfoList) { + return ExerciseModel( + name: exerciseInfoList.pose.name, + id: exerciseInfoList.pose.id, + thumbnail: exerciseInfoList.pose.thumbnail, + sets: exerciseInfoList.sets, + repetitions: exerciseInfoList.repetitions, + completes: List.generate(exerciseInfoList.sets!, (index) => false), + ); + } + + ExerciseModel copyWith({ + final String? name, + final int? id, + final String? thumbnail, + final int? sets, + final int? repetitions, + List? completes}) { + return ExerciseModel( + name: name ?? this.name, + id: id ?? this.id, + thumbnail: thumbnail ?? this.thumbnail, + sets: sets ?? this.sets, + repetitions: repetitions ?? this.repetitions, + completes: completes ?? this.completes, + ); + } +} + +class RestTimer { + Duration initialTime; + Duration currentTime; + + RestTimer({ + required this.initialTime, + required this.currentTime, + }); + + RestTimer copyWith({Duration? initialTime, Duration? currentTime}){ + return RestTimer( + initialTime: initialTime ?? this.initialTime, + currentTime: currentTime ?? this.currentTime, + ); + } +} diff --git a/lib/routine_start/presentation/provider/routine_start_exercise_provider.dart b/lib/routine_start/presentation/provider/routine_start_exercise_provider.dart new file mode 100644 index 00000000..d2c31c91 --- /dev/null +++ b/lib/routine_start/presentation/provider/routine_start_exercise_provider.dart @@ -0,0 +1,114 @@ +import 'dart:async'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../core/component/timer_sound_component.dart'; +import '../../../core/model/routine/maeumgagym_routine_list_model.dart'; +import '../../domain/model/routine_start_model.dart'; + +final routineStartExerciseProvider = StateNotifierProvider((ref) { + return RoutineStartExerciseNotifier(); +}); + +class RoutineStartExerciseNotifier extends StateNotifier { + RoutineStartExerciseNotifier() + : super( + RoutineStartModel( + routineId: -500, + restTimer: RestTimer( + initialTime: const Duration(seconds: 20), + currentTime: const Duration(seconds: 20), + ), + exercises: [], + ), + ); + + final Duration streamTimerValue = const Duration(seconds: 1); + bool timerStarted = false; + late StreamSubscription _stream; + + void startTimer(){ + timerStarted = true; + _stream = Stream.periodic(streamTimerValue, (x) => x,).listen((_) => onTick()); + } + + void cancelTimer(){ + timerStarted = false; + _stream.cancel(); + state.restTimer = state.restTimer.copyWith( + initialTime: state.restTimer.initialTime, + currentTime: state.restTimer.initialTime, + ); + } + + void setRoutineStartModel(int postId, List exerciseInfoList) { + state = RoutineStartModel.fromModel( + postId, + RestTimer( + initialTime: const Duration(seconds: 20), + currentTime: const Duration(seconds: 20), + ), + exerciseInfoList, + ); + } + + void setComplete(int exerciseIndex, int setIndex){ + RoutineStartModel dumState = state; + bool isState = !(dumState.exercises[exerciseIndex].completes![setIndex]); + + dumState.exercises[exerciseIndex].completes![setIndex] = isState; + state = dumState; + + // 완료를 누르고 timer가 시작되지 않았다면 + if(isState && !timerStarted){ + startTimer(); + } + // 완료를 누르고 timer가 시작된 상태라면? + else if(isState && timerStarted){ + cancelTimer(); + startTimer(); + } + } + + void onTick() { + if(state.restTimer.currentTime > streamTimerValue){ + state.restTimer.currentTime -= streamTimerValue; + } else { + TimerSoundComponent.timerPlay(); + cancelTimer(); + } + } + + void addRestTime() { + RestTimer restTimer = state.restTimer; + const Duration addTime = Duration(seconds: 10); + + if(restTimer.currentTime + addTime < const Duration(hours: 1)){ + if (timerStarted) { + state.restTimer.currentTime += addTime; + } else { + state.restTimer = RestTimer( + initialTime: restTimer.initialTime + addTime, + currentTime: restTimer.currentTime + addTime, + ); + } + } + } + + void minusRestTime(){ + RestTimer restTimer = state.restTimer; + const Duration minusTime = Duration(seconds: 10); + + if(restTimer.currentTime - minusTime > const Duration(seconds: 1)){ + if (timerStarted) { + state.restTimer.currentTime -= minusTime; + } else { + state.restTimer = RestTimer( + initialTime: restTimer.initialTime - minusTime, + currentTime: restTimer.currentTime - minusTime, + ); + } + } + } +} + diff --git a/lib/routine_start/presentation/provider/routine_start_page_view_provider.dart b/lib/routine_start/presentation/provider/routine_start_page_view_provider.dart new file mode 100644 index 00000000..714913fa --- /dev/null +++ b/lib/routine_start/presentation/provider/routine_start_page_view_provider.dart @@ -0,0 +1,3 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final routineStartPageViewProvider = StateProvider((ref) => 0); diff --git a/lib/routine_start/presentation/view/routine_start_main_screen.dart b/lib/routine_start/presentation/view/routine_start_main_screen.dart new file mode 100644 index 00000000..52fb6525 --- /dev/null +++ b/lib/routine_start/presentation/view/routine_start_main_screen.dart @@ -0,0 +1,229 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; +import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; +import 'package:maeum_ga_gym_flutter/pose/presentation/view/pose_detail_screen.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/provider/routine_start_exercise_provider.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/provider/routine_start_page_view_provider.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/widget/routine_start_main_bottom_sheet.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/widget/routine_start_main_list_widget.dart'; +import '../../../core/model/routine/maeumgagym_routine_list_model.dart'; +import '../widget/routine_start_main_app_bar.dart'; + +class RoutineStartMainScreen extends ConsumerStatefulWidget { + final int routineId; + final List routineList; + + const RoutineStartMainScreen({ + super.key, + required this.routineId, + required this.routineList, + }); + + @override + ConsumerState createState() => + _RoutineStartMainScreenState(); +} + +class _RoutineStartMainScreenState extends ConsumerState { + final ScrollController _scrollController = ScrollController(); + double _containerHeight = 200.0; + + Duration doExerciseTime = const Duration(seconds: 0); + late StreamSubscription stream; + + @override + void initState() { + super.initState(); + _scrollController.addListener(_onScroll); + + stream = Stream.periodic( + const Duration(seconds: 1), + (x) => x, + ).listen((event) { + doExerciseTime = Duration(seconds: event + 1); + setState(() {}); + }); + + WidgetsBinding.instance.addPostFrameCallback((_) { + ref.read(routineStartPageViewProvider.notifier).state = 0; + if (ref.read(routineStartExerciseProvider).routineId != widget.routineId || + ref.read(routineStartExerciseProvider).exercises.length != widget.routineList.length) { + ref + .read(routineStartExerciseProvider.notifier) + .setRoutineStartModel(widget.routineId, widget.routineList); + } + }); + } + + @override + void dispose() { + _scrollController.removeListener(_onScroll); + _scrollController.dispose(); + stream.cancel(); + super.dispose(); + } + + void _onScroll() { + const double maxHeight = 200.0; + const double minHeight = 160.0; + + setState(() { + _containerHeight = maxHeight - (_scrollController.offset / 5).clamp(0.0, maxHeight - minHeight); + }); + } + + @override + Widget build(BuildContext context) { + final exerciseRoutineList = ref.watch(routineStartExerciseProvider).exercises; + + return Scaffold( + backgroundColor: MaeumgagymColor.white, + appBar: RoutineStartMainAppBar( + time: doExerciseTime, + routineLength: exerciseRoutineList.length, + ), + bottomSheet: const RoutineStartMainBottomSheet(), + body: SafeArea( + child: PageView.builder( + onPageChanged: (value) => ref.read(routineStartPageViewProvider.notifier).state = value, + itemCount: exerciseRoutineList.length, + itemBuilder: (context, pageViewIndex) { + final routineData = exerciseRoutineList[pageViewIndex]; + + return Column( + children: [ + // 사진 + AnimatedContainer( + duration: const Duration(microseconds: 100), + width: MediaQuery.of(context).size.width, + height: _containerHeight, + color: MaeumgagymColor.gray25, + child: Center( + child: ImageWidget( + height: _containerHeight, + imageType: ImageType.pngNetwork, + image: routineData.thumbnail!, + ), + ), + ), + // 운동 이름 및 info + Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + PtdTextWidget.titleMedium( + routineData.name!, + MaeumgagymColor.black, + ), + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PoseDetailScreen( + id: widget.routineList[pageViewIndex].pose.id!, + poseData: widget.routineList[pageViewIndex].pose, + ), + ), + ); + }, + child: Container( + width: 40, + height: 28, + decoration: BoxDecoration( + color: MaeumgagymColor.gray50, + borderRadius: BorderRadius.circular(100), + ), + child: const Center( + child: ImageWidget( + width: 16, + image: Images.iconsNotDesignSysInfoIcon, + ), + ), + ), + ) + ], + ), + const SizedBox(height: 8), + Row( + children: [ + PtdTextWidget.labelMedium( + "횟수", + MaeumgagymColor.gray600, + ), + const SizedBox(width: 4), + PtdTextWidget.labelLarge( + (routineData.repetitions! * routineData.sets!) + .toString(), + MaeumgagymColor.blue500, + ), + PtdTextWidget.labelMedium( + "회", MaeumgagymColor.blue500), + ], + ) + ], + ), + ), + + Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + child: Row( + children: [ + SizedBox( + width: 80, + child: Center( + child: PtdTextWidget.bodyMedium( + "세트", MaeumgagymColor.gray500), + ), + ), + SizedBox( + width: MediaQuery.of(context).size.width - 160, + child: Center( + child: PtdTextWidget.bodyMedium( + "회", MaeumgagymColor.gray500)), + ), + SizedBox( + width: 40, + child: Center( + child: PtdTextWidget.bodyMedium( + "완료", MaeumgagymColor.gray500), + ), + ), + ], + ), + ), + + // list들 + Expanded( + child: ListView.builder( + controller: _scrollController, + itemCount: routineData.sets!, + itemBuilder: (context, listViewIndex) { + return RoutineStartMainListWidget( + onComplete: () { + ref + .read(routineStartExerciseProvider.notifier) + .setComplete(pageViewIndex, listViewIndex); + setState(() {}); + }, + pageViewIndex: pageViewIndex, + listViewIndex: listViewIndex, + ); + }, + ), + ), + ], + ); + }, + ), + ), + ); + } +} diff --git a/lib/routine_start/presentation/widget/routine_start_main_app_bar.dart b/lib/routine_start/presentation/widget/routine_start_main_app_bar.dart new file mode 100644 index 00000000..6e0b11a9 --- /dev/null +++ b/lib/routine_start/presentation/widget/routine_start_main_app_bar.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; +import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/provider/routine_start_page_view_provider.dart'; + +class RoutineStartMainAppBar extends ConsumerWidget implements PreferredSizeWidget { + final Duration time; + final int routineLength; + const RoutineStartMainAppBar({super.key, required this.routineLength, required this.time}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final double appbarWidth = MediaQuery.of(context).size.width - 32; + + return SafeArea( + child: PreferredSize( + preferredSize: preferredSize, + child: AppBar( + surfaceTintColor: MaeumgagymColor.white, + backgroundColor: MaeumgagymColor.white, + automaticallyImplyLeading: false, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: appbarWidth / 3, + child: Row( + children: [ + GestureDetector( + onTap: () => Navigator.pop(context), + child: const ImageWidget( + width: 28, + image: Images.arrowLeft, + ), + ), + const SizedBox(width: 16), + // PtdTextWidget.labelLarge("00:01", MaeumgagymColor.black) + time.inHours > 0 ? + PtdTextWidget.labelLarge( + "${time.inHours.toString().padLeft(2, "0")}" + ":${(time.inMinutes - (time.inHours * 60)).toString().padLeft(2, "0")}" + ":${(time.inSeconds - (time.inMinutes * 60)).toString().padLeft(2, "0")}", + MaeumgagymColor.black) : PtdTextWidget.labelLarge( + "${(time.inMinutes - (time.inHours * 60)).toString().padLeft(2, "0")}" + ":${(time.inSeconds - (time.inMinutes * 60)).toString().padLeft(2, "0")}", + MaeumgagymColor.black), + ], + ), + ), + Container( + alignment: Alignment.center, + width: appbarWidth / 3, + height: 10, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: routineLength, + itemBuilder: (context, index) { + if (index == ref.watch(routineStartPageViewProvider)) { + return Padding( + padding: const EdgeInsets.only(left: 2), + child: Container( + width: 16, + height: 6, + decoration: BoxDecoration( + color: MaeumgagymColor.blue500, + borderRadius: BorderRadius.circular(100), + ), + ), + ); + } else { + return Padding( + padding: const EdgeInsets.only(left: 2), + child: Container( + width: 10, + height: 6, + decoration: BoxDecoration( + color: MaeumgagymColor.gray100, + borderRadius: BorderRadius.circular(100), + ), + ), + ); + } + }, + ), + ), + SizedBox(width: appbarWidth / 3, height: 1), + ], + ), + ), + ), + ); + } + + @override + Size get preferredSize => const Size.fromHeight(52); +} diff --git a/lib/routine_start/presentation/widget/routine_start_main_bottom_sheet.dart b/lib/routine_start/presentation/widget/routine_start_main_bottom_sheet.dart new file mode 100644 index 00000000..a4d35dcc --- /dev/null +++ b/lib/routine_start/presentation/widget/routine_start_main_bottom_sheet.dart @@ -0,0 +1,90 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/widget/routine_start_main_bottom_sheet_button.dart'; + +import '../../../config/maeumgagym_color.dart'; +import '../../../core/component/image/images.dart'; +import '../../../core/component/text/pretendard/ptd_text_widget.dart'; +import '../provider/routine_start_exercise_provider.dart'; + +class RoutineStartMainBottomSheet extends StatefulWidget { + const RoutineStartMainBottomSheet({super.key}); + + @override + State createState() => _RoutineStartMainBottomSheetState(); +} + +class _RoutineStartMainBottomSheetState extends State { + late StreamSubscription stream; + + @override + void initState() { + super.initState(); + stream = Stream.periodic(const Duration(microseconds: 500), (x) => x).listen((_) => setState(() {})); + } + + @override + void dispose() { + super.dispose(); + stream.cancel(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + width: MediaQuery.of(context).size.width, + height: 110, + color: MaeumgagymColor.gray25, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + PtdTextWidget.labelSmall("휴식시간", MaeumgagymColor.blue500, null, null), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Consumer( + builder: (context, ref, child) => PtdTextWidget.titleLarge( + ref + .watch(routineStartExerciseProvider).restTimer + .currentTime.inSeconds.toString(), + MaeumgagymColor.black, + ), + ), + PtdTextWidget.titleMedium("초", MaeumgagymColor.black), + ], + ), + + Consumer( + builder: (context, ref, child) { + return Row( + children: [ + GestureDetector( + onTap: () => setState(() => ref.read(routineStartExerciseProvider.notifier).minusRestTime()), + child: const RoutineStartMainBottomSheetButton( + icon: Images.editRemoveMinus, + ), + ), + const SizedBox(width: 16), + GestureDetector( + onTap: () => setState(() => ref.read(routineStartExerciseProvider.notifier).addRestTime()), + child: const RoutineStartMainBottomSheetButton( + icon: Images.editAdd, + ), + ), + ], + ); + }, + ) + ], + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/routine_start/presentation/widget/routine_start_main_bottom_sheet_button.dart b/lib/routine_start/presentation/widget/routine_start_main_bottom_sheet_button.dart new file mode 100644 index 00000000..97177d30 --- /dev/null +++ b/lib/routine_start/presentation/widget/routine_start_main_bottom_sheet_button.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +import '../../../config/maeumgagym_color.dart'; +import '../../../core/component/image_widget.dart'; + +class RoutineStartMainBottomSheetButton extends StatelessWidget { + final String icon; + const RoutineStartMainBottomSheetButton({super.key, required this.icon}); + + @override + Widget build(BuildContext context) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: MaeumgagymColor.blue500, + shape: BoxShape.circle, + ), + child: Center( + child: ImageWidget( + width: 20, + color: MaeumgagymColor.white, + image: icon, + ), + ), + ); + } +} diff --git a/lib/routine_start/presentation/widget/routine_start_main_list_widget.dart b/lib/routine_start/presentation/widget/routine_start_main_list_widget.dart new file mode 100644 index 00000000..1206ef86 --- /dev/null +++ b/lib/routine_start/presentation/widget/routine_start_main_list_widget.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../config/maeumgagym_color.dart'; +import '../../../core/component/image/images.dart'; +import '../../../core/component/image_widget.dart'; +import '../../../core/component/text/pretendard/ptd_text_widget.dart'; +import '../provider/routine_start_exercise_provider.dart'; + +class RoutineStartMainListWidget extends ConsumerWidget { + final GestureTapCallback onComplete; + final int pageViewIndex, listViewIndex; + + const RoutineStartMainListWidget({ + super.key, + required this.pageViewIndex, + required this.listViewIndex, + required this.onComplete, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final routineData = ref.watch(routineStartExerciseProvider).exercises[pageViewIndex]; + return Padding( + padding: listViewIndex == (routineData.sets! - 1) ? const EdgeInsets.only(bottom: 300) : const EdgeInsets.all(0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 80, + height: 40, + decoration: BoxDecoration( + border: Border.all(color: MaeumgagymColor.gray50), + borderRadius: BorderRadius.circular(12), + ), + child: Center( + child: PtdTextWidget.bodyLarge( + (listViewIndex + 1).toString(), + MaeumgagymColor.black), + ), + ), + Container( + margin: const EdgeInsets.all(8), + width: MediaQuery.of(context).size.width - 176, + height: 40, + decoration: BoxDecoration( + border: Border.all(color: MaeumgagymColor.gray100), + borderRadius: BorderRadius.circular(12), + color: MaeumgagymColor.gray25, + ), + child: Center( + child: PtdTextWidget.bodyLarge( + routineData.repetitions.toString(), + MaeumgagymColor.black, + ), + ), + ), + Consumer( + builder: (context, ref, child) { + return GestureDetector( + onTap: onComplete, + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + border: Border.all( + color: routineData.completes![listViewIndex] + ? MaeumgagymColor.blue500 + : MaeumgagymColor.gray50, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Center( + child: Visibility( + visible: routineData.completes![listViewIndex], + child: ImageWidget( + width: 24, + color: MaeumgagymColor.blue500, + image: Images.iconsCheck, + ), + ), + ), + ), + ); + }, + ) + ], + ), + ); + } +} diff --git a/lib/self_care/data/date_source/remote/profile_remote_data_source.dart b/lib/self_care/data/date_source/remote/profile_remote_data_source.dart index dc4e5b09..245ad1b7 100644 --- a/lib/self_care/data/date_source/remote/profile_remote_data_source.dart +++ b/lib/self_care/data/date_source/remote/profile_remote_data_source.dart @@ -6,12 +6,11 @@ import 'package:maeum_ga_gym_flutter/self_care/domain/model/profile/profile_resp class ProfileRemoteDataSource { Future getUserProfile({ required String accessToken, - required String nickname, }) async { try { return dio .get( - "/user/$nickname", + "/user", options: Options( headers: { "Content-Type": "application/json", diff --git a/lib/self_care/data/repositoryImpl/profile_repository_impl.dart b/lib/self_care/data/repositoryImpl/profile_repository_impl.dart index e32efe3d..b1185bd8 100644 --- a/lib/self_care/data/repositoryImpl/profile_repository_impl.dart +++ b/lib/self_care/data/repositoryImpl/profile_repository_impl.dart @@ -9,11 +9,9 @@ class ProfileRepositoryImpl implements ProfileRepository { @override Future getUserProfile({ required String accessToken, - required String nickname, }) async { return await _remoteDataSource.getUserProfile( accessToken: accessToken, - nickname: nickname, ); } diff --git a/lib/self_care/domain/model/my_routine/exercise_info_response_model.dart b/lib/self_care/domain/model/my_routine/exercise_info_response_model.dart deleted file mode 100644 index bfdaf2ca..00000000 --- a/lib/self_care/domain/model/my_routine/exercise_info_response_model.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_pose_model.dart'; - -class ExerciseInfoResponseModel { - final AsyncValue statusCode; - RoutinePoseModel? pose; - final int? repetitions; - final int? sets; - - ExerciseInfoResponseModel({ - required this.statusCode, - required this.pose, - required this.repetitions, - required this.sets, - }); - - factory ExerciseInfoResponseModel.fromJson( - Map json, - int statusCode, - ) { - return ExerciseInfoResponseModel( - statusCode: AsyncData(statusCode), - pose: RoutinePoseModel.fromJson(json['pose']), - repetitions: json['repetitions'], - sets: json['sets'], - ); - } -} diff --git a/lib/self_care/domain/model/my_routine/routine_history_model.dart b/lib/self_care/domain/model/my_routine/routine_history_model.dart index c9d3c2e9..ddb0c064 100644 --- a/lib/self_care/domain/model/my_routine/routine_history_model.dart +++ b/lib/self_care/domain/model/my_routine/routine_history_model.dart @@ -1,11 +1,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/exercise_info_response_model.dart'; +import '../../../../core/model/routine/maeumgagym_routine_list_model.dart'; class RoutineHistoryModel { final AsyncValue statusCode; final int? id; final String? routineName; - List exerciseInfoList = []; + List exerciseInfoList = []; final String? date; RoutineHistoryModel({ @@ -22,8 +22,8 @@ class RoutineHistoryModel { statusCode: AsyncData(statusCode), id: json['id'], routineName: json['routine_name'], - exerciseInfoList: (json['exercise_info_list'] as List) - .map((exerciseInfoJson) => ExerciseInfoResponseModel.fromJson(exerciseInfoJson, statusCode)) + exerciseInfoList: json['exercise_info_response_list'] + .map((item) => ExerciseInfoList.fromJson(item)) .toList(), date: json['date'], ); diff --git a/lib/self_care/domain/model/my_routine/routine_pose_model.dart b/lib/self_care/domain/model/my_routine/routine_pose_model.dart deleted file mode 100644 index e0ea490a..00000000 --- a/lib/self_care/domain/model/my_routine/routine_pose_model.dart +++ /dev/null @@ -1,28 +0,0 @@ -class RoutinePoseModel { - final int? id; - final bool? needMachine; - final String? name; - List simplePart = []; - List exactPart = []; - final String? thumbnail; - - RoutinePoseModel({ - required this.id, - required this.needMachine, - required this.name, - required this.simplePart, - required this.exactPart, - required this.thumbnail, - }); - - factory RoutinePoseModel.fromJson(Map json) { - return RoutinePoseModel( - id: json['id'], - needMachine: json['need_machine'], - name: json['name'], - simplePart: List.from(json['simple_part']), - exactPart: List.from(json['exact_part']), - thumbnail: json['thumbnail'], - ); - } -} diff --git a/lib/self_care/domain/model/my_routine/routine_response_model.dart b/lib/self_care/domain/model/my_routine/routine_response_model.dart deleted file mode 100644 index aa16c4e1..00000000 --- a/lib/self_care/domain/model/my_routine/routine_response_model.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/exercise_info_response_model.dart'; -import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/routine_status_model.dart'; - -class RoutineResponseModel { - final AsyncValue statusCode; - final int? id; - final String? routineName; - List exerciseInfoResponseList = []; - List dayOfWeeks = []; - RoutineStatusModel? routineStatus; - - RoutineResponseModel({ - required this.statusCode, - required this.id, - required this.routineName, - required this.exerciseInfoResponseList, - required this.dayOfWeeks, - required this.routineStatus, - }); - - factory RoutineResponseModel.fromJson( - Map json, int statusCode) { - return RoutineResponseModel( - statusCode: AsyncData(statusCode), - id: json['id'], - routineName: json['routine_name'], - exerciseInfoResponseList: - (json['exercise_info_response_list'] as List) - .map((exerciseInfoResponseJson) => ExerciseInfoResponseModel.fromJson(exerciseInfoResponseJson, statusCode)) - .toList(), - dayOfWeeks: List.from(json['day_of_weeks']), - routineStatus: RoutineStatusModel.fromJson(json['routine_status']), - ); - } -} diff --git a/lib/self_care/domain/model/my_routine/routine_status_model.dart b/lib/self_care/domain/model/my_routine/routine_status_model.dart deleted file mode 100644 index e704bd28..00000000 --- a/lib/self_care/domain/model/my_routine/routine_status_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class RoutineStatusModel { - final bool? isArchived; - final bool? isShared; - - RoutineStatusModel({ - required this.isArchived, - required this.isShared, - }); - - factory RoutineStatusModel.fromJson(Map json) { - return RoutineStatusModel( - isArchived: json['is_archived'], - isShared: json['is_shared'], - ); - } -} diff --git a/lib/self_care/domain/repository/profile_repository.dart b/lib/self_care/domain/repository/profile_repository.dart index 96fb934b..2a30f5f4 100644 --- a/lib/self_care/domain/repository/profile_repository.dart +++ b/lib/self_care/domain/repository/profile_repository.dart @@ -4,7 +4,6 @@ import 'package:maeum_ga_gym_flutter/self_care/domain/model/profile/profile_resp abstract class ProfileRepository { Future getUserProfile({ required String accessToken, - required String nickname, }); Future> editUserProfile({ diff --git a/lib/self_care/domain/usecase/profile_usecase.dart b/lib/self_care/domain/usecase/profile_usecase.dart index 350bdd85..c5781fc0 100644 --- a/lib/self_care/domain/usecase/profile_usecase.dart +++ b/lib/self_care/domain/usecase/profile_usecase.dart @@ -9,11 +9,9 @@ class ProfileUseCase { Future getUserProfile({ required String accessToken, - required String nickname, }) async { return await _repository.getUserProfile( accessToken: accessToken, - nickname: nickname, ); } diff --git a/lib/self_care/presentation/provider/profile/self_care_profile_get_profile_provider.dart b/lib/self_care/presentation/provider/profile/self_care_profile_get_profile_provider.dart index c458eeb6..d171964b 100644 --- a/lib/self_care/presentation/provider/profile/self_care_profile_get_profile_provider.dart +++ b/lib/self_care/presentation/provider/profile/self_care_profile_get_profile_provider.dart @@ -26,23 +26,11 @@ class SelfCareUserGetProfileStateNotifier String? accessToken; - Future getUserProfile({ - required String nickname, - }) async { + Future getUserProfile() async { try { state = state.copyWith(statusCode: const AsyncLoading()); accessToken = await TokenSecureStorageDi.readLoginAccessToken(); - final response = await _userUseCase.getUserProfile( - accessToken: accessToken!, - nickname: nickname, - ); - state = state.copyWith( - statusCode: response.statusCode, - nickname: response.nickname, - profileImage: response.profileImage, - level: response.level, - totalWakatime: response.totalWakatime, - ); + state = await _userUseCase.getUserProfile(accessToken: accessToken!); } catch (err) { throw Exception(err.toString()); } diff --git a/lib/self_care/presentation/view/my_routine/self_care_my_routine_detail_screen.dart b/lib/self_care/presentation/view/my_routine/self_care_my_routine_detail_screen.dart index 52250725..d3f22dc6 100644 --- a/lib/self_care/presentation/view/my_routine/self_care_my_routine_detail_screen.dart +++ b/lib/self_care/presentation/view/my_routine/self_care_my_routine_detail_screen.dart @@ -4,10 +4,9 @@ import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; import 'package:maeum_ga_gym_flutter/core/component/maeumgagym_toast_message.dart'; -import 'package:maeum_ga_gym_flutter/home/presentation/providers/home_today_routines_provider.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/provider/routine_my_routine_my_routine_provider.dart'; +import 'package:maeum_ga_gym_flutter/routine_start/presentation/view/routine_start_main_screen.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/provider/my_routine/self_care_my_routine_delete_routine_provider.dart'; -import 'package:maeum_ga_gym_flutter/self_care/presentation/view/my_routine/self_care_my_routine_edit_screen.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/my_routine/self_care_my_routine_button.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/my_routine/self_care_my_routine_detail_dialog.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/my_routine/self_care_my_routine_detail_routine_item_widget.dart'; @@ -41,9 +40,8 @@ class _SelfCareMyRoutineDetailScreenState Widget build(BuildContext context) { final myRoutineState = ref.watch(routineMyRoutinesProvider); final myRoutineNotifier = ref.read(routineMyRoutinesProvider.notifier); - final deleteRoutineNotifier = - ref.read(selfCareMyRoutineDeleteRoutineProvider.notifier); final item = myRoutineState.routineList[widget.listIndex]; + ref.listen(selfCareMyRoutineDeleteRoutineProvider.select((value) => value), (previous, next) { if (next == const AsyncData(204)) { @@ -112,57 +110,34 @@ class _SelfCareMyRoutineDetailScreenState child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - child: GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () async { - await deleteRoutineNotifier.deleteRoutine( - routineId: item.id!); - await ref - .read(homeTodayRoutineController.notifier) - .getTodayRoutines(); - }, - child: SelfCareMyRoutineButton( - width: MediaQuery.of(context).size.width, - height: 58, - title: "루틴 삭제", - imageWidth: 24, - imageHeight: 24, - imagePath: Images.editTrash, - buttonColor: MaeumgagymColor.gray50, - textColor: MaeumgagymColor.gray800, - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: GestureDetector( - onTap: () => Navigator.push( + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () async { + Navigator.push( context, MaterialPageRoute( - builder: (context) { - return SelfCareMyRoutineEditScreen( - listIndex: widget.listIndex, - routineName: item.routineName.toString(), - ); - }, + builder: (context) => RoutineStartMainScreen( + routineId: item.id, + routineList: item.exerciseInfoResponseList, + ), ), - ), - child: SelfCareMyRoutineButton( - width: MediaQuery.of(context).size.width, - height: 58, - title: "루틴 수정", - imageWidth: 24, - imageHeight: 24, - imagePath: Images.editPencil, - imageColor: MaeumgagymColor.white, - buttonColor: MaeumgagymColor.blue500, - textColor: MaeumgagymColor.white, - ), + ); + }, + child: SelfCareMyRoutineButton( + width: MediaQuery.of(context).size.width - 92, + height: 58, + title: "루틴 시작하기", + imageWidth: 24, + imageHeight: 24, + imagePath: Images.mediaPlayFilled, + imageColor: MaeumgagymColor.white, + buttonColor: MaeumgagymColor.blue500, + textColor: MaeumgagymColor.white, ), ), - const SizedBox(width: 20), + // const SizedBox(width: 20), GestureDetector( onTap: () { showDialog( diff --git a/lib/self_care/presentation/view/my_routine/self_care_my_routine_edit_screen.dart b/lib/self_care/presentation/view/my_routine/self_care_my_routine_edit_screen.dart index aadcc571..f087f3c6 100644 --- a/lib/self_care/presentation/view/my_routine/self_care_my_routine_edit_screen.dart +++ b/lib/self_care/presentation/view/my_routine/self_care_my_routine_edit_screen.dart @@ -54,16 +54,16 @@ class _SelfCareMyRoutineEditScreenState item.exerciseInfoResponseList.length, (index) => ExerciseInfoEditRoutinePoseModel( poseModel: PoseDataModel( - id: item.exerciseInfoResponseList[index].pose!.id, + id: item.exerciseInfoResponseList[index].pose.id, thumbnail: - item.exerciseInfoResponseList[index].pose!.thumbnail, - name: item.exerciseInfoResponseList[index].pose!.name, + item.exerciseInfoResponseList[index].pose.thumbnail, + name: item.exerciseInfoResponseList[index].pose.name, needMachine: - item.exerciseInfoResponseList[index].pose!.needMachine, + item.exerciseInfoResponseList[index].pose.needMachine, simplePart: - item.exerciseInfoResponseList[index].pose!.simplePart, + item.exerciseInfoResponseList[index].pose.simplePart, exactPart: - item.exerciseInfoResponseList[index].pose!.exactPart, + item.exerciseInfoResponseList[index].pose.exactPart, ), repetitionsController: TextEditingController( text: item.exerciseInfoResponseList[index].repetitions @@ -205,8 +205,8 @@ class _SelfCareMyRoutineEditScreenState onTap: () async { await editPoseListNotifier.editRoutine( routineName: titleController.text, - isArchived: item.routineStatus!.isArchived!, - isShared: item.routineStatus!.isShared!, + isArchived: item.routineStatus.isArchived, + isShared: item.routineStatus.isShared, exerciseInfoRequestList: List.generate( editPoseListState.length, @@ -230,7 +230,7 @@ class _SelfCareMyRoutineEditScreenState .where((entry) => entry.value) .map((entry) => entry.key) .toList(), - routineId: item.id!, + routineId: item.id, ); await ref diff --git a/lib/self_care/presentation/view/my_routine/self_care_my_routine_empty_screen.dart b/lib/self_care/presentation/view/my_routine/self_care_my_routine_empty_screen.dart new file mode 100644 index 00000000..0a2a8928 --- /dev/null +++ b/lib/self_care/presentation/view/my_routine/self_care_my_routine_empty_screen.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; +import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; +import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/widget/routine_default_title_widget.dart'; + +class SelfCareMyRoutineEmptyScreen extends StatelessWidget { + const SelfCareMyRoutineEmptyScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const RoutineDefaultTitleContainer( + title: "내 루틴", + subTitle: "나만의 루틴을 구성하여\n규칙적인 운동을 해보세요.", + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Container( + width: 120, + height: 120, + decoration: BoxDecoration( + color: MaeumgagymColor.gray50, + borderRadius: BorderRadius.circular(24), + ), + child: const ImageWidget( + image: Images.iconsNotDesignSysRoutineIcon, + imageWidth: 75, + ), + ), + ), + const SizedBox(height: 24), + PtdTextWidget.titleMedium("아직 루틴이 없어요", MaeumgagymColor.gray600), + const SizedBox(height: 12), + PtdTextWidget.bodyMedium("루틴을 추가하여 규칙적으로 운동해 보세요.", MaeumgagymColor.gray500), + ], + ), + const SizedBox(height: 96), + ], + ), + ); + } +} diff --git a/lib/self_care/presentation/view/my_routine/self_care_my_routine_main_screen.dart b/lib/self_care/presentation/view/my_routine/self_care_my_routine_main_screen.dart index 73460b09..24212a90 100644 --- a/lib/self_care/presentation/view/my_routine/self_care_my_routine_main_screen.dart +++ b/lib/self_care/presentation/view/my_routine/self_care_my_routine_main_screen.dart @@ -5,6 +5,7 @@ import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/provider/routine_my_routine_my_routine_provider.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/view/my_routine/self_care_my_routine_add_screen.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/view/my_routine/self_care_my_routine_detail_screen.dart'; +import 'package:maeum_ga_gym_flutter/self_care/presentation/view/my_routine/self_care_my_routine_empty_screen.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/my_routine/self_care_my_routine_button.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/my_routine/self_care_my_routine_item_widget.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/self_care_default_app_bar.dart'; @@ -68,51 +69,58 @@ class _SelfCareMyRoutineMainScreenState iconPath: Images.arrowLeft, ), body: SafeArea( - child: SingleChildScrollView( - controller: scrollController, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const RoutineDefaultTitleContainer( - title: "내 루틴", - subTitle: "나만의 루틴을 구성하여\n규칙적인 운동을 해보세요.", - ), - const SizedBox(height: 32), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), + child: Builder( + builder: (context) { + if (myRoutineState.routineList.isEmpty) { + return const SelfCareMyRoutineEmptyScreen(); + } + return SingleChildScrollView( + controller: scrollController, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const RoutineDefaultTitleContainer( + title: "내 루틴", + subTitle: "나만의 루틴을 구성하여\n규칙적인 운동을 해보세요.", + ), + const SizedBox(height: 32), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), - /// Notifier에 입력된 Model 개수만큼 - itemCount: myRoutineState.routineList.length, - itemBuilder: (context, index) { - /// 공통된 변수 - return Padding( - padding: EdgeInsets.only( - bottom: index == myRoutineState.routineList.length - 1 - ? 0 - : 12), - child: GestureDetector( - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SelfCareMyRoutineDetailScreen( + /// Notifier에 입력된 Model 개수만큼 + itemCount: myRoutineState.routineList.length, + itemBuilder: (context, index) { + /// 공통된 변수 + return Padding( + padding: EdgeInsets.only( + bottom: index == myRoutineState.routineList.length - 1 + ? 0 + : 12), + child: GestureDetector( + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SelfCareMyRoutineDetailScreen( + listIndex: index, + ), + ), + ), + child: SelfCareMyRoutineItemWidget( listIndex: index, ), ), - ), - child: SelfCareMyRoutineItemWidget( - listIndex: index, - ), - ), - ); - }, + ); + }, + ), + const SizedBox(height: 98), + ], ), - const SizedBox(height: 98), - ], - ), - ), + ), + ); + } ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, diff --git a/lib/self_care/presentation/view/profile/self_care_profile_main_screen.dart b/lib/self_care/presentation/view/profile/self_care_profile_main_screen.dart index 1c35a276..bb1e5857 100644 --- a/lib/self_care/presentation/view/profile/self_care_profile_main_screen.dart +++ b/lib/self_care/presentation/view/profile/self_care_profile_main_screen.dart @@ -4,19 +4,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; -import 'package:maeum_ga_gym_flutter/self_care/presentation/provider/profile/self_care_profile_get_profile_provider.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/profile/self_care_profile_main_info_widget.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/profile/self_care_profile_main_setting_widget.dart'; - import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/self_care_default_app_bar.dart'; -class SelfCareProfileMainScreen extends ConsumerStatefulWidget { - final String nickname; +import '../../provider/profile/self_care_profile_get_profile_provider.dart'; - const SelfCareProfileMainScreen({ - Key? key, - required this.nickname, - }) : super(key: key); +class SelfCareProfileMainScreen extends ConsumerStatefulWidget { + const SelfCareProfileMainScreen({super.key}); @override ConsumerState createState() => @@ -28,76 +23,65 @@ class _SelfCareProfileMainScreenState @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - ref + WidgetsBinding.instance.addPostFrameCallback((_) async { + await ref .read(selfCareProfileGetProfileProvider.notifier) - .getUserProfile(nickname: widget.nickname); + .getUserProfile(); }); } @override Widget build(BuildContext context) { final profileState = ref.watch(selfCareProfileGetProfileProvider); + return Scaffold( backgroundColor: MaeumgagymColor.white, appBar: const SelfCareDefaultAppBar( iconPath: Images.arrowLeft, ), - body: SafeArea( - child: Center( - child: FittedBox( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: profileState.statusCode.when( - data: (data) { - if (data == 200) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 120, - height: 120, - child: CircleAvatar( - backgroundImage: NetworkImage( - profileState.profileImage.toString(), - ), + body: Builder(builder: (context) { + if (ref.watch(selfCareProfileGetProfileProvider).statusCode.isLoading) { + return Center( + child: CircularProgressIndicator( + color: MaeumgagymColor.blue500, + ), + ); + } else { + return SafeArea( + child: Center( + child: FittedBox( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + height: 120, + child: CircleAvatar( + backgroundImage: NetworkImage( + profileState.profileImage.toString(), ), ), - const SizedBox(height: 16), - PtdTextWidget.titleMedium( - profileState.nickname.toString(), - - /// 그럴일은 없겠지만 만약 진짜 만약 값이 null 이라면 null 그대로 출력하도록 구현 - MaeumgagymColor.black, - ), - const SizedBox(height: 32), - const SelfCareProfileMainInfoWidget(), - const SizedBox(height: 32), - const SelfCareProfileMainSettingWidget(), - const SizedBox(height: 31), - ], - ); - } else { - return Text( - "${profileState.statusCode}", - ); - } - }, - error: (error, stack) { - return const Text("에러"); - }, - loading: () { - return Center( - child: CircularProgressIndicator( - color: MaeumgagymColor.blue500, - ), - ); - }, + ), + const SizedBox(height: 16), + PtdTextWidget.titleMedium( + profileState.nickname.toString(), + MaeumgagymColor.black, + ), + const SizedBox(height: 32), + SelfCareProfileMainInfoWidget(totalWakaTime: profileState.totalWakatime!), + const SizedBox(height: 32), + const SelfCareProfileMainSettingWidget(), + const SizedBox(height: 31), + ], + ), + ), ), ), - ), - ), - ), + ); + } + }), ); } } diff --git a/lib/self_care/presentation/view/purpose/self_care_purpose_empty_screen.dart b/lib/self_care/presentation/view/purpose/self_care_purpose_empty_screen.dart new file mode 100644 index 00000000..ef3c029b --- /dev/null +++ b/lib/self_care/presentation/view/purpose/self_care_purpose_empty_screen.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; +import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; + +import '../../../../core/component/routine/presentation/widget/routine_default_title_widget.dart'; + +class SelfCarePurposeEmptyScreen extends StatelessWidget { + const SelfCarePurposeEmptyScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const RoutineDefaultTitleContainer( + title: "목표", + subTitle: "나만의 목표를 세워보세요.", + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Container( + width: 120, + height: 120, + decoration: BoxDecoration( + color: MaeumgagymColor.gray50, + borderRadius: BorderRadius.circular(24), + ), + child: const ImageWidget( + image: Images.iconsNotDesignSysTargetIcon, + imageWidth: 96, + ), + ), + ), + const SizedBox(height: 24), + PtdTextWidget.titleMedium("아직 목표가 없어요", MaeumgagymColor.gray600), + const SizedBox(height: 12), + PtdTextWidget.bodyMedium("목표를 추가하고 목표를 향해 달려보세요.", MaeumgagymColor.gray500), + ], + ), + const SizedBox(height: 96), + ], + ), + ); + } +} diff --git a/lib/self_care/presentation/view/purpose/self_care_purpose_main_screen.dart b/lib/self_care/presentation/view/purpose/self_care_purpose_main_screen.dart index d2607125..bac03557 100644 --- a/lib/self_care/presentation/view/purpose/self_care_purpose_main_screen.dart +++ b/lib/self_care/presentation/view/purpose/self_care_purpose_main_screen.dart @@ -5,6 +5,7 @@ import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/provider/purpose/self_care_purpose_my_purposes_provider.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/view/purpose/self_care_purpose_add_screen.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/view/purpose/self_care_purpose_detail_screen.dart'; +import 'package:maeum_ga_gym_flutter/self_care/presentation/view/purpose/self_care_purpose_empty_screen.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/my_routine/self_care_my_routine_button.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/purpose/self_care_purpose_item_widget.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/self_care_default_app_bar.dart'; @@ -75,56 +76,63 @@ class _SelfCarePurposeMainScreenState iconPath: Images.arrowLeft, ), body: SafeArea( - child: SingleChildScrollView( - controller: scrollController, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const RoutineDefaultTitleContainer( - title: "목표", - subTitle: "나만의 목표를 세워보세요.", - ), - const SizedBox(height: 32), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: myPurposeState.purposeList.length, // 임의로 넣은 아이템 갯수 - itemBuilder: (context, index) { - return Column( - children: [ - GestureDetector( - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => SelfCarePurposeDetailScreen( - purposeId: - myPurposeState.purposeList[index].id!), + child: Builder(builder: (context) { + if (myPurposeState.purposeList.isEmpty) { + return const SelfCarePurposeEmptyScreen(); + } + return SingleChildScrollView( + controller: scrollController, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const RoutineDefaultTitleContainer( + title: "목표", + subTitle: "나만의 목표를 세워보세요.", + ), + const SizedBox(height: 32), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: myPurposeState.purposeList.length, + // 임의로 넣은 아이템 갯수 + itemBuilder: (context, index) { + return Column( + children: [ + GestureDetector( + onTap: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + SelfCarePurposeDetailScreen( + purposeId: myPurposeState + .purposeList[index].id!), + ), + ), + child: SelfCarePurposeItemWidget( + purposeId: myPurposeState.purposeList[index].id!, + title: myPurposeState.purposeList[index].title + .toString(), + subTitle: myPurposeState + .purposeList[index].startDate + .toString(), ), ), - child: SelfCarePurposeItemWidget( - purposeId: myPurposeState.purposeList[index].id!, - title: myPurposeState.purposeList[index].title - .toString(), - subTitle: myPurposeState - .purposeList[index].startDate - .toString(), - ), - ), - SizedBox( - height: - index == myPurposeState.purposeList.length - 1 - ? 0 - : 12), - ], - ); - }, - ), - const SizedBox(height: 98), - ], + SizedBox( + height: + index == myPurposeState.purposeList.length - 1 + ? 0 + : 12), + ], + ); + }, + ), + const SizedBox(height: 98), + ], + ), ), - ), - ), + ); + }), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButton: GestureDetector( diff --git a/lib/self_care/presentation/view/self_care_main_screen.dart b/lib/self_care/presentation/view/self_care_main_screen.dart index 248979e1..41466efd 100644 --- a/lib/self_care/presentation/view/self_care_main_screen.dart +++ b/lib/self_care/presentation/view/self_care_main_screen.dart @@ -1,15 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; - import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; - -import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/main/dividing_line_widget.dart'; +import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/widget/routine_default_title_widget.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/calendar/self_care_timeline_widget.dart'; +import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/main/dividing_line_widget.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/main/self_care_main_profile_widget.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/widget/main/self_care_main_widget_list.dart'; -import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/widget/routine_default_title_widget.dart'; class SelfCareMainScreen extends ConsumerStatefulWidget { const SelfCareMainScreen({Key? key}) : super(key: key); @@ -29,8 +27,7 @@ class _SelfCareMainScreenState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 40), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 40), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/self_care/presentation/widget/main/self_care_item_widget.dart b/lib/self_care/presentation/widget/main/self_care_item_widget.dart index 38b5d027..105c778e 100644 --- a/lib/self_care/presentation/widget/main/self_care_item_widget.dart +++ b/lib/self_care/presentation/widget/main/self_care_item_widget.dart @@ -10,6 +10,7 @@ class SelfCareItemWidget extends StatelessWidget { final double width, height; + final Widget routePage; const SelfCareItemWidget({ Key? key, @@ -17,45 +18,54 @@ class SelfCareItemWidget extends StatelessWidget { required this.height, required this.imagePath, required this.title, + required this.routePage, }) : super(key: key); @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - height: 40, - width: 40, - alignment: Alignment.center, - // 이것도 align 지정안하면 크기 변경 안돼요 - decoration: BoxDecoration( - color: MaeumgagymColor.gray200, - borderRadius: BorderRadius.circular(8), + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => routePage, + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Container( + height: 40, + width: 40, + alignment: Alignment.center, + // 이것도 align 지정안하면 크기 변경 안돼요 + decoration: BoxDecoration( + color: MaeumgagymColor.gray200, + borderRadius: BorderRadius.circular(8), + ), + child: ImageWidget( + imageWidth: width, + imageHeight: height, + image: imagePath, + ), ), - child: ImageWidget( - imageWidth: width, - imageHeight: height, - image: imagePath, + const SizedBox(width: 16), + PtdTextWidget.bodyLarge( + title, + MaeumgagymColor.black, ), - ), - const SizedBox(width: 16), - PtdTextWidget.bodyLarge( - title, - MaeumgagymColor.black, - ), - ], - ), - ImageWidget( - width: 24, - image: Images.chevronRight, - color: MaeumgagymColor.gray200, - ), - ], + ], + ), + ImageWidget( + width: 24, + image: Images.chevronRight, + color: MaeumgagymColor.gray200, + ), + ], + ), ), ); } diff --git a/lib/self_care/presentation/widget/main/self_care_main_profile_widget.dart b/lib/self_care/presentation/widget/main/self_care_main_profile_widget.dart index 9c49e20e..97c9590c 100644 --- a/lib/self_care/presentation/widget/main/self_care_main_profile_widget.dart +++ b/lib/self_care/presentation/widget/main/self_care_main_profile_widget.dart @@ -4,10 +4,10 @@ import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; -import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/provider/routine_my_routine_my_routine_provider.dart'; -import 'package:maeum_ga_gym_flutter/self_care/presentation/provider/waka/self_care_waka_total_waka_provider.dart'; import 'package:maeum_ga_gym_flutter/self_care/presentation/view/profile/self_care_profile_main_screen.dart'; +import '../../provider/profile/self_care_profile_get_profile_provider.dart'; + class SelfCareMainProfileWidget extends ConsumerStatefulWidget { const SelfCareMainProfileWidget({Key? key}) : super(key: key); @@ -18,94 +18,64 @@ class SelfCareMainProfileWidget extends ConsumerStatefulWidget { class _SelfCareMainProfileContainerState extends ConsumerState { - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - ref.read(routineMyRoutinesProvider.notifier).getMyRoutineInit(); - ref.read(selfCareWakaTotalWakaProvider.notifier).totalWaka(); - }); - } - @override Widget build(BuildContext context) { - final routineAllMeState = ref.watch(routineMyRoutinesProvider); - final totalWakaState = ref.watch(selfCareWakaTotalWakaProvider); + final profileState = ref.watch(selfCareProfileGetProfileProvider); return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => Navigator.push( context, MaterialPageRoute( - builder: (context) => SelfCareProfileMainScreen( - nickname: routineAllMeState.userInfo!.nickname.toString()), + builder: (context) => const SelfCareProfileMainScreen(), ), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), - child: routineAllMeState.statusCode.when( - data: (data) { - if (data == 200) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(100), - child: Image.network( - routineAllMeState.userInfo!.profileImage.toString(), - width: 48, - height: 48, - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - PtdTextWidget.labelLarge( - routineAllMeState.userInfo!.nickname.toString(), - MaeumgagymColor.black, - ), - const SizedBox(width: 8), - const ImageWidget( - width: 18, - image: Images.iconsNotDesignSysProfileIcon, - ), - ], - ), - const SizedBox(height: 2), - PtdTextWidget.bodyMedium( - "${totalWakaState.totalSeconds}시간", - MaeumgagymColor.gray400, - ), - ], - ), - ], - ), - ImageWidget( - width: 24, - image: Images.chevronRight, - color: MaeumgagymColor.gray200, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(100), + child: Image.network( + profileState.profileImage.toString(), + width: 48, + height: 48, ), - ], - ); - } else { - return Text( - "${routineAllMeState.statusCode}", - ); - } - }, - error: (error, stack) { - return Text(routineAllMeState.statusCode.toString()); - }, - loading: () { - return Center( - child: CircularProgressIndicator( - color: MaeumgagymColor.blue500, - )); - }, + ), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + PtdTextWidget.labelLarge( + profileState.nickname.toString(), + MaeumgagymColor.black, + ), + const SizedBox(width: 8), + const ImageWidget( + width: 18, + image: Images.iconsNotDesignSysProfileIcon, + ), + ], + ), + const SizedBox(height: 2), + PtdTextWidget.bodyMedium( + "${profileState.totalWakatime}시간", + MaeumgagymColor.gray400, + ), + ], + ), + ], + ), + ImageWidget( + width: 24, + image: Images.chevronRight, + color: MaeumgagymColor.gray200, + ), + ], ), ), ); diff --git a/lib/self_care/presentation/widget/main/self_care_main_widget_list.dart b/lib/self_care/presentation/widget/main/self_care_main_widget_list.dart index 36b136ea..765df80c 100644 --- a/lib/self_care/presentation/widget/main/self_care_main_widget_list.dart +++ b/lib/self_care/presentation/widget/main/self_care_main_widget_list.dart @@ -25,61 +25,33 @@ class SelfCareMainWidgetList extends StatelessWidget { ), ), const SizedBox(height: 12), - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const SelfCareMyRoutineMainScreen(), - ), - ), - child: const SelfCareItemWidget( - width: 25, - height: 28, - imagePath: Images.iconsNotDesignSysRoutineIcon, - title: "내 루틴", - ), + const SelfCareItemWidget( + width: 25, + height: 28, + imagePath: Images.iconsNotDesignSysRoutineIcon, + title: "내 루틴", + routePage: SelfCareMyRoutineMainScreen(), ), - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const SelfCarePurposeMainScreen(), - ), - ), - child: const SelfCareItemWidget( - width: 32, - height: 32, - imagePath: Images.iconsNotDesignSysTargetIcon, - title: "목표", - ), + const SelfCareItemWidget( + width: 25, + height: 28, + imagePath: Images.iconsNotDesignSysTargetIcon, + title: "목표", + routePage: SelfCarePurposeMainScreen(), ), - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const EmptyViewScreen(), - ), - ), - child: const SelfCareItemWidget( - width: 16, - height: 26, - imagePath: Images.iconsNotDesignSysDietIcon, - title: "식단", - ), + const SelfCareItemWidget( + width: 25, + height: 28, + imagePath: Images.iconsNotDesignSysDietIcon, + title: "식단", + routePage: EmptyViewScreen(), ), - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const EmptyViewScreen(), - ), - ), - child: const SelfCareItemWidget( - width: 24, - height: 24, - imagePath: Images.iconsNotDesignSysTodayExcersizeCompleteIcon, - title: "오운완", - ), + const SelfCareItemWidget( + width: 25, + height: 28, + imagePath: Images.iconsNotDesignSysTodayExcersizeCompleteIcon, + title: "오운완", + routePage: EmptyViewScreen(), ), ], ), diff --git a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_dialog.dart b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_dialog.dart index 5e260d71..8c98ec31 100644 --- a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_dialog.dart +++ b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_dialog.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; @@ -9,8 +8,12 @@ import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_wid import 'package:maeum_ga_gym_flutter/self_care/domain/model/my_routine/exercise_info_request_model.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/provider/routine_my_routine_my_routine_provider.dart'; import 'package:maeum_ga_gym_flutter/core/component/routine/presentation/provider/routine_my_routine_edit_routine_provider.dart'; +import 'package:maeum_ga_gym_flutter/self_care/presentation/provider/my_routine/self_care_my_routine_delete_routine_provider.dart'; import 'package:top_snackbar_flutter/top_snack_bar.dart'; +import '../../../../home/presentation/providers/home_today_routines_provider.dart'; +import '../../view/my_routine/self_care_my_routine_edit_screen.dart'; + class SelfCareMyRoutineDetailDialog extends ConsumerStatefulWidget { final int listIndex; @@ -33,37 +36,33 @@ class _SelfCareMyRoutineDetailDialogState ); } - Future _updateState({ - bool? changeArchived, - bool? changeShared, - }) async { - final myRoutineState = ref.watch(routineMyRoutinesProvider); - final editRoutineNotifier = - ref.read(routineMyRoutineEditRoutineProvider.notifier); - final item = myRoutineState.routineList[widget.listIndex]; - - await editRoutineNotifier.editRoutine( - routineName: item.routineName.toString(), - isArchived: changeArchived ?? item.routineStatus!.isArchived!, - isShared: changeShared ?? item.routineStatus!.isShared!, - exerciseInfoRequestList: List.filled( - item.exerciseInfoResponseList.length, - ExerciseInfoRequestModel( - repetitions: - item.exerciseInfoResponseList[widget.listIndex].repetitions, - sets: item.exerciseInfoResponseList[widget.listIndex].sets, - id: item.exerciseInfoResponseList[widget.listIndex].pose!.id, - ), - ), - routineId: item.id!, - dayOfWeeks: item.dayOfWeeks, - ); - } - @override Widget build(BuildContext context) { + Future updateState({ + bool? changeArchived, + bool? changeShared, + }) async { + final myRoutineState = ref.watch(routineMyRoutinesProvider); + final editRoutineNotifier = ref.read(routineMyRoutineEditRoutineProvider.notifier); + final item = myRoutineState.routineList[widget.listIndex]; + + List exerciseListModel = + item.exerciseInfoResponseList.map((e) => ExerciseInfoRequestModel(id: e.pose.id, repetitions: e.repetitions, sets: e.sets)).toList(); + + await editRoutineNotifier.editRoutine( + routineName: item.routineName.toString(), + isArchived: changeArchived ?? item.routineStatus.isArchived, + isShared: changeShared ?? item.routineStatus.isShared, + exerciseInfoRequestList: exerciseListModel, + routineId: item.id, + dayOfWeeks: item.dayOfWeeks, + ); + } + + final deleteRoutineNotifier = ref.read(selfCareMyRoutineDeleteRoutineProvider.notifier); final myRoutineState = ref.watch(routineMyRoutinesProvider); final item = myRoutineState.routineList[widget.listIndex]; + ref.listen(routineMyRoutineEditRoutineProvider.select((value) => value), (previous, next) { if (next == const AsyncData(200)) { @@ -92,11 +91,45 @@ class _SelfCareMyRoutineDetailDialogState GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { - if (item.routineStatus!.isShared == true) { - _updateState(changeShared: false); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return SelfCareMyRoutineEditScreen( + listIndex: widget.listIndex, + routineName: item.routineName.toString(), + ); + }, + ), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Row( + children: [ + ImageWidget( + image: Images.editPencil, + color: MaeumgagymColor.black, + imageHeight: 24, + imageWidth: 24, + ), + const SizedBox(width: 12), + PtdTextWidget.bodyLarge( + "수정", + MaeumgagymColor.black, + ), + ], + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + if (item.routineStatus.isShared) { + updateState(changeShared: false); _showToast(message: "루틴 공유를 취소했어요."); } else { - _updateState(changeShared: true); + updateState(changeShared: true); _showToast(message: "루틴을 공유했어요."); } }, @@ -112,7 +145,7 @@ class _SelfCareMyRoutineDetailDialogState ), const SizedBox(width: 12), PtdTextWidget.bodyLarge( - item.routineStatus!.isShared! ? "공유 취소" : "공유", + item.routineStatus.isShared ? "공유 취소" : "공유", MaeumgagymColor.black, ), ], @@ -122,11 +155,11 @@ class _SelfCareMyRoutineDetailDialogState GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { - if (item.routineStatus!.isArchived == true) { - _updateState(changeArchived: false); + if (item.routineStatus.isArchived) { + updateState(changeArchived: false); _showToast(message: "루틴 보관을 취소했어요."); } else { - _updateState(changeArchived: true); + updateState(changeArchived: true); _showToast(message: "루틴을 보관했어요."); } }, @@ -142,7 +175,36 @@ class _SelfCareMyRoutineDetailDialogState ), const SizedBox(width: 12), PtdTextWidget.bodyLarge( - !item.routineStatus!.isArchived! ? "보관 취소" : "보관", + !item.routineStatus.isArchived ? "보관" : "보관 취소", + MaeumgagymColor.black, + ), + ], + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () async { + Navigator.pop(context); + + await deleteRoutineNotifier.deleteRoutine(routineId: item.id); + await ref + .read(homeTodayRoutineController.notifier) + .getTodayRoutines(); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Row( + children: [ + ImageWidget( + image: Images.editTrash, + color: MaeumgagymColor.black, + imageHeight: 24, + imageWidth: 24, + ), + const SizedBox(width: 12), + PtdTextWidget.bodyLarge( + "삭제", MaeumgagymColor.black, ), ], diff --git a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_routine_item_widget.dart b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_routine_item_widget.dart index 5e494d9b..6d6d69a3 100644 --- a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_routine_item_widget.dart +++ b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_routine_item_widget.dart @@ -2,7 +2,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:maeum_ga_gym_flutter/config/maeumgagym_color.dart'; import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; @@ -34,7 +33,7 @@ class SelfCareMyRoutineDetailRoutineItemWidget extends ConsumerWidget { width: 80, height: 80, imageType: ImageType.pngNetwork, - image: item.pose!.thumbnail.toString(), + image: item.pose.thumbnail.toString(), backgroundColor: MaeumgagymColor.gray25, ), ), @@ -43,7 +42,7 @@ class SelfCareMyRoutineDetailRoutineItemWidget extends ConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ PtdTextWidget.bodyLarge( - item.pose!.name.toString(), + item.pose.name.toString(), MaeumgagymColor.black, ), const SizedBox(height: 2), diff --git a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_title_widget.dart b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_title_widget.dart index 1bb72cee..10cc32a2 100644 --- a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_title_widget.dart +++ b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_detail_title_widget.dart @@ -32,17 +32,30 @@ class SelfCareMyRoutineDetailTitleWidget extends ConsumerWidget { MaeumgagymColor.black, ), const SizedBox(height: 12), - if (!item.routineStatus!.isArchived!) - PtdTextWidget.bodyMedium( - item.dayOfWeeks.isEmpty - ? "사용중" - : "사용중 | ${item.dayOfWeeks.map((str) => str[0]).join(", ")}", - MaeumgagymColor.blue500, - ) + Builder( + builder: (context) { + if (!item.routineStatus.isArchived){ + return PtdTextWidget.bodyMedium( + item.dayOfWeeks.isEmpty + ? "사용중" + : "사용중 | ${item.dayOfWeeks.map((str) => str[0]).join(", ")}", + MaeumgagymColor.blue500, + ); + } else { + return PtdTextWidget.bodyMedium( + item.dayOfWeeks.isEmpty + ? "보관중" + : "보관중 | ${item.dayOfWeeks.map((str) => str[0]).join(", ")}", + MaeumgagymColor.gray400, + ); + } + }, + ) + ], ), ), - if (item.routineStatus!.isShared!) + if (item.routineStatus.isShared) RoutineMyRoutineSharedWidget(color: MaeumgagymColor.blue50), ], ); diff --git a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_item_widget.dart b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_item_widget.dart index 37a8a852..66cce6ea 100644 --- a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_item_widget.dart +++ b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_item_widget.dart @@ -48,11 +48,11 @@ class _SelfCareGoalRoutineItemWidgetState ), const SizedBox(height: 4), PtdTextWidget.bodySmall( - (item.routineStatus!.isArchived! ? "보관중" : "사용중") + + (item.routineStatus.isArchived ? "보관중" : "사용중") + (item.dayOfWeeks.isNotEmpty ? " | ${item.dayOfWeeks.map((str) => str[0]).join(", ")}" : ""), - item.routineStatus!.isArchived! + item.routineStatus.isArchived ? MaeumgagymColor.gray400 : MaeumgagymColor.blue500, ), @@ -61,7 +61,7 @@ class _SelfCareGoalRoutineItemWidgetState ), Row( children: [ - item.routineStatus!.isShared! + item.routineStatus.isShared ? const RoutineMyRoutineSharedWidget() : const SizedBox(), const SizedBox(width: 12), diff --git a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_manage_bottom_sheet.dart b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_manage_bottom_sheet.dart index 30585d59..17ab95a8 100644 --- a/lib/self_care/presentation/widget/my_routine/self_care_my_routine_manage_bottom_sheet.dart +++ b/lib/self_care/presentation/widget/my_routine/self_care_my_routine_manage_bottom_sheet.dart @@ -40,25 +40,26 @@ class _SelfCareMyRoutineManageBottomSheetState bool? changeShared, }) async { final myRoutineState = ref.watch(routineMyRoutinesProvider); - final editRoutineNotifier = - ref.read(routineMyRoutineEditRoutineProvider.notifier); + final editRoutineNotifier = ref.read(routineMyRoutineEditRoutineProvider.notifier); final item = myRoutineState.routineList[widget.listIndex]; await editRoutineNotifier.editRoutine( routineName: item.routineName.toString(), - isArchived: changeArchived ?? item.routineStatus!.isArchived!, - isShared: changeShared ?? item.routineStatus!.isShared!, + isArchived: changeArchived ?? item.routineStatus.isArchived, + isShared: changeShared ?? item.routineStatus.isShared, exerciseInfoRequestList: List.generate( item.exerciseInfoResponseList.length, (index) => ExerciseInfoRequestModel( repetitions: item.exerciseInfoResponseList[index].repetitions, sets: item.exerciseInfoResponseList[index].sets, - id: item.exerciseInfoResponseList[index].pose!.id, + id: item.exerciseInfoResponseList[index].pose.id, ), ), - routineId: item.id!, + routineId: item.id, dayOfWeeks: item.dayOfWeeks, ); + + } @override @@ -66,15 +67,16 @@ class _SelfCareMyRoutineManageBottomSheetState final myRoutineState = ref.watch(routineMyRoutinesProvider); final myRoutineNotifier = ref.read(routineMyRoutinesProvider.notifier); final item = myRoutineState.routineList[widget.listIndex]; - final deleteRoutineNotifier = - ref.read(selfCareMyRoutineDeleteRoutineProvider.notifier); + final deleteRoutineNotifier = ref.read(selfCareMyRoutineDeleteRoutineProvider.notifier); final todayRoutineNotifier = ref.read(homeTodayRoutineController.notifier); + ref.listen(routineMyRoutineEditRoutineProvider.select((value) => value), (previous, next) { if (next == const AsyncData(200)) { myRoutineNotifier.getMyRoutineInit(); } }); + ref.listen(selfCareMyRoutineDeleteRoutineProvider.select((value) => value), (previous, next) { if (next == const AsyncData(204)) { @@ -82,6 +84,7 @@ class _SelfCareMyRoutineManageBottomSheetState myRoutineNotifier.getMyRoutineInit(); } }); + return Container( width: MediaQuery.of(context).size.width, decoration: BoxDecoration( @@ -127,8 +130,8 @@ class _SelfCareMyRoutineManageBottomSheetState ), GestureDetector( behavior: HitTestBehavior.translucent, - onTap: () async { - if (item.routineStatus!.isArchived == true) { + onTap: () { + if (item.routineStatus.isArchived == true) { _updateState(changeArchived: false); _showToast(message: "루틴 보관을 취소했어요."); } else { @@ -137,14 +140,14 @@ class _SelfCareMyRoutineManageBottomSheetState } }, child: SelfCareDefaultManageItemWidget( - title: item.routineStatus!.isArchived! ? "보관 취소" : "보관", + title: item.routineStatus.isArchived ? "보관 취소" : "보관", iconPath: Images.iconsInbox, ), ), GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { - if (item.routineStatus!.isShared == true) { + if (item.routineStatus.isShared == true) { _updateState(changeShared: false); _showToast(message: "루틴 공유를 취소했어요."); } else { @@ -153,7 +156,7 @@ class _SelfCareMyRoutineManageBottomSheetState } }, child: SelfCareDefaultManageItemWidget( - title: item.routineStatus!.isShared! ? "공유 취소" : "공유", + title: item.routineStatus.isShared ? "공유 취소" : "공유", iconPath: Images.iconsEarth, ), ), @@ -161,7 +164,7 @@ class _SelfCareMyRoutineManageBottomSheetState behavior: HitTestBehavior.translucent, onTap: () async { await deleteRoutineNotifier.deleteRoutine( - routineId: item.id!); + routineId: item.id); await todayRoutineNotifier.getTodayRoutines(); }, child: const SelfCareDefaultManageItemWidget( diff --git a/lib/self_care/presentation/widget/profile/self_care_profile_main_info_widget.dart b/lib/self_care/presentation/widget/profile/self_care_profile_main_info_widget.dart index 33f12deb..639c80be 100644 --- a/lib/self_care/presentation/widget/profile/self_care_profile_main_info_widget.dart +++ b/lib/self_care/presentation/widget/profile/self_care_profile_main_info_widget.dart @@ -5,14 +5,15 @@ import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; import 'package:maeum_ga_gym_flutter/core/component/maeungagym_text_style.dart'; import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; -import 'package:maeum_ga_gym_flutter/self_care/presentation/provider/profile/self_care_profile_get_profile_provider.dart'; class SelfCareProfileMainInfoWidget extends ConsumerWidget { - const SelfCareProfileMainInfoWidget({Key? key}) : super(key: key); + final int totalWakaTime; + + const SelfCareProfileMainInfoWidget({super.key, required this.totalWakaTime,}); + @override Widget build(BuildContext context, WidgetRef ref) { - final profileState = ref.watch(selfCareProfileGetProfileProvider); return SafeArea( child: Container( width: MediaQuery.of(context).size.width, @@ -58,7 +59,7 @@ class SelfCareProfileMainInfoWidget extends ConsumerWidget { ), TextSpan( style: MaeumGaGymTextStyle.bodyMedium(MaeumgagymColor.blue500), - text: profileState.totalWakatime.toString(), + text: totalWakaTime.toString() ), const TextSpan( text: "시간 운동하셨어요!", diff --git a/lib/sign_up/presentation/view/splash_screen.dart b/lib/sign_up/presentation/view/splash_screen.dart index 65075426..992a738f 100644 --- a/lib/sign_up/presentation/view/splash_screen.dart +++ b/lib/sign_up/presentation/view/splash_screen.dart @@ -13,6 +13,7 @@ import '../../../core/di/token_secure_storage_di.dart'; import '../../../core/re_issue/presentation/maeumgagym_re_issue_provider.dart'; import '../../../home/presentation/providers/home_quotes_provider.dart'; import '../../../home/presentation/providers/home_today_routines_provider.dart'; +import '../../../self_care/presentation/provider/profile/self_care_profile_get_profile_provider.dart'; class SplashScreen extends ConsumerStatefulWidget { const SplashScreen({super.key}); @@ -55,6 +56,8 @@ class _SplashScreenState extends ConsumerState { await ref.read(poseRecommendController.notifier).getRecommendPose(); + await ref.read(selfCareProfileGetProfileProvider.notifier).getUserProfile(); + context.go('/home'); }, error: (err, _) { diff --git a/lib/sign_up/presentation/widget/sign_up_nick_name/maeumgagym_text_field.dart b/lib/sign_up/presentation/widget/sign_up_nick_name/maeumgagym_text_field.dart index 07adfdd0..6d14442a 100644 --- a/lib/sign_up/presentation/widget/sign_up_nick_name/maeumgagym_text_field.dart +++ b/lib/sign_up/presentation/widget/sign_up_nick_name/maeumgagym_text_field.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/flutter_svg.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image/images.dart'; +import 'package:maeum_ga_gym_flutter/core/component/image_widget.dart'; import 'package:maeum_ga_gym_flutter/core/component/text/pretendard/ptd_text_widget.dart'; import '../../../../config/maeumgagym_color.dart'; @@ -122,12 +123,16 @@ class MaeumgagymTextField extends ConsumerWidget { textFieldNotifier.isText(false); textFieldNotifier.clicked(false); }, - child: textFieldState.inText && - textFieldState.onClicked || - textFieldState.inText - ? SvgPicture.asset( - 'assets/image/sign_up_icon/close_circle.svg') - : const SizedBox(), + child: + textFieldState.inText && textFieldState.onClicked || + textFieldState.inText + ? ImageWidget( + image: Images.iconsCloseCircle, + width: 24, + height: 24, + color: MaeumgagymColor.gray400, + ) + : const SizedBox(), ), ), ], diff --git a/pubspec.yaml b/pubspec.yaml index 825417e6..32d925db 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: A new Flutter project. publish_to: 'none' -version: 0.9.43+108 +version: 0.9.49+114 environment: sdk: '>=3.0.6 <4.0.0'