Refactoring naming to be less Facebook centric (not totally excised)

This commit is contained in:
Hank Grabowski 2022-01-17 11:48:55 -05:00
parent 5fbd79e20e
commit 0c47ad1432
34 changed files with 314 additions and 777 deletions

View file

@ -52,7 +52,7 @@ class FriendicaArchiveBrowser extends StatelessWidget {
theme: FriendicaArchiveBrowserTheme.light,
darkTheme: FriendicaArchiveBrowserTheme.dark,
themeMode: settingsController.themeMode,
scrollBehavior: FacebookAppScrollingBehavior(),
scrollBehavior: AppScrollingBehavior(),
home: MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => settingsController),

View file

@ -1,15 +1,15 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_comment.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_comment.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:friendica_archive_browser/src/settings/settings_controller.dart';
import 'package:friendica_archive_browser/src/utils/clipboard_helper.dart';
import 'package:provider/provider.dart';
import 'facebook_link_elements_component.dart';
import 'facebook_media_timeline_component.dart';
import 'link_elements_component.dart';
import 'media_timeline_component.dart';
class CommentCard extends StatelessWidget {
final FacebookComment comment;
final FriendicaComment comment;
const CommentCard({Key? key, required this.comment}) : super(key: key);
@ -64,12 +64,11 @@ class CommentCard extends StatelessWidget {
],
if (comment.links.isNotEmpty) ...[
const SizedBox(height: spacingHeight),
FacebookLinkElementsComponent(links: comment.links)
LinkElementsComponent(links: comment.links)
],
if (comment.mediaAttachments.isNotEmpty) ...[
const SizedBox(height: spacingHeight),
FacebookMediaTimelineComponent(
mediaAttachments: comment.mediaAttachments)
MediaTimelineComponent(mediaAttachments: comment.mediaAttachments)
],
],
),

View file

