forked from visual-space/visual-editor
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
15 Toolbar - Headings dropdown after text size
- Loading branch information
1 parent
7d4e80c
commit 4ca6bbf
Showing
8 changed files
with
129 additions
and
237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Default header styles used in the editor | ||
// Every style is linked to the suitable attribute | ||
const Map<String, int> HEADER_STYLES = { | ||
'N': 0, | ||
'H1': 1, | ||
'H2': 2, | ||
'H3': 3, | ||
}; | ||
|
||
const INITIAL_HEADER_STYLE = 0; |
191 changes: 0 additions & 191 deletions
191
lib/toolbar/widgets/buttons/select-header-style-buttons.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,191 +0,0 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:flutter/foundation.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
import '../../../controller/controllers/editor-controller.dart'; | ||
import '../../../document/models/attributes/attribute.model.dart'; | ||
import '../../../document/models/attributes/attributes-aliases.model.dart'; | ||
import '../../../document/models/attributes/attributes.model.dart'; | ||
import '../../../editor/services/run-build.service.dart'; | ||
import '../../../shared/models/editor-icon-theme.model.dart'; | ||
import '../../../shared/state/editor-state-receiver.dart'; | ||
import '../../../shared/state/editor.state.dart'; | ||
import '../../../styles/services/styles.service.dart'; | ||
import '../../services/toolbar.service.dart'; | ||
import '../toolbar.dart'; | ||
|
||
// Lists the 3 (currently hardcoded) heading types. | ||
// To be replaced with a dropdown in the future. | ||
// TODO Split in methods | ||
// ignore: must_be_immutable | ||
class SelectHeaderStyleButtons extends StatefulWidget with EditorStateReceiver { | ||
final EditorController controller; | ||
final double iconSize; | ||
final double buttonsSpacing; | ||
final EditorIconThemeM? iconTheme; | ||
late EditorState _state; | ||
|
||
SelectHeaderStyleButtons({ | ||
required this.controller, | ||
required this.buttonsSpacing, | ||
this.iconSize = defaultIconSize, | ||
this.iconTheme, | ||
Key? key, | ||
}) : super(key: key) { | ||
controller.setStateInEditorStateReceiver(this); | ||
} | ||
|
||
@override | ||
_SelectHeaderStyleButtonsState createState() => _SelectHeaderStyleButtonsState(); | ||
|
||
@override | ||
void cacheStateStore(EditorState state) { | ||
_state = state; | ||
} | ||
} | ||
|
||
class _SelectHeaderStyleButtonsState extends State<SelectHeaderStyleButtons> { | ||
late final RunBuildService _runBuildService; | ||
late final ToolbarService _toolbarService; | ||
late final StylesService _stylesService; | ||
|
||
AttributeM? _attr; | ||
StreamSubscription? _runBuild$L; | ||
|
||
@override | ||
void initState() { | ||
_runBuildService = RunBuildService(widget._state); | ||
_toolbarService = ToolbarService(widget._state); | ||
_stylesService = StylesService(widget._state); | ||
|
||
_attr = _getHeaderAttr(); | ||
|
||
_subscribeToRunBuild(); | ||
super.initState(); | ||
} | ||
|
||
@override | ||
void didUpdateWidget(covariant SelectHeaderStyleButtons oldWidget) { | ||
super.didUpdateWidget(oldWidget); | ||
|
||
// If a new controller was generated by setState() in the parent | ||
// we need to subscribe to the new state store. | ||
if (oldWidget.controller != widget.controller) { | ||
_runBuild$L?.cancel(); | ||
widget.controller.setStateInEditorStateReceiver(widget); | ||
_subscribeToRunBuild(); | ||
_attr = _getHeaderAttr(); | ||
} | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_runBuild$L?.cancel(); | ||
super.dispose(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final _valueToText = <AttributeM, String>{ | ||
AttributesM.header: 'N', | ||
AttributesAliasesM.h1: 'H1', | ||
AttributesAliasesM.h2: 'H2', | ||
AttributesAliasesM.h3: 'H3', | ||
}; | ||
|
||
final _valueAttribute = <AttributeM>[AttributesM.header, AttributesAliasesM.h1, AttributesAliasesM.h2, AttributesAliasesM.h3]; | ||
final _valueString = <String>['N', 'H1', 'H2', 'H3']; | ||
|
||
final theme = Theme.of(context); | ||
final style = TextStyle( | ||
fontWeight: FontWeight.w600, | ||
fontSize: widget.iconSize * 0.7, | ||
); | ||
|
||
return Row( | ||
mainAxisSize: MainAxisSize.min, | ||
children: List.generate(4, (index) { | ||
return Container( | ||
// ignore: prefer_const_constructors | ||
margin: EdgeInsets.symmetric( | ||
horizontal: !kIsWeb ? 1.0 : widget.buttonsSpacing, | ||
), | ||
child: ConstrainedBox( | ||
constraints: BoxConstraints.tightFor( | ||
width: widget.iconSize * iconButtonFactor, | ||
height: widget.iconSize * iconButtonFactor, | ||
), | ||
child: RawMaterialButton( | ||
hoverElevation: 0, | ||
highlightElevation: 0, | ||
elevation: 0, | ||
visualDensity: VisualDensity.compact, | ||
shape: RoundedRectangleBorder( | ||
borderRadius: BorderRadius.circular( | ||
widget.iconTheme?.borderRadius ?? 2, | ||
), | ||
), | ||
fillColor: _valueToText[_attr] == _valueString[index] | ||
? (widget.iconTheme?.iconSelectedFillColor ?? theme.toggleableActiveColor) | ||
: (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor), | ||
|
||
// Export a nice and clean version of this method in the styles service. Similar to other buttons. | ||
onPressed: isEnabled | ||
? () => _stylesService.formatSelection( | ||
_valueAttribute[index], | ||
) | ||
: null, | ||
child: Text( | ||
_valueString[index], | ||
style: style.copyWith( | ||
color: isEnabled | ||
? _valueToText[_attr] == _valueString[index] | ||
? (widget.iconTheme?.iconSelectedColor ?? theme.primaryIconTheme.color) | ||
: (widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color) | ||
: theme.disabledColor, | ||
), | ||
), | ||
), | ||
), | ||
); | ||
}), | ||
); | ||
} | ||
|
||
// === PRIVATE === | ||
|
||
bool get isEnabled => _toolbarService.isStylingEnabled; | ||
|
||
void _subscribeToRunBuild() { | ||
_runBuild$L = _runBuildService.runBuild$.listen( | ||
(_) => setState(() { | ||
_attr = _getHeaderAttr(); | ||
}), | ||
); | ||
} | ||
|
||
AttributeM? _getHeaderAttr() { | ||
if (!_documentControllerInitialised) { | ||
return null; | ||
} | ||
|
||
final toggler = _toolbarService.getToolbarButtonToggler(); | ||
final attribute = toggler[AttributesM.header.key]; | ||
|
||
if (attribute != null) { | ||
// Checkbox tapping causes text selection to go to offset 0 | ||
toggler.remove(AttributesM.header.key); | ||
|
||
return attribute; | ||
} | ||
|
||
final selectionStyle = _stylesService.getSelectionStyle(); | ||
|
||
return selectionStyle.attributes[AttributesM.header.key] ?? AttributesM.header; | ||
} | ||
|
||
bool get _documentControllerInitialised { | ||
return widget._state.refs.documentControllerInitialised == true; | ||
} | ||
} | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
import '../../../controller/controllers/editor-controller.dart'; | ||
import '../../../document/models/attributes/attribute.model.dart'; | ||
import '../../../document/models/attributes/attributes-aliases.model.dart'; | ||
import '../../../document/models/attributes/attributes.model.dart'; | ||
import '../../../shared/models/editor-icon-theme.model.dart'; | ||
import '../../../shared/state/editor-state-receiver.dart'; | ||
import '../../../shared/state/editor.state.dart'; | ||
import '../../../shared/widgets/editor-dropdown.dart'; | ||
import '../../../styles/services/styles.service.dart'; | ||
import '../../models/dropdown-option.model.dart'; | ||
|
||
// Controls the header style of the currently selected text. | ||
// ignore: must_be_immutable | ||
class HeaderStylesDropdown extends StatelessWidget | ||
with EditorStateReceiver { | ||
late final StylesService _stylesService; | ||
|
||
final Map<String, int> headerStyles; | ||
final double iconSize; | ||
final EditorIconThemeM? iconTheme; | ||
final EditorController controller; | ||
int initialHeaderStyleValue; | ||
late List<DropDownOptionM<int>> options; | ||
late EditorState _state; | ||
|
||
HeaderStylesDropdown({ | ||
required this.headerStyles, | ||
required this.controller, | ||
required this.initialHeaderStyleValue, | ||
this.iconSize = 40, | ||
this.iconTheme, | ||
Key? key, | ||
}) : super(key: key) { | ||
controller.setStateInEditorStateReceiver(this); | ||
_stylesService = StylesService(_state); | ||
|
||
options = _mapStylesToDropdownOptions(headerStyles); | ||
} | ||
|
||
@override | ||
void cacheStateStore(EditorState state) { | ||
_state = state; | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) => EditorDropdown<int>( | ||
iconTheme: iconTheme, | ||
iconSize: iconSize, | ||
attribute: AttributesM.header, | ||
controller: controller, | ||
options: options, | ||
initialValue: _getInitialHeaderStyle(), | ||
onSelected: (style) => _stylesService.formatSelection( | ||
_getHeaderAttributeByStyle(style.value), | ||
), | ||
); | ||
|
||
List<DropDownOptionM<int>> _getInitialHeaderStyle() { | ||
return [ | ||
options.firstWhere( | ||
(option) => option.value == initialHeaderStyleValue, | ||
), | ||
]; | ||
} | ||
|
||
List<DropDownOptionM<int>> _mapStylesToDropdownOptions( | ||
Map<String, int> headerStyles, | ||
) => | ||
headerStyles.entries | ||
.map( | ||
(style) => DropDownOptionM( | ||
name: style.key, | ||
value: style.value, | ||
), | ||
) | ||
.toList(); | ||
|
||
AttributeM _getHeaderAttributeByStyle(int size) { | ||
if (size == 1) { | ||
return AttributesAliasesM.h1; | ||
} | ||
if (size == 2) { | ||
return AttributesAliasesM.h2; | ||
} | ||
if (size == 3) { | ||
return AttributesAliasesM.h3; | ||
} | ||
|
||
// Normal text | ||
return AttributesM.header; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.