232 lines
6.4 KiB
Dart
232 lines
6.4 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:localization/localization.dart';
|
|
import 'package:loris/business_logic/account/account.dart';
|
|
import 'package:loris/business_logic/posting/mentions.dart';
|
|
import 'package:loris/business_logic/timeline/media.dart';
|
|
import '../../global.dart' as global;
|
|
|
|
class TimelinePartModel {
|
|
late List<ThreadModel> threads;
|
|
late int minId;
|
|
late int maxId;
|
|
}
|
|
|
|
enum Visibility { public, unlisted, private, direct }
|
|
|
|
extension VisibilityExtension on Visibility {
|
|
bool get boostable {
|
|
switch (this) {
|
|
case Visibility.direct:
|
|
return false;
|
|
case Visibility.private:
|
|
return false;
|
|
case Visibility.public:
|
|
return true;
|
|
case Visibility.unlisted:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
String get name {
|
|
switch (this) {
|
|
case Visibility.direct:
|
|
return "direct-visibility".i18n();
|
|
case Visibility.private:
|
|
return "private-visibility".i18n();
|
|
case Visibility.public:
|
|
return "public-visibility".i18n();
|
|
case Visibility.unlisted:
|
|
return "unlisted-visibility".i18n();
|
|
}
|
|
}
|
|
|
|
String get queryParam {
|
|
switch (this) {
|
|
case Visibility.direct:
|
|
return "direct";
|
|
case Visibility.private:
|
|
return "private";
|
|
case Visibility.public:
|
|
return "public";
|
|
case Visibility.unlisted:
|
|
return "unlisted";
|
|
}
|
|
}
|
|
|
|
IconData get icon {
|
|
switch (this) {
|
|
case Visibility.direct:
|
|
return Icons.message;
|
|
case Visibility.private:
|
|
return Icons.lock;
|
|
case Visibility.public:
|
|
return Icons.public;
|
|
case Visibility.unlisted:
|
|
return Icons.lock_open;
|
|
}
|
|
}
|
|
}
|
|
|
|
class PostModel implements Comparable {
|
|
late String identity;
|
|
late String id;
|
|
late String? reblogId;
|
|
late String createdAt;
|
|
late String uri;
|
|
late String content;
|
|
late Visibility visibility;
|
|
late bool sensitive;
|
|
late String spoilerText;
|
|
late bool favourited;
|
|
late bool reblogged;
|
|
late AccountModel account;
|
|
late AccountModel? rebloggedBy;
|
|
late List<MediaAttachmentModel> attachments;
|
|
late List<MentionModel> mentions = [];
|
|
// exists if post is a reblog
|
|
late String originalId;
|
|
|
|
PostModel.fromJson(Map<String, dynamic> json, this.identity) {
|
|
id = json["id"] as String;
|
|
reblogId = null;
|
|
createdAt = json["created_at"];
|
|
// in case of reblog
|
|
if (json["reblog"] != null) {
|
|
rebloggedBy = AccountModel.fromJson(json["account"], identity);
|
|
json = json["reblog"];
|
|
reblogId = json["id"];
|
|
} else {
|
|
rebloggedBy = null;
|
|
}
|
|
originalId = json["id"];
|
|
uri = json["uri"] as String;
|
|
content = json["content"] as String;
|
|
visibility = Visibility.values.firstWhere(
|
|
// ignore: prefer_interpolation_to_compose_strings
|
|
(element) => element.toString() == "Visibility." + json["visibility"]);
|
|
sensitive = json["sensitive"] as bool;
|
|
spoilerText = json["spoiler_text"] as String;
|
|
favourited = json["favourited"] as bool;
|
|
reblogged = json["reblogged"] as bool;
|
|
account = AccountModel.fromJson(json["account"], identity);
|
|
attachments = [];
|
|
List<dynamic> jsonAttachmentList = json["media_attachments"];
|
|
for (int i = 0; i < jsonAttachmentList.length; i++) {
|
|
attachments.add(MediaAttachmentModel.fromJson(jsonAttachmentList[i]));
|
|
}
|
|
List<dynamic> jsonMentionList = json["mentions"];
|
|
for (var element in jsonMentionList) {
|
|
mentions.add(MentionModel.fromJson(element));
|
|
}
|
|
}
|
|
|
|
// get instance of account that received this post
|
|
String getReceiverInstance() {
|
|
return identity.substring(identity.indexOf("@"));
|
|
}
|
|
|
|
@override
|
|
int compareTo(dynamic b) {
|
|
return id.compareTo(b.id);
|
|
}
|
|
|
|
Future<ThreadModel> getThread() async {
|
|
final activeId = global.settings!.activeIdentity;
|
|
if (global.settings!.identities[activeId] == null) {
|
|
return ThreadModel([this]);
|
|
}
|
|
final token = global.settings!.identities[activeId]!.token;
|
|
final baseUrl = global.settings!.identities[activeId]!.instanceUrl;
|
|
Map<String, String> headers = {"Authorization": "Bearer $token"};
|
|
headers.addAll(global.defaultHeaders);
|
|
String currentId = reblogId ?? id;
|
|
final url = Uri(
|
|
scheme: "https",
|
|
host: baseUrl,
|
|
path: "/api/v1/statuses/$currentId/context",
|
|
);
|
|
http.Response response = await http.get(url, headers: headers);
|
|
if (response.statusCode != 200 || response.body.isEmpty) {
|
|
return ThreadModel([this]);
|
|
}
|
|
final json = jsonDecode(response.body);
|
|
final List<dynamic> ancestorsJson = json["ancestors"];
|
|
|
|
List<PostModel> posts = [this];
|
|
int i = 0;
|
|
while (i < ancestorsJson.length) {
|
|
posts.add(PostModel.fromJson(ancestorsJson[i], activeId));
|
|
i++;
|
|
}
|
|
return ThreadModel(posts);
|
|
}
|
|
}
|
|
|
|
class ThreadModel {
|
|
late List<PostModel> posts;
|
|
ThreadModel(List<PostModel> allPosts) {
|
|
allPosts.sort();
|
|
posts = allPosts;
|
|
}
|
|
}
|
|
|
|
enum TimelineType {
|
|
public,
|
|
local,
|
|
home,
|
|
}
|
|
|
|
Future<List<ThreadModel>> getTimelineFromServer(
|
|
String? index,
|
|
String identity,
|
|
TimelineType timelineType,
|
|
) async {
|
|
final activeId = identity;
|
|
if (global.settings!.identities[activeId] == null) {
|
|
return [];
|
|
}
|
|
final limit = global.settings?.batchSize;
|
|
final token = global.settings?.identities[activeId]?.token;
|
|
|
|
Map<String, String> query = {"limit": limit.toString()};
|
|
if (index != null) {
|
|
query.addAll({"max_id": index});
|
|
}
|
|
if (timelineType == TimelineType.local) {
|
|
query.addAll({"local": "true"});
|
|
}
|
|
|
|
String tlType = "home";
|
|
if (timelineType == TimelineType.public ||
|
|
timelineType == TimelineType.local) {
|
|
tlType = "public";
|
|
}
|
|
|
|
final baseUrl = global.settings!.identities[activeId]!.instanceUrl;
|
|
final url = Uri(
|
|
scheme: "https",
|
|
host: baseUrl,
|
|
path: "/api/v1/timelines/$tlType",
|
|
queryParameters: query,
|
|
);
|
|
|
|
Map<String, String> headers = {"Authorization": "Bearer $token"};
|
|
headers.addAll(global.defaultHeaders);
|
|
|
|
http.Response response = await http.get(url, headers: headers);
|
|
|
|
while (response.statusCode != 200) {
|
|
await Future.delayed(const Duration(seconds: 5));
|
|
response = await http.get(url, headers: headers);
|
|
}
|
|
|
|
final List<dynamic> json = await jsonDecode(response.body);
|
|
List<ThreadModel> threads = [];
|
|
for (int i = 0; i < json.length; i++) {
|
|
threads.add(await PostModel.fromJson(json[i], identity).getThread());
|
|
}
|
|
return threads;
|
|
}
|