mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-04-18 14:42:54 +00:00
improved websocket connection state info
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
587740f306
commit
527bf51bff
11 changed files with 283 additions and 222 deletions
|
|
@ -31,7 +31,7 @@ import 'package:twonly/src/views/camera/camera_preview_components/zoom_selector.
|
|||
import 'package:twonly/src/views/camera/share_image_editor.view.dart';
|
||||
import 'package:twonly/src/views/camera/share_image_editor/action_button.dart';
|
||||
import 'package:twonly/src/views/components/avatar_icon.component.dart';
|
||||
import 'package:twonly/src/views/components/loader.dart';
|
||||
import 'package:twonly/src/views/components/loader/three_rotating_dots.loader.dart';
|
||||
import 'package:twonly/src/views/components/media_view_sizing.dart';
|
||||
import 'package:twonly/src/views/home.view.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'package:twonly/src/views/camera/share_image_editor/layers/link_preview/c
|
|||
import 'package:twonly/src/views/camera/share_image_editor/layers/link_preview/cards/youtube.card.dart';
|
||||
import 'package:twonly/src/views/camera/share_image_editor/layers/link_preview/parse_link.dart';
|
||||
import 'package:twonly/src/views/camera/share_image_editor/layers/link_preview/parser/base.dart';
|
||||
import 'package:twonly/src/views/components/loader.dart';
|
||||
import 'package:twonly/src/views/components/loader/three_rotating_dots.loader.dart';
|
||||
|
||||
class LinkPreviewLayer extends StatefulWidget {
|
||||
const LinkPreviewLayer({
|
||||
|
|
@ -32,8 +32,9 @@ class _LinkPreviewLayerState extends State<LinkPreviewLayer> {
|
|||
|
||||
Future<void> initAsync() async {
|
||||
if (widget.layerData.metadata == null) {
|
||||
widget.layerData.metadata =
|
||||
await getMetadata(widget.layerData.link.toString());
|
||||
widget.layerData.metadata = await getMetadata(
|
||||
widget.layerData.link.toString(),
|
||||
);
|
||||
if (widget.layerData.metadata == null) {
|
||||
widget.layerData.error = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||
import 'package:twonly/src/views/camera/share_image_editor/layers/link_preview/parser/base.dart';
|
||||
import 'package:twonly/src/views/components/loader.dart';
|
||||
import 'package:twonly/src/views/components/loader/three_rotating_dots.loader.dart';
|
||||
|
||||
class MastodonPostCard extends StatelessWidget {
|
||||
const MastodonPostCard({required this.info, super.key});
|
||||
|
|
|
|||
|
|
@ -9,15 +9,14 @@ import 'package:provider/provider.dart';
|
|||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/constants/routes.keys.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/providers/connection.provider.dart';
|
||||
import 'package:twonly/src/providers/purchases.provider.dart';
|
||||
import 'package:twonly/src/services/subscription.service.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/connection_info.comp.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/feedback_btn.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/group_list_item.dart';
|
||||
import 'package:twonly/src/views/components/avatar_icon.component.dart';
|
||||
import 'package:twonly/src/views/components/connection_status_badge.dart';
|
||||
import 'package:twonly/src/views/components/notification_badge.dart';
|
||||
|
||||
class ChatListView extends StatefulWidget {
|
||||
|
|
@ -45,8 +44,9 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
final stream = twonlyDB.groupsDao.watchGroupsForChatList();
|
||||
_contactsSub = stream.listen((groups) {
|
||||
setState(() {
|
||||
_groupsNotPinned =
|
||||
groups.where((x) => !x.pinned && !x.archived).toList();
|
||||
_groupsNotPinned = groups
|
||||
.where((x) => !x.pinned && !x.archived)
|
||||
.toList();
|
||||
_groupsPinned = groups.where((x) => x.pinned && !x.archived).toList();
|
||||
_groupsArchived = groups.where((x) => x.archived).toList();
|
||||
});
|
||||
|
|
@ -64,8 +64,10 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
}
|
||||
|
||||
final changeLog = await rootBundle.loadString('CHANGELOG.md');
|
||||
final changeLogHash =
|
||||
(await compute(Sha256().hash, changeLog.codeUnits)).bytes;
|
||||
final changeLogHash = (await compute(
|
||||
Sha256().hash,
|
||||
changeLog.codeUnits,
|
||||
)).bytes;
|
||||
if (!gUser.hideChangeLog &&
|
||||
gUser.lastChangeLogHash.toString() != changeLogHash.toString()) {
|
||||
await updateUserdata((u) {
|
||||
|
|
@ -93,22 +95,23 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isConnected = context.watch<CustomChangeProvider>().isConnected;
|
||||
final plan = context.watch<PurchasesProvider>().plan;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await context.push(Routes.settingsProfile);
|
||||
if (!mounted) return;
|
||||
setState(() {}); // gUser has updated
|
||||
},
|
||||
child: AvatarIcon(
|
||||
myAvatar: true,
|
||||
fontSize: 14,
|
||||
color: context.color.onSurface.withAlpha(20),
|
||||
ConnectionStatusBadge(
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
await context.push(Routes.settingsProfile);
|
||||
if (!mounted) return;
|
||||
setState(() {}); // gUser has updated
|
||||
},
|
||||
child: AvatarIcon(
|
||||
myAvatar: true,
|
||||
fontSize: 14,
|
||||
color: context.color.onSurface.withAlpha(20),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
|
|
@ -121,8 +124,10 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
color: context.color.primary,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 5,
|
||||
vertical: 3,
|
||||
),
|
||||
child: Text(
|
||||
plan.name,
|
||||
style: TextStyle(
|
||||
|
|
@ -163,87 +168,77 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
),
|
||||
],
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: isConnected ? Container() : const ConnectionInfo(),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await apiService.close(() {});
|
||||
await apiService.connect();
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
},
|
||||
child: (_groupsNotPinned.isEmpty &&
|
||||
_groupsPinned.isEmpty &&
|
||||
_groupsArchived.isEmpty)
|
||||
? Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: OutlinedButton.icon(
|
||||
icon: const Icon(Icons.person_add),
|
||||
onPressed: () => context.push(Routes.chatsAddNewUser),
|
||||
label: Text(
|
||||
context.lang.chatListViewSearchUserNameBtn,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: _groupsPinned.length +
|
||||
(_groupsPinned.isNotEmpty ? 1 : 0) +
|
||||
_groupsNotPinned.length +
|
||||
(_groupsArchived.isNotEmpty ? 1 : 0),
|
||||
itemBuilder: (context, index) {
|
||||
if (index >=
|
||||
_groupsNotPinned.length +
|
||||
_groupsPinned.length +
|
||||
(_groupsPinned.isNotEmpty ? 1 : 0)) {
|
||||
if (_groupsArchived.isEmpty) return Container();
|
||||
return ListTile(
|
||||
title: Text(
|
||||
'${context.lang.archivedChats} (${_groupsArchived.length})',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
onTap: () => context.push(Routes.chatsArchived),
|
||||
);
|
||||
}
|
||||
// Check if the index is for the pinned users
|
||||
if (index < _groupsPinned.length) {
|
||||
final group = _groupsPinned[index];
|
||||
return GroupListItem(
|
||||
key: ValueKey(group.groupId),
|
||||
group: group,
|
||||
);
|
||||
}
|
||||
|
||||
// If there are pinned users, account for the Divider
|
||||
var adjustedIndex = index - _groupsPinned.length;
|
||||
if (_groupsPinned.isNotEmpty && adjustedIndex == 0) {
|
||||
return const Divider();
|
||||
}
|
||||
|
||||
// Adjust the index for the contacts list
|
||||
adjustedIndex -= (_groupsPinned.isNotEmpty ? 1 : 0);
|
||||
|
||||
// Get the contacts that are not pinned
|
||||
final group = _groupsNotPinned.elementAt(
|
||||
adjustedIndex,
|
||||
);
|
||||
return GroupListItem(
|
||||
key: ValueKey(group.groupId),
|
||||
group: group,
|
||||
);
|
||||
},
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await apiService.close(() {});
|
||||
await apiService.connect();
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
},
|
||||
child:
|
||||
(_groupsNotPinned.isEmpty &&
|
||||
_groupsPinned.isEmpty &&
|
||||
_groupsArchived.isEmpty)
|
||||
? Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: OutlinedButton.icon(
|
||||
icon: const Icon(Icons.person_add),
|
||||
onPressed: () => context.push(Routes.chatsAddNewUser),
|
||||
label: Text(
|
||||
context.lang.chatListViewSearchUserNameBtn,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount:
|
||||
_groupsPinned.length +
|
||||
(_groupsPinned.isNotEmpty ? 1 : 0) +
|
||||
_groupsNotPinned.length +
|
||||
(_groupsArchived.isNotEmpty ? 1 : 0),
|
||||
itemBuilder: (context, index) {
|
||||
if (index >=
|
||||
_groupsNotPinned.length +
|
||||
_groupsPinned.length +
|
||||
(_groupsPinned.isNotEmpty ? 1 : 0)) {
|
||||
if (_groupsArchived.isEmpty) return Container();
|
||||
return ListTile(
|
||||
title: Text(
|
||||
'${context.lang.archivedChats} (${_groupsArchived.length})',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
onTap: () => context.push(Routes.chatsArchived),
|
||||
);
|
||||
}
|
||||
// Check if the index is for the pinned users
|
||||
if (index < _groupsPinned.length) {
|
||||
final group = _groupsPinned[index];
|
||||
return GroupListItem(
|
||||
key: ValueKey(group.groupId),
|
||||
group: group,
|
||||
);
|
||||
}
|
||||
|
||||
// If there are pinned users, account for the Divider
|
||||
var adjustedIndex = index - _groupsPinned.length;
|
||||
if (_groupsPinned.isNotEmpty && adjustedIndex == 0) {
|
||||
return const Divider();
|
||||
}
|
||||
|
||||
// Adjust the index for the contacts list
|
||||
adjustedIndex -= (_groupsPinned.isNotEmpty ? 1 : 0);
|
||||
|
||||
// Get the contacts that are not pinned
|
||||
final group = _groupsNotPinned.elementAt(
|
||||
adjustedIndex,
|
||||
);
|
||||
return GroupListItem(
|
||||
key: ValueKey(group.groupId),
|
||||
group: group,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
floatingActionButton: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
|
||||
class ConnectionInfo extends StatefulWidget {
|
||||
const ConnectionInfo({super.key});
|
||||
|
||||
@override
|
||||
State<ConnectionInfo> createState() => _ConnectionInfoWidgetState();
|
||||
}
|
||||
|
||||
class _ConnectionInfoWidgetState extends State<ConnectionInfo>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _positionAnim;
|
||||
late Animation<double> _widthAnim;
|
||||
|
||||
bool showAnimation = false;
|
||||
|
||||
final double minBarWidth = 40;
|
||||
final double maxBarWidth = 150;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
|
||||
_positionAnim = Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
||||
);
|
||||
|
||||
_widthAnim = TweenSequence([
|
||||
TweenSequenceItem(
|
||||
tween: Tween<double>(begin: minBarWidth, end: maxBarWidth),
|
||||
weight: 50,
|
||||
),
|
||||
TweenSequenceItem(
|
||||
tween: Tween<double>(begin: maxBarWidth, end: minBarWidth),
|
||||
weight: 50,
|
||||
),
|
||||
]).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
|
||||
|
||||
// Delay start by 2 seconds
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
if (mounted) {
|
||||
unawaited(_controller.repeat(reverse: true));
|
||||
setState(() {
|
||||
showAnimation = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!showAnimation) return Container();
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
return SizedBox(
|
||||
width: screenWidth,
|
||||
height: 1,
|
||||
child: AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (context, child) {
|
||||
final barWidth = _widthAnim.value;
|
||||
final left = _positionAnim.value * (screenWidth - barWidth);
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
left: left,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
width: barWidth,
|
||||
decoration: BoxDecoration(
|
||||
color: context.color.primary,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ import 'package:twonly/src/views/camera/camera_send_to.view.dart';
|
|||
import 'package:twonly/src/views/chats/media_viewer_components/additional_message_content.dart';
|
||||
import 'package:twonly/src/views/chats/media_viewer_components/reaction_buttons.component.dart';
|
||||
import 'package:twonly/src/views/components/animate_icon.dart';
|
||||
import 'package:twonly/src/views/components/loader.dart';
|
||||
import 'package:twonly/src/views/components/loader/three_rotating_dots.loader.dart';
|
||||
import 'package:twonly/src/views/components/media_view_sizing.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
|
|
|
|||
43
lib/src/views/components/connection_status_badge.dart
Normal file
43
lib/src/views/components/connection_status_badge.dart
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/src/providers/connection.provider.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/components/loader/ripple.loader.dart';
|
||||
|
||||
class ConnectionStatusBadge extends StatelessWidget {
|
||||
const ConnectionStatusBadge({
|
||||
required this.child,
|
||||
super.key,
|
||||
});
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isConnected = context.watch<CustomChangeProvider>().isConnected;
|
||||
return Stack(
|
||||
children: [
|
||||
if (!isConnected)
|
||||
const Positioned.fill(
|
||||
child: SpinKitRipple(
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: isConnected
|
||||
? context.color.primary.withAlpha(100)
|
||||
: Colors.red,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(0.5),
|
||||
child: Center(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
114
lib/src/views/components/loader/ripple.loader.dart
Normal file
114
lib/src/views/components/loader/ripple.loader.dart
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// FROM: https://github.com/jogboms/flutter_spinkit/blob/master/lib/src/ripple.dart
|
||||
|
||||
// ignore_for_file: prefer_int_literals
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SpinKitRipple extends StatefulWidget {
|
||||
const SpinKitRipple({
|
||||
super.key,
|
||||
this.color,
|
||||
this.size = 50.0,
|
||||
this.borderWidth = 6.0,
|
||||
this.itemBuilder,
|
||||
this.duration = const Duration(milliseconds: 1800),
|
||||
this.controller,
|
||||
}) : assert(
|
||||
!(itemBuilder is IndexedWidgetBuilder && color is Color) &&
|
||||
!(itemBuilder == null && color == null),
|
||||
'You should specify either a itemBuilder or a color',
|
||||
);
|
||||
|
||||
final Color? color;
|
||||
final double size;
|
||||
final double borderWidth;
|
||||
final IndexedWidgetBuilder? itemBuilder;
|
||||
final Duration duration;
|
||||
final AnimationController? controller;
|
||||
|
||||
@override
|
||||
State<SpinKitRipple> createState() => _SpinKitRippleState();
|
||||
}
|
||||
|
||||
class _SpinKitRippleState extends State<SpinKitRipple>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _animation1;
|
||||
late Animation<double> _animation2;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_controller =
|
||||
(widget.controller ??
|
||||
AnimationController(vsync: this, duration: widget.duration))
|
||||
..addListener(() {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
})
|
||||
..repeat();
|
||||
_animation1 = Tween(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(0.0, 0.75),
|
||||
),
|
||||
);
|
||||
_animation2 = Tween(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(0.25, 1),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (widget.controller == null) {
|
||||
_controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Opacity(
|
||||
opacity: 1.0 - _animation1.value,
|
||||
child: Transform.scale(
|
||||
scale: _animation1.value,
|
||||
child: _itemBuilder(0),
|
||||
),
|
||||
),
|
||||
Opacity(
|
||||
opacity: 1.0 - _animation2.value,
|
||||
child: Transform.scale(
|
||||
scale: _animation2.value,
|
||||
child: _itemBuilder(1),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _itemBuilder(int index) {
|
||||
return SizedBox.fromSize(
|
||||
size: Size.square(widget.size),
|
||||
child: widget.itemBuilder != null
|
||||
? widget.itemBuilder!(context, index)
|
||||
: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: widget.color!,
|
||||
width: widget.borderWidth,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import 'package:twonly/src/database/twonly.db.dart';
|
|||
import 'package:twonly/src/model/memory_item.model.dart';
|
||||
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/components/loader.dart';
|
||||
import 'package:twonly/src/views/components/loader/three_rotating_dots.loader.dart';
|
||||
import 'package:twonly/src/views/memories/memories_item_thumbnail.dart';
|
||||
import 'package:twonly/src/views/memories/memories_photo_slider.view.dart';
|
||||
|
||||
|
|
@ -43,8 +43,8 @@ class MemoriesViewState extends State<MemoriesView> {
|
|||
}
|
||||
|
||||
Future<void> initAsync() async {
|
||||
final nonHashedFiles =
|
||||
await twonlyDB.mediaFilesDao.getAllNonHashedStoredMediaFiles();
|
||||
final nonHashedFiles = await twonlyDB.mediaFilesDao
|
||||
.getAllNonHashedStoredMediaFiles();
|
||||
if (nonHashedFiles.isNotEmpty) {
|
||||
setState(() {
|
||||
_filesToMigrate = nonHashedFiles.length;
|
||||
|
|
@ -100,8 +100,9 @@ class MemoriesViewState extends State<MemoriesView> {
|
|||
),
|
||||
);
|
||||
for (var i = 0; i < galleryItems.length; i++) {
|
||||
final month = DateFormat('MMMM yyyy')
|
||||
.format(galleryItems[i].mediaService.mediaFile.createdAt);
|
||||
final month = DateFormat(
|
||||
'MMMM yyyy',
|
||||
).format(galleryItems[i].mediaService.mediaFile.createdAt);
|
||||
if (lastMonth != month) {
|
||||
lastMonth = month;
|
||||
months.add(month);
|
||||
|
|
@ -259,15 +260,16 @@ class MemoriesViewState extends State<MemoriesView> {
|
|||
int index,
|
||||
) async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
opaque: false,
|
||||
pageBuilder: (context, a1, a2) => MemoriesPhotoSliderView(
|
||||
galleryItems: galleryItems,
|
||||
initialIndex: index,
|
||||
),
|
||||
),
|
||||
) as bool?;
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
opaque: false,
|
||||
pageBuilder: (context, a1, a2) => MemoriesPhotoSliderView(
|
||||
galleryItems: galleryItems,
|
||||
initialIndex: index,
|
||||
),
|
||||
),
|
||||
)
|
||||
as bool?;
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:twonly/src/constants/routes.keys.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/components/loader.dart';
|
||||
import 'package:twonly/src/views/components/loader/three_rotating_dots.loader.dart';
|
||||
|
||||
class DiagnosticsView extends StatefulWidget {
|
||||
const DiagnosticsView({super.key});
|
||||
|
|
@ -98,8 +98,11 @@ class _LogViewerWidgetState extends State<LogViewerWidget> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_entries =
|
||||
widget.logLines.split('\n').reversed.map(_LogEntry.parse).toList();
|
||||
_entries = widget.logLines
|
||||
.split('\n')
|
||||
.reversed
|
||||
.map(_LogEntry.parse)
|
||||
.toList();
|
||||
}
|
||||
|
||||
void _setFilter(String level) => setState(() => _filterLevel = level);
|
||||
|
|
@ -187,8 +190,9 @@ class _LogViewerWidgetState extends State<LogViewerWidget> {
|
|||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip:
|
||||
_showTimestamps ? 'Hide timestamps' : 'Show timestamps',
|
||||
tooltip: _showTimestamps
|
||||
? 'Hide timestamps'
|
||||
: 'Show timestamps',
|
||||
onPressed: _toggleTimestamps,
|
||||
icon: Icon(
|
||||
_showTimestamps
|
||||
|
|
|
|||
Loading…
Reference in a new issue