styled_text.dart 3.73 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

7
typedef _TextTransformer = Widget Function(String name, String text);
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

// From https://en.wikiquote.org/wiki/2001:_A_Space_Odyssey_(film)
const String _kDialogText = '''
Dave: Open the pod bay doors, please, HAL. Open the pod bay doors, please, HAL. Hello, HAL. Do you read me? Hello, HAL. Do you read me? Do you read me, HAL?
HAL: Affirmative, Dave. I read you.
Dave: Open the pod bay doors, HAL.
HAL: I'm sorry, Dave. I'm afraid I can't do that.
Dave: What's the problem?
HAL: I think you know what the problem is just as well as I do.
Dave: What are you talking about, HAL?
HAL: This mission is too important for me to allow you to jeopardize it.''';

// [["Dave", "Open the pod bay..."] ...]
final List<List<String>> _kNameLines = _kDialogText
  .split('\n')
23
  .map<List<String>>((String line) => line.split(':'))
24 25
  .toList();

26 27
final TextStyle _kDaveStyle = TextStyle(color: Colors.indigo.shade400, height: 1.8);
final TextStyle _kHalStyle = TextStyle(color: Colors.red.shade400, fontFamily: 'monospace');
28 29
const TextStyle _kBold = TextStyle(fontWeight: FontWeight.bold);
const TextStyle _kUnderline = TextStyle(
30
  decoration: TextDecoration.underline,
31
  decorationColor: Color(0xFF000000),
32
  decorationStyle: TextDecorationStyle.wavy,
33 34 35
);

Widget toStyledText(String name, String text) {
36
  final TextStyle lineStyle = (name == 'Dave') ? _kDaveStyle : _kHalStyle;
37 38 39
  return RichText(
    key: Key(text),
    text: TextSpan(
Adam Barth's avatar
Adam Barth committed
40 41
      style: lineStyle,
      children: <TextSpan>[
42
        TextSpan(
Adam Barth's avatar
Adam Barth committed
43 44
          style: _kBold,
          children: <TextSpan>[
45
            TextSpan(
Adam Barth's avatar
Adam Barth committed
46
              style: _kUnderline,
47
              text: name,
Adam Barth's avatar
Adam Barth committed
48
            ),
49 50
            const TextSpan(text: ':'),
          ],
Adam Barth's avatar
Adam Barth committed
51
        ),
52 53 54
        TextSpan(text: text),
      ],
    ),
55 56 57
  );
}

58
Widget toPlainText(String name, String text) => Text('$name:$text');
59

60
class SpeakerSeparator extends StatelessWidget {
61
  const SpeakerSeparator({super.key});
62

63
  @override
64
  Widget build(BuildContext context) {
65
    return Container(
66
      constraints: const BoxConstraints.expand(height: 0.0),
67
      margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 64.0),
68
      decoration: const BoxDecoration(
69
        border: Border(
70 71
          bottom: BorderSide(color: Color.fromARGB(24, 0, 0, 0)),
        ),
72
      ),
73 74 75 76
    );
  }
}

77
class StyledTextDemo extends StatefulWidget {
78
  const StyledTextDemo({super.key});
79

80
  @override
81
  State<StyledTextDemo> createState() => _StyledTextDemoState();
82 83 84
}

class _StyledTextDemoState extends State<StyledTextDemo> {
85
  _TextTransformer _toText = toStyledText;
86 87 88 89 90 91 92

  void _handleTap() {
    setState(() {
      _toText = (_toText == toPlainText) ? toStyledText : toPlainText;
    });
  }

93
  @override
94
  Widget build(BuildContext context) {
95
    return GestureDetector(
96
      onTap: _handleTap,
97
      child: Container(
98
        padding: const EdgeInsets.symmetric(horizontal: 8.0),
99
        child: Column(
100
          mainAxisAlignment: MainAxisAlignment.center,
101
          crossAxisAlignment: CrossAxisAlignment.start,
102 103 104 105
          children: _kNameLines
            .map<Widget>((List<String> nameAndText) => _toText(nameAndText[0], nameAndText[1]))
            .expand((Widget line) => <Widget>[
              line,
106
              const SpeakerSeparator(),
107 108
            ])
            .toList()..removeLast(),
109 110
        ),
      ),
111 112 113 114 115
    );
  }
}

void main() {
116 117 118 119
  runApp(MaterialApp(
    theme: ThemeData.light(),
    home: Scaffold(
      appBar: AppBar(
120
        title: const Text('Hal and Dave'),
121
      ),
122
      body: Material(
123
        color: Colors.grey.shade50,
124
        child: const StyledTextDemo(),
125 126
      ),
    ),
127 128
  ));
}