Add keyboard shortcuts for usage with BT Pedal
This commit is contained in:
42
lib/bt_pedal_shortcuts.dart
Normal file
42
lib/bt_pedal_shortcuts.dart
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class BtPedalShortcuts extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
final VoidCallback? onTurnPageForward;
|
||||||
|
final VoidCallback? onTurnPageBackward;
|
||||||
|
|
||||||
|
const BtPedalShortcuts({
|
||||||
|
super.key,
|
||||||
|
required this.child,
|
||||||
|
this.onTurnPageForward,
|
||||||
|
this.onTurnPageBackward,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BtPedalShortcuts> createState() => _BtPedalShortcutsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BtPedalShortcutsState extends State<BtPedalShortcuts> {
|
||||||
|
String lastAction = "Press pedal...";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CallbackShortcuts(
|
||||||
|
bindings: <ShortcutActivator, VoidCallback>{
|
||||||
|
// Shortcuts for page forward
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowUp):
|
||||||
|
widget.onTurnPageForward ?? () => {},
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowRight):
|
||||||
|
widget.onTurnPageForward ?? () => {},
|
||||||
|
|
||||||
|
// Shortcuts for page backward
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowDown):
|
||||||
|
widget.onTurnPageBackward ?? () => {},
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowLeft):
|
||||||
|
widget.onTurnPageBackward ?? () => {},
|
||||||
|
},
|
||||||
|
child: Focus(autofocus: true, child: widget.child),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import 'package:flutter_drawing_board/flutter_drawing_board.dart';
|
|||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:pdfrx/pdfrx.dart';
|
import 'package:pdfrx/pdfrx.dart';
|
||||||
import 'package:sheetless/api.dart';
|
import 'package:sheetless/api.dart';
|
||||||
|
import 'package:sheetless/bt_pedal_shortcuts.dart';
|
||||||
import 'package:sheetless/sheet.dart';
|
import 'package:sheetless/sheet.dart';
|
||||||
import 'package:sheetless/storage_helper.dart';
|
import 'package:sheetless/storage_helper.dart';
|
||||||
|
|
||||||
@@ -86,192 +87,203 @@ class _SheetViewerPageState extends State<SheetViewerPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void turnPage(int numTurns) {
|
||||||
|
setState(() {
|
||||||
|
page += numTurns;
|
||||||
|
page = page.clamp(1, numPages);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return BtPedalShortcuts(
|
||||||
appBar: AppBar(
|
onTurnPageForward: () => turnPage(1),
|
||||||
title: Text(widget.sheet.name),
|
onTurnPageBackward: () => turnPage(-1),
|
||||||
actions: [
|
child: Scaffold(
|
||||||
IconButton(
|
appBar: AppBar(
|
||||||
onPressed: () {
|
title: Text(widget.sheet.name),
|
||||||
setState(() {
|
actions: [
|
||||||
if (widget.config.twoPageMode) {
|
IconButton(
|
||||||
// TODO: notification that paint mode only in single page mode
|
onPressed: () {
|
||||||
} else {
|
setState(() {
|
||||||
paintMode = !paintMode;
|
if (widget.config.twoPageMode) {
|
||||||
}
|
// TODO: notification that paint mode only in single page mode
|
||||||
});
|
} else {
|
||||||
},
|
paintMode = !paintMode;
|
||||||
icon: Icon(Icons.brush),
|
}
|
||||||
),
|
});
|
||||||
IconButton(
|
},
|
||||||
onPressed: () {
|
icon: Icon(Icons.brush),
|
||||||
setState(() {
|
|
||||||
widget.config.twoPageMode = !widget.config.twoPageMode;
|
|
||||||
storageHelper.writeConfig(widget.config);
|
|
||||||
if (widget.config.twoPageMode) {
|
|
||||||
paintMode = false;
|
|
||||||
// TODO: notification that paint mode was deactivated since only possible in single page mode
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
widget.config.twoPageMode ? Icons.filter_1 : Icons.filter_2,
|
|
||||||
),
|
),
|
||||||
),
|
IconButton(
|
||||||
],
|
onPressed: () {
|
||||||
),
|
setState(() {
|
||||||
body: FutureBuilder(
|
widget.config.twoPageMode = !widget.config.twoPageMode;
|
||||||
future: documentLoaded,
|
storageHelper.writeConfig(widget.config);
|
||||||
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
|
if (widget.config.twoPageMode) {
|
||||||
if (snapshot.hasData && document != null) {
|
paintMode = false;
|
||||||
numPages = document!.pages.length;
|
// TODO: notification that paint mode was deactivated since only possible in single page mode
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
widget.config.twoPageMode ? Icons.filter_1 : Icons.filter_2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: documentLoaded,
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
|
||||||
|
if (snapshot.hasData && document != null) {
|
||||||
|
numPages = document!.pages.length;
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: !paintMode,
|
visible: !paintMode,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTapUp: (TapUpDetails details) {
|
onTapUp: (TapUpDetails details) {
|
||||||
// Get the size of the screen
|
// Get the size of the screen
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(
|
||||||
|
context,
|
||||||
|
).size.width;
|
||||||
|
|
||||||
// print("Touch at y = ${details.localPosition.dy}");
|
// print("Touch at y = ${details.localPosition.dy}");
|
||||||
// print("Touch at x = ${details.localPosition.dx}");
|
// print("Touch at x = ${details.localPosition.dx}");
|
||||||
// print("Screenwidth = ${screenWidth}");
|
// print("Screenwidth = ${screenWidth}");
|
||||||
// Check where the user tapped
|
// Check where the user tapped
|
||||||
// if (details.localPosition.dy < 100) {
|
// if (details.localPosition.dy < 100) {
|
||||||
// TODO
|
// TODO
|
||||||
// setState(() {
|
// setState(() {
|
||||||
// toggleFullscreen();
|
// toggleFullscreen();
|
||||||
// });
|
// });
|
||||||
if (details.localPosition.dx < screenWidth / 2) {
|
if (details.localPosition.dx < screenWidth / 2) {
|
||||||
// Left half of the screen
|
// Left half of the screen
|
||||||
setState(() {
|
turnPage(-1);
|
||||||
page = page > 1 ? page - 1 : 1;
|
} else {
|
||||||
});
|
// Right half of the screen
|
||||||
} else {
|
turnPage(1);
|
||||||
// Right half of the screen
|
}
|
||||||
setState(() {
|
},
|
||||||
page = page < numPages ? page + 1 : numPages;
|
child: Row(
|
||||||
});
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
}
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
},
|
spacing: 0,
|
||||||
child: Row(
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
Expanded(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
spacing: 0,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
PdfPageView(
|
|
||||||
key: ValueKey(page),
|
|
||||||
document: document,
|
|
||||||
pageNumber: page,
|
|
||||||
maximumDpi: 300,
|
|
||||||
alignment: widget.config.twoPageMode
|
|
||||||
? Alignment.centerRight
|
|
||||||
: Alignment.center,
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: Container(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
padding: EdgeInsets.only(bottom: 5),
|
|
||||||
child: Text('$page / $numPages'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
|
||||||
visible: widget.config.twoPageMode == true,
|
|
||||||
child: Expanded(
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
PdfPageView(
|
PdfPageView(
|
||||||
key: ValueKey(page),
|
key: ValueKey(page),
|
||||||
document: document,
|
document: document,
|
||||||
pageNumber: page + 1,
|
pageNumber: page,
|
||||||
maximumDpi: 300,
|
maximumDpi: 300,
|
||||||
alignment: Alignment.centerLeft,
|
alignment: widget.config.twoPageMode
|
||||||
// alignment: Alignment.center,
|
? Alignment.centerRight
|
||||||
|
: Alignment.center,
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
padding: EdgeInsets.only(bottom: 5),
|
padding: EdgeInsets.only(bottom: 5),
|
||||||
child: Text('${page + 1} / $numPages'),
|
child: Text('$page / $numPages'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Visibility(
|
||||||
],
|
visible: widget.config.twoPageMode == true,
|
||||||
),
|
child: Expanded(
|
||||||
),
|
child: Stack(
|
||||||
),
|
children: [
|
||||||
|
PdfPageView(
|
||||||
// Positioned.fill(
|
key: ValueKey(page),
|
||||||
Visibility(
|
document: document,
|
||||||
visible: paintMode,
|
pageNumber: page + 1,
|
||||||
child: SizedBox.expand(
|
maximumDpi: 300,
|
||||||
child: LayoutBuilder(
|
alignment: Alignment.centerLeft,
|
||||||
builder: (context, constraints) {
|
// alignment: Alignment.center,
|
||||||
final maxSize = Size(
|
),
|
||||||
constraints.maxWidth,
|
Positioned.fill(
|
||||||
constraints.maxHeight,
|
child: Container(
|
||||||
);
|
alignment: Alignment.bottomCenter,
|
||||||
final pageSizeUnscaled = document!.pages
|
padding: EdgeInsets.only(bottom: 5),
|
||||||
.elementAt(page)
|
child: Text(
|
||||||
.size;
|
'${page + 1} / $numPages',
|
||||||
final pageSizeScaled = calcScaledPageSize(
|
),
|
||||||
maxSize,
|
),
|
||||||
pageSizeUnscaled,
|
),
|
||||||
);
|
],
|
||||||
return DrawingBoard(
|
),
|
||||||
background: SizedBox(
|
|
||||||
width: pageSizeScaled.width,
|
|
||||||
height: pageSizeScaled.height,
|
|
||||||
child: PdfPageView(
|
|
||||||
document: document,
|
|
||||||
pageNumber: page,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// showDefaultTools: true,
|
],
|
||||||
// showDefaultActions: true,
|
),
|
||||||
boardConstrained: true,
|
|
||||||
minScale: 1,
|
|
||||||
maxScale: 3,
|
|
||||||
alignment: Alignment.topRight,
|
|
||||||
boardBoundaryMargin: EdgeInsets.all(0),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
// Positioned.fill(
|
||||||
|
Visibility(
|
||||||
|
visible: paintMode,
|
||||||
|
child: SizedBox.expand(
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final maxSize = Size(
|
||||||
|
constraints.maxWidth,
|
||||||
|
constraints.maxHeight,
|
||||||
|
);
|
||||||
|
final pageSizeUnscaled = document!.pages
|
||||||
|
.elementAt(page)
|
||||||
|
.size;
|
||||||
|
final pageSizeScaled = calcScaledPageSize(
|
||||||
|
maxSize,
|
||||||
|
pageSizeUnscaled,
|
||||||
|
);
|
||||||
|
return DrawingBoard(
|
||||||
|
background: SizedBox(
|
||||||
|
width: pageSizeScaled.width,
|
||||||
|
height: pageSizeScaled.height,
|
||||||
|
child: PdfPageView(
|
||||||
|
document: document,
|
||||||
|
pageNumber: page,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// showDefaultTools: true,
|
||||||
|
// showDefaultActions: true,
|
||||||
|
boardConstrained: true,
|
||||||
|
minScale: 1,
|
||||||
|
maxScale: 3,
|
||||||
|
alignment: Alignment.topRight,
|
||||||
|
boardBoundaryMargin: EdgeInsets.all(0),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.displaySmall!.copyWith(color: Colors.red),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
snapshot.error.toString(),
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
);
|
} else {
|
||||||
} else if (snapshot.hasError) {
|
return const Center(child: CircularProgressIndicator());
|
||||||
return Center(
|
}
|
||||||
child: Text(
|
},
|
||||||
style: Theme.of(
|
),
|
||||||
context,
|
|
||||||
).textTheme.displaySmall!.copyWith(color: Colors.red),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
snapshot.error.toString(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const Center(child: CircularProgressIndicator());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user