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

Custom launch url function #108

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 1 addition & 4 deletions packages/zefyr/lib/src/widgets/buttons.dart
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,7 @@ class _LinkButtonState extends State<LinkButton> {
final editor = ZefyrToolbar.of(context).editor;
var link = getLink();
assert(link != null);
if (await canLaunch(link)) {
editor.hideKeyboard();
await launch(link, forceWebView: true);
}
await ZefyrToolbar.of(context).editor.onLaunchUrl(link);
}

void _handleInputChange() {
Expand Down
30 changes: 29 additions & 1 deletion packages/zefyr/lib/src/widgets/common.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) 2018, the Zefyr project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:notus/notus.dart';
import 'package:flutter/gestures.dart';

import 'editable_box.dart';
import 'horizontal_rule.dart';
Expand Down Expand Up @@ -110,9 +112,20 @@ class _RawZefyrLineState extends State<RawZefyrLine> {

TextSpan buildText(BuildContext context) {
final theme = ZefyrTheme.of(context);
final List<TextSpan> children = widget.node.children

List<TextSpan> children;

if(ZefyrScope.of(context).isEditable) {
children = widget.node.children
.map((node) => _segmentToTextSpan(node, theme))
.toList(growable: false);
} else {
children = widget.node.children
.map((node) => _segmentToTextSpanView(node, theme))
.toList(growable: true);
children.add(TextSpan(text: ' ', style: TextStyle(fontSize: 1.0)));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a small space at the end of each line in view mode to prevent the tail empty part from being tappable.

}

return new TextSpan(style: widget.style, children: children);
}

Expand All @@ -126,6 +139,21 @@ class _RawZefyrLineState extends State<RawZefyrLine> {
);
}

TextSpan _segmentToTextSpanView(Node node, ZefyrThemeData theme) {
final TextNode segment = node;
final attrs = segment.style;

return new TextSpan(
text: segment.value,
style: _getTextStyle(attrs, theme),
recognizer: (attrs.contains(NotusAttribute.link) ?
(new TapGestureRecognizer()..onTap = () async {
var link = attrs.get(NotusAttribute.link).value;
await ZefyrScope.of(context).onLaunchUrl(link);
}) : null),
);
}

