Toy project to learn Flutter/Dart.
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.

164 lines
5.2 KiB

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'pokemon.dart'; // list of pokemon names
import 'animation.dart'; // particles
import 'list.dart'; // list view widget
import 'utils.dart'; // utility structures and functions
// main
void main() {
runApp(
ChangeNotifierProvider(create: (BuildContext _) { PokemonProvider pP = PokemonProvider(); pP.initialize(); return pP;}, child: const MyApp())
);
}
// app widget
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// root widget
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Pokemon Swiper',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
'/': (context) => const PokeWidget(),
'/list': (context) => const PokeList(),
},
);
}
}
// PokeWidget
class PokeWidget extends StatefulWidget {
const PokeWidget({Key? key}) : super(key: key);
@override
State<PokeWidget> createState() => _PokeState();
}
// PokeState
class _PokeState extends State<PokeWidget> {
StreamController<Particle> controller = StreamController<Particle>();
// generates particles to show that status of the pokemon changed
void _setCurrentStatus(PokemonProvider pP, Status status) {
pP.setCurrentStatus(status);
// add 10 particles
for(int i = 0; i < particleNumber; i++){
controller.add(animParticle(status)); // launch particle
}
}
// swiper function
// detects if movement is large enough to trigger action
// generate pokemon shadow at the good posistion and call _setCurrentStatus
Function(DraggableDetails) _swiper(pP) {return (DraggableDetails details) {_swipedCard(pP, details);};}
void _swipedCard(PokemonProvider pP, DraggableDetails details) {
Size screenSize = MediaQuery.of(context).size;
// arbitrary guess of image size (would be better if known)
double imageWidth = 220.0;
double imageHeight = 120.0;
String current = padint(pP.currentIndex+1);
double threshold=imageWidth/4;
// initial offset of image (position of top left corner in pixels)
double x0=(screenSize.width-imageWidth)/2;
double y0=(screenSize.height-imageHeight)/2;
// shift in pixel
double dx = details.offset.dx - x0;
double dy = details.offset.dy - y0;
Alignment currentAlignment = Alignment(4.0*dx/screenSize.width, 4.0*dy/screenSize.height);
Alignment finalAlignment = currentAlignment*10;
// print("offset : ${details.offset}, x0 : $x0, y0 : $y0, dx : $dx, dy : $dy");
// print("current alignment: $currentAlignment");
if(dx < - threshold) { // left
_setCurrentStatus(pP, Status.rejected);
controller.add(Particle(
child: Image.asset("assets/pokemon/$current.png"),
start: currentAlignment,
end: finalAlignment,
duration: const Duration(milliseconds: 500),
status: AnimStatus.running,
));
pP.next();
} else if(dx > threshold) { //right
_setCurrentStatus(pP, Status.accepted);
controller.add(Particle(
child: Image.asset("assets/pokemon/$current.png"),
start: currentAlignment,
end: finalAlignment,
duration: const Duration(milliseconds: 500),
status: AnimStatus.running,
));
pP.next();
} else { // nope
}
}
@override
Widget build(BuildContext context) {
PokemonProvider pP = Provider.of<PokemonProvider>(context);
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(pP.currentName()),
actions: [IconButton(onPressed: () { Navigator.pushNamed(context, '/list');}, icon: const Icon(Icons.list_rounded))],
),
body: Stack( // main stack
fit: StackFit.expand,
children: [
EmojiRainWidget(stream: controller.stream,),
Center(
child: Draggable(
child: Image.asset(pP.currentImage()),
feedback: Image.asset(pP.currentImage()),
childWhenDragging: Image.asset(pP.nextImage()),
onDragEnd: _swiper(pP),
),
)
]),
floatingActionButton: Wrap(children: [
SizedBox(
height: 70.0,
width: 70.0,
child: FittedBox(
child: ClipPath(
child: FloatingActionButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: statusColor(pP.currentStatus()),
onPressed: () => _setCurrentStatus(pP, Status.favorite),
tooltip: 'fav',
child: Text("${pP.currentIndex}"),
heroTag: "fav",
),
clipper: StarClipper(),
),
),
),
FloatingActionButton(
backgroundColor: Colors.grey,
onPressed: () => pP.previous(),
tooltip: 'prev',
child: const Text('<'),
heroTag: "prev",
),
FloatingActionButton(
backgroundColor: Colors.grey,
onPressed: () => pP.next(),
tooltip: 'next',
child: const Text('>'),
heroTag: "next",
),
],
crossAxisAlignment: WrapCrossAlignment.center,)
);
}
}