mirror of
https://github.com/ChronosX88/wind.git
synced 2024-12-05 02:22:17 +00:00
Implement new thread creation
This commit is contained in:
parent
cf15aae5ac
commit
1bcc2613b4
112
lib/create_thread_screen.dart
Normal file
112
lib/create_thread_screen.dart
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:wind/thread_list_model.dart';
|
||||||
|
import 'package:wind/thread_model.dart';
|
||||||
|
|
||||||
|
class CreateThreadScreen extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _CreateThreadScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateThreadScreenState extends State<CreateThreadScreen> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(title: Text("Создать новый тред")),
|
||||||
|
body: Center(
|
||||||
|
child: Container(
|
||||||
|
width: 640,
|
||||||
|
child: Consumer<ThreadModel>(
|
||||||
|
builder: (context, value, child) => CreateThreadForm(model: value),
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateThreadForm extends StatefulWidget {
|
||||||
|
CreateThreadForm({Key? key, required this.model}) : super(key: key);
|
||||||
|
|
||||||
|
ThreadModel model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
CreateThreadFormState createState() {
|
||||||
|
return CreateThreadFormState(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a corresponding State class.
|
||||||
|
// This class holds data related to the form.
|
||||||
|
class CreateThreadFormState extends State<CreateThreadForm> {
|
||||||
|
CreateThreadFormState(this.model);
|
||||||
|
|
||||||
|
ThreadModel model;
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
String _subject = "";
|
||||||
|
String _text = "";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
child: TextFormField(
|
||||||
|
onSaved: ((newValue) {
|
||||||
|
_subject = newValue!;
|
||||||
|
}),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(), labelText: "Название поста"),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'Пожалуйста, введите название';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16),
|
||||||
|
child: TextFormField(
|
||||||
|
onSaved: (newValue) {
|
||||||
|
_text = newValue!;
|
||||||
|
},
|
||||||
|
minLines: 5,
|
||||||
|
keyboardType: TextInputType.multiline,
|
||||||
|
maxLines: 35,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(), labelText: "Текст поста"),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'Пожалуйста, введите текст';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
_formKey.currentState!.save();
|
||||||
|
model.createThread(_subject, _text).then((value) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(content: Text('Тред создан!')),
|
||||||
|
);
|
||||||
|
Provider.of<ThreadListModel>(context, listen: false)
|
||||||
|
.update();
|
||||||
|
Navigator.pop(context);
|
||||||
|
}, onError: (error) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'При создании треда произошла ошибка: ${error.toString()}')),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text("Создать"))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
125
lib/main.dart
125
lib/main.dart
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:wind/create_thread_screen.dart';
|
||||||
import 'package:wind/newsgroup_list_view.dart';
|
import 'package:wind/newsgroup_list_view.dart';
|
||||||
import 'package:wind/nntp_client.dart';
|
import 'package:wind/nntp_client.dart';
|
||||||
import 'package:wind/thread_list_view.dart';
|
import 'package:wind/thread_list_view.dart';
|
||||||
@ -47,6 +48,9 @@ class MyApp extends StatelessWidget {
|
|||||||
threadNumber:
|
threadNumber:
|
||||||
int.parse(uriData.queryParametersAll['num']!.first));
|
int.parse(uriData.queryParametersAll['num']!.first));
|
||||||
break;
|
break;
|
||||||
|
case '/thread/create':
|
||||||
|
pageView = CreateThreadScreen();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pageView = MyHomePage(title: 'Wind');
|
pageView = MyHomePage(title: 'Wind');
|
||||||
break;
|
break;
|
||||||
@ -82,64 +86,69 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// This method is rerun every time setState is called, for instance as done
|
return Consumer<ThreadListModel>(
|
||||||
// by the _incrementCounter method above.
|
builder: (context, value, child) => Scaffold(
|
||||||
//
|
appBar: AppBar(
|
||||||
// The Flutter framework has been optimized to make rerunning build methods
|
title: Text(widget.title),
|
||||||
// fast, so that you can just rebuild anything that needs updating rather
|
actions: value.currentGroup != ""
|
||||||
// than having to individually change instances of widgets.
|
? [
|
||||||
return Scaffold(
|
TextButton.icon(
|
||||||
appBar: AppBar(
|
onPressed: () =>
|
||||||
// Here we take the value from the MyHomePage object that was created by
|
Navigator.pushNamed(context, "/thread/create"),
|
||||||
// the App.build method, and use it to set our appbar title.
|
icon: Icon(Icons.add),
|
||||||
title: Text(widget.title),
|
label: Text("Создать тред"),
|
||||||
actions: [
|
style: TextButton.styleFrom(
|
||||||
TextButton.icon(
|
primary: Theme.of(context).colorScheme.onPrimary),
|
||||||
onPressed: () {
|
),
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
TextButton.icon(
|
||||||
const SnackBar(
|
onPressed: () {
|
||||||
content: Text('Обновление списка тредов...')),
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
);
|
const SnackBar(
|
||||||
Provider.of<ThreadListModel>(context, listen: false).update();
|
content: Text('Обновление списка тредов...')),
|
||||||
},
|
);
|
||||||
label: const Text("Обновить"),
|
Provider.of<ThreadListModel>(context, listen: false)
|
||||||
style: TextButton.styleFrom(
|
.update();
|
||||||
primary: Theme.of(context).colorScheme.onPrimary),
|
},
|
||||||
icon: Icon(Icons.sync))
|
label: const Text("Обновить"),
|
||||||
],
|
style: TextButton.styleFrom(
|
||||||
),
|
primary: Theme.of(context).colorScheme.onPrimary),
|
||||||
body: Center(
|
icon: Icon(Icons.sync))
|
||||||
child: Container(
|
]
|
||||||
child: Row(
|
: [],
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: 300,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.all(16),
|
|
||||||
child: Text(
|
|
||||||
"Новостные группы",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold, fontSize: 20),
|
|
||||||
)),
|
|
||||||
Expanded(
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) =>
|
|
||||||
NewsgroupListView(client: nntpClient))),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const VerticalDivider(thickness: 1, width: 1),
|
|
||||||
Expanded(
|
|
||||||
child: Center(
|
|
||||||
child: Consumer<ThreadListModel>(
|
|
||||||
builder: ((context, value, child) => ThreadListView())),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
));
|
body: Center(
|
||||||
|
child: Container(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 300,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.all(16),
|
||||||
|
child: Text(
|
||||||
|
"Новостные группы",
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold, fontSize: 20),
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) =>
|
||||||
|
NewsgroupListView(client: nntpClient))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const VerticalDivider(thickness: 1, width: 1),
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Consumer<ThreadListModel>(
|
||||||
|
builder: ((context, value, child) => ThreadListView())),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class MessageItemView extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: this.isOpPost
|
padding: this.isOpPost
|
||||||
? EdgeInsets.only(bottom: 10, left: 10, right: 10, top: 16)
|
? EdgeInsets.only(bottom: 10, left: 10, right: 10, top: 16)
|
||||||
: isLast
|
: isLast
|
||||||
? EdgeInsets.only(left: 10, right: 10, bottom: 16)
|
? EdgeInsets.only(left: 10, right: 10, bottom: 16)
|
||||||
|
@ -40,7 +40,7 @@ class ThreadListModel extends ChangeNotifier {
|
|||||||
_curItems.add(ThreadItem(
|
_curItems.add(ThreadItem(
|
||||||
msg.getHeaderValue("Message-Id")!,
|
msg.getHeaderValue("Message-Id")!,
|
||||||
number,
|
number,
|
||||||
msg.getHeaderValue("Subject")!,
|
msg.decodeSubject()!,
|
||||||
msg.getHeaderValue("From")!,
|
msg.getHeaderValue("From")!,
|
||||||
msg.getHeaderValue("Date")!,
|
msg.getHeaderValue("Date")!,
|
||||||
msg.decodeTextPlainPart()!));
|
msg.decodeTextPlainPart()!));
|
||||||
|
@ -13,7 +13,7 @@ class ThreadModel extends ChangeNotifier {
|
|||||||
var mi = MessageItem(
|
var mi = MessageItem(
|
||||||
msg.getHeaderValue("Message-Id")!,
|
msg.getHeaderValue("Message-Id")!,
|
||||||
number,
|
number,
|
||||||
msg.getHeaderValue("Subject")!,
|
msg.decodeSubject()!,
|
||||||
msg.getHeaderValue("From")!,
|
msg.getHeaderValue("From")!,
|
||||||
msg.getHeaderValue("Date")!,
|
msg.getHeaderValue("Date")!,
|
||||||
msg.decodeTextPlainPart()!);
|
msg.decodeTextPlainPart()!);
|
||||||
@ -37,7 +37,7 @@ class ThreadModel extends ChangeNotifier {
|
|||||||
null,
|
null,
|
||||||
message.getHeaderValue("From")!,
|
message.getHeaderValue("From")!,
|
||||||
message.getHeaderValue("Date")!,
|
message.getHeaderValue("Date")!,
|
||||||
message.decodeTextPlainPart()!));
|
message.decodeTextPlainPart()!.trim()));
|
||||||
});
|
});
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
@ -45,7 +45,7 @@ class ThreadModel extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<int> postMessage(MimeMessage opPost, String text) async {
|
Future<int> postMessage(MimeMessage opPost, String text) async {
|
||||||
var msg = MessageBuilder.buildSimpleTextMessage(
|
var msg = MessageBuilder.buildSimpleTextMessage(
|
||||||
MailAddress.empty(), [], text,
|
MailAddress.empty(), [], text.trim(),
|
||||||
subject: "Re: " + opPost.decodeSubject()!);
|
subject: "Re: " + opPost.decodeSubject()!);
|
||||||
msg.setHeader("From", "anonymous");
|
msg.setHeader("From", "anonymous");
|
||||||
msg.addHeader("In-Reply-To", opPost.getHeaderValue("Message-Id"));
|
msg.addHeader("In-Reply-To", opPost.getHeaderValue("Message-Id"));
|
||||||
@ -54,6 +54,15 @@ class ThreadModel extends ChangeNotifier {
|
|||||||
return await client!.postArticle(msg);
|
return await client!.postArticle(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<int> createThread(String subject, String text) async {
|
||||||
|
var msg = MessageBuilder.buildSimpleTextMessage(
|
||||||
|
MailAddress.empty(), [], text.trim(),
|
||||||
|
subject: subject);
|
||||||
|
msg.setHeader("From", "anonymous");
|
||||||
|
msg.addHeader("Newsgroups", client!.currentGroup!);
|
||||||
|
return await client!.postArticle(msg);
|
||||||
|
}
|
||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user