You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

424 lines
14 KiB

import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_audios.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart';
import 'package:hadi_hoda_flutter/core/constants/my_constants.dart';
import 'package:hadi_hoda_flutter/core/status/base_status.dart';
import 'package:hadi_hoda_flutter/core/utils/local_storage.dart';
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart';
import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart';
import 'package:hadi_hoda_flutter/core/widgets/animations/rotation_planet.dart';
import 'package:hadi_hoda_flutter/core/widgets/animations/ship_anim.dart';
import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart';
import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart';
import 'package:hadi_hoda_flutter/core/widgets/pop_scope/my_pop_scope.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_bloc.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_event.dart';
import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart';
import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart';
import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_bloc.dart';
import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_event.dart';
import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_state.dart';
import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/coming_soon_level.dart';
import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/diamond_level.dart';
import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_path.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 '../../domain/entity/level_location.dart';
class LevelPage extends StatefulWidget {
const LevelPage({super.key});
@override
State<LevelPage> createState() => _LevelPageState();
}
class _LevelPageState extends State<LevelPage> {
static const double _muteThreshold = 0.001;
@override
void initState() {
super.initState();
if (!kDebugMode) _triggerRemainingLevelsDownload();
}
void _triggerRemainingLevelsDownload() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
final maxLevelCount =
int.tryParse(
LocalStorage.readData(key: MyConstants.maxLevelCount) ?? '20',
) ??
20;
context.read<DownloadBloc>().add(
StartDownloadEvent(toLevel: maxLevelCount),
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: MyPopScope(
backHome: true,
child: Stack(
alignment: Alignment.center,
children: [
SingleChildScrollView(
controller: context.read<LevelBloc>().scrollController,
reverse: true,
child: Stack(
alignment: Alignment.center,
children: [
_background(context),
_planets(context),
_path(context),
],
),
),
_topSection(context),
Positioned(
bottom: 0,
child: Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [_ship(context), _playButton(context)],
),
),
],
),
),
);
}
Positioned _planets(BuildContext context) {
return Positioned.fill(
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
bottom: 0.2.h,
right: setSize(context: context, mobile: -40, tablet: -80),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet1,
size: setSize(context: context, mobile: 180),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 0.5.h, tablet: 0.8.h),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet2,
size: setSize(context: context, mobile: 110),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 0.55.h, tablet: 0.9.h),
left: setSize(context: context, mobile: -120, tablet: -200),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet3,
size: setSize(context: context, mobile: 250),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 0.85.h, tablet: 1.4.h),
right: 30,
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet4,
size: setSize(context: context, mobile: 100),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 0.95.h, tablet: 1.65.h),
left: setSize(context: context, mobile: -130, tablet: -220),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet5,
size: setSize(context: context, mobile: 250),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 1.25.h, tablet: 2.1.h),
right: setSize(context: context, mobile: 20, tablet: 20),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet6,
size: setSize(context: context, mobile: 60),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 1.28.h, tablet: 2.2.h),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet7,
size: setSize(context: context, mobile: 100),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 1.4.h, tablet: 2.3.h),
right: setSize(context: context, mobile: -50, tablet: -120),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet8,
size: setSize(context: context, mobile: 200),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 1.5.h, tablet: 2.6.h),
left: -20,
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet9,
size: setSize(context: context, mobile: 100),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 1.58.h, tablet: 2.8.h),
child: RotationPlanet(
child: MyImage(
image: MyAssets.planet10,
size: setSize(context: context, mobile: 60),
),
),
),
Positioned(
bottom: setSize(context: context, mobile: 1.65.h, tablet: 2.9.h),
right: 20,
child: MyImage(
image: MyAssets.satellite,
size: setSize(context: context, mobile: 80),
),
),
Positioned(
bottom: setSize(context: context, mobile: 1.63.h, tablet: 2.9.h),
left: setSize(context: context, mobile: 80, tablet: 0.2.w),
child: MyImage(
image: MyAssets.planetFinal,
size: setSize(context: context, mobile: 250),
),
),
],
),
);
}
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(
child: Stack(
children: [
Positioned.fill(
top: 250,
bottom: 150,
right: 50,
left: 50,
child: Stack(
alignment: Alignment.center,
children: [
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(),
),
],
],
),
);
},
);
}
Widget _levelLocation({
required List<LevelLocation> locationList,
required List<NodeEntity> nodeList,
}) {
return BlocBuilder<LevelBloc, LevelState>(
builder: (context, state) {
return Stack(
clipBehavior: Clip.none,
children: [
...List.generate(locationList.length, (index) {
final node = nodeList.elementAtOrNull(index);
final location = locationList[index];
if (node?.nodeType == NodeType.comingSoon)
return const SizedBox();
return Positioned(
top: location.top,
bottom: location.bottom,
right: location.right,
left: location.left,
child: BlocBuilder<LevelBloc, LevelState>(
buildWhen: (previous, current) =>
previous.chooseLevel?.id != current.chooseLevel?.id,
builder: (context, state) => NodeWidget(
chooseLevel: state.chooseLevel,
levelIndex: location.index,
node: node,
type: context.read<LevelBloc>().getLevelType,
getReward: context.read<LevelBloc>().getReward,
onRewardPressed: (prize) {
context.read<LevelBloc>().showReward(
context: context,
prize: prize,
);
},
onTap: (LevelEntity level, LevelType type) {
context.read<LevelBloc>().add(
ChooseLevelEvent(level, type),
);
},
),
),
);
}),
],
);
},
);
}
Widget _ship(BuildContext context) {
return const ShipAnim(child: MyImage(image: MyAssets.ship));
}
Widget _playButton(BuildContext context) {
return BlocBuilder<LevelBloc, LevelState>(
buildWhen: (previous, current) =>
previous.chooseLevel?.id != current.chooseLevel?.id,
builder: (context, state) {
return PlayButton(
level: state.chooseLevel ?? LevelEntity(),
onTap: (level) =>
context.read<LevelBloc>().goToQuestionPage(context, level),
);
},
);
}
Positioned _topSection(BuildContext context) {
return Positioned(
left: MySpaces.s16,
right: MySpaces.s16,
top: setPlatform(android: MySpaces.s20, iOS: 50),
child: Column(
children: [
Row(
spacing: MySpaces.s16,
children: [
MyInkwell(
onTap: () => context.read<LevelBloc>().goToHomePage(context),
audio: MyAudios.back,
child: MyImage(
image: MyAssets.homeButton,
size: setSize(context: context, tablet: 80),
),
),
const Spacer(),
DiamondLevel(diamonds: context.read<LevelBloc>().diamonds),
StreamBuilder<double>(
initialData: 1,
stream: context.read<LevelBloc>().volumeStream,
builder: (context, snapshot) => MyInkwell(
onTap: () => context.read<LevelBloc>().changeMute(),
child: MyImage(
image: (snapshot.data ?? 1) <= _muteThreshold
? MyAssets.musicOff
: MyAssets.musicOn,
size: setSize(context: context, tablet: 80),
),
),
),
],
),
// _downloadIndicator(),
],
),
);
}
// Widget _downloadIndicator() {
// return BlocBuilder<DownloadBloc, DownloadState>(
// buildWhen: (prev, curr) => prev.status != curr.status,
// builder: (context, downloadState) {
// if (downloadState.status is! BaseLoading) {
// return const SizedBox.shrink();
// }
// return Padding(
// padding: const EdgeInsets.only(top: MySpaces.s10),
// child: DownloadLoadingWidget(
// loadingStream: context.read<DownloadBloc>().loadingStream,
// ),
// );
// },
// );
// }
Widget _background(BuildContext context) {
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,
),
),
);
}
}