@ -1,12 +1,12 @@
import 'dart:ui';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_post.dart';
import 'package:latlng/latlng.dart';
import 'package:map/map.dart';
import 'marker_data.dart';
extension GeoSpatialPostExtensions on FacebookPost {
extension GeoSpatialPostExtensions on FriendicaPost {
MarkerData toMarkerData(MapTransformer transformer, Color color) {
final latLon = LatLng(locationData.latitude, locationData.longitude);
final offset = transformer.fromLatLngToXYCoords(latLon);

View file

@ -1,9 +1,9 @@
import 'dart:ui';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_post.dart';
class MarkerData {
final List<FacebookPost> posts;
final List<FriendicaPost> posts;
final Offset pos;
final Color color;

View file

@ -4,23 +4,21 @@ import 'package:logging/logging.dart';
import 'package:metadata_fetch/metadata_fetch.dart';
import 'package:url_launcher/url_launcher.dart';
class FacebookLinkElementsComponent extends StatefulWidget {
static final _logger = Logger('$FacebookLinkElementsComponent');
class LinkElementsComponent extends StatefulWidget {
static final _logger = Logger('$LinkElementsComponent');
final List<Uri> links;
const FacebookLinkElementsComponent({Key? key, required this.links})
const LinkElementsComponent({Key? key, required this.links})
: super(key: key);
@override
State<FacebookLinkElementsComponent> createState() =>
_FacebookLinkElementsComponentState();
State<LinkElementsComponent> createState() => _LinkElementsComponentState();
}
class _FacebookLinkElementsComponentState
extends State<FacebookLinkElementsComponent> {
class _LinkElementsComponentState extends State<LinkElementsComponent> {
final previewWidth = 500.0;
final previewHeight = 165.0;
static final _logger = Logger('$_FacebookLinkElementsComponentState');
static final _logger = Logger('$_LinkElementsComponentState');
final _linkPreviewData = <Metadata>[];
@override
@ -73,7 +71,7 @@ class _FacebookLinkElementsComponentState
onPressed: () async {
await canLaunch(l.url!)
? await launch(l.url!)
: FacebookLinkElementsComponent._logger
: LinkElementsComponent._logger
.info('Failed to launch ${l.url}');
},
child: _buildLinkPreview(context, l))),

View file

@ -1,21 +1,20 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/screens/facebook_media_slideshow_screen.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/screens/media_slideshow_screen.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:friendica_archive_browser/src/settings/settings_controller.dart';
import 'package:provider/provider.dart';
import 'facebook_media_wrapper_component.dart';
import 'media_wrapper_component.dart';
class FacebookMediaTimelineComponent extends StatelessWidget {
class MediaTimelineComponent extends StatelessWidget {
static const double _maxHeightWidth = 400.0;
final List<FacebookMediaAttachment> mediaAttachments;
final List<FriendicaMediaAttachment> mediaAttachments;
const FacebookMediaTimelineComponent(
{Key? key, required this.mediaAttachments})
const MediaTimelineComponent({Key? key, required this.mediaAttachments})
: super(key: key);
@override
@ -49,12 +48,12 @@ class FacebookMediaTimelineComponent extends StatelessWidget {
ChangeNotifierProvider.value(value: settingsController),
Provider.value(value: pathMapper)
],
child: FacebookMediaSlideshowScreen(
child: MediaSlideShowScreen(
mediaAttachments: mediaAttachments,
initialIndex: index));
}));
},
child: FacebookMediaWrapperComponent(
child: MediaWrapperComponent(
mediaAttachment: mediaAttachments[index],
preferredWidth: isSingle ? singleWidth : preferredMultiWidth,
),

View file

@ -2,22 +2,22 @@ import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:friendica_archive_browser/src/settings/settings_controller.dart';
import 'package:friendica_archive_browser/src/utils/snackbar_status_builder.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
class FacebookMediaWrapperComponent extends StatelessWidget {
static final _logger = Logger('$FacebookMediaWrapperComponent');
class MediaWrapperComponent extends StatelessWidget {
static final _logger = Logger('$MediaWrapperComponent');
static const double _noPreferredValue = -1.0;
final FacebookMediaAttachment mediaAttachment;
final FriendicaMediaAttachment mediaAttachment;
final double preferredWidth;
final double preferredHeight;
const FacebookMediaWrapperComponent(
const MediaWrapperComponent(
{Key? key,
required this.mediaAttachment,
this.preferredWidth = _noPreferredValue,
@ -39,11 +39,11 @@ class FacebookMediaWrapperComponent extends StatelessWidget {
: MediaQuery.of(context).size.height;
if (mediaAttachment.estimatedType() ==
FacebookAttachmentMediaType.unknown) {
FriendicaAttachmentMediaType.unknown) {
return Text('Unable to resolve type for ${mediaAttachment.uri.path}');
}
if (mediaAttachment.estimatedType() == FacebookAttachmentMediaType.video) {
if (mediaAttachment.estimatedType() == FriendicaAttachmentMediaType.video) {
final title = "Video (click to play): " + mediaAttachment.title;
final thumbnailImageResult = _uriToImage(
mediaAttachment.thumbnailUri, pathMapper,
@ -75,7 +75,7 @@ class FacebookMediaWrapperComponent extends StatelessWidget {
);
}
if (mediaAttachment.estimatedType() == FacebookAttachmentMediaType.image) {
if (mediaAttachment.estimatedType() == FriendicaAttachmentMediaType.image) {
final imageResult = _uriToImage(mediaAttachment.uri, pathMapper);
if (imageResult.image == null) {
final errorPath = imageResult.path.isNotEmpty

View file

@ -1,18 +1,18 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_location_data.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_timeline_type.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/location_data.dart';
import 'package:friendica_archive_browser/src/friendica/models/timeline_type.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:friendica_archive_browser/src/settings/settings_controller.dart';
import 'package:friendica_archive_browser/src/utils/clipboard_helper.dart';
import 'package:provider/provider.dart';
import 'facebook_link_elements_component.dart';
import 'facebook_media_timeline_component.dart';
import 'link_elements_component.dart';
import 'media_timeline_component.dart';
class PostCard extends StatelessWidget {
final FacebookPost post;
final FriendicaPost post;
const PostCard({Key? key, required this.post}) : super(key: key);
@ -53,14 +53,14 @@ class PostCard extends StatelessWidget {
style: const TextStyle(
fontStyle: FontStyle.italic,
)),
if (post.timelineType != FacebookTimelineType.active)
if (post.timelineType != TimelineType.active)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Tooltip(
message:
'Post is in ${post.timelineType == FacebookTimelineType.trash ? 'Trash' : 'Archive'}',
'Post is in ${post.timelineType == TimelineType.trash ? 'Trash' : 'Archive'}',
child: Icon(
post.timelineType == FacebookTimelineType.trash
post.timelineType == TimelineType.trash
? Icons.delete_outline
: Icons.archive_outlined,
color: Theme.of(context).disabledColor,
@ -84,12 +84,11 @@ class PostCard extends StatelessWidget {
post.locationData.toWidget(spacingHeight),
if (post.links.isNotEmpty) ...[
const SizedBox(height: spacingHeight),
FacebookLinkElementsComponent(links: post.links)
LinkElementsComponent(links: post.links)
],
if (post.mediaAttachments.isNotEmpty) ...[
const SizedBox(height: spacingHeight),
FacebookMediaTimelineComponent(
mediaAttachments: post.mediaAttachments)
MediaTimelineComponent(mediaAttachments: post.mediaAttachments)
]
],
),

View file

@ -1,101 +0,0 @@
import 'package:logging/logging.dart';
import 'model_utils.dart';
class FacebookSavedItem {
static final _logger = Logger('$FacebookSavedItem');
final String externalName;
final int timestamp;
final String title;
final String text;
final Uri uri;
FacebookSavedItem(
{this.externalName = '',
this.timestamp = 0,
this.title = '',
this.text = '',
required this.uri});
FacebookSavedItem copy(
{String? externalName,
int? timestamp,
String? title,
String? text,
Uri? uri}) {
return FacebookSavedItem(
externalName: externalName ?? this.externalName,
timestamp: timestamp ?? this.timestamp,
title: title ?? this.title,
text: text ?? this.text,
uri: uri ?? this.uri,
);
}
static FacebookSavedItem fromFacebookJson(Map<String, dynamic> json) {
final knownTopLevelKeys = ['attachments', 'title', 'timestamp'];
final knownExternalContextKeys = ['name', 'source', 'url'];
int timestamp = json['timestamp'] ?? 0;
logAdditionalKeys(knownTopLevelKeys, json.keys, _logger, Level.WARNING,
'Unknown root key');
final title = json['title'] ?? '';
var name = '';
var linkUri = Uri.parse('');
var externalName = '';
if (json.containsKey('attachments')) {
final attachments = json['attachments'] ?? <Map<String, dynamic>>[];
if (attachments.length > 1) {
_logger.severe(
'Saved item has multiple attachment items, will only use first: ${attachments.length}');
}
var found = false;
for (Map<String, dynamic> attachment in attachments) {
final dataItem = attachment['data'] ?? <Map<String, dynamic>>[];
if (dataItem.length > 1) {
_logger.severe(
'Attachment has multiple data items, will only use first: ${dataItem.length}');
}
for (Map<String, dynamic> externalItem in dataItem) {
logAdditionalKeys(['external_context'], externalItem.keys, _logger,
Level.WARNING, 'Unknown external data item key');
final externalData =
externalItem['external_context'] ?? <String, String>{};
logAdditionalKeys(knownExternalContextKeys, externalData.keys,
_logger, Level.WARNING, 'Unknown external context key');
name = externalData['name'] ?? '';
final source = externalData['source'] ?? '';
final url = externalData['url'] ?? '';
final sourceUri = Uri.parse(source);
final urlUri = Uri.parse(url);
if (sourceUri.scheme.startsWith('http')) {
linkUri = sourceUri;
externalName = url;
} else {
linkUri = urlUri;
externalName = source;
}
found = true;
break;
}
if (found) {
break;
}
}
}
return FacebookSavedItem(
timestamp: timestamp,
externalName: externalName,
title: title,
text: name,
uri: linkUri);
}
}

View file

@ -1,20 +1,20 @@
import 'package:logging/logging.dart';
import 'facebook_comment.dart';
import 'facebook_media_attachment.dart';
import 'friendica_comment.dart';
import 'friendica_media_attachment.dart';
import 'model_utils.dart';
class FacebookAlbum {
static final _logger = Logger('$FacebookAlbum');
class FriendicaAlbum {
static final _logger = Logger('$FriendicaAlbum');
final String name;
final String description;
final int lastModifiedTimestamp;
final FacebookMediaAttachment coverPhoto;
final List<FacebookMediaAttachment> photos;
final List<FacebookComment> comments;
final FriendicaMediaAttachment coverPhoto;
final List<FriendicaMediaAttachment> photos;
final List<FriendicaComment> comments;
FacebookAlbum(
FriendicaAlbum(
{required this.name,
required this.description,
required this.lastModifiedTimestamp,
@ -22,7 +22,7 @@ class FacebookAlbum {
required this.photos,
required this.comments});
static FacebookAlbum fromJson(Map<String, dynamic> json) {
static FriendicaAlbum fromJson(Map<String, dynamic> json) {
final knownAlbumKeys = [
'name',
'photos',
@ -38,21 +38,21 @@ class FacebookAlbum {
String name = json['name'] ?? '';
String description = json['description'] ?? '';
int lastModifiedTimestamp = json['last_modified_timestamp'] ?? 0;
FacebookMediaAttachment coverPhoto = json.containsKey('cover_photo')
? FacebookMediaAttachment.fromFacebookJson(json['cover_photo'])
: FacebookMediaAttachment.blank();
FriendicaMediaAttachment coverPhoto = json.containsKey('cover_photo')
? FriendicaMediaAttachment.fromFacebookJson(json['cover_photo'])
: FriendicaMediaAttachment.blank();
final photos = <FacebookMediaAttachment>[];
final photos = <FriendicaMediaAttachment>[];
for (Map<String, dynamic> photoJson in json['photos'] ?? []) {
photos.add(FacebookMediaAttachment.fromFacebookJson(photoJson));
photos.add(FriendicaMediaAttachment.fromFacebookJson(photoJson));
}
final comments = <FacebookComment>[];
final comments = <FriendicaComment>[];
for (Map<String, dynamic> commentsJson in json['comments'] ?? []) {
comments.add(FacebookComment.fromInnerCommentJson(commentsJson));
comments.add(FriendicaComment.fromInnerCommentJson(commentsJson));
}
return FacebookAlbum(
return FriendicaAlbum(
name: name,
description: description,
lastModifiedTimestamp: lastModifiedTimestamp,

View file

@ -2,11 +2,11 @@ import 'package:friendica_archive_browser/src/friendica/services/path_mapping_se
import 'package:intl/intl.dart';
import 'package:logging/logging.dart';
import 'facebook_media_attachment.dart';
import 'friendica_media_attachment.dart';
import 'model_utils.dart';
class FacebookComment {
static final _logger = Logger('$FacebookComment');
class FriendicaComment {
static final _logger = Logger('$FriendicaComment');
final int creationTimestamp;
@ -18,22 +18,22 @@ class FacebookComment {
final String title;
final List<FacebookMediaAttachment> mediaAttachments;
final List<FriendicaMediaAttachment> mediaAttachments;
final List<Uri> links;
FacebookComment(
FriendicaComment(
{this.creationTimestamp = 0,
this.author = '',
this.comment = '',
this.group = '',
this.title = '',
List<FacebookMediaAttachment>? mediaAttachments,
List<FriendicaMediaAttachment>? mediaAttachments,
List<Uri>? links})
: mediaAttachments = mediaAttachments ?? <FacebookMediaAttachment>[],
: mediaAttachments = mediaAttachments ?? <FriendicaMediaAttachment>[],
links = links ?? <Uri>[];
FacebookComment.randomBuilt()
FriendicaComment.randomBuilt()
: creationTimestamp = DateTime.now().millisecondsSinceEpoch,
author = 'Random Author ${randomId()}',
comment = 'Random comment text ${randomId()}',
@ -44,19 +44,19 @@ class FacebookComment {
Uri.parse('http://localhost/${randomId()}')
],
mediaAttachments = [
FacebookMediaAttachment.randomBuilt(),
FacebookMediaAttachment.randomBuilt()
FriendicaMediaAttachment.randomBuilt(),
FriendicaMediaAttachment.randomBuilt()
];
FacebookComment copy(
FriendicaComment copy(
{int? creationTimestamp,
String? author,
String? comment,
String? group,
String? title,
List<FacebookMediaAttachment>? mediaAttachments,
List<FriendicaMediaAttachment>? mediaAttachments,
List<Uri>? links}) {
return FacebookComment(
return FriendicaComment(
creationTimestamp: creationTimestamp ?? this.creationTimestamp,
author: author ?? this.author,
comment: comment ?? this.comment,
@ -90,14 +90,14 @@ class FacebookComment {
].join('\n');
}
FacebookComment.fromJson(Map<String, dynamic> json)
FriendicaComment.fromJson(Map<String, dynamic> json)
: creationTimestamp = json['creationTimeStamp'] ?? 0,
author = json['author'] ?? '',
comment = json['comment'] ?? '',
group = json['group'] ?? '',
title = json['title'] ?? '',
mediaAttachments = (json['mediaAttachments'] as List<dynamic>? ?? [])
.map((j) => FacebookMediaAttachment.fromJson(j))
.map((j) => FriendicaMediaAttachment.fromJson(j))
.toList(),
links = (json['links'] as List<dynamic>? ?? [])
.map((j) => Uri.parse(j))
@ -115,15 +115,15 @@ class FacebookComment {
bool hasImages() => mediaAttachments
.where((element) =>
element.estimatedType() == FacebookAttachmentMediaType.image)
element.estimatedType() == FriendicaAttachmentMediaType.image)
.isNotEmpty;
bool hasVideos() => mediaAttachments
.where((element) =>
element.estimatedType() == FacebookAttachmentMediaType.video)
element.estimatedType() == FriendicaAttachmentMediaType.video)
.isNotEmpty;
static FacebookComment fromInnerCommentJson(
static FriendicaComment fromInnerCommentJson(
Map<String, dynamic> commentSubData) {
final knownCommentKeys = ['comment', 'timestamp', 'group', 'author'];
if (_logger.isLoggable(Level.WARNING)) {
@ -135,7 +135,7 @@ class FacebookComment {
final author = commentSubData['author'] ?? '';
final timestamp = commentSubData['timestamp'] ?? 0;
return FacebookComment(
return FriendicaComment(
creationTimestamp: timestamp,
author: author,
group: group,
@ -143,7 +143,7 @@ class FacebookComment {
);
}
static FacebookComment fromFacebookJson(Map<String, dynamic> json) {
static FriendicaComment fromFacebookJson(Map<String, dynamic> json) {
final knownTopLevelKeys = ['timestamp', 'data', 'title', 'attachments'];
final knownExternalContextKeys = ['external_context', 'media', 'name'];
int timestamp = json['timestamp'] ?? 0;
@ -151,13 +151,13 @@ class FacebookComment {
logAdditionalKeys(knownTopLevelKeys, json.keys, _logger, Level.WARNING,
'Unknown top level comment keys');
FacebookComment basicCommentData = FacebookComment();
FriendicaComment basicCommentData = FriendicaComment();
if (json.containsKey('data')) {
final data = json['data'];
for (var dataItem in data) {
if (dataItem.containsKey('comment')) {
basicCommentData =
FacebookComment.fromInnerCommentJson(dataItem['comment']);
FriendicaComment.fromInnerCommentJson(dataItem['comment']);
} else {
_logger.warning(
"No comment or update key sequence in post @$timestamp: ${dataItem.keys}");
@ -167,7 +167,7 @@ class FacebookComment {
final String title = json['title'] ?? '';
final links = <Uri>[];
final mediaAttachments = <FacebookMediaAttachment>[];
final mediaAttachments = <FriendicaMediaAttachment>[];
if (json.containsKey('attachments')) {
for (Map<String, dynamic> attachment in json['attachments']) {
@ -191,13 +191,13 @@ class FacebookComment {
}
} else if (dataItem.containsKey('media')) {
mediaAttachments.add(
FacebookMediaAttachment.fromFacebookJson(dataItem['media']));
FriendicaMediaAttachment.fromFacebookJson(dataItem['media']));
}
}
}
}
return FacebookComment(
return FriendicaComment(
creationTimestamp: timestamp,
author: basicCommentData.author,
comment: basicCommentData.comment,

View file

@ -2,8 +2,8 @@ import 'package:logging/logging.dart';
import 'model_utils.dart';
class FacebookFriend {
static final _logger = Logger('$FacebookFriend');
class FriendicaContact {
static final _logger = Logger('$FriendicaContact');
final FriendStatus status;
final String name;
@ -15,7 +15,7 @@ class FacebookFriend {
final int sentTimestamp;
final bool markedAsSpam;
FacebookFriend(
FriendicaContact(
{this.status = FriendStatus.unknown,
required this.name,
this.contactInfo = '',
@ -31,7 +31,7 @@ class FacebookFriend {
return 'FacebookFriend{status: $status, name: $name, contactInfo: $contactInfo, friendSinceTimestamp: $friendSinceTimestamp, receivedTimestamp: $receivedTimestamp, rejectedTimestamp: $rejectedTimestamp, removeTimestamp: $removeTimestamp, sentTimestamp: $sentTimestamp, markedAsSpam: $markedAsSpam}';
}
static FacebookFriend fromJson(
static FriendicaContact fromJson(
Map<String, dynamic> json, FriendStatus status) {
final knownTopLevelKeys = [
'timestamp',
@ -49,42 +49,42 @@ class FacebookFriend {
switch (status) {
case FriendStatus.friends:
return FacebookFriend(
return FriendicaContact(
name: name,
status: status,
contactInfo: contactInfo,
markedAsSpam: markedAsSpam,
friendSinceTimestamp: timestamp);
case FriendStatus.requestReceived:
return FacebookFriend(
return FriendicaContact(
name: name,
status: status,
contactInfo: contactInfo,
markedAsSpam: markedAsSpam,
receivedTimestamp: timestamp);
case FriendStatus.rejectedRequest:
return FacebookFriend(
return FriendicaContact(
name: name,
status: status,
contactInfo: contactInfo,
markedAsSpam: markedAsSpam,
rejectedTimestamp: timestamp);
case FriendStatus.removed:
return FacebookFriend(
return FriendicaContact(
name: name,
status: status,
contactInfo: contactInfo,
markedAsSpam: markedAsSpam,
removeTimestamp: timestamp);
case FriendStatus.sentFriendRequest:
return FacebookFriend(
return FriendicaContact(
name: name,
status: status,
contactInfo: contactInfo,
markedAsSpam: markedAsSpam,
sentTimestamp: timestamp);
case FriendStatus.unknown:
return FacebookFriend(
return FriendicaContact(
name: name,
status: status,
contactInfo: contactInfo,

View file

@ -3,13 +3,13 @@ import 'dart:io';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:logging/logging.dart';
import 'facebook_comment.dart';
import 'friendica_comment.dart';
import 'model_utils.dart';
enum FacebookAttachmentMediaType { unknown, image, video }
enum FriendicaAttachmentMediaType { unknown, image, video }
class FacebookMediaAttachment {
static final _logger = Logger('$FacebookMediaAttachment');
class FriendicaMediaAttachment {
static final _logger = Logger('$FriendicaMediaAttachment');
static final _graphicsExtensions = ['jpg', 'png', 'gif', 'tif'];
static final _movieExtensions = ['avi', 'mp4', 'mpg', 'wmv'];
@ -19,7 +19,7 @@ class FacebookMediaAttachment {
final Map<String, String> metadata;
final List<FacebookComment> comments;
final List<FriendicaComment> comments;
final Uri thumbnailUri;
@ -27,7 +27,7 @@ class FacebookMediaAttachment {
final String description;
FacebookMediaAttachment(
FriendicaMediaAttachment(
{required this.uri,
required this.creationTimestamp,
required this.metadata,
@ -36,19 +36,19 @@ class FacebookMediaAttachment {
required this.description,
required this.comments});
FacebookMediaAttachment.randomBuilt()
FriendicaMediaAttachment.randomBuilt()
: uri = Uri.parse('http://localhost/${randomId()}'),
creationTimestamp = DateTime.now().millisecondsSinceEpoch,
title = 'Random title ${randomId()}',
thumbnailUri = Uri.parse('${randomId()}.jpg'),
description = 'Random description ${randomId()}',
comments = [
FacebookComment.randomBuilt(),
FacebookComment.randomBuilt()
FriendicaComment.randomBuilt(),
FriendicaComment.randomBuilt()
],
metadata = {'value1': randomId(), 'value2': randomId()};
FacebookMediaAttachment.fromUriOnly(this.uri)
FriendicaMediaAttachment.fromUriOnly(this.uri)
: creationTimestamp = 0,
thumbnailUri = Uri.file(''),
title = '',
@ -56,14 +56,14 @@ class FacebookMediaAttachment {
comments = [],
metadata = {};
FacebookMediaAttachment.fromUriAndTime(this.uri, this.creationTimestamp)
FriendicaMediaAttachment.fromUriAndTime(this.uri, this.creationTimestamp)
: thumbnailUri = Uri.file(''),
title = '',
description = '',
comments = [],
metadata = {};
FacebookMediaAttachment.blank()
FriendicaMediaAttachment.blank()
: uri = Uri(),
creationTimestamp = 0,
thumbnailUri = Uri.file(''),
@ -85,15 +85,15 @@ class FacebookMediaAttachment {
return mapper.toFullPath(uri.toString());
}
FacebookAttachmentMediaType estimatedType() => mediaTypeFromString(uri.path);
FriendicaAttachmentMediaType estimatedType() => mediaTypeFromString(uri.path);
FacebookMediaAttachment.fromJson(Map<String, dynamic> json)
FriendicaMediaAttachment.fromJson(Map<String, dynamic> json)
: uri = Uri.parse(json['uri']),
creationTimestamp = json['creationTimestamp'],
metadata = (json['metadata'] as Map<String, dynamic>? ?? {})
.map((key, value) => MapEntry(key, value.toString())),
comments = (json['comments'] as List<dynamic>? ?? [])
.map((j) => FacebookComment.fromJson(j))
.map((j) => FriendicaComment.fromJson(j))
.toList(),
thumbnailUri = Uri.parse(json['thumbnailUri'] ?? ''),
title = json['title'] ?? '',
@ -109,7 +109,7 @@ class FacebookMediaAttachment {
'description': description,
};
static FacebookMediaAttachment fromFacebookJson(Map<String, dynamic> json) {
static FriendicaMediaAttachment fromFacebookJson(Map<String, dynamic> json) {
final Uri uri = Uri.parse(json['uri']);
final int timestamp = json['creation_timestamp'] ?? 0;
final String title = json['title'] ?? '';
@ -130,13 +130,13 @@ class FacebookMediaAttachment {
metadata[key] = value;
}
});
final comments = <FacebookComment>[];
final comments = <FriendicaComment>[];
for (Map<String, dynamic> commentJson in json['comments'] ?? {}) {
final comment = FacebookComment.fromInnerCommentJson(commentJson);
final comment = FriendicaComment.fromInnerCommentJson(commentJson);
comments.add(comment);
}
return FacebookMediaAttachment(
return FriendicaMediaAttachment(
uri: uri,
creationTimestamp: timestamp,
metadata: metadata,
@ -146,25 +146,25 @@ class FacebookMediaAttachment {
description: description);
}
static FacebookAttachmentMediaType mediaTypeFromString(String path) {
static FriendicaAttachmentMediaType mediaTypeFromString(String path) {
final separator = Platform.isWindows ? '\\' : '/';
final lastSlash = path.lastIndexOf(separator) + 1;
final filename = path.substring(lastSlash);
final lastPeriod = filename.lastIndexOf('.') + 1;
if (lastPeriod == 0) {
return FacebookAttachmentMediaType.unknown;
return FriendicaAttachmentMediaType.unknown;
}
final extension = filename.substring(lastPeriod).toLowerCase();
if (_graphicsExtensions.contains(extension)) {
return FacebookAttachmentMediaType.image;
return FriendicaAttachmentMediaType.image;
}
if (_movieExtensions.contains(extension)) {
return FacebookAttachmentMediaType.video;
return FriendicaAttachmentMediaType.video;
}
return FacebookAttachmentMediaType.unknown;
return FriendicaAttachmentMediaType.unknown;
}
}

View file

@ -2,13 +2,13 @@ import 'package:friendica_archive_browser/src/friendica/services/path_mapping_se
import 'package:intl/intl.dart';
import 'package:logging/logging.dart';
import 'facebook_location_data.dart';
import 'facebook_media_attachment.dart';
import 'facebook_timeline_type.dart';
import 'friendica_media_attachment.dart';
import 'location_data.dart';
import 'model_utils.dart';
import 'timeline_type.dart';
class FacebookPost {
static final _logger = Logger('$FacebookPost');
class FriendicaPost {
static final _logger = Logger('$FriendicaPost');
final int creationTimestamp;
@ -20,55 +20,55 @@ class FacebookPost {
final String title;
final List<FacebookMediaAttachment> mediaAttachments;
final List<FriendicaMediaAttachment> mediaAttachments;
final FacebookLocationData locationData;
final LocationData locationData;
final List<Uri> links;
final FacebookTimelineType timelineType;
final TimelineType timelineType;
FacebookPost(
FriendicaPost(
{this.creationTimestamp = 0,
this.backdatedTimestamp = 0,
this.modificationTimestamp = 0,
this.post = '',
this.title = '',
this.locationData = const FacebookLocationData(),
this.locationData = const LocationData(),
required this.timelineType,
List<FacebookMediaAttachment>? mediaAttachments,
List<FriendicaMediaAttachment>? mediaAttachments,
List<Uri>? links})
: mediaAttachments = mediaAttachments ?? <FacebookMediaAttachment>[],
: mediaAttachments = mediaAttachments ?? <FriendicaMediaAttachment>[],
links = links ?? <Uri>[];
FacebookPost.randomBuilt()
FriendicaPost.randomBuilt()
: creationTimestamp = DateTime.now().millisecondsSinceEpoch,
backdatedTimestamp = DateTime.now().millisecondsSinceEpoch,
modificationTimestamp = DateTime.now().millisecondsSinceEpoch,
post = 'Random post text ${randomId()}',
title = 'Random title ${randomId()}',
locationData = FacebookLocationData.randomBuilt(),
timelineType = FacebookTimelineType.active,
locationData = LocationData.randomBuilt(),
timelineType = TimelineType.active,
links = [
Uri.parse('http://localhost/${randomId()}'),
Uri.parse('http://localhost/${randomId()}')
],
mediaAttachments = [
FacebookMediaAttachment.randomBuilt(),
FacebookMediaAttachment.randomBuilt()
FriendicaMediaAttachment.randomBuilt(),
FriendicaMediaAttachment.randomBuilt()
];
FacebookPost copy(
FriendicaPost copy(
{int? creationTimestamp,
int? backdatedTimestamp,
int? modificationTimestamp,
String? post,
String? title,
FacebookLocationData? locationData,
List<FacebookMediaAttachment>? mediaAttachments,
FacebookTimelineType? timelineType,
LocationData? locationData,
List<FriendicaMediaAttachment>? mediaAttachments,
TimelineType? timelineType,
List<Uri>? links}) {
return FacebookPost(
return FriendicaPost(
creationTimestamp: creationTimestamp ?? this.creationTimestamp,
backdatedTimestamp: backdatedTimestamp ?? this.backdatedTimestamp,
modificationTimestamp:
@ -107,20 +107,20 @@ class FacebookPost {
bool hasImages() => mediaAttachments
.where((element) =>
element.estimatedType() == FacebookAttachmentMediaType.image)
element.estimatedType() == FriendicaAttachmentMediaType.image)
.isNotEmpty;
bool hasVideos() => mediaAttachments
.where((element) =>
element.estimatedType() == FacebookAttachmentMediaType.video)
element.estimatedType() == FriendicaAttachmentMediaType.video)
.isNotEmpty;
static FacebookPost fromJson(
Map<String, dynamic> json, FacebookTimelineType timelineType) {
static FriendicaPost fromJson(
Map<String, dynamic> json, TimelineType timelineType) {
final int timestamp = json['timestamp'] ?? 0;
var modificationTimestamp = timestamp;
var backdatedTimestamp = timestamp;
var locationData = const FacebookLocationData();
var locationData = const LocationData();
String post = '';
if (json.containsKey('data')) {
final data = json['data'];
@ -140,7 +140,7 @@ class FacebookPost {
final String title = json['title'] ?? '';
final links = <Uri>[];
final mediaAttachments = <FacebookMediaAttachment>[];
final mediaAttachments = <FriendicaMediaAttachment>[];
if (json.containsKey('attachments')) {
for (Map<String, dynamic> attachment in json['attachments']) {
@ -156,9 +156,9 @@ class FacebookPost {
}
} else if (dataItem.containsKey('media')) {
mediaAttachments.add(
FacebookMediaAttachment.fromFacebookJson(dataItem['media']));
FriendicaMediaAttachment.fromFacebookJson(dataItem['media']));
} else if (dataItem.containsKey('place')) {
locationData = FacebookLocationData.fromJson(dataItem['place']);
locationData = LocationData.fromJson(dataItem['place']);
} else {
//TODO Add Facebook Post Poll Processing
if (dataItem.containsKey('poll')) continue;
@ -175,7 +175,7 @@ class FacebookPost {
}
}
late final FacebookLocationData actualLocationData;
late final LocationData actualLocationData;
if (locationData.hasPosition) {
actualLocationData = locationData;
} else {
@ -186,7 +186,7 @@ class FacebookPost {
final metadata = mediaWithPosition.first.metadata;
final latitude = double.tryParse(metadata['latitude'] ?? '') ?? 0.0;
final longitude = double.tryParse(metadata['longitude'] ?? '') ?? 0.0;
actualLocationData = FacebookLocationData(
actualLocationData = LocationData(
latitude: latitude, longitude: longitude, hasPosition: true);
} else {
actualLocationData = locationData;
@ -199,7 +199,7 @@ class FacebookPost {
.map((m) => m.title)
.firstWhere((t) => t.isNotEmpty, orElse: () => '');
return FacebookPost(
return FriendicaPost(
creationTimestamp: timestamp,
modificationTimestamp: modificationTimestamp,
backdatedTimestamp: backdatedTimestamp,

View file

@ -1,11 +1,11 @@
import 'dart:math';
import 'package:flutter/widgets.dart';
import 'package:friendica_archive_browser/src/friendica/components/facebook_link_elements_component.dart';
import 'package:friendica_archive_browser/src/friendica/components/link_elements_component.dart';
import 'model_utils.dart';
class FacebookLocationData {
class LocationData {
final String name;
final double latitude;
@ -20,7 +20,7 @@ class FacebookLocationData {
final String url;
const FacebookLocationData(
const LocationData(
{this.name = '',
this.latitude = 0.0,
this.longitude = 0.0,
@ -29,7 +29,7 @@ class FacebookLocationData {
this.address = '',
this.url = ''});
FacebookLocationData.randomBuilt()
LocationData.randomBuilt()
: name = 'Location name ${randomId()}',
latitude = Random().nextDouble(),
longitude = Random().nextDouble(),
@ -59,7 +59,7 @@ class FacebookLocationData {
bool hasData() =>
name.isNotEmpty || address.isNotEmpty || url.isNotEmpty || hasPosition;
static FacebookLocationData fromJson(Map<String, dynamic> json) {
static LocationData fromJson(Map<String, dynamic> json) {
final name = json['name'] ?? '';
final address = json['address'] ?? '';
final url = json['url'] ?? '';
@ -74,7 +74,7 @@ class FacebookLocationData {
altitude = position['altitude'] ?? 0.0;
}
return FacebookLocationData(
return LocationData(
name: name,
address: address,
url: url,
@ -85,7 +85,7 @@ class FacebookLocationData {
}
}
extension WidgetExtensions on FacebookLocationData {
extension WidgetExtensions on LocationData {
Widget toWidget(double spacingHeight) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
@ -110,7 +110,7 @@ extension WidgetExtensions on FacebookLocationData {
],
if (url.isNotEmpty) ...[
SizedBox(height: spacingHeight),
FacebookLinkElementsComponent(
LinkElementsComponent(
links: [Uri.parse(url)],
),
],

View file

@ -1,4 +1,4 @@
enum FacebookTimelineType {
enum TimelineType {
active,
archive,
trash,

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/components/comment_card.dart';
import 'package:friendica_archive_browser/src/friendica/components/filter_control_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_comment.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_comment.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/screens/error_screen.dart';
@ -14,10 +14,10 @@ import 'package:result_monad/result_monad.dart';
import '../../screens/loading_status_screen.dart';
import '../../screens/standin_status_screen.dart';
class FacebookCommentsScreen extends StatelessWidget {
static final _logger = Logger('$FacebookCommentsScreen');
class CommentsScreen extends StatelessWidget {
static final _logger = Logger('$CommentsScreen');
const FacebookCommentsScreen({Key? key}) : super(key: key);
const CommentsScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -26,7 +26,7 @@ class FacebookCommentsScreen extends StatelessWidget {
_logger.fine('Build FacebookPostListView');
return FutureBuilder<Result<List<FacebookComment>, ExecError>>(
return FutureBuilder<Result<List<FriendicaComment>, ExecError>>(
future: service.getComments(),
builder: (context, snapshot) {
_logger.fine('Future Comment builder called');
@ -55,7 +55,7 @@ class FacebookCommentsScreen extends StatelessWidget {
class _FacebookCommentsScreenWidget extends StatelessWidget {
static final _logger = Logger('$_FacebookCommentsScreenWidget');
final List<FacebookComment> comments;
final List<FriendicaComment> comments;
final String username;
const _FacebookCommentsScreenWidget(
@ -65,7 +65,7 @@ class _FacebookCommentsScreenWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
_logger.fine('Redrawing');
return FilterControl<FacebookComment, dynamic>(
return FilterControl<FriendicaComment, dynamic>(
allItems: comments,
imagesOnlyFilterFunction: (comment) => comment.hasImages(),
videosOnlyFilterFunction: (comment) => comment.hasVideos(),

View file

@ -1,136 +0,0 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/components/filter_control_component.dart';
import 'package:friendica_archive_browser/src/friendica/components/post_card.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_saved_item.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_timeline_type.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/screens/error_screen.dart';
import 'package:friendica_archive_browser/src/settings/settings_controller.dart';
import 'package:friendica_archive_browser/src/utils/exec_error.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';
import '../../screens/loading_status_screen.dart';
import '../../screens/standin_status_screen.dart';
class FacebookSavedItemsScreen extends StatelessWidget {
static final _logger = Logger('$FacebookSavedItemsScreen');
const FacebookSavedItemsScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
_logger.info('Build FacebookSavedItemsScreen');
final service = Provider.of<FacebookArchiveDataService>(context);
final username = Provider.of<SettingsController>(context).facebookName;
return FutureBuilder<Result<List<FacebookSavedItem>, ExecError>>(
future: service.getSavedItems(),
builder: (context, snapshot) {
_logger.info('FacebookSavedItemsScreen Future builder called');
if (!snapshot.hasData ||
snapshot.connectionState != ConnectionState.done) {
return const LoadingStatusScreen(title: 'Loading savedItems');
}
final savedItemsResult = snapshot.requireData;
if (savedItemsResult.isFailure) {
return ErrorScreen(
title: 'Error getting saved items',
error: savedItemsResult.error);
}
final allSavedItems = savedItemsResult.value;
final savedItems = username.isEmpty
? allSavedItems.toList()
: allSavedItems.map((item) {
var newTitle = item.title;
if (item.title == username) {
newTitle = 'You posted';
} else {
newTitle = item.title
.replaceAll(username, 'You')
.replaceAll(wholeWordRegEx('his'), 'your')
.replaceAll(wholeWordRegEx('her'), 'your');
}
if (newTitle == item.title) {
return item;
} else {
return item.copy(title: newTitle);
}
}).toList();
if (savedItems.isEmpty) {
return const StandInStatusScreen(
title: 'No saved items were found');
}
_logger.fine('Build Saved Items ListView');
final savedItemsAsPosts = savedItems
.map((item) => FacebookPost(
creationTimestamp: item.timestamp,
title: item.title,
post: item.text,
links: item.uri.toString().isNotEmpty ? [item.uri] : [],
timelineType: FacebookTimelineType.active))
.toList();
return _FacebookSavedItemsScreenWidget(
savedItemsAsPosts: savedItemsAsPosts);
});
}
}
class _FacebookSavedItemsScreenWidget extends StatelessWidget {
static final _logger = Logger('$_FacebookSavedItemsScreenWidget');
final List<FacebookPost> savedItemsAsPosts;
const _FacebookSavedItemsScreenWidget(
{Key? key, required this.savedItemsAsPosts})
: super(key: key);
@override
Widget build(BuildContext context) {
_logger.fine('Redrawing');
return FilterControl<FacebookPost, dynamic>(
allItems: savedItemsAsPosts,
textSearchFilterFunction: (post, text) =>
post.title.contains(text) ||
post.post.contains(text) ||
post.links.where((l) => l.toString().contains(text)).isNotEmpty,
itemToDateTimeFunction: (post) =>
DateTime.fromMillisecondsSinceEpoch(post.creationTimestamp * 1000),
dateRangeFilterFunction: (post, start, stop) =>
timestampInRange(post.creationTimestamp * 1000, start, stop),
builder: (context, items) {
if (items.isEmpty) {
return const StandInStatusScreen(
title: 'No saved items meet filter criteria');
}
return ScrollConfiguration(
behavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false),
child: ListView.separated(
primary: false,
restorationId: 'facebookSavedItemsListView',
itemCount: items.length,
itemBuilder: (context, index) {
_logger.finer('Rendering Saved Item List Item');
return PostCard(post: items[index]);
},
separatorBuilder: (context, index) {
return const Divider(
color: Colors.black,
thickness: 0.2,
);
}),
);
});
}
}

View file

@ -1,104 +0,0 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/components/filter_control_component.dart';
import 'package:friendica_archive_browser/src/friendica/components/post_card.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/screens/error_screen.dart';
import 'package:friendica_archive_browser/src/utils/exec_error.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';
import '../../screens/loading_status_screen.dart';
import '../../screens/standin_status_screen.dart';
class FacebookVideosScreen extends StatelessWidget {
static final _logger = Logger('$FacebookVideosScreen');
const FacebookVideosScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
_logger.fine('Build FacebookVideosScreen');
final service = Provider.of<FacebookArchiveDataService>(context);
return FutureBuilder<Result<List<FacebookPost>, ExecError>>(
future: service.getPosts(),
builder: (context, snapshot) {
_logger.fine('FacebookVideosScreen Future builder called');
if (!snapshot.hasData ||
snapshot.connectionState != ConnectionState.done) {
return const LoadingStatusScreen(title: 'Loading videos');
}
final result = snapshot.requireData;
if (result.isFailure) {
return ErrorScreen(
title: 'Error getting video posts', error: result.error);
}
final videos = result.value
.where((p) => p.mediaAttachments
.where((m) =>
m.estimatedType() == FacebookAttachmentMediaType.video)
.isNotEmpty)
.toList();
if (videos.isEmpty) {
return const StandInStatusScreen(title: 'No videos were found');
}
_logger.fine('Build Videos ListView');
return _FacebookVideosScreenWidget(posts: videos);
});
}
}
class _FacebookVideosScreenWidget extends StatelessWidget {
static final _logger = Logger('$_FacebookVideosScreenWidget');
final List<FacebookPost> posts;
const _FacebookVideosScreenWidget({Key? key, required this.posts})
: super(key: key);
@override
Widget build(BuildContext context) {
_logger.fine('Redrawing');
return FilterControl<FacebookPost, dynamic>(
allItems: posts,
textSearchFilterFunction: (post, text) =>
post.title.contains(text) || post.post.contains(text),
itemToDateTimeFunction: (post) =>
DateTime.fromMillisecondsSinceEpoch(post.creationTimestamp * 1000),
dateRangeFilterFunction: (post, start, stop) =>
timestampInRange(post.creationTimestamp * 1000, start, stop),
builder: (context, items) {
if (items.isEmpty) {
return const StandInStatusScreen(
title: 'No videos meet filter criteria');
}
return ScrollConfiguration(
behavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false),
child: ListView.separated(
primary: false,
restorationId: 'facebookVideosListView',
itemCount: items.length,
itemBuilder: (context, index) {
_logger.finer('Rendering Facebook Video List Item');
return PostCard(post: items[index]);
},
separatorBuilder: (context, index) {
return const Divider(
color: Colors.black,
thickness: 0.2,
);
}),
);
});
}
}

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_friend.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_contact.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/screens/error_screen.dart';
import 'package:friendica_archive_browser/src/screens/loading_status_screen.dart';
@ -11,10 +11,10 @@ import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';
class FacebookFriendsScreen extends StatelessWidget {
static final _logger = Logger('$FacebookFriendsScreen');
class FriendsScreen extends StatelessWidget {
static final _logger = Logger('$FriendsScreen');
const FacebookFriendsScreen({Key? key}) : super(key: key);
const FriendsScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -22,7 +22,7 @@ class FacebookFriendsScreen extends StatelessWidget {
final rootPath = Provider.of<SettingsController>(context).rootFolder;
_logger.fine('Build FacebookFriendsScreen');
return FutureBuilder<Result<List<FacebookFriend>, ExecError>>(
return FutureBuilder<Result<List<FriendicaContact>, ExecError>>(
future: service.getFriends(),
builder: (context, snapshot) {
_logger.fine('Future Friends builder called');
@ -50,7 +50,7 @@ class FacebookFriendsScreen extends StatelessWidget {
}
class _FacebookFriendsScreenWidget extends StatelessWidget {
final List<FacebookFriend> friends;
final List<FriendicaContact> friends;
final String rootPath;
const _FacebookFriendsScreenWidget(

View file

@ -6,7 +6,7 @@ import 'package:friendica_archive_browser/src/friendica/components/geo/geo_exten
import 'package:friendica_archive_browser/src/friendica/components/geo/map_bounds.dart';
import 'package:friendica_archive_browser/src/friendica/components/geo/marker_data.dart';
import 'package:friendica_archive_browser/src/friendica/components/post_card.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
@ -25,10 +25,10 @@ import 'package:network_to_file_image/network_to_file_image.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';
class FacebookGeospatialViewScreen extends StatelessWidget {
static final _logger = Logger('$FacebookGeospatialViewScreen');
class GeospatialViewScreen extends StatelessWidget {
static final _logger = Logger('$GeospatialViewScreen');
const FacebookGeospatialViewScreen({Key? key}) : super(key: key);
const GeospatialViewScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -36,7 +36,7 @@ class FacebookGeospatialViewScreen extends StatelessWidget {
final service = Provider.of<FacebookArchiveDataService>(context);
final username = Provider.of<SettingsController>(context).facebookName;
return FutureBuilder<Result<List<FacebookPost>, ExecError>>(
return FutureBuilder<Result<List<FriendicaPost>, ExecError>>(
future: service.getPosts(),
builder: (context, snapshot) {
_logger.info('FacebookGeospatialViewScreen Future builder called');
@ -86,7 +86,7 @@ class FacebookGeospatialViewScreen extends StatelessWidget {
}
class GeospatialView extends StatefulWidget {
final List<FacebookPost> posts;
final List<FriendicaPost> posts;
const GeospatialView({Key? key, required this.posts}) : super(key: key);
@ -108,8 +108,8 @@ class _GeospatialViewState extends State<GeospatialView> {
);
Offset? dragStart;
final postsInList = <FacebookPost>[];
final postsInView = <FacebookPost>[];
final postsInList = <FriendicaPost>[];
final postsInView = <FriendicaPost>[];
double scaleStart = 1.0;
@override

View file

@ -3,33 +3,31 @@ import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:friendica_archive_browser/src/friendica/components/facebook_media_wrapper_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/components/media_wrapper_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:friendica_archive_browser/src/settings/settings_controller.dart';
import 'package:friendica_archive_browser/src/themes.dart';
import 'package:friendica_archive_browser/src/utils/snackbar_status_builder.dart';
import 'package:provider/provider.dart';
class FacebookMediaSlideshowScreen extends StatefulWidget {
class MediaSlideShowScreen extends StatefulWidget {
static const _spacing = 5.0;
final List<FacebookMediaAttachment> mediaAttachments;
final List<FriendicaMediaAttachment> mediaAttachments;
final int initialIndex;
const FacebookMediaSlideshowScreen(
const MediaSlideShowScreen(
{Key? key, required this.mediaAttachments, required this.initialIndex})
: super(key: key);
@override
State<FacebookMediaSlideshowScreen> createState() =>
_FacebookMediaSlideshowScreenState();
State<MediaSlideShowScreen> createState() => _MediaSlideShowScreenState();
}
class _FacebookMediaSlideshowScreenState
extends State<FacebookMediaSlideshowScreen> {
class _MediaSlideShowScreenState extends State<MediaSlideShowScreen> {
static const fastestChangeMS = 250;
FacebookMediaAttachment media = FacebookMediaAttachment.blank();
FriendicaMediaAttachment media = FriendicaMediaAttachment.blank();
int index = 0;
int lastKeyInducedIndexChange = 0;
@ -113,15 +111,13 @@ class _FacebookMediaSlideshowScreenState
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: FacebookMediaWrapperComponent(
child: MediaWrapperComponent(
mediaAttachment: media,
),
),
const SizedBox(
height: FacebookMediaSlideshowScreen._spacing),
const SizedBox(height: MediaSlideShowScreen._spacing),
SelectableText(media.description),
const SizedBox(
height: FacebookMediaSlideshowScreen._spacing),
const SizedBox(height: MediaSlideShowScreen._spacing),
SelectableText(
formatter.format(DateTime.fromMillisecondsSinceEpoch(
media.creationTimestamp * 1000)),

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/components/facebook_media_wrapper_component.dart';
import 'package:friendica_archive_browser/src/friendica/components/filter_control_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_album.dart';
import 'package:friendica_archive_browser/src/friendica/components/media_wrapper_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_album.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
@ -14,19 +14,19 @@ import 'package:result_monad/result_monad.dart';
import '../../screens/loading_status_screen.dart';
import '../../screens/standin_status_screen.dart';
import 'facebook_photo_album_screen.dart';
import 'photo_album_screen.dart';
class FacebookPhotoAlbumsBrowserScreen extends StatelessWidget {
static final _logger = Logger('$FacebookPhotoAlbumsBrowserScreen');
class PhotoAlbumsBrowserScreen extends StatelessWidget {
static final _logger = Logger('$PhotoAlbumsBrowserScreen');
const FacebookPhotoAlbumsBrowserScreen({Key? key}) : super(key: key);
const PhotoAlbumsBrowserScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
_logger.fine('Build FacebookAlbumListView');
final service = Provider.of<FacebookArchiveDataService>(context);
return FutureBuilder<Result<List<FacebookAlbum>, ExecError>>(
return FutureBuilder<Result<List<FriendicaAlbum>, ExecError>>(
future: service.getAlbums(),
builder: (futureBuilderContext, snapshot) {
_logger.fine('FacebookAlbumListView Future builder called');
@ -55,7 +55,7 @@ class FacebookPhotoAlbumsBrowserScreen extends StatelessWidget {
}
class _FacebookPhotoAlbumsBrowserScreenWidget extends StatelessWidget {
final List<FacebookAlbum> albums;
final List<FriendicaAlbum> albums;
const _FacebookPhotoAlbumsBrowserScreenWidget(
{Key? key, required this.albums})
@ -66,7 +66,7 @@ class _FacebookPhotoAlbumsBrowserScreenWidget extends StatelessWidget {
final settingsController = Provider.of<SettingsController>(context);
final pathMapper = Provider.of<PathMappingService>(context);
return FilterControl<FacebookAlbum, dynamic>(
return FilterControl<FriendicaAlbum, dynamic>(
allItems: albums,
textSearchFilterFunction: (album, text) =>
album.name.contains(text) || album.description.contains(text),
@ -96,7 +96,7 @@ class _FacebookPhotoAlbumsBrowserScreenWidget extends StatelessWidget {
return MultiProvider(providers: [
ChangeNotifierProvider.value(value: settingsController),
Provider.value(value: pathMapper)
], child: FacebookPhotoAlbumScreen(album: album));
], child: PhotoAlbumScreen(album: album));
}));
},
child: SizedBox(
@ -106,7 +106,7 @@ class _FacebookPhotoAlbumsBrowserScreenWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FacebookMediaWrapperComponent(
MediaWrapperComponent(
preferredWidth: 150,
preferredHeight: 150,
mediaAttachment: album.coverPhoto),

View file

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/components/facebook_media_wrapper_component.dart';
import 'package:friendica_archive_browser/src/friendica/components/filter_control_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_album.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/components/media_wrapper_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_album.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:friendica_archive_browser/src/screens/standin_status_screen.dart';
@ -10,14 +10,13 @@ import 'package:friendica_archive_browser/src/settings/settings_controller.dart'
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'facebook_media_slideshow_screen.dart';
import 'media_slideshow_screen.dart';
class FacebookPhotoAlbumScreen extends StatelessWidget {
static final _logger = Logger('$FacebookPhotoAlbumScreen');
final FacebookAlbum album;
class PhotoAlbumScreen extends StatelessWidget {
static final _logger = Logger('$PhotoAlbumScreen');
final FriendicaAlbum album;
const FacebookPhotoAlbumScreen({Key? key, required this.album})
: super(key: key);
const PhotoAlbumScreen({Key? key, required this.album}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -26,7 +25,7 @@ class FacebookPhotoAlbumScreen extends StatelessWidget {
return album.photos.isEmpty
? _buildEmptyGalleryScrene(context)
: FilterControl<FacebookMediaAttachment, dynamic>(
: FilterControl<FriendicaMediaAttachment, dynamic>(
allItems: album.photos,
textSearchFilterFunction: (photo, text) =>
photo.title.contains(text) || photo.description.contains(text),
@ -57,7 +56,7 @@ class FacebookPhotoAlbumScreen extends StatelessWidget {
class _FacebookPhotoAlbumScreenWidget extends StatelessWidget {
static final _logger = Logger('$_FacebookPhotoAlbumScreenWidget');
final List<FacebookMediaAttachment> photos;
final List<FriendicaMediaAttachment> photos;
final String albumName;
final String albumDescription;
@ -116,12 +115,12 @@ class _FacebookPhotoAlbumScreenWidget extends StatelessWidget {
value: settingsController),
Provider.value(value: pathMapper)
],
child: FacebookMediaSlideshowScreen(
child: MediaSlideShowScreen(
mediaAttachments: photos,
initialIndex: index));
}));
},
child: FacebookMediaWrapperComponent(
child: MediaWrapperComponent(
mediaAttachment: photos[index],
preferredWidth: 300,
preferredHeight: 300,

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/components/filter_control_component.dart';
import 'package:friendica_archive_browser/src/friendica/components/post_card.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/screens/error_screen.dart';
@ -14,10 +14,10 @@ import 'package:result_monad/result_monad.dart';
import '../../screens/loading_status_screen.dart';
import '../../screens/standin_status_screen.dart';
class FacebookPostsScreen extends StatelessWidget {
static final _logger = Logger('$FacebookPostsScreen');
class PostsScreen extends StatelessWidget {
static final _logger = Logger('$PostsScreen');
const FacebookPostsScreen({Key? key}) : super(key: key);
const PostsScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -25,7 +25,7 @@ class FacebookPostsScreen extends StatelessWidget {
final service = Provider.of<FacebookArchiveDataService>(context);
final username = Provider.of<SettingsController>(context).facebookName;
return FutureBuilder<Result<List<FacebookPost>, ExecError>>(
return FutureBuilder<Result<List<FriendicaPost>, ExecError>>(
future: service.getPosts(),
builder: (context, snapshot) {
_logger.info('FacebookPostListView Future builder called');
@ -82,7 +82,7 @@ class FacebookPostsScreen extends StatelessWidget {
class _FacebookPostsScreenWidget extends StatelessWidget {
static final _logger = Logger('$_FacebookPostsScreenWidget');
final List<FacebookPost> posts;
final List<FriendicaPost> posts;
const _FacebookPostsScreenWidget({Key? key, required this.posts})
: super(key: key);
@ -90,7 +90,7 @@ class _FacebookPostsScreenWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
_logger.fine('Redrawing');
return FilterControl<FacebookPost, dynamic>(
return FilterControl<FriendicaPost, dynamic>(
allItems: posts,
imagesOnlyFilterFunction: (post) => post.hasImages(),
videosOnlyFilterFunction: (post) => post.hasVideos(),

View file

@ -3,7 +3,7 @@ import 'package:friendica_archive_browser/src/components/heatmap_widget.dart';
import 'package:friendica_archive_browser/src/components/timechart_widget.dart';
import 'package:friendica_archive_browser/src/components/word_frequency_widget.dart';
import 'package:friendica_archive_browser/src/friendica/components/filter_control_component.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/models/model_utils.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_archive_service.dart';
import 'package:friendica_archive_browser/src/models/time_element.dart';
@ -12,15 +12,15 @@ import 'package:friendica_archive_browser/src/utils/snackbar_status_builder.dart
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
class FacebookStatsScreen extends StatefulWidget {
const FacebookStatsScreen({Key? key}) : super(key: key);
class StatsScreen extends StatefulWidget {
const StatsScreen({Key? key}) : super(key: key);
@override
State<FacebookStatsScreen> createState() => _FacebookStatsScreenState();
State<StatsScreen> createState() => _StatsScreenState();
}
class _FacebookStatsScreenState extends State<FacebookStatsScreen> {
static final _logger = Logger("$_FacebookStatsScreenState");
class _StatsScreenState extends State<StatsScreen> {
static final _logger = Logger("$_StatsScreenState");
FacebookArchiveDataService? archiveDataService;
final allItems = <TimeElement>[];
StatType statType = StatType.selectType;
@ -90,7 +90,7 @@ class _FacebookStatsScreenState extends State<FacebookStatsScreen> {
onSuccess: (posts) => posts
.where((post) => post.hasVideos())
.expand((post) => post.mediaAttachments.where((m) =>
m.estimatedType() == FacebookAttachmentMediaType.video))
m.estimatedType() == FriendicaAttachmentMediaType.video))
.map((e) => TimeElement(
timeInMS: e.creationTimestamp * 1000,
hasImages: false,

View file

@ -2,12 +2,11 @@ import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_album.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_comment.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_friend.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_saved_item.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_timeline_type.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_album.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_comment.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_contact.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/timeline_type.dart';
import 'package:friendica_archive_browser/src/friendica/services/facebook_file_reader.dart';
import 'package:friendica_archive_browser/src/utils/exec_error.dart';
import 'package:logging/logging.dart';
@ -41,15 +40,14 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
_logger.fine('Create new FacebookArchiveFolderReader');
}
FutureResult<List<FacebookPost>, ExecError> readPosts() async {
final posts = <FacebookPost>[];
FutureResult<List<FriendicaPost>, ExecError> readPosts() async {
final posts = <FriendicaPost>[];
final errors = <ExecError>[];
final yourPostPath = '$rootDirectoryPath/posts/your_posts_1.json';
if (File(yourPostPath).existsSync()) {
(await _getJsonList(yourPostPath))
.andThen(
(json) => _parsePostResults(json, FacebookTimelineType.active))
.andThen((json) => _parsePostResults(json, TimelineType.active))
.match(
onSuccess: (newPosts) => posts.addAll(newPosts),
onError: (error) {
@ -66,8 +64,8 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
? Result.ok(json['archive_v2'])
: Result.error(
ExecError.message('No archive_v2 key in $archivedPostsPath')))
.andThen((archivedPostsJson) => _parsePostResults(
archivedPostsJson, FacebookTimelineType.archive))
.andThen((archivedPostsJson) =>
_parsePostResults(archivedPostsJson, TimelineType.archive))
.match(
onSuccess: (archivedPosts) => posts.addAll(archivedPosts),
onError: (error) {
@ -85,7 +83,7 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
: Result.error(
ExecError.message('No trash_v2 key in $trashPostsPath')))
.andThen((archivedPostsJson) =>
_parsePostResults(archivedPostsJson, FacebookTimelineType.trash))
_parsePostResults(archivedPostsJson, TimelineType.trash))
.match(
onSuccess: (archivedPosts) => posts.addAll(archivedPosts),
onError: (error) {
@ -103,7 +101,7 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
return Result.ok(posts);
}
FutureResult<List<FacebookComment>, ExecError> readComments() async {
FutureResult<List<FriendicaComment>, ExecError> readComments() async {
final path = '$rootDirectoryPath/comments_and_reactions/comments.json';
final jsonResult = await _getJson(path);
if (jsonResult.isFailure) {
@ -117,8 +115,9 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
}
final commentsJson = jsonData['comments_v2'] as List<dynamic>;
final commentsResult = runCatching(() => Result.ok(
commentsJson.map((e) => FacebookComment.fromFacebookJson(e)).toList()));
final commentsResult = runCatching(() => Result.ok(commentsJson
.map((e) => FriendicaComment.fromFacebookJson(e))
.toList()));
commentsResult.match(
onSuccess: (value) => _logger.fine('Comments processed into PODOs'),
@ -128,10 +127,10 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
return commentsResult.mapExceptionErrorToExecError();
}
FutureResult<List<FacebookAlbum>, ExecError> readPhotoAlbums() async {
FutureResult<List<FriendicaAlbum>, ExecError> readPhotoAlbums() async {
final albumFolderPath = '$rootDirectoryPath/posts/album';
final folder = Directory(albumFolderPath);
final albums = <FacebookAlbum>[];
final albums = <FriendicaAlbum>[];
if (!folder.existsSync()) {
final msg = 'Photos folder does not exist; $albumFolderPath';
@ -157,7 +156,7 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
jsonResult.match(
onSuccess: (json) {
final albumResult =
runCatching(() => Result.ok(FacebookAlbum.fromJson(json)));
runCatching(() => Result.ok(FriendicaAlbum.fromJson(json)));
albumResult.match(
onSuccess: (album) {
albums.add(album);
@ -173,14 +172,14 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
return Result.ok(albums);
}
FutureResult<List<FacebookFriend>, ExecError> readFriends() async {
FutureResult<List<FriendicaContact>, ExecError> readFriends() async {
final basePath = '$rootDirectoryPath/friends_and_followers';
final friendsFile = File('$basePath/friends.json');
final receivedFile = File('$basePath/friend_requests_received.json');
final rejectedFile = File('$basePath/rejected_friend_requests.json');
final removedFile = File('$basePath/removed_friends.json');
final sentFile = File('$basePath/friend_requests_sent.json');
final allFriends = <FacebookFriend>[];
final allFriends = <FriendicaContact>[];
if (!Directory(basePath).existsSync()) {
_logger.severe('Friends base folder does not exist: $basePath');
@ -226,39 +225,6 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
return Result.ok(allFriends);
}
FutureResult<List<FacebookSavedItem>, ExecError> readSavedItems() async {
final path =
'$rootDirectoryPath/saved_items_and_collections/saved_items_and_collections.json';
final jsonResult = await _getJson(path);
if (jsonResult.isFailure) {
return Result.error(jsonResult.error);
}
final jsonData = jsonResult.value;
if (!jsonData.containsKey('saves_and_collections_v2')) {
return Result.error(ExecError(
errorMessage:
'Saved Items and Collections JSON file is malformed: $path'));
}
final savedItemsJson =
jsonData['saves_and_collections_v2'] as List<dynamic>;
final savedItemsResult = runCatching(() => Result.ok(savedItemsJson
.map((e) => FacebookSavedItem.fromFacebookJson(e))
.toList()));
savedItemsResult
.andThen(
(items) => Result.ok(items.where((e) => e.timestamp != 0).toList()))
.match(
onSuccess: (value) =>
_logger.fine('Saved Items processed into PODOs'),
onError: (error) => _logger
.severe('Error mapping JSON to saved items data: $error'));
return savedItemsResult.mapExceptionErrorToExecError();
}
static bool validateCanReadArchive(String path) {
_logger.fine('Validating whether path is a valid Facebook Archive: $path');
final baseDir = Directory(path);
@ -277,10 +243,10 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
return true;
}
Result<List<FacebookPost>, ExecError> _parsePostResults(
List<dynamic> json, FacebookTimelineType timelineType) {
Result<List<FriendicaPost>, ExecError> _parsePostResults(
List<dynamic> json, TimelineType timelineType) {
final postsResult = runCatching(() => Result.ok(
json.map((e) => FacebookPost.fromJson(e, timelineType)).toList()));
json.map((e) => FriendicaPost.fromJson(e, timelineType)).toList()));
postsResult.match(
onSuccess: (value) => _logger.fine('Posts processed into PODOs'),
@ -351,9 +317,9 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
return jsonParseResult;
}
FutureResult<List<FacebookFriend>, ExecError> _readFriendsJsonFile(
FutureResult<List<FriendicaContact>, ExecError> _readFriendsJsonFile(
File file, FriendStatus status, String topKey) async {
final friends = <FacebookFriend>[];
final friends = <FriendicaContact>[];
if (file.existsSync()) {
final json = (await _getJson(file.path)).fold(
@ -364,7 +330,8 @@ class FacebookArchiveFolderReader extends ChangeNotifier {
});
final List<dynamic> invited = json[topKey] ?? <Map<String, dynamic>>[];
try {
final entries = invited.map((f) => FacebookFriend.fromJson(f, status));
final entries =
invited.map((f) => FriendicaContact.fromJson(f, status));
_logger.fine(
'${entries.length} friends of type $status found in ${file.path}');
friends.addAll(entries);

View file

@ -1,16 +1,14 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_album.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_comment.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_friend.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_post.dart';
import 'package:friendica_archive_browser/src/friendica/models/facebook_saved_item.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_album.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_comment.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_contact.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_media_attachment.dart';
import 'package:friendica_archive_browser/src/friendica/models/friendica_post.dart';
import 'package:friendica_archive_browser/src/friendica/services/path_mapping_service.dart';
import 'package:friendica_archive_browser/src/utils/exec_error.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:result_monad/result_monad.dart';
import 'facebook_archive_reader.dart';
@ -19,11 +17,10 @@ class FacebookArchiveDataService extends ChangeNotifier {
static final _logger = Logger('$FacebookArchiveDataService');
final PathMappingService pathMappingService;
final String appDataDirectory;
final List<FacebookAlbum> albums = [];
final List<FacebookPost> posts = [];
final List<FacebookComment> comments = [];
final List<FacebookFriend> friends = [];
final List<FacebookSavedItem> savedItems = [];
final List<FriendicaAlbum> albums = [];
final List<FriendicaPost> posts = [];
final List<FriendicaComment> comments = [];
final List<FriendicaContact> friends = [];
bool canUseConvoCacheFile = true;
FacebookArchiveDataService(
@ -38,29 +35,12 @@ class FacebookArchiveDataService extends ChangeNotifier {
posts.clear();
comments.clear();
friends.clear();
savedItems.clear();
notifyListeners();
canUseConvoCacheFile = false;
_logger.finer('Deleting files');
try {
final convoCacheFile = File(_conversationCachePath);
if (convoCacheFile.existsSync()) {
convoCacheFile.deleteSync();
}
if (convoCacheFile.existsSync()) {
_logger.severe(
'Attempted to delete conversations cache file but it did not succeed. ${convoCacheFile.path}');
}
} catch (e) {
_logger.severe(
'Exception thrown while attempting to clear conversations cache file: $e');
}
canUseConvoCacheFile = true;
_logger.fine('clearCaches complete');
}
FutureResult<List<FacebookPost>, ExecError> getPosts() async {
FutureResult<List<FriendicaPost>, ExecError> getPosts() async {
_logger.fine('Request for posts');
if (posts.isNotEmpty) {
_logger.fine(
@ -82,7 +62,7 @@ class FacebookArchiveDataService extends ChangeNotifier {
return Result.ok(List.unmodifiable(posts));
}
FutureResult<List<FacebookComment>, ExecError> getComments() async {
FutureResult<List<FriendicaComment>, ExecError> getComments() async {
_logger.fine('Request for comments');
if (comments.isNotEmpty) {
_logger.fine(
@ -104,7 +84,7 @@ class FacebookArchiveDataService extends ChangeNotifier {
return Result.ok(List.unmodifiable(comments));
}
FutureResult<List<FacebookFriend>, ExecError> getFriends() async {
FutureResult<List<FriendicaContact>, ExecError> getFriends() async {
_logger.fine('Request for friends');
if (friends.isNotEmpty) {
_logger.fine(
@ -124,7 +104,7 @@ class FacebookArchiveDataService extends ChangeNotifier {
return Result.ok(List.unmodifiable(friends));
}
FutureResult<List<FacebookAlbum>, ExecError> getAlbums() async {
FutureResult<List<FriendicaAlbum>, ExecError> getAlbums() async {
_logger.fine('Request for albums');
if (albums.isNotEmpty) {
_logger.fine(
@ -154,32 +134,8 @@ class FacebookArchiveDataService extends ChangeNotifier {
return Result.ok(List.unmodifiable(albums));
}
FutureResult<List<FacebookSavedItem>, ExecError> getSavedItems() async {
_logger.fine('Request for saved items');
if (savedItems.isNotEmpty) {
_logger.fine(
'Saved items already loaded, returning existing ${savedItems.length} comments');
return Result.ok(List.unmodifiable(savedItems));
}
_logger.finer('No previously pulled saved items, reading from disk');
final savedItemsResult = await _readAllSavedItems();
savedItemsResult.match(
onSuccess: (newSavedItems) {
savedItems.clear();
savedItems.addAll(newSavedItems);
savedItems.sort((c1, c2) => -c1.timestamp.compareTo(c2.timestamp));
},
onError: (error) => _logger.severe('Error loading savedItems: $error'));
_logger.fine('Returning ${savedItems.length} saved items');
return Result.ok(List.unmodifiable(savedItems));
}
String get _conversationCachePath =>
p.join(appDataDirectory, 'convo_cache.json');
FutureResult<List<FacebookPost>, ExecError> _readAllPosts() async {
final allPosts = <FacebookPost>[];
FutureResult<List<FriendicaPost>, ExecError> _readAllPosts() async {
final allPosts = <FriendicaPost>[];
bool hadSuccess = false;
for (final topLevelDir in _topLevelDirs) {
try {
@ -206,8 +162,8 @@ class FacebookArchiveDataService extends ChangeNotifier {
'Unable to find any post JSON files in $_baseArchiveFolder'));
}
FutureResult<List<FacebookComment>, ExecError> _readAllComments() async {
final allComments = <FacebookComment>[];
FutureResult<List<FriendicaComment>, ExecError> _readAllComments() async {
final allComments = <FriendicaComment>[];
bool hadSuccess = false;
for (final topLevelDir in _topLevelDirs) {
try {
@ -234,8 +190,8 @@ class FacebookArchiveDataService extends ChangeNotifier {
'Unable to find any comment JSON files in $_baseArchiveFolder'));
}
FutureResult<List<FacebookFriend>, ExecError> _readAllFriends() async {
final allFriends = <FacebookFriend>[];
FutureResult<List<FriendicaContact>, ExecError> _readAllFriends() async {
final allFriends = <FriendicaContact>[];
bool hadSuccess = false;
for (final topLevelDir in _topLevelDirs) {
try {
@ -262,8 +218,8 @@ class FacebookArchiveDataService extends ChangeNotifier {
'Unable to find any album JSON files in $_baseArchiveFolder'));
}
FutureResult<List<FacebookAlbum>, ExecError> _readAllAlbums() async {
final allAlbums = <FacebookAlbum>[];
FutureResult<List<FriendicaAlbum>, ExecError> _readAllAlbums() async {
final allAlbums = <FriendicaAlbum>[];
bool hadSuccess = false;
for (final topLevelDir in _topLevelDirs) {
try {
@ -290,35 +246,7 @@ class FacebookArchiveDataService extends ChangeNotifier {
'Unable to find any album JSON files in $_baseArchiveFolder'));
}
FutureResult<List<FacebookSavedItem>, ExecError> _readAllSavedItems() async {
final allSavedItems = <FacebookSavedItem>[];
bool hadSuccess = false;
for (final topLevelDir in _topLevelDirs) {
try {
_logger.fine(
'Attempting to find/parse saved items JSON data in ${topLevelDir.path}');
final reader = FacebookArchiveFolderReader(topLevelDir.path);
final savedItemsResult = await reader.readSavedItems();
savedItemsResult.match(
onSuccess: (newSavedItem) {
allSavedItems.addAll(newSavedItem);
hadSuccess = true;
},
onError: (error) => _logger.fine(error));
} catch (e) {
_logger.severe('Exception thrown trying to read saved items, $e');
}
}
if (hadSuccess) {
return Result.ok(allSavedItems);
}
return Result.error(ExecError.message(
'Unable to find any saved items JSON files in $_baseArchiveFolder'));
}
FutureResult<FacebookAlbum, ExecError> _generatePostsAlbum() async {
FutureResult<FriendicaAlbum, ExecError> _generatePostsAlbum() async {
const name = 'Photos in Posts';
const description = 'Photos that were added to posts';
final posts = await getPosts();
@ -330,15 +258,15 @@ class FacebookArchiveDataService extends ChangeNotifier {
final photos = posts.value
.map((p) => p.mediaAttachments)
.expand((m) => m)
.where((m) => m.estimatedType() == FacebookAttachmentMediaType.image)
.where((m) => m.estimatedType() == FriendicaAttachmentMediaType.image)
.toList();
photos
.sort((p1, p2) => p1.creationTimestamp.compareTo(p2.creationTimestamp));
final lastModified = photos.isEmpty ? 0 : photos.last.creationTimestamp;
final coverPhoto =
photos.isEmpty ? FacebookMediaAttachment.blank() : photos.last;
photos.isEmpty ? FriendicaMediaAttachment.blank() : photos.last;
final album = FacebookAlbum(
final album = FriendicaAlbum(
name: name,
description: description,
lastModifiedTimestamp: lastModified,

View file

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'friendica/screens/facebook_photo_album_browser_screen.dart';
import 'friendica/screens/facebook_posts_screen.dart';
import 'friendica/screens/facebook_stats_screen.dart';
import 'friendica/screens/photo_album_browser_screen.dart';
import 'friendica/screens/posts_screen.dart';
import 'friendica/screens/stats_screen.dart';
import 'friendica/services/facebook_archive_reader.dart';
import 'settings/settings_controller.dart';
import 'settings/settings_view.dart';
@ -25,10 +25,10 @@ class _HomeState extends State<Home> {
@override
void initState() {
_pageData.addAll([
AppPageData('Posts', Icons.home, () => const FacebookPostsScreen()),
AppPageData('Posts', Icons.home, () => const PostsScreen()),
AppPageData('Photos', Icons.photo_library,
() => const FacebookPhotoAlbumsBrowserScreen()),
AppPageData('Stats', Icons.bar_chart, () => const FacebookStatsScreen()),
() => const PhotoAlbumsBrowserScreen()),
AppPageData('Stats', Icons.bar_chart, () => const StatsScreen()),
AppPageData('Settings', Icons.settings, () => _buildSettingsView()),
]);
for (var i = 0; i < _pageData.length; i++) {

View file

@ -1,6 +1,6 @@
{
"appTitle": "Kyanite",
"appTitle": "Friendica Archive Browser",
"@appTitle": {
"description": "A viewer of Facebook Archive Folders"
"description": "A browser of Friendica Archive Folders"
}
}

View file

@ -2,7 +2,7 @@ import 'dart:ui';
import 'package:flutter/material.dart';
class FacebookAppScrollingBehavior extends MaterialScrollBehavior {
class AppScrollingBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,

View file

@ -49,13 +49,4 @@ void main() {
onError: (error) => fail(error.toString()));
});
});
group('Test Read Saved Items JSON', () {
test('Read savedItems from disk', () async {
final savedItems =
(await FacebookArchiveFolderReader(rootPath).readSavedItems()).value;
expect(savedItems.length, equals(6));
savedItems.forEach(print);
});
});
}

View file

@ -25,8 +25,12 @@ void main() {
test('With Data', () {
final data = [
TimeElement(timeInMS: DateTime(2020, 10, 19).millisecondsSinceEpoch),
TimeElement(timeInMS: DateTime(2020, 10, 20, 12,00,00).millisecondsSinceEpoch),
TimeElement(timeInMS: DateTime(2020, 10, 20, 13,00,00).millisecondsSinceEpoch),
TimeElement(
timeInMS:
DateTime(2020, 10, 20, 12, 00, 00).millisecondsSinceEpoch),
TimeElement(
timeInMS:
DateTime(2020, 10, 20, 13, 00, 00).millisecondsSinceEpoch),
TimeElement(timeInMS: DateTime(2020, 10, 23).millisecondsSinceEpoch),
TimeElement(timeInMS: DateTime(2020, 10, 24).millisecondsSinceEpoch),
TimeElement(timeInMS: DateTime(2020, 10, 25).millisecondsSinceEpoch),
@ -128,7 +132,6 @@ void main() {
});
});
group('Test Yearly stats', () {
test('With no data', () {
final bins = TimeStatGenerator([]).calculateStatsByYear();
@ -163,5 +166,4 @@ void main() {
}
});
});
}

View file

@ -4,7 +4,6 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:friendica_archive_browser/src/utils/word_map_generator.dart';
void main() {
test('Empty collection stats', () {
final generator = WordMapGenerator();
expect(generator.getTopList(10).isEmpty, true);
@ -49,6 +48,7 @@ void main() {
final list = generator.getTopList(10);
list.forEach(print);
expect(list.length, equals(2));
expect(list.map((e) => e.word).toSet().containsAll(['test', 'testing']), true);
expect(
list.map((e) => e.word).toSet().containsAll(['test', 'testing']), true);
});
}