full_screen_dialog_demo.dart 8.53 KB
Newer Older
Hans Muller's avatar
Hans Muller committed
1 2 3 4
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
import 'dart:async';

Hans Muller's avatar
Hans Muller committed
7
import 'package:flutter/material.dart';
8
import 'package:intl/intl.dart';
Hans Muller's avatar
Hans Muller committed
9 10

// This demo is based on
11
// https://material.io/design/components/dialogs.html#full-screen-dialog
Hans Muller's avatar
Hans Muller committed
12 13 14 15 16 17 18

enum DismissDialogAction {
  cancel,
  discard,
  save,
}

19
class DateTimeItem extends StatelessWidget {
20
  DateTimeItem({ Key key, DateTime dateTime, @required this.onChanged })
21
    : assert(onChanged != null),
22 23
      date = DateTime(dateTime.year, dateTime.month, dateTime.day),
      time = TimeOfDay(hour: dateTime.hour, minute: dateTime.minute),
24
      super(key: key);
Hans Muller's avatar
Hans Muller committed
25 26 27 28 29

  final DateTime date;
  final TimeOfDay time;
  final ValueChanged<DateTime> onChanged;

30
  @override
Hans Muller's avatar
Hans Muller committed
31 32 33
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);

34
    return DefaultTextStyle(
35
      style: theme.textTheme.subhead,
36
      child: Row(
Hans Muller's avatar
Hans Muller committed
37
        children: <Widget>[
38 39
          Expanded(
            child: Container(
40
              padding: const EdgeInsets.symmetric(vertical: 8.0),
41 42
              decoration: BoxDecoration(
                border: Border(bottom: BorderSide(color: theme.dividerColor))
Hans Muller's avatar
Hans Muller committed
43
              ),
44
              child: InkWell(
Hans Muller's avatar
Hans Muller committed
45 46 47 48 49
                onTap: () {
                  showDatePicker(
                    context: context,
                    initialDate: date,
                    firstDate: date.subtract(const Duration(days: 30)),
50
                    lastDate: date.add(const Duration(days: 30)),
Hans Muller's avatar
Hans Muller committed
51
                  )
52
                  .then<void>((DateTime value) {
53
                    if (value != null)
54
                      onChanged(DateTime(value.year, value.month, value.day, time.hour, time.minute));
Hans Muller's avatar
Hans Muller committed
55 56
                  });
                },
57
                child: Row(
58
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
Hans Muller's avatar
Hans Muller committed
59
                  children: <Widget>[
60
                    Text(DateFormat('EEE, MMM d yyyy').format(date)),
61
                    const Icon(Icons.arrow_drop_down, color: Colors.black54),
62 63 64 65
                  ],
                ),
              ),
            ),
Hans Muller's avatar
Hans Muller committed
66
          ),
67
          Container(
68 69
            margin: const EdgeInsets.only(left: 8.0),
            padding: const EdgeInsets.symmetric(vertical: 8.0),
70 71
            decoration: BoxDecoration(
              border: Border(bottom: BorderSide(color: theme.dividerColor))
Hans Muller's avatar
Hans Muller committed
72
            ),
73
            child: InkWell(
Hans Muller's avatar
Hans Muller committed
74 75 76
              onTap: () {
                showTimePicker(
                  context: context,
77
                  initialTime: time,
Hans Muller's avatar
Hans Muller committed
78
                )
79
                .then<void>((TimeOfDay value) {
80
                  if (value != null)
81
                    onChanged(DateTime(date.year, date.month, date.day, value.hour, value.minute));
Hans Muller's avatar
Hans Muller committed
82 83
                });
              },
84
              child: Row(
Hans Muller's avatar
Hans Muller committed
85
                children: <Widget>[
86
                  Text('${time.format(context)}'),
87
                  const Icon(Icons.arrow_drop_down, color: Colors.black54),
88 89 90 91 92 93
                ],
              ),
            ),
          ),
        ],
      ),
Hans Muller's avatar
Hans Muller committed
94 95 96 97
    );
  }
}

98
class FullScreenDialogDemo extends StatefulWidget {
99
  @override
100
  FullScreenDialogDemoState createState() => FullScreenDialogDemoState();
Hans Muller's avatar
Hans Muller committed
101 102 103
}

