diff --git a/src/ui/flutter_app/lib/l10n/intl_de.arb b/src/ui/flutter_app/lib/l10n/intl_de.arb index f6424f5a..3d16e40b 100644 --- a/src/ui/flutter_app/lib/l10n/intl_de.arb +++ b/src/ui/flutter_app/lib/l10n/intl_de.arb @@ -208,6 +208,14 @@ "@startNewGame": { "description": "Start new game" }, + "importGame": "Spiel importieren", + "@importGame": { + "description": "Import game" + }, + "gameImported": "Spiel aus der Zwischenablage importiert.", + "@gameImported": { + "description": "Game imported from clipboard." + }, "startRecording": "Starte die Aufnahme", "@startRecording": { "description": "Start recording" diff --git a/src/ui/flutter_app/lib/l10n/intl_en.arb b/src/ui/flutter_app/lib/l10n/intl_en.arb index 76289495..67b473ca 100644 --- a/src/ui/flutter_app/lib/l10n/intl_en.arb +++ b/src/ui/flutter_app/lib/l10n/intl_en.arb @@ -208,6 +208,14 @@ "@startNewGame": { "description": "Start new game" }, + "importGame": "Import game", + "@importGame": { + "description": "Import game" + }, + "gameImported": "Game imported from clipboard.", + "@gameImported": { + "description": "Game imported from clipboard." + }, "startRecording": "Start recording", "@startRecording": { "description": "Start recording" diff --git a/src/ui/flutter_app/lib/l10n/intl_fa.arb b/src/ui/flutter_app/lib/l10n/intl_fa.arb index 96651bfa..3f9556f8 100644 --- a/src/ui/flutter_app/lib/l10n/intl_fa.arb +++ b/src/ui/flutter_app/lib/l10n/intl_fa.arb @@ -208,6 +208,14 @@ "@startNewGame": { "description": "Start new game" }, + "importGame": "وارد کردن بازی", + "@importGame": { + "description": "Import game" + }, + "gameImported": "بازی از کلیپ بورد وارد شده است.", + "@gameImported": { + "description": "Game imported from clipboard." + }, "startRecording": "شروع به ضبط کنید", "@startRecording": { "description": "Start recording" diff --git a/src/ui/flutter_app/lib/l10n/intl_zh.arb b/src/ui/flutter_app/lib/l10n/intl_zh.arb index ebe5d310..0ef6754d 100644 --- a/src/ui/flutter_app/lib/l10n/intl_zh.arb +++ b/src/ui/flutter_app/lib/l10n/intl_zh.arb @@ -52,6 +52,8 @@ "thinking": "对方思考中...", "newGame": "新局", "startNewGame": "开始新局", + "importGame": "导入棋谱", + "gameImported": "棋谱已从剪贴板导入", "startRecording": "开始录制", "recording": "录制中...", "stopRecording": "停止录制", diff --git a/src/ui/flutter_app/lib/mill/recorder.dart b/src/ui/flutter_app/lib/mill/recorder.dart index 63b014cf..6710563b 100644 --- a/src/ui/flutter_app/lib/mill/recorder.dart +++ b/src/ui/flutter_app/lib/mill/recorder.dart @@ -26,6 +26,7 @@ class GameRecorder { int cur = -1; String? lastPositionWithRemove = ""; var _history = []; + final tag = "[GameRecorder]"; GameRecorder({this.cur = -1, this.lastPositionWithRemove}); @@ -37,6 +38,76 @@ class GameRecorder { _history = newHistory; } + String parseNotation(String ntt) { + String move = ""; + + if (ntt.length == 3 && ntt[0] == "x") { + if (notationToMove[ntt.substring(1, 3)] != null) { + move = '-' + notationToMove[ntt.substring(1, 3)]!; + } + } else if (ntt.length == 2) { + if (notationToMove[ntt] != null) { + move = notationToMove[ntt]!; + } + } else if (ntt.length == 5 && ntt[2] == '-') { + if (notationToMove[(ntt.substring(0, 2))] != null && + notationToMove[(ntt.substring(3, 5))] != null) { + move = notationToMove[(ntt.substring(0, 2))]! + + '->' + + notationToMove[(ntt.substring(3, 5))]!; + } + } else if ((ntt.length == 8 && ntt[2] == '-' && ntt[5] == 'x') || + (ntt.length == 5 && ntt[2] == 'x')) { + print("$tag Not support parsing format oo-ooxo notation."); + } else { + print("$tag Parse notation $ntt failed."); + } + + return move; + } + + void import(String moveList) { + List newHistory = []; + List list = moveList.split(' '); + + for (var i in list) { + i = i.trim(); + if (i.length > 0 && !i.endsWith(".")) { + if (i.length == 5 && i[2] == 'x') { + // "a1xc3" + String m1 = parseNotation(i.substring(0, 2)); + if (m1 != "") { + newHistory.add(Move(m1)); + } + String m2 = parseNotation(i.substring(2)); + if (m2 != "") { + newHistory.add(Move(m2)); + } + } else if (i.length == 8 && i[2] == '-' && i[5] == 'x') { + // "a1-b2xc3" + String m1 = parseNotation(i.substring(0, 5)); + if (m1 != "") { + newHistory.add(Move(m1)); + } + String m2 = parseNotation(i.substring(5)); + if (m2 != "") { + newHistory.add(Move(m2)); + } + } else { + // no x + String m = parseNotation(i); + if (m != "") { + newHistory.add(Move(m)); + } + } + } + } + + if (newHistory.length > 0) { + setHistory(newHistory); + } + } + void jumpToHead() { cur = 0; } diff --git a/src/ui/flutter_app/lib/mill/types.dart b/src/ui/flutter_app/lib/mill/types.dart index 703d863f..5fc80f30 100644 --- a/src/ui/flutter_app/lib/mill/types.dart +++ b/src/ui/flutter_app/lib/mill/types.dart @@ -323,6 +323,8 @@ Map squareToIndex = { 31: 0 }; +Map indexToSquare = squareToIndex.map((k, v) => MapEntry(v, k)); + /* a b c d e f g 7 X --- X --- X 7 @@ -365,6 +367,31 @@ Map squareToNotation = { 31: "a7" }; -Map indexToSquare = squareToIndex.map((k, v) => MapEntry(v, k)); +Map notationToMove = { + "d5": "(1,1)", + "e5": "(1,2)", + "e4": "(1,3)", + "e3": "(1,4)", + "d3": "(1,5)", + "c3": "(1,6)", + "c4": "(1,7)", + "c5": "(1,8)", + "d6": "(2,1)", + "f6": "(2,2)", + "f4": "(2,3)", + "f2": "(2,4)", + "d2": "(2,5)", + "b2": "(2,6)", + "b4": "(2,7)", + "b6": "(2,8)", + "d7": "(3,1)", + "g7": "(3,2)", + "g4": "(3,3)", + "g1": "(3,4)", + "d1": "(3,5)", + "a1": "(3,6)", + "a4": "(3,7)", + "a7": "(3,8)", +}; enum GameResult { pending, win, lose, draw, none } diff --git a/src/ui/flutter_app/lib/widgets/game_page.dart b/src/ui/flutter_app/lib/widgets/game_page.dart index 8edff90b..8123183c 100644 --- a/src/ui/flutter_app/lib/widgets/game_page.dart +++ b/src/ui/flutter_app/lib/widgets/game_page.dart @@ -549,6 +549,28 @@ class _GamePageState extends State } } + onImportGameButtonPressed() async { + Navigator.of(context).pop(); + + ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); + + if (data == null || data.text == null) { + return; + } + + String text = data.text!; + + print("Clipboard text:"); + print('$text'); + + await onTakeBackAllButtonPressed(pop: false); + await Game.instance.position.recorder.clear(); + await Game.instance.position.recorder.import(text); + await onStepForwardAllButtonPressed(pop: false); + + showTip(S.of(context).gameImported); + } + /* onStartRecordingButtonPressed() async { Navigator.of(context).pop(); @@ -655,6 +677,15 @@ class _GamePageState extends State ), onPressed: onStartNewGameButtonPressed, ), + SizedBox(height: AppTheme.sizedBoxHeight), + SimpleDialogOption( + child: Text( + S.of(context).importGame, + style: AppTheme.simpleDialogOptionTextStyle, + textAlign: TextAlign.center, + ), + onPressed: onImportGameButtonPressed, + ), /* SizedBox(height: AppTheme.sizedBoxHeight), Config.experimentsEnabled