mirror of
https://github.com/ChronosX88/wind.git
synced 2024-12-05 02:22:17 +00:00
Implement thread loading
This commit is contained in:
parent
fabb0767b5
commit
839f91d735
@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:wind/newsgroup_list_view.dart';
|
||||
import 'package:wind/nntp_client.dart';
|
||||
import 'package:wind/thread_list_view.dart';
|
||||
import 'package:wind/thread_model.dart';
|
||||
import 'package:wind/thread_screen.dart';
|
||||
|
||||
import 'thread_list_model.dart';
|
||||
@ -16,6 +17,12 @@ void main() {
|
||||
model!.client = client;
|
||||
return model;
|
||||
}),
|
||||
ChangeNotifierProxyProvider<NNTPClient, ThreadModel>(
|
||||
create: (context) => ThreadModel(),
|
||||
update: (context, client, model) {
|
||||
model!.client = client;
|
||||
return model;
|
||||
}),
|
||||
], child: MyApp()));
|
||||
}
|
||||
|
||||
|
80
lib/message_item_view.dart
Normal file
80
lib/message_item_view.dart
Normal file
@ -0,0 +1,80 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MessageItemView extends StatelessWidget {
|
||||
const MessageItemView({Key? key, required this.item, required this.isOpPost})
|
||||
: super(key: key);
|
||||
|
||||
final MessageItem item;
|
||||
final bool isOpPost;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: this.isOpPost ? EdgeInsets.only(bottom: 10) : EdgeInsets.all(0),
|
||||
child: Card(
|
||||
elevation: 5,
|
||||
child: InkWell(
|
||||
splashColor: Colors.indigo.withAlpha(30),
|
||||
onTap: () => {},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
isOpPost
|
||||
? Container(
|
||||
child: Text(
|
||||
item.subject!,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 21),
|
||||
),
|
||||
margin: EdgeInsets.only(top: 16, left: 16, right: 16),
|
||||
)
|
||||
: Container(),
|
||||
Container(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
item.author,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Colors.blue,
|
||||
fontSize: 15),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
Text(
|
||||
item.date,
|
||||
style: TextStyle(fontSize: 15),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
Text(
|
||||
"#${item.number}",
|
||||
style: TextStyle(fontSize: 15, color: Colors.grey),
|
||||
)
|
||||
],
|
||||
),
|
||||
margin: isOpPost
|
||||
? EdgeInsets.only(
|
||||
top: 5, bottom: 2, left: 16, right: 16)
|
||||
: EdgeInsets.only(top: 16, left: 16),
|
||||
),
|
||||
Container(
|
||||
child: Text(item.body, style: TextStyle(fontSize: 17)),
|
||||
margin: EdgeInsets.all(16),
|
||||
)
|
||||
],
|
||||
),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
class MessageItem {
|
||||
final String id;
|
||||
final int number;
|
||||
final String? subject;
|
||||
final String author;
|
||||
final String date;
|
||||
final String body;
|
||||
|
||||
MessageItem(
|
||||
this.id, this.number, this.subject, this.author, this.date, this.body);
|
||||
}
|
@ -126,6 +126,31 @@ class NNTPClient {
|
||||
|
||||
return threads;
|
||||
}
|
||||
|
||||
Future<List<Tuple2<int, MimeMessage>>> getThread(
|
||||
int threadNumber) async {
|
||||
if (currentGroup == null) throw new ArgumentError("current group is null");
|
||||
|
||||
List<Tuple2<int, MimeMessage>> threads = [];
|
||||
|
||||
var newThreadList = await _sendCommand(
|
||||
"THREAD", [threadNumber.toString()]);
|
||||
|
||||
newThreadList.lines.removeAt(0);
|
||||
newThreadList.lines.removeLast(); // remove dot
|
||||
|
||||
await Future.forEach<String>(newThreadList.lines, (element) async {
|
||||
await _sendCommand("ARTICLE", [element]).then((response) {
|
||||
response.lines.removeAt(0);
|
||||
response.lines.removeLast();
|
||||
var rawMsg = response.lines.join("\r\n");
|
||||
threads
|
||||
.add(Tuple2(int.parse(element), MimeMessage.parseFromText(rawMsg)));
|
||||
});
|
||||
});
|
||||
|
||||
return threads;
|
||||
}
|
||||
}
|
||||
|
||||
class _NNTPCommand {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wind/thread_list_model.dart';
|
||||
import 'package:wind/thread_screen.dart';
|
||||
|
||||
class ThreadListView extends StatefulWidget {
|
||||
@override
|
||||
@ -96,7 +97,8 @@ class ThreadListItemView extends StatelessWidget {
|
||||
elevation: 5,
|
||||
child: InkWell(
|
||||
splashColor: Colors.indigo.withAlpha(30),
|
||||
onTap: () => Navigator.pushNamed(context, "/thread"),
|
||||
onTap: () => Navigator.pushNamed(context, "/thread",
|
||||
arguments: ThreadScreenArguments(item)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -123,6 +125,11 @@ class ThreadListItemView extends StatelessWidget {
|
||||
item.date,
|
||||
style: TextStyle(fontSize: 15),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
Text(
|
||||
"#${item.number}",
|
||||
style: TextStyle(fontSize: 15, color: Colors.grey),
|
||||
)
|
||||
],
|
||||
),
|
||||
margin: EdgeInsets.only(top: 5, bottom: 2, left: 16, right: 16),
|
||||
|
29
lib/thread_model.dart
Normal file
29
lib/thread_model.dart
Normal file
@ -0,0 +1,29 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:wind/message_item_view.dart';
|
||||
import 'package:wind/nntp_client.dart';
|
||||
|
||||
class ThreadModel extends ChangeNotifier {
|
||||
NNTPClient? client;
|
||||
|
||||
Future<List<MessageItem>> getThread(int threadNumber) async {
|
||||
if (client!.currentGroup == "") return [];
|
||||
|
||||
List<MessageItem> items = [];
|
||||
|
||||
var thread = await client!.getThread(threadNumber);
|
||||
|
||||
thread.forEach((pair) {
|
||||
var messageNum = pair.item1;
|
||||
var message = pair.item2;
|
||||
items.add(MessageItem(
|
||||
message.getHeaderValue("Message-Id")!,
|
||||
messageNum,
|
||||
null,
|
||||
message.getHeaderValue("From")!,
|
||||
message.getHeaderValue("Date")!,
|
||||
message.decodeTextPlainPart()!));
|
||||
});
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
@ -1,4 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wind/message_item_view.dart';
|
||||
import 'package:wind/nntp_client.dart';
|
||||
import 'package:wind/thread_list_view.dart';
|
||||
import 'package:wind/thread_model.dart';
|
||||
|
||||
class ThreadScreenArguments {
|
||||
final ThreadItem item;
|
||||
|
||||
ThreadScreenArguments(this.item);
|
||||
}
|
||||
|
||||
class ThreadScreen extends StatefulWidget {
|
||||
@override
|
||||
@ -6,12 +17,53 @@ class ThreadScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class ThreadScreenState extends State<ThreadScreen> {
|
||||
late NNTPClient client;
|
||||
late int threadNumber;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var args =
|
||||
ModalRoute.of(context)!.settings.arguments as ThreadScreenArguments;
|
||||
client = context.read<NNTPClient>();
|
||||
threadNumber = args.item.number;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("Thread"),
|
||||
title: Text("Thread #${args.item.number}"),
|
||||
),
|
||||
body: Center(
|
||||
child: Container(
|
||||
width: 640,
|
||||
child: FutureBuilder<List<MessageItem>>(
|
||||
future: _fetch(context),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
List<MessageItem> data = List.from(snapshot.data!);
|
||||
data.insert(
|
||||
0,
|
||||
MessageItem(args.item.id, args.item.number, args.item.subject,
|
||||
args.item.author, args.item.date, args.item.body));
|
||||
return _listView(data);
|
||||
} else if (snapshot.hasError) {
|
||||
return Text("${snapshot.error}");
|
||||
}
|
||||
return Center(child: CircularProgressIndicator());
|
||||
},
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<MessageItem>> _fetch(BuildContext context) async {
|
||||
var model = context.read<ThreadModel>();
|
||||
return await model.getThread(threadNumber);
|
||||
}
|
||||
|
||||
Widget _listView(List<MessageItem> data) {
|
||||
return ListView.builder(
|
||||
itemCount: data.length,
|
||||
itemBuilder: (context, index) {
|
||||
return MessageItemView(item: data[index], isOpPost: index == 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user