Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fetch crossword from firestore #32

Merged
merged 23 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3e7bf3f
feat: use crossword repository in bloc
B0berman Mar 4, 2024
4d8169b
test: add app and bloc tests
B0berman Mar 5, 2024
c96a7dc
Merge branch 'main' of https://github.com/VGVentures/io_crossword int…
B0berman Mar 6, 2024
a2b669c
feat: remove initial section request
B0berman Mar 6, 2024
9787c51
feat: remove unused state and fix tests
B0berman Mar 6, 2024
23e7ddc
chore: merge main
B0berman Mar 6, 2024
b21bbf4
test: fix tests and fix section positioning
B0berman Mar 7, 2024
0cbf8e9
chore: remove unused code
B0berman Mar 7, 2024
c698d0c
Merge branch 'main' of https://github.com/VGVentures/io_crossword int…
B0berman Mar 7, 2024
94962bd
Merge branch 'main' of https://github.com/VGVentures/io_crossword int…
B0berman Mar 7, 2024
dd559ee
fix: fix words highlight
B0berman Mar 8, 2024
c3d305b
test: fix highlight test
B0berman Mar 8, 2024
a9e338b
test: fix crossword_game_tests
B0berman Mar 8, 2024
9a9dc05
test: fix bloc tests
B0berman Mar 8, 2024
480b9fb
test: update test board
B0berman Mar 8, 2024
d2c1aac
fix: fix crossword file for horizontal words
B0berman Mar 11, 2024
5795126
chore: left print
B0berman Mar 11, 2024
4e5dd6b
test: add hightlight word changes test
B0berman Mar 11, 2024
4f9f522
feat: pr suggestions
B0berman Mar 11, 2024
507ffa3
chore: analysis
B0berman Mar 11, 2024
6188658
feat: use Axis in board generator
B0berman Mar 11, 2024
1020c4f
feat: update in board generator instead of section creation
B0berman Mar 11, 2024
ee895de
chore: put back enum in create section
B0berman Mar 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 1 addition & 142 deletions assets/test/test_board.json

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions lib/app/view/app.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import 'package:crossword_repository/crossword_repository.dart';
import 'package:flame/cache.dart';
import 'package:flame_audio/flame_audio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:io_crossword/l10n/l10n.dart';
import 'package:io_crossword/loading/loading.dart';
import 'package:provider/provider.dart';

