aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorryo <ryo@nopwd.lol>2025-01-06 17:17:26 +0000
committerryo <ryo@nopwd.lol>2025-01-06 17:17:26 +0000
commitbb2cb9683b011adca411e5c805fbb87fc0867e14 (patch)
tree83a8241759baaab808a2647899666a2bfc9aae3b
Initial commit
-rw-r--r--README13
-rw-r--r--main.dart220
-rw-r--r--pubspec.yaml90
-rw-r--r--server.dart44
4 files changed, 367 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..cf06593
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
+Flutter Todo App
+================
+Copy main.dart to a ready project and compile it.
+Run server.dart anywhere you want, it creates users files inside
+the folder it is running.
+
+App Tutorial
+============
+It's not user-friendly, I'll work on it later.
+
+1. Login
+2. Insert your todo and press that plus button
+3. Save
diff --git a/main.dart b/main.dart
new file mode 100644
index 0000000..313f649
--- /dev/null
+++ b/main.dart
@@ -0,0 +1,220 @@
+import 'package:flutter/material.dart';
+import 'dart:io';
+import 'package:http/http.dart' as http;
+
+void main() {
+ runApp(const MyApp());
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Demo',
+ theme: ThemeData(
+ brightness: Brightness.dark,
+ primaryColor: Colors.white,
+ ),
+ home: const MyHomePage(title: 'Flutter Demo Home Page'),
+ );
+ }
+}
+
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({super.key, required this.title});
+
+ final String title;
+
+ @override
+ State<MyHomePage> createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State<MyHomePage> {
+ final TextEditingController _todoController = TextEditingController();
+ final TextEditingController _usernameController = TextEditingController();
+ final List<String> _values = <String>['first todo', 'second work'];
+ final List<bool> _dones = <bool>[true, false];
+ var _username = "test";
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: Text("Text App"),
+ backgroundColor: Color(0xff2d3f76),
+ ),
+ body: Center(
+ child: Container(
+ padding: EdgeInsets.all(16.0),
+ child: Column(children: _showTodos()))),
+ floatingActionButton: FloatingActionButton(
+ onPressed: () {
+ setState(() {
+ if (_todoController.text.isNotEmpty) {
+ _values.add(_todoController.text);
+ _dones.add(false);
+ _todoController.clear();
+ }
+ });
+ },
+ tooltip: 'Add Todo',
+ child: const Icon(Icons.add),
+ ),
+ bottomNavigationBar: BottomNavigationBar(
+ items: [
+ BottomNavigationBarItem(
+ icon: IconButton(
+ onPressed: () => _showDialog(), icon: Icon(Icons.login)),
+ label: "Login"),
+ BottomNavigationBarItem(
+ icon: IconButton(
+ onPressed: () => _saveTodos(), icon: Icon(Icons.save)),
+ label: "Save"),
+ ],
+ backgroundColor: Color(0xff222436),
+ ));
+ }
+
+ List<Widget> _showTodos() {
+ List<Widget> todos = [];
+ for (int i = 0; i < _values.length; i++) {
+ String context = _values[i];
+ todos.add(Row(children: <Widget>[
+ Checkbox(
+ value: _dones[i],
+ onChanged: (bool? value) {
+ setState(() {
+ _dones[i] = value!;
+ });
+ }),
+ SizedBox(width: 10),
+ Text(context),
+ Spacer(),
+ IconButton(
+ onPressed: () {
+ setState(() {
+ int i = _values.indexOf(context);
+ _values.remove(context);
+ _dones.removeAt(i);
+ });
+ },
+ icon: Icon(
+ Icons.delete,
+ color: Colors.red,
+ ),
+ ),
+ ]));
+ }
+ if (_values.isEmpty) {
+ todos.add(Text('Nothing here'));
+ }
+ todos.add(SizedBox(height: 10));
+ todos.add(TextField(
+ controller: _todoController,
+ decoration: const InputDecoration(
+ border: OutlineInputBorder(),
+ labelText: 'Insert Todo',
+ ),
+ ));
+ return todos;
+ }
+
+ Future<void> _showDialog() async {
+ return showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return AlertDialog(
+ title: const Text('Login'),
+ content: TextField(
+ controller: _usernameController,
+ decoration: const InputDecoration(hintText: 'Username'),
+ autofocus: true,
+ ),
+ actions: <Widget>[
+ OutlinedButton(
+ style: OutlinedButton.styleFrom(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(12),
+ ),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ child: const Text('Cancel'),
+ ),
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(12),
+ ),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop();
+ _username = _usernameController.text;
+ _values.clear();
+ _dones.clear();
+ _loadTodos();
+ _usernameController.clear();
+ },
+ child: const Text('Login'),
+ ),
+ ],
+ );
+ });
+ }
+
+ void _loadTodos() async {
+ String uri = "http://127.0.0.1:6969/$_username.txt";
+ try {
+ http.Response response = await http.get(Uri.parse(uri));
+ if (response.statusCode == 200) {
+ print("Successfully got the data");
+ } else {
+ print('Error getting data: ${response.statusCode}');
+ return;
+ }
+
+ setState(() {
+ todoDecode(response.body, _values, _dones);
+ });
+ print(_values);
+ print(_dones);
+ } on SocketException catch (e) {
+ print(e.message);
+ }
+ }
+
+ void _saveTodos() async {
+ String uri = "http://127.0.0.1:6969/$_username.txt";
+ var data = todoEncode(_values, _dones);
+ print(data);
+ try {
+ http.Response response = await http.post(Uri.parse(uri), body: data);
+ if (response.statusCode == 200) {
+ print('Data sent successfully');
+ } else {
+ print('Error sending data: ${response.statusCode}');
+ }
+ } catch (e) {
+ print(e.toString());
+ }
+ }
+}
+
+String todoEncode(List<String> values, List<bool> dones) {
+ String data = "";
+ for (int i = 0; i < values.length; i++) {
+ data += '${dones[i] ? 1 : 0}:${values[i]}\n';
+ }
+ return data;
+}
+
+void todoDecode(String todos, List<String> values, List<bool> dones) {
+ var tmp = todos.split('\n');
+ for (int i = 0; i < tmp.length - 1; i++) {
+ values.add(tmp[i].substring(2));
+ dones.add(tmp[i][0] == '0' ? false : true);
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..748e57e
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,90 @@
+name: test
+description: "Simple todo app."
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+# In Windows, build-name is used as the major, minor, and patch parts
+# of the product and file versions while build-number is used as the build suffix.
+version: 1.0.0+1
+
+environment:
+ sdk: ^3.6.0
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ #cupertino_icons: ^1.0.8
+ http: ^1.2.2
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^5.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/to/resolution-aware-images
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/to/asset-from-package
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/to/font-from-package
diff --git a/server.dart b/server.dart
new file mode 100644
index 0000000..eb5307d
--- /dev/null
+++ b/server.dart
@@ -0,0 +1,44 @@
+import 'dart:convert';
+import 'dart:io';
+
+void main() async {
+ const int port = 6969;
+ final requests = await HttpServer.bind('localhost', port);
+ print('Started server bind to localhost:$port');
+ await for (final request in requests) {
+ print('uri: ${request.uri}');
+ if (request.method == 'GET') {
+ print('Processing GET method');
+ processGet(request);
+ } else if (request.method == 'POST') {
+ print('Processing POST method');
+ processPost(request);
+ }
+ }
+}
+
+void processGet(HttpRequest request) async {
+ var filename = request.uri.toString().substring(1);
+ bool exist = await File(filename).exists();
+ String data = '';
+ if (exist) {
+ var data = await File(filename).readAsString();
+ print('Sent data:');
+ print(data);
+ } else {
+ File(filename).writeAsString('');
+ print('Created file $filename');
+ }
+ request.response
+ ..statusCode = HttpStatus.ok
+ ..write(data)
+ ..close();
+}
+
+void processPost(HttpRequest request) async {
+ var filename = request.uri.path.substring(1);
+ String data = await utf8.decoder.bind(request).join();
+ File(filename).writeAsString(data);
+ print('Received data:');
+ print(data);
+}