0
0
Fluttermobile~20 mins

File storage in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Simple Note Saver
This screen lets users write a note and save it to a file on the device. They can also load the saved note back to edit or view it.
Target UI
┌─────────────────────────────┐
│ Simple Note Saver           │
├─────────────────────────────┤
│ [TextField: multiline note] │
│                             │
│                             │
│                             │
│                             │
├────────────┬───────────────┤
│ Save Note  │ Load Note     │
└────────────┴───────────────┘
A multiline TextField for user to type a note
A Save Note button that writes the note to a local file
A Load Note button that reads the note from the file and shows it in the TextField
Use path_provider package to get the app's documents directory
Handle errors gracefully with simple print statements
Starter Code
Flutter
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';

class SimpleNoteSaver extends StatefulWidget {
  @override
  _SimpleNoteSaverState createState() => _SimpleNoteSaverState();
}

class _SimpleNoteSaverState extends State<SimpleNoteSaver> {
  final TextEditingController _controller = TextEditingController();

  // TODO: Add methods to get file path, save note, and load note

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Simple Note Saver')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Expanded(
              child: TextField(
                controller: _controller,
                maxLines: null,
                expands: true,
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'Type your note here...',
                ),
              ),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: () {
                    // TODO: Implement save note
                  },
                  child: Text('Save Note'),
                ),
                ElevatedButton(
                  onPressed: () {
                    // TODO: Implement load note
                  },
                  child: Text('Load Note'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Task 4
Solution
Flutter
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';

class SimpleNoteSaver extends StatefulWidget {
  @override
  _SimpleNoteSaverState createState() => _SimpleNoteSaverState();
}

class _SimpleNoteSaverState extends State<SimpleNoteSaver> {
  final TextEditingController _controller = TextEditingController();

  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();
    return directory.path;
  }

  Future<File> get _localFile async {
    final path = await _localPath;
    return File('$path/note.txt');
  }

  Future<void> _saveNote() async {
    try {
      final file = await _localFile;
      await file.writeAsString(_controller.text);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Note saved')),
      );
    } catch (e) {
      print('Error saving note: $e');
    }
  }

  Future<void> _loadNote() async {
    try {
      final file = await _localFile;
      String contents = await file.readAsString();
      setState(() {
        _controller.text = contents;
      });
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Note loaded')),
      );
    } catch (e) {
      print('Error loading note: $e');
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('No saved note found')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Simple Note Saver')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Expanded(
              child: TextField(
                controller: _controller,
                maxLines: null,
                expands: true,
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'Type your note here...',
                ),
              ),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: _saveNote,
                  child: Text('Save Note'),
                ),
                ElevatedButton(
                  onPressed: _loadNote,
                  child: Text('Load Note'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

This app uses the path_provider package to find a safe place on the device to store files. We get the documents directory path asynchronously.

We create a file named note.txt in that directory to save the note text.

The _saveNote method writes the current text from the TextField to the file. It shows a small message when done.

The _loadNote method reads the text from the file and updates the TextField with it. If no file exists, it shows a message.

Both methods handle errors by printing them to the console and showing user-friendly SnackBars.

This keeps the UI simple and responsive while demonstrating basic file storage in Flutter.

Final Result
Completed Screen
┌─────────────────────────────┐
│ Simple Note Saver           │
├─────────────────────────────┤
│ Type your note here...      │
│                             │
│                             │
│                             │
│                             │
├────────────┬───────────────┤
│ Save Note  │ Load Note     │
└────────────┴───────────────┘
User types text in the large box.
Tapping 'Save Note' writes the text to a file and shows 'Note saved' message.
Tapping 'Load Note' reads the saved text from the file and displays it in the box, showing 'Note loaded' message.
If no saved note exists, loading shows 'No saved note found' message.
Stretch Goal
Add a Clear button that empties the TextField and deletes the saved note file.
💡 Hint
Use File.delete() to remove the file and set the TextField controller text to empty string.