class FullScreenDialogDemoState extends State<FullScreenDialogDemo> {
104 105
  DateTime _fromDateTime = DateTime.now();
  DateTime _toDateTime = DateTime.now();
106 107
  bool _allDayValue = false;
  bool _saveNeeded = false;
108 109 110
  bool _hasLocation = false;
  bool _hasName = false;
  String _eventName;
Hans Muller's avatar
Hans Muller committed
111

112
  Future<bool> _onWillPop() async {
113
    _saveNeeded = _hasLocation || _hasName || _saveNeeded;
114 115
    if (!_saveNeeded)
      return true;
Hans Muller's avatar
Hans Muller committed
116 117

    final ThemeData theme = Theme.of(context);
118
    final TextStyle dialogTextStyle = theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color);
Hans Muller's avatar
Hans Muller committed
119

120
    return await showDialog<bool>(
Hans Muller's avatar
Hans Muller committed
121
      context: context,
122
      builder: (BuildContext context) {
123 124
        return AlertDialog(
          content: Text(
125
            'Discard new event?',
126
            style: dialogTextStyle,
Hans Muller's avatar
Hans Muller committed
127
          ),
128
          actions: <Widget>[
129
            FlatButton(
130 131 132
              child: const Text('CANCEL'),
              onPressed: () {
                Navigator.of(context).pop(false); // Pops the confirmation dialog but not the page.
133
              },
134
            ),
135
            FlatButton(
136 137 138
              child: const Text('DISCARD'),
              onPressed: () {
                Navigator.of(context).pop(true); // Returning true to _onWillPop will pop again.
139 140
              },
            ),
141 142 143
          ],
        );
      },
144
    ) ?? false;
Hans Muller's avatar
Hans Muller committed
145 146
  }

147
  @override
Hans Muller's avatar
Hans Muller committed
148 149 150
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);

151 152 153
    return Scaffold(
      appBar: AppBar(
        title: Text(_hasName ? _eventName : 'Event Name TBD'),
154
        actions: <Widget> [
155 156
          FlatButton(
            child: Text('SAVE', style: theme.textTheme.body1.copyWith(color: Colors.white)),
Hans Muller's avatar
Hans Muller committed
157 158
            onPressed: () {
              Navigator.pop(context, DismissDialogAction.save);
159 160 161
            },
          ),
        ],
Hans Muller's avatar
Hans Muller committed
162
      ),
163
      body: Form(
164
        onWillPop: _onWillPop,
165 166 167 168 169 170 171 172 173 174 175 176 177 178
        child: Scrollbar(
          child: ListView(
            padding: const EdgeInsets.all(16.0),
            children: <Widget>[
              Container(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                alignment: Alignment.bottomLeft,
                child: TextField(
                  decoration: const InputDecoration(
                    labelText: 'Event name',
                    filled: true,
                  ),
                  style: theme.textTheme.headline,
                  onChanged: (String value) {
179
                    setState(() {
180 181 182 183
                      _hasName = value.isNotEmpty;
                      if (_hasName) {
                        _eventName = value;
                      }
184
                    });
185 186
                  },
                ),
187 188 189 190 191 192 193 194 195 196 197
              ),
              Container(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                alignment: Alignment.bottomLeft,
                child: TextField(
                  decoration: const InputDecoration(
                    labelText: 'Location',
                    hintText: 'Where is the event?',
                    filled: true,
                  ),
                  onChanged: (String value) {
198
                    setState(() {
199
                      _hasLocation = value.isNotEmpty;
200
                    });
201
                  },
202
                ),
203
              ),
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text('From', style: theme.textTheme.caption),
                  DateTimeItem(
                    dateTime: _fromDateTime,
                    onChanged: (DateTime value) {
                      setState(() {
                        _fromDateTime = value;
                        _saveNeeded = true;
                      });
                    },
                  ),
                ],
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text('To', style: theme.textTheme.caption),
                  DateTimeItem(
                    dateTime: _toDateTime,
                    onChanged: (DateTime value) {
226
                      setState(() {
227
                        _toDateTime = value;
228 229
                        _saveNeeded = true;
                      });
230
                    },
231
                  ),
xster's avatar
xster committed
232
                  const Text('All-day'),
233 234
                ],
              ),
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
              Container(
                decoration: BoxDecoration(
                  border: Border(bottom: BorderSide(color: theme.dividerColor))
                ),
                child: Row(
                  children: <Widget> [
                    Checkbox(
                      value: _allDayValue,
                      onChanged: (bool value) {
                        setState(() {
                          _allDayValue = value;
                          _saveNeeded = true;
                        });
                      },
                    ),
                    const Text('All-day'),
                  ],
                ),
              ),
            ]
            .map<Widget>((Widget child) {
              return Container(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                height: 96.0,
                child: child,
              );
            })
            .toList(),
          ),
264
        ),
265
      ),
Hans Muller's avatar
Hans Muller committed
266 267 268
    );
  }
}