TextStyle _getTextStyle(NotusStyle style, ZefyrThemeData theme) {
TextStyle result = new TextStyle();
if (style.containsSame(NotusAttribute.bold)) {
Expand Down
2 changes: 2 additions & 0 deletions packages/zefyr/lib/src/widgets/editable_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class ZefyrEditableText extends StatefulWidget {
@required this.controller,
@required this.focusNode,
@required this.imageDelegate,
@required this.onLaunchUrl,
this.autofocus: true,
this.enabled: true,
this.padding: const EdgeInsets.symmetric(horizontal: 16.0),
Expand All @@ -42,6 +43,7 @@ class ZefyrEditableText extends StatefulWidget {
final ZefyrController controller;
final FocusNode focusNode;
final ZefyrImageDelegate imageDelegate;
final Function onLaunchUrl;
final bool autofocus;
final bool enabled;
final ScrollPhysics physics;
Expand Down
19 changes: 19 additions & 0 deletions packages/zefyr/lib/src/widgets/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/widgets.dart';
import 'package:url_launcher/url_launcher.dart';

import 'controller.dart';
import 'editable_text.dart';
Expand All @@ -22,6 +23,7 @@ class ZefyrEditor extends StatefulWidget {
this.padding: const EdgeInsets.symmetric(horizontal: 16.0),
this.toolbarDelegate,
this.imageDelegate,
this.onLaunchUrl,
this.physics,
}) : super(key: key);

Expand All @@ -31,6 +33,7 @@ class ZefyrEditor extends StatefulWidget {
final bool enabled;
final ZefyrToolbarDelegate toolbarDelegate;
final ZefyrImageDelegate imageDelegate;
final Function onLaunchUrl;
final ScrollPhysics physics;

/// Padding around editable area.
Expand All @@ -42,6 +45,7 @@ class ZefyrEditor extends StatefulWidget {

class _ZefyrEditorState extends State<ZefyrEditor> {
ZefyrImageDelegate _imageDelegate;
Function _onLaunchUrl;
ZefyrScope _scope;
ZefyrThemeData _themeData;
GlobalKey<ZefyrToolbarState> _toolbarKey;
Expand Down Expand Up @@ -85,10 +89,18 @@ class _ZefyrEditorState extends State<ZefyrEditor> {
}
}

Future<void> _launchUrl(String link) async {
if(await canLaunch(link)) {
await launch(link, forceWebView: true);
}
}

@override
void initState() {
super.initState();
_imageDelegate = widget.imageDelegate ?? new ZefyrDefaultImageDelegate();

_onLaunchUrl = widget.onLaunchUrl ?? _launchUrl;
}

@override
Expand All @@ -100,6 +112,11 @@ class _ZefyrEditorState extends State<ZefyrEditor> {
_imageDelegate = widget.imageDelegate ?? new ZefyrDefaultImageDelegate();
_scope.imageDelegate = _imageDelegate;
}

if (widget.onLaunchUrl != oldWidget.onLaunchUrl) {
_onLaunchUrl = widget.onLaunchUrl ?? _launchUrl;
_scope.onLaunchUrl = _onLaunchUrl;
}
}

@override
Expand All @@ -114,6 +131,7 @@ class _ZefyrEditorState extends State<ZefyrEditor> {
if (_scope == null) {
_scope = ZefyrScope.editable(
imageDelegate: _imageDelegate,
onLaunchUrl: _onLaunchUrl,
controller: widget.controller,
focusNode: widget.focusNode,
focusScope: FocusScope.of(context),
Expand Down Expand Up @@ -147,6 +165,7 @@ class _ZefyrEditorState extends State<ZefyrEditor> {
controller: _scope.controller,
focusNode: _scope.focusNode,
imageDelegate: _scope.imageDelegate,
onLaunchUrl: _scope.onLaunchUrl,
autofocus: widget.autofocus,
enabled: widget.enabled,
padding: widget.padding,
Expand Down
23 changes: 20 additions & 3 deletions packages/zefyr/lib/src/widgets/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,33 @@ class ZefyrScope extends ChangeNotifier {
/// Creates a view-only scope.
///
/// Normally used in [ZefyrView].
ZefyrScope.view({@required ZefyrImageDelegate imageDelegate})
: assert(imageDelegate != null),
ZefyrScope.view({
@required ZefyrImageDelegate imageDelegate,
@required Future<void> onLaunchUrl(String url),
}) : assert(imageDelegate != null),
assert(onLaunchUrl != null),
isEditable = false,
_imageDelegate = imageDelegate;
_imageDelegate = imageDelegate,
_onLaunchUrl = onLaunchUrl;

/// Creates editable scope.
///
/// Normally used in [ZefyrEditor].
ZefyrScope.editable({
@required ZefyrController controller,
@required ZefyrImageDelegate imageDelegate,
@required Future<void> onLaunchUrl(String url),
@required FocusNode focusNode,
@required FocusScopeNode focusScope,
}) : assert(controller != null),
assert(imageDelegate != null),
assert(onLaunchUrl != null),
assert(focusNode != null),
assert(focusScope != null),
isEditable = true,
_controller = controller,
_imageDelegate = imageDelegate,
_onLaunchUrl = onLaunchUrl,
_focusNode = focusNode,
_focusScope = focusScope,
_cursorTimer = CursorTimer(),
Expand All @@ -70,6 +77,16 @@ class ZefyrScope extends ChangeNotifier {
}
}

Function _onLaunchUrl;
Function get onLaunchUrl => _onLaunchUrl;
set onLaunchUrl(Future<void> func(String url)) {
assert(func != null);
if (_onLaunchUrl != func) {
_onLaunchUrl = func;
notifyListeners();
}
}

ZefyrController _controller;
ZefyrController get controller => _controller;
set controller(ZefyrController value) {
Expand Down
25 changes: 21 additions & 4 deletions packages/zefyr/lib/src/widgets/view.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:notus/notus.dart';
import 'package:url_launcher/url_launcher.dart';

import 'code.dart';
import 'common.dart';
Expand All @@ -16,9 +17,14 @@ import 'theme.dart';
class ZefyrView extends StatefulWidget {
final NotusDocument document;
final ZefyrImageDelegate imageDelegate;
final Function onLaunchUrl;

const ZefyrView({Key key, @required this.document, this.imageDelegate})
: super(key: key);
const ZefyrView({
Key key,
@required this.document,
this.imageDelegate,
this.onLaunchUrl,
}) : super(key: key);

@override
ZefyrViewState createState() => ZefyrViewState();
Expand All @@ -29,17 +35,22 @@ class ZefyrViewState extends State<ZefyrView> {
ZefyrThemeData _themeData;

ZefyrImageDelegate get imageDelegate => widget.imageDelegate;
Function get onLaunchUrl => widget.onLaunchUrl;

@override
void initState() {
super.initState();
_scope = ZefyrScope.view(imageDelegate: widget.imageDelegate);
_scope = ZefyrScope.view(
imageDelegate: widget.imageDelegate ?? new ZefyrDefaultImageDelegate(),
onLaunchUrl: widget.onLaunchUrl ?? _launchUrl,
);
}

@override
void didUpdateWidget(ZefyrView oldWidget) {
super.didUpdateWidget(oldWidget);
_scope.imageDelegate = widget.imageDelegate;
_scope.imageDelegate = widget.imageDelegate ?? new ZefyrDefaultImageDelegate();
_scope.onLaunchUrl = widget.onLaunchUrl ?? _launchUrl;
}

@override
Expand Down Expand Up @@ -104,4 +115,10 @@ class ZefyrViewState extends State<ZefyrView> {

throw new UnimplementedError('Block format $blockStyle.');
}

Future<void> _launchUrl(String link) async {
if(await canLaunch(link)) {
await launch(link, forceWebView: true);
}
}
}