class App extends StatelessWidget {
const App({super.key});
const App({required this.crosswordRepository, super.key});

final CrosswordRepository crosswordRepository;

@override
Widget build(BuildContext context) {
return MultiBlocProvider(
return MultiProvider(
providers: [
Provider.value(value: crosswordRepository),
BlocProvider(
create: (_) => PreloadCubit(
Images(prefix: ''),
Expand Down
3 changes: 3 additions & 0 deletions lib/bootstrap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:developer';

import 'package:bloc/bloc.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/widgets.dart';

Expand All @@ -22,6 +23,7 @@ class AppBlocObserver extends BlocObserver {
}

typedef BootstrapBuilder = FutureOr<Widget> Function(
FirebaseFirestore firestore,
FirebaseAuth firebaseAuth,
);

Expand All @@ -36,6 +38,7 @@ Future<void> bootstrap(BootstrapBuilder builder) async {

runApp(
await builder(
FirebaseFirestore.instance,
FirebaseAuth.instance,
),
);
Expand Down
120 changes: 27 additions & 93 deletions lib/crossword/bloc/crossword_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,113 +1,47 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:crossword_repository/crossword_repository.dart';
import 'package:equatable/equatable.dart';
import 'package:game_domain/game_domain.dart';

part 'crossword_event.dart';
part 'crossword_state.dart';

var _id = 0;
int _defaultIdGenerator() => _id++;

class CrosswordBloc extends Bloc<CrosswordEvent, CrosswordState> {
CrosswordBloc({
int Function()? idGenerator,
}) : _idGenerator = idGenerator ?? _defaultIdGenerator,
super(const CrosswordInitial()) {
on<InitialBoardLoadRequested>(_onInitialBoardLoadRequested);
CrosswordBloc(this.crosswordRepository) : super(const CrosswordInitial()) {
on<BoardSectionRequested>(_onBoardSectionRequested);
on<WordSelected>(_onWordSelected);
}

// TODO(any): Replace with real data
final int Function() _idGenerator;

Future<void> _onInitialBoardLoadRequested(
InitialBoardLoadRequested event,
Emitter<CrosswordState> emit,
) async {
final section = BoardSection(
id: '${_idGenerator()}',
position: const Point(2, 2),
size: 40,
words: [
Word(
axis: Axis.horizontal,
position: const Point(0, 0),
answer: 'flutter',
clue: 'flutter',
hints: const ['dart', 'mobile', 'cross-platform'],
visible: true,
solvedTimestamp: null,
),
],
borderWords: const [],
);

emit(
CrosswordLoaded(
width: 40,
height: 40,
sectionSize: 400,
sections: {
(section.position.x, section.position.y): section,
},
),
);
}
final CrosswordRepository crosswordRepository;

Future<void> _onBoardSectionRequested(
BoardSectionRequested event,
Emitter<CrosswordState> emit,
) async {
final loadedState = state;
if (loadedState is CrosswordLoaded) {
final section = BoardSection(
id: '${_idGenerator()}',
position: Point(event.position.$1, event.position.$2),
size: 40,
words: [
Word(
axis: Axis.horizontal,
position: const Point(0, 0),
answer: 'flutter',
clue: 'flutter',
hints: const ['dart', 'mobile', 'cross-platform'],
visible: false,
solvedTimestamp: null,
),
Word(
axis: Axis.vertical,
position: const Point(8, 3),
answer: 'dino',
clue: 'flutter',
hints: const ['dart', 'mobile', 'cross-platform'],
visible: true,
solvedTimestamp: null,
),
Word(
position: const Point(4, 6),
axis: Axis.horizontal,
answer: 'sparky',
clue: 'flutter',
hints: const ['dart', 'mobile', 'cross-platform'],
visible: true,
solvedTimestamp: null,
),
],
borderWords: const [],
);

emit(
loadedState.copyWith(
sections: {
...loadedState.sections,
(section.position.x, section.position.y): section,
},
),
);
}
return emit.forEach(
crosswordRepository.watchSectionFromPosition(
event.position.$1,
event.position.$2,
),
onData: (section) {
if (section == null) return state;
AyadLaouissi marked this conversation as resolved.
Show resolved Hide resolved
final newSection = {
(section.position.x, section.position.y): section,
};

return CrosswordLoaded(
sectionSize: section.size,
sections: state is CrosswordLoaded
? {
...(state as CrosswordLoaded).sections,
...newSection,
}
: {...newSection},
);
},
);
}

FutureOr<void> _onWordSelected(
Expand All @@ -117,8 +51,8 @@ class CrosswordBloc extends Bloc<CrosswordEvent, CrosswordState> {
final currentState = state;
if (currentState is CrosswordLoaded) {
emit(
currentState.withSelectedWord(
WordSelection(
currentState.copyWith(
selectedWord: WordSelection(
section: event.section,
wordId: event.wordId,
),
Expand Down
7 changes: 0 additions & 7 deletions lib/crossword/bloc/crossword_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ sealed class CrosswordEvent extends Equatable {
const CrosswordEvent();
}

class InitialBoardLoadRequested extends CrosswordEvent {
const InitialBoardLoadRequested();

@override
List<Object> get props => [];
}

class BoardSectionRequested extends CrosswordEvent {
const BoardSectionRequested(this.position);

Expand Down
22 changes: 5 additions & 17 deletions lib/crossword/bloc/crossword_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ sealed class CrosswordState extends Equatable {

class CrosswordInitial extends CrosswordState {
const CrosswordInitial();
@override
List<Object> get props => [];
}

class CrosswordLoading extends CrosswordState {
const CrosswordLoading();
@override
List<Object> get props => [];
}
Expand All @@ -31,10 +26,11 @@ class WordSelection extends Equatable {

class CrosswordLoaded extends CrosswordState {
const CrosswordLoaded({
required this.width,
required this.height,
required this.sectionSize,
required this.sections,
// TODO(any): get configuration from db
this.width = 40,
this.height = 40,
B0berman marked this conversation as resolved.
Show resolved Hide resolved
this.selectedWord,
});

Expand All @@ -49,22 +45,14 @@ class CrosswordLoaded extends CrosswordState {
int? height,
int? sectionSize,
Map<(int, int), BoardSection>? sections,
WordSelection? selectedWord,
}) {
return CrosswordLoaded(
width: width ?? this.width,
height: height ?? this.height,
sectionSize: sectionSize ?? this.sectionSize,
sections: sections ?? this.sections,
);
}

CrosswordState withSelectedWord(WordSelection? selectedWord) {
return CrosswordLoaded(
width: width,
height: height,
sectionSize: sectionSize,
sections: sections,
selectedWord: selectedWord,
selectedWord: selectedWord ?? this.selectedWord,
);
}

Expand Down
17 changes: 11 additions & 6 deletions lib/crossword/game/components/section_component.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ class SectionTapController extends PositionComponent

@override
void onTapUp(TapUpEvent event) {
final localPosition = event.localPosition;
final boardSection = parent._boardSection;

if (boardSection != null) {
final absolutePosition =
boardSection.position * CrosswordGame.cellSize * boardSection.size;
final localPosition = event.localPosition +
Vector2(
absolutePosition.x.toDouble(),
absolutePosition.y.toDouble(),
);
for (final word in boardSection.words) {
final wordLength =
(word.answer.length * CrosswordGame.cellSize).toDouble();
Expand Down Expand Up @@ -210,11 +216,10 @@ class SectionComponent extends PositionComponent

final y =
word.axis == Axis.vertical ? word.position.y + c : word.position.y;
final offset = sectionPosition +
Vector2(
x * CrosswordGame.cellSize.toDouble(),
y * CrosswordGame.cellSize.toDouble(),
);
final offset = Vector2(
x * CrosswordGame.cellSize.toDouble(),
y * CrosswordGame.cellSize.toDouble(),
);

spriteBatch.add(
source: rect,
Expand Down
6 changes: 3 additions & 3 deletions lib/crossword/game/crossword_game.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class CrosswordGame extends FlameGame with PanDetector {
// TODO(erickzanardo): Use the assets cubit instead
lettersSprite = await images.load('letters.png');

sectionSize = state.sectionSize;
sectionSize = state.sectionSize * cellSize;

totalArea = Size(
(state.width * cellSize).toDouble(),
Expand All @@ -47,8 +47,8 @@ class CrosswordGame extends FlameGame with PanDetector {
..priority = 1
..viewport = (MaxViewport()..anchor = Anchor.topLeft)
..viewfinder.position = Vector2(
totalArea.width / 2,
totalArea.height / 2,
totalArea.width,
totalArea.height,
);

_updateVisibleSections();
Expand Down
10 changes: 4 additions & 6 deletions lib/crossword/view/crossword_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:crossword_repository/crossword_repository.dart';
import 'package:flame/game.dart' hide Route;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand All @@ -9,8 +10,9 @@ class CrosswordPage extends StatelessWidget {
static Route<void> route() {
return MaterialPageRoute<void>(
builder: (_) => BlocProvider(
create: (BuildContext context) =>
CrosswordBloc()..add(const InitialBoardLoadRequested()),
create: (BuildContext context) => CrosswordBloc(
context.read<CrosswordRepository>(),
)..add(const BoardSectionRequested((0, 0))),
child: const CrosswordPage(),
),
);
Expand All @@ -34,10 +36,6 @@ class CrosswordView extends StatelessWidget {
child = const Center(
child: CircularProgressIndicator(),
);
} else if (state is CrosswordLoading) {
child = const Center(
child: CircularProgressIndicator(),
);
} else if (state is CrosswordError) {
child = const Center(child: Text('Error loading crossword'));
} else if (state is CrosswordLoaded) {
Expand Down
7 changes: 5 additions & 2 deletions lib/main_development.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';

import 'package:authentication_repository/authentication_repository.dart';
import 'package:crossword_repository/crossword_repository.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/widgets.dart';
import 'package:io_crossword/app/app.dart';
Expand All @@ -16,15 +17,17 @@ void main() async {

unawaited(
bootstrap(
(firebaseAuth) async {
(firestore, firebaseAuth) async {
final authenticationRepository = AuthenticationRepository(
firebaseAuth: firebaseAuth,
);

await authenticationRepository.signInAnonymously();
await authenticationRepository.idToken.first;

return const App();
return App(
crosswordRepository: CrosswordRepository(db: firestore),
);
},
),
);
Expand Down
Loading
Loading