|
|
@ -1,3 +1,4 @@ |
|
|
|
|
|
import 'package:collection/collection.dart'; |
|
|
import 'package:flutter/foundation.dart'; |
|
|
import 'package:flutter/foundation.dart'; |
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:flutter_bloc/flutter_bloc.dart'; |
|
|
import 'package:flutter_bloc/flutter_bloc.dart'; |
|
|
@ -27,6 +28,8 @@ import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_p |
|
|
import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/node_widget.dart'; |
|
|
import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/node_widget.dart'; |
|
|
import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/play_button.dart'; |
|
|
import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/play_button.dart'; |
|
|
|
|
|
|
|
|
|
|
|
import '../../domain/entity/level_location.dart'; |
|
|
|
|
|
|
|
|
class LevelPage extends StatefulWidget { |
|
|
class LevelPage extends StatefulWidget { |
|
|
const LevelPage({super.key}); |
|
|
const LevelPage({super.key}); |
|
|
|
|
|
|
|
|
@ -46,8 +49,14 @@ class _LevelPageState extends State<LevelPage> { |
|
|
void _triggerRemainingLevelsDownload() { |
|
|
void _triggerRemainingLevelsDownload() { |
|
|
WidgetsBinding.instance.addPostFrameCallback((_) { |
|
|
WidgetsBinding.instance.addPostFrameCallback((_) { |
|
|
if (!mounted) return; |
|
|
if (!mounted) return; |
|
|
final maxLevelCount = int.tryParse(LocalStorage.readData(key: MyConstants.maxLevelCount) ?? '20') ?? 20; |
|
|
|
|
|
context.read<DownloadBloc>().add(StartDownloadEvent(toLevel: maxLevelCount)); |
|
|
|
|
|
|
|
|
final maxLevelCount = |
|
|
|
|
|
int.tryParse( |
|
|
|
|
|
LocalStorage.readData(key: MyConstants.maxLevelCount) ?? '20', |
|
|
|
|
|
) ?? |
|
|
|
|
|
20; |
|
|
|
|
|
context.read<DownloadBloc>().add( |
|
|
|
|
|
StartDownloadEvent(toLevel: maxLevelCount), |
|
|
|
|
|
); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -68,7 +77,6 @@ class _LevelPageState extends State<LevelPage> { |
|
|
_background(context), |
|
|
_background(context), |
|
|
_planets(context), |
|
|
_planets(context), |
|
|
_path(context), |
|
|
_path(context), |
|
|
|
|
|
|
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
@ -78,12 +86,9 @@ class _LevelPageState extends State<LevelPage> { |
|
|
child: Stack( |
|
|
child: Stack( |
|
|
alignment: Alignment.center, |
|
|
alignment: Alignment.center, |
|
|
clipBehavior: Clip.none, |
|
|
clipBehavior: Clip.none, |
|
|
children: [ |
|
|
|
|
|
_ship(context), |
|
|
|
|
|
_playButton(context), |
|
|
|
|
|
], |
|
|
|
|
|
|
|
|
children: [_ship(context), _playButton(context)], |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
) |
|
|
|
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
@ -214,7 +219,21 @@ class _LevelPageState extends State<LevelPage> { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Widget _path(BuildContext context) { |
|
|
Widget _path(BuildContext context) { |
|
|
|
|
|
return BlocBuilder<LevelBloc, LevelState>( |
|
|
|
|
|
builder: (context, state) { |
|
|
|
|
|
final locationList = context.read<LevelBloc>().locationList; |
|
|
|
|
|
final nodeList = context.read<LevelBloc>().nodeList; |
|
|
|
|
|
final comingSoon = locationList.firstWhereIndexedOrNull(( |
|
|
|
|
|
index, |
|
|
|
|
|
location, |
|
|
|
|
|
) { |
|
|
|
|
|
final node = nodeList.elementAtOrNull(index); |
|
|
|
|
|
return node?.nodeType == NodeType.comingSoon; |
|
|
|
|
|
}); |
|
|
return Positioned.fill( |
|
|
return Positioned.fill( |
|
|
|
|
|
child: Stack( |
|
|
|
|
|
children: [ |
|
|
|
|
|
Positioned.fill( |
|
|
top: 250, |
|
|
top: 250, |
|
|
bottom: 150, |
|
|
bottom: 150, |
|
|
right: 50, |
|
|
right: 50, |
|
|
@ -222,44 +241,64 @@ class _LevelPageState extends State<LevelPage> { |
|
|
child: Stack( |
|
|
child: Stack( |
|
|
alignment: Alignment.center, |
|
|
alignment: Alignment.center, |
|
|
children: [ |
|
|
children: [ |
|
|
const Positioned.fill( |
|
|
|
|
|
child: LevelPath(), |
|
|
|
|
|
|
|
|
const Positioned.fill(child: LevelPath()), |
|
|
|
|
|
Positioned.fill( |
|
|
|
|
|
child: _levelLocation( |
|
|
|
|
|
locationList: locationList, |
|
|
|
|
|
nodeList: nodeList, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
if (comingSoon != null) ...[ |
|
|
|
|
|
Positioned( |
|
|
|
|
|
top: 0, |
|
|
|
|
|
right: 0, |
|
|
|
|
|
left: 0, |
|
|
|
|
|
bottom: (comingSoon.bottom ?? 0) + 190, |
|
|
|
|
|
child: _lockMapShadowCover(), |
|
|
|
|
|
), |
|
|
|
|
|
Positioned( |
|
|
|
|
|
left: 50, |
|
|
|
|
|
right: 50, |
|
|
|
|
|
bottom: (comingSoon.bottom ?? 0) + 195, |
|
|
|
|
|
child: const ComingSoonLevel(), |
|
|
), |
|
|
), |
|
|
Positioned.fill(child: _levelLocation(context)), |
|
|
|
|
|
|
|
|
], |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
|
|
|
}, |
|
|
|
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Widget _levelLocation(BuildContext context) { |
|
|
|
|
|
|
|
|
Widget _levelLocation({ |
|
|
|
|
|
required List<LevelLocation> locationList, |
|
|
|
|
|
required List<NodeEntity> nodeList, |
|
|
|
|
|
}) { |
|
|
return BlocBuilder<LevelBloc, LevelState>( |
|
|
return BlocBuilder<LevelBloc, LevelState>( |
|
|
builder: (context, state) => Stack( |
|
|
|
|
|
|
|
|
builder: (context, state) { |
|
|
|
|
|
return Stack( |
|
|
clipBehavior: Clip.none, |
|
|
clipBehavior: Clip.none, |
|
|
children: [ |
|
|
children: [ |
|
|
...List.generate( |
|
|
|
|
|
context.read<LevelBloc>().nodeList.length, |
|
|
|
|
|
(index) { |
|
|
|
|
|
final node = context.read<LevelBloc>().nodeList[index]; |
|
|
|
|
|
if(node.nodeType == NodeType.comingSoon) { |
|
|
|
|
|
if(node.nodeType == NodeType.comingSoon) { |
|
|
|
|
|
return Positioned( |
|
|
|
|
|
left: 0, |
|
|
|
|
|
right: 0, |
|
|
|
|
|
bottom: (context.read<LevelBloc>().locationList[index].bottom ?? 0) + 88, |
|
|
|
|
|
child: const ComingSoonLevel()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
...List.generate(locationList.length, (index) { |
|
|
|
|
|
final node = nodeList.elementAtOrNull(index); |
|
|
|
|
|
final location = locationList[index]; |
|
|
|
|
|
if (node?.nodeType == NodeType.comingSoon) |
|
|
|
|
|
return const SizedBox(); |
|
|
return Positioned( |
|
|
return Positioned( |
|
|
top: context.read<LevelBloc>().locationList[index].top, |
|
|
|
|
|
bottom: context.read<LevelBloc>().locationList[index].bottom, |
|
|
|
|
|
right: context.read<LevelBloc>().locationList[index].right, |
|
|
|
|
|
left: context.read<LevelBloc>().locationList[index].left, |
|
|
|
|
|
|
|
|
top: location.top, |
|
|
|
|
|
bottom: location.bottom, |
|
|
|
|
|
right: location.right, |
|
|
|
|
|
left: location.left, |
|
|
child: BlocBuilder<LevelBloc, LevelState>( |
|
|
child: BlocBuilder<LevelBloc, LevelState>( |
|
|
buildWhen: (previous, current) => |
|
|
buildWhen: (previous, current) => |
|
|
previous.chooseLevel?.id != current.chooseLevel?.id, |
|
|
previous.chooseLevel?.id != current.chooseLevel?.id, |
|
|
builder: (context, state) => NodeWidget( |
|
|
builder: (context, state) => NodeWidget( |
|
|
chooseLevel: state.chooseLevel, |
|
|
chooseLevel: state.chooseLevel, |
|
|
node: context.read<LevelBloc>().nodeList[index], |
|
|
|
|
|
|
|
|
levelIndex: location.index, |
|
|
|
|
|
node: node, |
|
|
type: context.read<LevelBloc>().getLevelType, |
|
|
type: context.read<LevelBloc>().getLevelType, |
|
|
getReward: context.read<LevelBloc>().getReward, |
|
|
getReward: context.read<LevelBloc>().getReward, |
|
|
onRewardPressed: (prize) { |
|
|
onRewardPressed: (prize) { |
|
|
@ -276,17 +315,15 @@ class _LevelPageState extends State<LevelPage> { |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
}), |
|
|
], |
|
|
], |
|
|
), |
|
|
|
|
|
|
|
|
); |
|
|
|
|
|
}, |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Widget _ship(BuildContext context) { |
|
|
Widget _ship(BuildContext context) { |
|
|
return const ShipAnim( |
|
|
|
|
|
child: MyImage(image: MyAssets.ship), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
return const ShipAnim(child: MyImage(image: MyAssets.ship)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Widget _playButton(BuildContext context) { |
|
|
Widget _playButton(BuildContext context) { |
|
|
@ -299,7 +336,7 @@ class _LevelPageState extends State<LevelPage> { |
|
|
onTap: (level) => |
|
|
onTap: (level) => |
|
|
context.read<LevelBloc>().goToQuestionPage(context, level), |
|
|
context.read<LevelBloc>().goToQuestionPage(context, level), |
|
|
); |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
}, |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -322,9 +359,7 @@ class _LevelPageState extends State<LevelPage> { |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
const Spacer(), |
|
|
const Spacer(), |
|
|
DiamondLevel( |
|
|
|
|
|
diamonds: context.read<LevelBloc>().diamonds, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
DiamondLevel(diamonds: context.read<LevelBloc>().diamonds), |
|
|
StreamBuilder<double>( |
|
|
StreamBuilder<double>( |
|
|
initialData: 1, |
|
|
initialData: 1, |
|
|
stream: context.read<LevelBloc>().volumeStream, |
|
|
stream: context.read<LevelBloc>().volumeStream, |
|
|
@ -364,9 +399,26 @@ class _LevelPageState extends State<LevelPage> { |
|
|
// } |
|
|
// } |
|
|
|
|
|
|
|
|
Widget _background(BuildContext context) { |
|
|
Widget _background(BuildContext context) { |
|
|
return const MyImage( |
|
|
|
|
|
image: MyAssets.mapBackground, |
|
|
|
|
|
fit: BoxFit.cover, |
|
|
|
|
|
|
|
|
return const MyImage(image: MyAssets.mapBackground, fit: BoxFit.cover); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Widget _lockMapShadowCover() { |
|
|
|
|
|
return Container( |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
gradient: LinearGradient( |
|
|
|
|
|
colors: [ |
|
|
|
|
|
Colors.black.withValues(alpha: .8), |
|
|
|
|
|
Colors.black54, |
|
|
|
|
|
Colors.black54, |
|
|
|
|
|
Colors.black54, |
|
|
|
|
|
Colors.black54, |
|
|
|
|
|
Colors.black54, |
|
|
|
|
|
Colors.transparent, |
|
|
|
|
|
], |
|
|
|
|
|
begin: AlignmentGeometry.topCenter, |
|
|
|
|
|
end: AlignmentGeometry.bottomCenter, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |