@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
66import 'package:flutter_pecha/core/analytics/analytics_events.dart' ;
77import 'package:flutter_pecha/core/analytics/analytics_providers.dart' ;
88import 'package:flutter_pecha/core/config/locale/locale_notifier.dart' ;
9+ import 'package:flutter_pecha/core/config/router/app_routes.dart' ;
910import 'package:flutter_pecha/core/error/failures.dart' ;
1011import 'package:flutter_pecha/core/constants/app_assets.dart' ;
1112import 'package:flutter_pecha/core/l10n/generated/app_localizations.dart' ;
@@ -23,6 +24,7 @@ import 'package:flutter_pecha/features/plans/data/models/user/user_plans_model.d
2324import 'package:flutter_pecha/features/plans/data/utils/series_plan_utils.dart' ;
2425import 'package:flutter_pecha/features/plans/data/models/user/user_tasks_dto.dart' ;
2526import 'package:flutter_pecha/features/plans/domain/subtask_navigation.dart' ;
27+ import 'package:flutter_pecha/features/plans/presentation/utils/plan_day_share.dart' ;
2628import 'package:flutter_pecha/features/plans/presentation/widgets/plan_navigation/plan_navigator.dart' ;
2729import 'package:flutter_pecha/core/extensions/context_ext.dart' ;
2830import 'package:flutter_pecha/features/plans/data/models/response/user_plan_day_detail_response.dart' ;
@@ -60,6 +62,8 @@ class _PlanDetailsState extends ConsumerState<PlanDetails> {
6062 final Set <String > _togglingTaskIds = {};
6163 final Map <int , bool > _dayCompletionTracker = {};
6264 final Map <String , bool > _optimisticCompletions = {};
65+ final GlobalKey _shareButtonKey = GlobalKey ();
66+ bool _isSharing = false ;
6367
6468 @override
6569 void initState () {
@@ -215,7 +219,14 @@ class _PlanDetailsState extends ConsumerState<PlanDetails> {
215219 return AppBar (
216220 leading: IconButton (
217221 icon: const Icon (AppAssets .arrowLeft),
218- onPressed: () => context.pop (),
222+ onPressed: () {
223+ if (context.canPop ()) {
224+ context.pop ();
225+ } else {
226+ // Opened via deep link with no route beneath — go home.
227+ context.go (AppRoutes .home);
228+ }
229+ },
219230 ),
220231 title: Text (widget.plan.title, style: TextStyle (fontSize: 20 )),
221232 elevation: 0 ,
@@ -711,38 +722,101 @@ class _PlanDetailsState extends ConsumerState<PlanDetails> {
711722 tasks.isNotEmpty &&
712723 tasks.any (PlanSubtaskNavigation .isUserTaskNavigable);
713724
725+ final shareableImageUrl = dayData? .shareableImageUrl? .trim ();
726+ final showShareButton =
727+ dayData != null &&
728+ dayData.isCompleted &&
729+ shareableImageUrl != null &&
730+ shareableImageUrl.isNotEmpty;
731+
732+ final buttonStyle = FilledButton .styleFrom (
733+ backgroundColor: Theme .of (context).colorScheme.onSurface,
734+ foregroundColor: Theme .of (context).colorScheme.surface,
735+ disabledBackgroundColor: Theme .of (
736+ context,
737+ ).colorScheme.onSurface.withValues (alpha: 0.5 ),
738+ disabledForegroundColor: Theme .of (
739+ context,
740+ ).colorScheme.surface.withValues (alpha: 0.85 ),
741+ padding: const EdgeInsets .symmetric (vertical: 16 ),
742+ shape: RoundedRectangleBorder (borderRadius: BorderRadius .circular (20 )),
743+ );
744+
714745 return SafeArea (
715746 child: Padding (
716747 padding: const EdgeInsets .all (16.0 ),
717748 child: SizedBox (
718749 width: double .infinity,
719- child: FilledButton (
720- onPressed:
721- hasReadableContent
722- ? () => _startReading (tasks, audioUrl: audioUrl)
723- : null ,
724- style: FilledButton .styleFrom (
725- backgroundColor: Theme .of (context).colorScheme.onSurface,
726- foregroundColor: Theme .of (context).colorScheme.surface,
727- disabledBackgroundColor: Theme .of (
728- context,
729- ).colorScheme.onSurface.withValues (alpha: 0.5 ),
730- padding: const EdgeInsets .symmetric (vertical: 16 ),
731- shape: RoundedRectangleBorder (
732- borderRadius: BorderRadius .circular (20 ),
733- ),
734- ),
735- child: Text (
736- localizations.start_reading,
737- style: const TextStyle (
738- fontSize: 16 ,
739- fontWeight: FontWeight .bold,
740- letterSpacing: - 0.3 ,
741- ),
742- ),
743- ),
750+ child:
751+ showShareButton
752+ ? FilledButton .icon (
753+ key: _shareButtonKey,
754+ onPressed:
755+ _isSharing
756+ ? null
757+ : () =>
758+ _shareDay (shareableImageUrl, dayData.dayNumber),
759+ style: buttonStyle,
760+ icon:
761+ _isSharing
762+ ? SizedBox (
763+ width: 18 ,
764+ height: 18 ,
765+ child: CircularProgressIndicator (
766+ strokeWidth: 2 ,
767+ color: Theme .of (
768+ context,
769+ ).colorScheme.surface.withValues (alpha: 0.85 ),
770+ ),
771+ )
772+ : const Icon (AppAssets .readerShare, size: 22 ),
773+ label: Text (
774+ localizations.share,
775+ style: const TextStyle (
776+ fontSize: 16 ,
777+ fontWeight: FontWeight .bold,
778+ letterSpacing: - 0.3 ,
779+ ),
780+ ),
781+ )
782+ : FilledButton (
783+ onPressed:
784+ hasReadableContent
785+ ? () => _startReading (tasks, audioUrl: audioUrl)
786+ : null ,
787+ style: buttonStyle,
788+ child: Text (
789+ localizations.start_reading,
790+ style: const TextStyle (
791+ fontSize: 16 ,
792+ fontWeight: FontWeight .bold,
793+ letterSpacing: - 0.3 ,
794+ ),
795+ ),
796+ ),
744797 ),
745798 ),
746799 );
747800 }
801+
802+ Future <void > _shareDay (String shareableImageUrl, int dayNumber) async {
803+ if (_isSharing) return ;
804+
805+ setState (() => _isSharing = true );
806+
807+ try {
808+ await sharePlanDayImage (
809+ context: context,
810+ shareableImageUrl: shareableImageUrl,
811+ dayNumber: dayNumber,
812+ planId: widget.plan.id,
813+ planLanguage: widget.plan.language,
814+ shareButtonKey: _shareButtonKey,
815+ );
816+ } finally {
817+ if (mounted) {
818+ setState (() => _isSharing = false );
819+ }
820+ }
821+ }
748822}
0 commit comments