18
loading...
This website collects cookies to deliver better user experience
dependencies:
flutter:
sdk: flutter
flutter_hooks: ^0.17.0
hooks_riverpod: ^0.14.0+4
quiver: ^3.0.1
flutter pub get
enum PlayerType {
BLACK,
WHITE,
}
import 'package:quiver/core.dart';
class Coordinate {
final int x;
final int y;
Coordinate(this.x, this.y);
@override
bool operator ==(Object o) => o is Coordinate && o.y == y && o.x == x;
@override
int get hashCode => hash2(x, y);
}
import 'package:drag_drop_state_management/app/model/coordinate.dart';
class Square {
final Coordinate coordinate;
Square(this.coordinate);
}
class Checker {
final int id;
final PlayerType type;
final bool isDragging;
final Coordinate coordinate;
Checker(this.id, this.type, this.coordinate, {this.isDragging = false});
Checker copyWith({bool? isDragging, Coordinate? coordinate}) {
print('hello');
return Checker(this.id, type, coordinate ?? this.coordinate,
isDragging: isDragging ?? this.isDragging);
}
@override
bool operator ==(Object o) => o is Checker && o.id == id;
@override
int get hashCode => id;
}
final _currentPlayer = StateProvider((ref) => PlayerType.BLACK);
final currentPlayer = Provider((ref) => ref.watch(_currentPlayer).state);
final checkers = StateNotifierProvider>(
(ref) => CheckerNotifier(ref.read));
class CheckerNotifier extends StateNotifier> {
Reader read;
CheckerNotifier(this.read)
: super([
Checker(1, PlayerType.BLACK, new Coordinate(0, 0)),
Checker(2, PlayerType.WHITE, new Coordinate(0, 1))
]);
void add(Checker checker) {
state = [...state, checker];
}
void startDrag(Checker selectedChecker) {
state = [
for (final checker in state)
if (checker == selectedChecker)
checker.copyWith(isDragging: true)
else
checker,
];
}
void cancelDrag(Checker selectedChecker) {
state = [
for (final checker in state)
if (checker == selectedChecker)
checker.copyWith(isDragging: false)
else
checker,
];
}
void finishDrag(Checker selectedChecker, Coordinate coordinate) {
state = [
for (final checker in state)
if (checker == selectedChecker)
checker.copyWith(isDragging: false, coordinate: coordinate)
else
checker
];
read(_currentPlayer.notifier).state =
read(_currentPlayer.notifier).state == PlayerType.BLACK
? PlayerType.WHITE
: PlayerType.BLACK;
}
}
void main() => runApp(ProviderScope(child: DragAndDropExample()));
class DragAndDropExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.green,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Scaffold(
appBar: AppBar(
title: Text("Drag and Drop Example"),
),
body: BoardPage(),
),
);
}
}
class BoardPage extends StatelessWidget {
final List squares = SquareInitializer.squares();
@override
Widget build(BuildContext context) {
return GridView.count(
physics: new NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(4),
crossAxisCount: 8,
children: squares.map((square) => SquareWidget(square)).toList(),
);
}
}
class SquareInitializer {
static List squares() {
List squares = [];
for (var y = 0; y < 8; y++) {
for (var x = 0; x < 8; x++) {
squares.add(Square(Coordinate(x, y)));
}
}
return squares;
}
}
List checking = useProvider(checkers);
Checker? checkerOnSquare = checking
.firstWhereOrNull((element) => element.coordinate == square.coordinate);
context.read(checkers.notifier).finishDrag(data, square.coordinate);
class SquareWidget extends HookWidget {
final Square square;
SquareWidget(this.square);
Color getColor(bool willAccept) {
if (willAccept) {
return Colors.brown[300]!;
}
if (square.coordinate.x % 2 == square.coordinate.y % 2) {
return Colors.brown[500]!;
}
return Colors.brown[100]!;
}
@override
Widget build(BuildContext context) {
final willAccept = useState(false);
List checking = useProvider(checkers);
Checker? checkerOnSquare = checking
.firstWhereOrNull((element) => element.coordinate == square.coordinate);
return DragTarget(
builder: (BuildContext context, List candidateData, List rejectedData) {
return Container(
child: checkerOnSquare != null && !checkerOnSquare.isDragging
? CheckerWidget(checkerOnSquare)
: Container(),
color: getColor(willAccept.value));
},
onWillAccept: (data) {
willAccept.value = true;
return true;
},
onLeave: (data) {
willAccept.value = false;
},
onAccept: (Checker data) {
willAccept.value = false;
context.read(checkers.notifier).finishDrag(data, square.coordinate);
},
);
}
}
class CheckerWidget extends HookWidget {
final Checker checker;
int allowMove(PlayerType playerType) {
if (playerType == checker.type) {
return 1;
}
return 0;
}
getColor() {
if (PlayerType.WHITE == checker.type) {
return Colors.white;
}
return Colors.black;
}
const CheckerWidget(this.checker);
@override
Widget build(BuildContext context) {
final current = useProvider(currentPlayer);
return Draggable(
data: checker,
maxSimultaneousDrags: allowMove(current),
onDragStarted: () {
context.read(checkers.notifier).startDrag(checker);
},
onDraggableCanceled: (a, b) {
context.read(checkers.notifier).cancelDrag(checker);
},
feedback: Container(
child: Icon(
Icons.circle,
color: getColor(),
size: 35,
),
),
child: Container(
child: Icon(
Icons.circle,
color: getColor(),
size: 35,
),
),
);
}
}
onWillAccept: (data) {
willAccept.value = true;
return true;
},
void finishDrag(Checker selectedChecker, Coordinate coordinate) {
Checker? checkerOnDestination =
state.firstWhereOrNull((checker) => checker.coordinate == coordinate);
Coordinate origin = selectedChecker.coordinate;
state = [
for (final checker in state)
if (checker == selectedChecker)
checker.copyWith(isDragging: false, coordinate: coordinate)
else if (checker == checkerOnDestination)
checker.copyWith(coordinate: origin)
else
checker
];
read(_currentPlayer.notifier).state =
read(_currentPlayer.notifier).state == PlayerType.BLACK
? PlayerType.WHITE
: PlayerType.BLACK;
}
final count = StateProvider((ref) => 0);
void finishDrag(Checker selectedChecker, Coordinate coordinate) {
Checker? checkerOnDestination =
state.firstWhereOrNull((checker) => checker.coordinate == coordinate);
Coordinate origin = selectedChecker.coordinate;
state = [
for (final checker in state)
if (checker == selectedChecker)
checker.copyWith(isDragging: false, coordinate: coordinate)
else if (checker == checkerOnDestination)
checker.copyWith(coordinate: origin)
else
checker
];
read(count.notifier).state = read(count.notifier).state + 1;
read(_currentPlayer.notifier).state =
read(_currentPlayer.notifier).state == PlayerType.BLACK
? PlayerType.WHITE
: PlayerType.BLACK;
}
List checkers = state.where((element) => element.coordinate.y == coordinate.y).toList();