Skip to content

Commit 09766ec

Browse files
feat: added support for Dynamic fractal
1 parent 04b9700 commit 09766ec

File tree

11 files changed

+553
-9
lines changed

11 files changed

+553
-9
lines changed

lib/src/app.dart

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
44
import 'package:flutter_localizations/flutter_localizations.dart';
55
import 'package:go_router/go_router.dart';
66
import 'package:t3_memassist/memory_assistant.dart';
7+
import 'package:t3_vault/src/features/greatwall/presentation/pages/dynamic_fractal_derivation_level_page.dart';
8+
import 'package:t3_vault/src/features/greatwall/presentation/pages/dynamic_fractal_tree_inputs_page.dart';
79
import 'package:t3_vault/src/features/memorization_assistant/presentation/pages/eka_memo_card_practice_page.dart';
810
import 'package:t3_vault/src/features/memorization_assistant/presentation/pages/memo_card_decks_page.dart';
911
import 'package:t3_vault/src/features/memorization_assistant/presentation/pages/sa0_memo_card_practice_page.dart';
@@ -334,6 +336,30 @@ class T3Vault extends StatelessWidget {
334336
),
335337
],
336338
),
339+
GoRoute(
340+
path: DynamicFractalTreeInputsPage.routeName,
341+
pageBuilder:
342+
(BuildContext context, GoRouterState state) {
343+
return MaterialPage(
344+
restorationId:
345+
'router.root.knowledge.dynamic_fractal_inputs',
346+
child: DynamicFractalTreeInputsPage(),
347+
);
348+
},
349+
routes: <RouteBase>[
350+
GoRoute(
351+
path: ConfirmationPage.routeName,
352+
pageBuilder: (BuildContext context,
353+
GoRouterState state) {
354+
return const MaterialPage(
355+
restorationId: 'router.root.knowledge.'
356+
'dynamic_fractal_inputs.confirmation',
357+
child: ConfirmationPage(),
358+
);
359+
},
360+
),
361+
],
362+
),
337363
],
338364
),
339365
GoRoute(
@@ -356,12 +382,22 @@ class T3Vault extends StatelessWidget {
356382
);
357383
},
358384
),
385+
GoRoute(
386+
path: DynamicFractalDerivationLevelPage.routeName,
387+
pageBuilder:
388+
(BuildContext context, GoRouterState state) {
389+
return const MaterialPage(
390+
restorationId: 'router.root.dynamic_fractal_derivation_level',
391+
child: DynamicFractalDerivationLevelPage(),
392+
);
393+
},
394+
),
359395
GoRoute(
360396
path: DerivationResultPage.routeName,
361397
pageBuilder:
362398
(BuildContext context, GoRouterState state) {
363399
return const MaterialPage(
364-
restorationId: 'router.root.derivation_result',
400+
restorationId: 'router.root.dynamic_fractal_derivation_level_page',
365401
child: DerivationResultPage(),
366402
);
367403
},

lib/src/common/localization/app_en.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
"@formosaTreeInputsPageTitle": {
2525
"description": "Formosa Tree Inputs Page: Title of the page"
2626
},
27+
"dynamicFractalTreeInputsPageTitle": "Dynamic Fractal Input Parameters",
28+
"@dynamicFractalTreeInputsPageTitle": {
29+
"description": "Dynamic Fractal Tree Inputs Page: Title of the page"
30+
},
2731
"confirmationPageTitle": "Confirmation",
2832
"@confirmationPageTitle": {
2933
"description": "Confirmation Page: Title of the page"

lib/src/features/greatwall/presentation/blocs/greatwall/greatwall_bloc.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ class GreatWallBloc extends Bloc<GreatWallEvent, GreatWallState> {
3232
await Future<void>.delayed(
3333
const Duration(seconds: 1),
3434
() {
35-
_greatWall!.makeTacitDerivation(choice: event.choiceNumber.toString());
35+
_greatWall!.makeTacitDerivation(choice: event.choice);
3636
},
3737
);
38-
if (event.choiceNumber == 0 && _currentLevel > 1) {
38+
if (event.choice == "0" && _currentLevel > 1) {
3939
_currentLevel--;
4040
} else {
4141
_currentLevel++;

lib/src/features/greatwall/presentation/blocs/greatwall/greatwall_event.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ final class GreatWallPasswordVisibilityToggled extends GreatWallEvent {}
7373
final class GreatWallDerivationStarted extends GreatWallEvent {}
7474

7575
final class GreatWallDerivationStepMade extends GreatWallEvent {
76-
final int choiceNumber;
76+
final String choice;
7777

78-
GreatWallDerivationStepMade(this.choiceNumber);
78+
GreatWallDerivationStepMade(this.choice);
7979

8080
@override
81-
List<Object> get props => [choiceNumber];
81+
List<Object> get props => [choice];
8282
}
8383

8484
final class GreatWallDerivationFinished extends GreatWallEvent {}

lib/src/features/greatwall/presentation/pages/confirmation_page.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
22
import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'package:go_router/go_router.dart';
44
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
5+
import 'package:great_wall/great_wall.dart';
6+
import 'package:t3_vault/src/features/greatwall/presentation/pages/dynamic_fractal_derivation_level_page.dart';
57
import 'package:t3_vault/src/features/greatwall/states/derivation_state.dart';
68

79
import '../../../../common/settings/presentation/pages/settings_page.dart';
@@ -87,7 +89,11 @@ class ConfirmationPage extends StatelessWidget {
8789
context
8890
.read<GreatWallBloc>()
8991
.add(GreatWallDerivationStarted());
90-
context.go('/${DerivationLevelPage.routeName}');
92+
if((state.tacitKnowledge) is DynamicFractalTacitKnowledge) {
93+
context.go('/${DynamicFractalDerivationLevelPage.routeName}');
94+
} else {
95+
context.go('/${DerivationLevelPage.routeName}');
96+
}
9197
},
9298
);
9399
},

lib/src/features/greatwall/presentation/pages/derivation_level_page.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class DerivationLevelPage extends StatelessWidget {
5353
if (state.currentLevel > 1) {
5454
context
5555
.read<GreatWallBloc>()
56-
.add(GreatWallDerivationStepMade(0));
56+
.add(GreatWallDerivationStepMade("0"));
5757
context.go('/${DerivationLevelPage.routeName}');
5858
}
5959
},
@@ -80,7 +80,7 @@ class DerivationLevelPage extends StatelessWidget {
8080
() {
8181
if (!context.mounted) return;
8282
context.read<GreatWallBloc>().add(
83-
GreatWallDerivationStepMade(index + 1));
83+
GreatWallDerivationStepMade((index + 1).toString()));
8484
if (state.currentLevel < state.treeDepth) {
8585
context.go(
8686
'/${DerivationLevelPage.routeName}',
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
import 'dart:ui';
2+
import 'package:flutter/gestures.dart';
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_bloc/flutter_bloc.dart';
5+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
6+
import 'package:go_router/go_router.dart';
7+
8+
9+
import '../../../../common/settings/presentation/pages/settings_page.dart';
10+
import '../blocs/blocs.dart';
11+
import 'derivation_result_page.dart';
12+
13+
class DynamicFractalDerivationLevelPage extends StatefulWidget {
14+
static const routeName = 'dynamic_fractal_derivation_level';
15+
16+
const DynamicFractalDerivationLevelPage({super.key});
17+
18+
@override
19+
State<DynamicFractalDerivationLevelPage> createState() {
20+
return _DynamicFractalDerivationLevelPageState();
21+
}
22+
}
23+
24+
class _DynamicFractalDerivationLevelPageState
25+
extends State<DynamicFractalDerivationLevelPage> {
26+
final Offset exponent = const Offset(2.0, 0.0);
27+
FragmentShader? _shader; // Nullable until initialized
28+
double _zoom = 2.00000000;
29+
Offset _offset = const Offset(0.00000000, 0.00000000);
30+
Offset _selectedPosition = const Offset(0.00000000, 0.00000000);
31+
final double _gridSize = 0.00001;
32+
33+
final int _maxIterations = 100; // todo: max iterations
34+
35+
@override
36+
void initState() {
37+
WidgetsBinding.instance.addPostFrameCallback((_) {
38+
_loadShader();
39+
});
40+
super.initState();
41+
_offset = _offset - const Offset(1.0, 1.0);
42+
}
43+
44+
void _loadShader() async {
45+
try {
46+
final program =
47+
await FragmentProgram.fromAsset('shaders/burningShipShader.frag');
48+
setState(() {
49+
_shader = program.fragmentShader(); // Initialize the shader
50+
});
51+
} catch (e) {
52+
print('Failed to load shader: $e');
53+
}
54+
}
55+
56+
@override
57+
Widget build(BuildContext context) {
58+
return Scaffold(
59+
appBar: AppBar(
60+
title: Text(AppLocalizations.of(context)!.derivationLevelPageTitle),
61+
leading: IconButton(
62+
icon: const Icon(Icons.arrow_back),
63+
onPressed: () {
64+
context.read<GreatWallBloc>().add(GreatWallReset());
65+
Navigator.of(context).pop();
66+
},
67+
),
68+
actions: [
69+
IconButton(
70+
icon: const Icon(Icons.settings),
71+
onPressed: () {
72+
context.go('/${SettingsPage.routeName}');
73+
},
74+
),
75+
],
76+
),
77+
body: Center(
78+
child: BlocBuilder<GreatWallBloc, GreatWallState>(
79+
builder: (context, state) {
80+
if (state is GreatWallDeriveInProgress) {
81+
return const Center(
82+
child: CircularProgressIndicator(),
83+
);
84+
} else if (state is GreatWallDeriveStepSuccess) {
85+
return _shader == null
86+
? const Center(
87+
child: CircularProgressIndicator()) // Show a loading indicator
88+
: Listener(
89+
onPointerSignal: (PointerSignalEvent event) {
90+
// this just changes the zoom, do not change offset here
91+
if (event is PointerScrollEvent) {
92+
setState(() {
93+
// Adjust zoom level based on scroll delta
94+
var zoomFactor = event.scrollDelta.dy > 0 ? 1.1 : 0.9;
95+
96+
var zoomDelta = zoomFactor *
97+
zoomFactor *
98+
(event.scrollDelta.dy > 0 ? 1 : -1);
99+
_zoom *= zoomFactor;
100+
print("position ${event.position}");
101+
102+
print(_zoom);
103+
});
104+
}
105+
},
106+
child: GestureDetector(
107+
onTapDown: (details) {
108+
setState(() {
109+
var aspectRatio = MediaQuery.of(context).size.width /
110+
MediaQuery.of(context).size.height;
111+
var mouseX = details.localPosition.dx /
112+
MediaQuery.of(context).size.width;
113+
var mouseY = details.localPosition.dy /
114+
MediaQuery.of(context).size.height;
115+
var posX = mouseX * _zoom * aspectRatio +
116+
_offset.dx +
117+
0.5 * _gridSize;
118+
var posY = mouseY * _zoom + _offset.dy + 0.5 * _gridSize;
119+
posX = double.parse(posX.toStringAsFixed(5)) -
120+
0.5 * _gridSize;
121+
posY = double.parse(posY.toStringAsFixed(5)) -
122+
0.5 * _gridSize;
123+
posX = double.parse(posX.toStringAsFixed(6));
124+
posY = double.parse(posY.toStringAsFixed(6));
125+
print(details.localPosition);
126+
_selectedPosition = Offset(posX, posY);
127+
print('${_selectedPosition.dx}, ${_selectedPosition.dy}');
128+
});
129+
},
130+
onScaleUpdate: (details) {
131+
setState(() {
132+
// this changes the zoom and offset
133+
134+
if (details.scale != 1.0) {
135+
var zoomFactor = details.scale < 1.0 ? 1.01 : 0.99;
136+
//
137+
_zoom *= zoomFactor * details.scale;
138+
print("scale ${details.scale.clamp(0.9999, 1.0001)}");
139+
print("zoom $_zoom");
140+
}
141+
// handle pan
142+
143+
_offset =
144+
_offset - details.focalPointDelta * _zoom * 0.001;
145+
});
146+
},
147+
child: Scaffold(
148+
body: CustomPaint(
149+
painter: _BurningShipAdvFractalPainter(
150+
shader: _shader!,
151+
zoom: _zoom,
152+
offset: _offset,
153+
maxIterations: _maxIterations,
154+
gridSize: _gridSize,
155+
selectedPosition: _selectedPosition,
156+
exponent: exponent,
157+
),
158+
size: Size.infinite,
159+
),
160+
floatingActionButton: FloatingActionButton(
161+
onPressed: () {
162+
Future.delayed(
163+
const Duration(seconds: 1),
164+
() {
165+
if (!context.mounted) return;
166+
if (state.currentLevel < state.treeDepth) {
167+
print("x: ${_selectedPosition.dx}, y: ${_selectedPosition.dy} submitted");
168+
context
169+
.read<GreatWallBloc>()
170+
.add(GreatWallDerivationStepMade("x: ${_selectedPosition.dx}, y: ${_selectedPosition.dy}"));
171+
context.go('/${DynamicFractalDerivationLevelPage.routeName}');
172+
} else {
173+
print("process completed");
174+
context
175+
.read<GreatWallBloc>()
176+
.add(GreatWallDerivationFinished());
177+
context.go(
178+
'/${DerivationResultPage.routeName}',
179+
);
180+
}
181+
},
182+
);
183+
184+
// widget.onSubmit(_selectedPosition);
185+
},
186+
child: const Icon(Icons.check),
187+
),
188+
),
189+
)
190+
);
191+
} else {
192+
return Center(
193+
child: Text(AppLocalizations.of(context)!.noLevel),
194+
);
195+
}
196+
}
197+
),
198+
),
199+
);
200+
}
201+
}
202+
203+
class _BurningShipAdvFractalPainter extends CustomPainter {
204+
final FragmentShader shader;
205+
final double zoom;
206+
final Offset offset;
207+
final int maxIterations;
208+
final double gridSize;
209+
Offset selectedPosition;
210+
Offset exponent;
211+
212+
_BurningShipAdvFractalPainter({
213+
required this.shader,
214+
required this.zoom,
215+
required this.offset,
216+
required this.maxIterations,
217+
required this.gridSize,
218+
required this.selectedPosition,
219+
required this.exponent,
220+
});
221+
222+
@override
223+
void paint(Canvas canvas, Size size) {
224+
shader.setFloat(0, size.width);
225+
shader.setFloat(1, size.height);
226+
shader.setFloat(2, offset.dx);
227+
shader.setFloat(3, offset.dy);
228+
shader.setFloat(4, zoom);
229+
shader.setFloat(5, maxIterations.toDouble());
230+
shader.setFloat(6, gridSize);
231+
shader.setFloat(7, selectedPosition.dx);
232+
shader.setFloat(8, selectedPosition.dy);
233+
shader.setFloat(9, exponent.dx);
234+
shader.setFloat(10, exponent.dy);
235+
236+
final paint = Paint()..shader = shader;
237+
238+
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
239+
}
240+
241+
@override
242+
bool shouldRepaint(covariant CustomPainter oldDelegate) {
243+
return true;
244+
}
245+
}

0 commit comments

Comments
 (0)