Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
4a3e6a9e15 | |||
00092ba7b6 | |||
b5da8ece4a | |||
dfe9165bc9 | |||
3d45b54236 | |||
7f63fe7f0e | |||
bc5dbab9c5 | |||
9910fc7a92 | |||
2356eac118 | |||
0135b8d838 |
@ -145,14 +145,14 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- screen_brightness_ios (0.1.0):
|
- screen_brightness_ios (0.1.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- SDWebImage (5.19.4):
|
- SDWebImage (5.19.6):
|
||||||
- SDWebImage/Core (= 5.19.4)
|
- SDWebImage/Core (= 5.19.6)
|
||||||
- SDWebImage/Core (5.19.4)
|
- SDWebImage/Core (5.19.6)
|
||||||
- Sentry/HybridSDK (8.32.0)
|
- Sentry/HybridSDK (8.33.0)
|
||||||
- sentry_flutter (8.6.0):
|
- sentry_flutter (8.7.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- Sentry/HybridSDK (= 8.32.0)
|
- Sentry/HybridSDK (= 8.33.0)
|
||||||
- share_plus (0.0.1):
|
- share_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
@ -319,9 +319,9 @@ SPEC CHECKSUMS:
|
|||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
protocol_handler_ios: a5db8abc38526ee326988b808be621e5fd568990
|
protocol_handler_ios: a5db8abc38526ee326988b808be621e5fd568990
|
||||||
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
||||||
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
|
SDWebImage: a79252b60f4678812d94316c91da69ec83089c9f
|
||||||
Sentry: 96ae1dcdf01a644bc3a3b1dc279cecaf48a833fb
|
Sentry: 8560050221424aef0bebc8e31eedf00af80f90a6
|
||||||
sentry_flutter: 090351ce1ff5f96a4b33ef9455b7e3b28185387d
|
sentry_flutter: e26b861f744e5037a3faf9bf56603ec65d658a61
|
||||||
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Flutter
|
import Flutter
|
||||||
|
|
||||||
@UIApplicationMain
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
|
@ -138,9 +138,7 @@ class AttachmentUploaderController extends GetxController {
|
|||||||
queueOfUpload[idx].isCompleted = true;
|
queueOfUpload[idx].isCompleted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
queueOfUpload.value = queueOfUpload
|
queueOfUpload.removeWhere((x) => x.error == null);
|
||||||
.where((x) => x.error == null && x.isCompleted)
|
|
||||||
.toList(growable: true);
|
|
||||||
_stopProgressSyncTimer();
|
_stopProgressSyncTimer();
|
||||||
_syncProgress();
|
_syncProgress();
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ import 'package:solian/widgets/app_bar_leading.dart';
|
|||||||
import 'package:solian/widgets/app_bar_title.dart';
|
import 'package:solian/widgets/app_bar_title.dart';
|
||||||
import 'package:solian/widgets/channel/channel_call_indicator.dart';
|
import 'package:solian/widgets/channel/channel_call_indicator.dart';
|
||||||
import 'package:solian/widgets/chat/call/chat_call_action.dart';
|
import 'package:solian/widgets/chat/call/chat_call_action.dart';
|
||||||
import 'package:solian/widgets/chat/chat_event.dart';
|
|
||||||
import 'package:solian/widgets/chat/chat_event_list.dart';
|
import 'package:solian/widgets/chat/chat_event_list.dart';
|
||||||
import 'package:solian/widgets/chat/chat_message_input.dart';
|
import 'package:solian/widgets/chat/chat_message_input.dart';
|
||||||
import 'package:solian/widgets/current_state_action.dart';
|
import 'package:solian/widgets/current_state_action.dart';
|
||||||
@ -39,7 +38,10 @@ class ChannelChatScreen extends StatefulWidget {
|
|||||||
State<ChannelChatScreen> createState() => _ChannelChatScreenState();
|
State<ChannelChatScreen> createState() => _ChannelChatScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
class _ChannelChatScreenState extends State<ChannelChatScreen>
|
||||||
|
with WidgetsBindingObserver {
|
||||||
|
DateTime? _isOutOfSyncSince;
|
||||||
|
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
int? _accountId;
|
int? _accountId;
|
||||||
|
|
||||||
@ -123,20 +125,38 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _keepUpdateWithServer() {
|
||||||
|
_getOngoingCall();
|
||||||
|
_chatController.getEvents(_channel!, widget.realm);
|
||||||
|
setState(() => _isOutOfSyncSince = null);
|
||||||
|
}
|
||||||
|
|
||||||
Event? _messageToReplying;
|
Event? _messageToReplying;
|
||||||
Event? _messageToEditing;
|
Event? _messageToEditing;
|
||||||
|
|
||||||
Widget buildHistoryBody(Event item, {bool isMerged = false}) {
|
@override
|
||||||
return ChatEvent(
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
key: Key('m${item.uuid}'),
|
switch (state) {
|
||||||
item: item,
|
case AppLifecycleState.resumed:
|
||||||
isMerged: isMerged,
|
if (_isOutOfSyncSince == null) break;
|
||||||
chatController: _chatController,
|
if (DateTime.now().difference(_isOutOfSyncSince!).inSeconds < 60) break;
|
||||||
);
|
_keepUpdateWithServer();
|
||||||
|
break;
|
||||||
|
case AppLifecycleState.paused:
|
||||||
|
if (mounted) {
|
||||||
|
setState(() => _isOutOfSyncSince = DateTime.now());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
_accountId = Get.find<AuthProvider>().userProfile.value!['id'];
|
_accountId = Get.find<AuthProvider>().userProfile.value!['id'];
|
||||||
|
|
||||||
_chatController = ChatEventController();
|
_chatController = ChatEventController();
|
||||||
@ -147,21 +167,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
_chatController.getEvents(_channel!, widget.realm);
|
_chatController.getEvents(_channel!, widget.realm);
|
||||||
_listenMessages();
|
_listenMessages();
|
||||||
});
|
});
|
||||||
|
|
||||||
super.initState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_isBusy || _channel == null) {
|
|
||||||
return Material(
|
|
||||||
color: Theme.of(context).colorScheme.surface,
|
|
||||||
child: const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String title = _channel?.name ?? 'loading'.tr;
|
String title = _channel?.name ?? 'loading'.tr;
|
||||||
String? placeholder;
|
String? placeholder;
|
||||||
|
|
||||||
@ -185,7 +194,8 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
actions: [
|
actions: [
|
||||||
const BackgroundStateWidget(),
|
const BackgroundStateWidget(),
|
||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
if (_isBusy) return const SizedBox();
|
if (_isBusy || _channel == null) return const SizedBox();
|
||||||
|
|
||||||
return ChatCallButton(
|
return ChatCallButton(
|
||||||
realm: _channel!.realm,
|
realm: _channel!.realm,
|
||||||
channel: _channel!,
|
channel: _channel!,
|
||||||
@ -195,6 +205,8 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.more_vert),
|
icon: const Icon(Icons.more_vert),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
if (_channel == null) return;
|
||||||
|
|
||||||
AppRouter.instance
|
AppRouter.instance
|
||||||
.pushNamed(
|
.pushNamed(
|
||||||
'channelDetail',
|
'channelDetail',
|
||||||
@ -219,66 +231,94 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Builder(builder: (context) {
|
||||||
children: [
|
if (_isBusy || _channel == null) {
|
||||||
if (_ongoingCall != null)
|
return const Center(
|
||||||
ChannelCallIndicator(
|
child: CircularProgressIndicator(),
|
||||||
channel: _channel!,
|
);
|
||||||
ongoingCall: _ongoingCall!,
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (_ongoingCall != null)
|
||||||
|
ChannelCallIndicator(
|
||||||
|
channel: _channel!,
|
||||||
|
ongoingCall: _ongoingCall!,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ChatEventList(
|
||||||
|
scope: widget.realm,
|
||||||
|
channel: _channel!,
|
||||||
|
chatController: _chatController,
|
||||||
|
onEdit: (item) {
|
||||||
|
setState(() => _messageToEditing = item);
|
||||||
|
},
|
||||||
|
onReply: (item) {
|
||||||
|
setState(() => _messageToReplying = item);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
if (_isOutOfSyncSince != null)
|
||||||
child: ChatEventList(
|
ListTile(
|
||||||
scope: widget.realm,
|
contentPadding: const EdgeInsets.only(left: 16, right: 8),
|
||||||
channel: _channel!,
|
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
chatController: _chatController,
|
leading: const Icon(Icons.history_toggle_off),
|
||||||
onEdit: (item) {
|
title: Text('messageOutOfSync'.tr),
|
||||||
setState(() => _messageToEditing = item);
|
subtitle: Text('messageOutOfSyncCaption'.tr),
|
||||||
},
|
trailing: IconButton(
|
||||||
onReply: (item) {
|
icon: const Icon(Icons.close),
|
||||||
setState(() => _messageToReplying = item);
|
onPressed: () {
|
||||||
},
|
setState(() => _isOutOfSyncSince = null);
|
||||||
),
|
|
||||||
),
|
|
||||||
Obx(() {
|
|
||||||
if (_chatController.isLoading.isTrue) {
|
|
||||||
return const LinearProgressIndicator().animate().slideY();
|
|
||||||
} else {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
ClipRect(
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
|
|
||||||
child: SafeArea(
|
|
||||||
child: ChatMessageInput(
|
|
||||||
edit: _messageToEditing,
|
|
||||||
reply: _messageToReplying,
|
|
||||||
realm: widget.realm,
|
|
||||||
placeholder: placeholder,
|
|
||||||
channel: _channel!,
|
|
||||||
onSent: (Event item) {
|
|
||||||
setState(() {
|
|
||||||
_chatController.addPendingEvent(item);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onReset: () {
|
|
||||||
setState(() {
|
|
||||||
_messageToReplying = null;
|
|
||||||
_messageToEditing = null;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
onTap: _isBusy
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
_keepUpdateWithServer();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
if (_chatController.isLoading.isTrue) {
|
||||||
|
return const LinearProgressIndicator().animate().slideY();
|
||||||
|
} else {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
ClipRect(
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
|
||||||
|
child: SafeArea(
|
||||||
|
child: ChatMessageInput(
|
||||||
|
edit: _messageToEditing,
|
||||||
|
reply: _messageToReplying,
|
||||||
|
realm: widget.realm,
|
||||||
|
placeholder: placeholder,
|
||||||
|
channel: _channel!,
|
||||||
|
onSent: (Event item) {
|
||||||
|
setState(() {
|
||||||
|
_chatController.addPendingEvent(item);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onReset: () {
|
||||||
|
setState(() {
|
||||||
|
_messageToReplying = null;
|
||||||
|
_messageToEditing = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
);
|
||||||
),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_subscription?.cancel();
|
_subscription?.cancel();
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:solian/controllers/chat_events_controller.dart';
|
||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/providers/theme_switcher.dart';
|
import 'package:solian/providers/theme_switcher.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
@ -93,6 +94,18 @@ class _SettingScreenState extends State<SettingScreen> {
|
|||||||
AppRouter.instance.pushNamed('about');
|
AppRouter.instance.pushNamed('about');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
TextButton(
|
||||||
|
style: const ButtonStyle(
|
||||||
|
visualDensity: VisualDensity(horizontal: -4, vertical: -4),
|
||||||
|
),
|
||||||
|
child: Text('messageHistoryWipe'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
final chatHistory = ChatEventController();
|
||||||
|
chatHistory.initialize().then((_) async {
|
||||||
|
await chatHistory.database.localEvents.wipeLocalEvents();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
).paddingSymmetric(horizontal: 12, vertical: 8),
|
).paddingSymmetric(horizontal: 12, vertical: 8),
|
||||||
],
|
],
|
||||||
|
@ -370,4 +370,8 @@ const i18nEnglish = {
|
|||||||
'callStatusDisconnected': 'Disconnected',
|
'callStatusDisconnected': 'Disconnected',
|
||||||
'callStatusConnecting': 'Connecting',
|
'callStatusConnecting': 'Connecting',
|
||||||
'callStatusReconnected': 'Reconnecting',
|
'callStatusReconnected': 'Reconnecting',
|
||||||
|
'messageOutOfSync': 'May Out of Sync with Server',
|
||||||
|
'messageOutOfSyncCaption':
|
||||||
|
'Since the App has entered the background, there may be a time difference between the message list and the server. Click to Refresh.',
|
||||||
|
'messageHistoryWipe': 'Wipe local message history',
|
||||||
};
|
};
|
||||||
|
@ -337,4 +337,7 @@ const i18nSimplifiedChinese = {
|
|||||||
'callStatusDisconnected': '已断开',
|
'callStatusDisconnected': '已断开',
|
||||||
'callStatusConnecting': '连接中',
|
'callStatusConnecting': '连接中',
|
||||||
'callStatusReconnected': '重连中',
|
'callStatusReconnected': '重连中',
|
||||||
|
'messageOutOfSync': '消息可能与服务器脱节',
|
||||||
|
'messageOutOfSyncCaption': '由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。',
|
||||||
|
'messageHistoryWipe': '清除消息记录',
|
||||||
};
|
};
|
||||||
|
@ -159,8 +159,9 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
|||||||
}
|
}
|
||||||
var track = await LocalVideoTrack.createScreenShareTrack(
|
var track = await LocalVideoTrack.createScreenShareTrack(
|
||||||
ScreenShareCaptureOptions(
|
ScreenShareCaptureOptions(
|
||||||
|
captureScreenAudio: true,
|
||||||
sourceId: source.id,
|
sourceId: source.id,
|
||||||
maxFrameRate: 15.0,
|
maxFrameRate: 30.0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await _participant.publishVideoTrack(track);
|
await _participant.publishVideoTrack(track);
|
||||||
@ -174,6 +175,7 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
|||||||
var track = await LocalVideoTrack.createScreenShareTrack(
|
var track = await LocalVideoTrack.createScreenShareTrack(
|
||||||
const ScreenShareCaptureOptions(
|
const ScreenShareCaptureOptions(
|
||||||
useiOSBroadcastExtension: true,
|
useiOSBroadcastExtension: true,
|
||||||
|
captureScreenAudio: true,
|
||||||
maxFrameRate: 30.0,
|
maxFrameRate: 30.0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -4,17 +4,17 @@ import 'package:get/utils.dart';
|
|||||||
abstract class AppNavigation {
|
abstract class AppNavigation {
|
||||||
static List<AppNavigationDestination> destinations = [
|
static List<AppNavigationDestination> destinations = [
|
||||||
AppNavigationDestination(
|
AppNavigationDestination(
|
||||||
icon: const Icon(Icons.home),
|
icon: Icons.home,
|
||||||
label: 'home'.tr,
|
label: 'home'.tr,
|
||||||
page: 'home',
|
page: 'home',
|
||||||
),
|
),
|
||||||
AppNavigationDestination(
|
AppNavigationDestination(
|
||||||
icon: const Icon(Icons.workspaces),
|
icon: Icons.workspaces,
|
||||||
label: 'realms'.tr,
|
label: 'realms'.tr,
|
||||||
page: 'realms',
|
page: 'realms',
|
||||||
),
|
),
|
||||||
AppNavigationDestination(
|
AppNavigationDestination(
|
||||||
icon: const Icon(Icons.forum),
|
icon: Icons.forum,
|
||||||
label: 'channelTypeDirect'.tr,
|
label: 'channelTypeDirect'.tr,
|
||||||
page: 'chat',
|
page: 'chat',
|
||||||
),
|
),
|
||||||
@ -25,7 +25,7 @@ abstract class AppNavigation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AppNavigationDestination {
|
class AppNavigationDestination {
|
||||||
final Widget icon;
|
final IconData icon;
|
||||||
final String label;
|
final String label;
|
||||||
final String page;
|
final String page;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/models/account_status.dart';
|
import 'package:solian/models/account_status.dart';
|
||||||
@ -40,15 +42,6 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
rootScaffoldKey.currentState!.closeDrawer();
|
rootScaffoldKey.currentState!.closeDrawer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSettingButton() {
|
|
||||||
return IconButton(
|
|
||||||
icon: const Icon(Icons.settings),
|
|
||||||
onPressed: () {
|
|
||||||
AppRouter.instance.pushNamed('settings');
|
|
||||||
_closeDrawer();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -63,6 +56,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
backgroundColor:
|
backgroundColor:
|
||||||
SolianTheme.isLargeScreen(context) ? Colors.transparent : null,
|
SolianTheme.isLargeScreen(context) ? Colors.transparent : null,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
|
bottom: false,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Obx(() {
|
Obx(() {
|
||||||
@ -72,7 +66,6 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
leading: const Icon(Icons.account_circle),
|
leading: const Icon(Icons.account_circle),
|
||||||
title: Text('guest'.tr),
|
title: Text('guest'.tr),
|
||||||
subtitle: Text('unsignedIn'.tr),
|
subtitle: Text('unsignedIn'.tr),
|
||||||
trailing: _buildSettingButton(),
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AppRouter.instance.goNamed('account');
|
AppRouter.instance.goNamed('account');
|
||||||
_closeDrawer();
|
_closeDrawer();
|
||||||
@ -81,7 +74,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
contentPadding: const EdgeInsets.only(left: 20, right: 20),
|
||||||
title: Text(
|
title: Text(
|
||||||
auth.userProfile.value!['nick'],
|
auth.userProfile.value!['nick'],
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@ -137,7 +130,6 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
trailing: _buildSettingButton(),
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AppRouter.instance.goNamed('account');
|
AppRouter.instance.goNamed('account');
|
||||||
_closeDrawer();
|
_closeDrawer();
|
||||||
@ -154,7 +146,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}).paddingOnly(top: 8),
|
}).paddingSymmetric(vertical: 8),
|
||||||
const Divider(thickness: 0.3, height: 1),
|
const Divider(thickness: 0.3, height: 1),
|
||||||
Column(
|
Column(
|
||||||
children: AppNavigation.destinations
|
children: AppNavigation.destinations
|
||||||
@ -163,7 +155,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
contentPadding: const EdgeInsets.symmetric(
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
horizontal: 20,
|
horizontal: 20,
|
||||||
),
|
),
|
||||||
leading: e.icon,
|
leading: Icon(e.icon, size: 20).paddingAll(2),
|
||||||
title: Text(e.label),
|
title: Text(e.label),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -182,6 +174,26 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const Divider(thickness: 0.3, height: 1),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
minTileHeight: 0,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
),
|
||||||
|
leading: const Icon(Icons.settings, size: 20).paddingAll(2),
|
||||||
|
title: Text('settings'.tr),
|
||||||
|
onTap: () {
|
||||||
|
AppRouter.instance.pushNamed('settings');
|
||||||
|
_closeDrawer();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingOnly(
|
||||||
|
top: 8,
|
||||||
|
bottom: math.max(8, MediaQuery.of(context).padding.bottom),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -68,6 +68,7 @@ class AppNavigationRegions extends StatelessWidget {
|
|||||||
.map((element) {
|
.map((element) {
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
minTileHeight: 0,
|
minTileHeight: 0,
|
||||||
|
initiallyExpanded: true,
|
||||||
tilePadding: const EdgeInsets.only(left: 20, right: 24),
|
tilePadding: const EdgeInsets.only(left: 20, right: 24),
|
||||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
|
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
collapsedBackgroundColor:
|
collapsedBackgroundColor:
|
||||||
@ -80,6 +81,7 @@ class AppNavigationRegions extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
|
const SliverPadding(padding: EdgeInsets.only(bottom: 8)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,7 @@ class _PostActionState extends State<PostAction> {
|
|||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
if ((PlatformInfo.isAndroid || PlatformInfo.isIOS) && !noUri) {
|
if ((PlatformInfo.isAndroid || PlatformInfo.isIOS) && !noUri) {
|
||||||
await Share.shareUri(
|
await Share.shareUri(
|
||||||
Uri.parse('https://sn.solsynth.dev/posts/view/${widget.item.id}'),
|
Uri.parse('https://solsynth.dev/posts/${widget.item.id}'),
|
||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -57,7 +57,7 @@ class _PostActionState extends State<PostAction> {
|
|||||||
'username': widget.item.author.nick,
|
'username': widget.item.author.nick,
|
||||||
'content':
|
'content':
|
||||||
'${extraContent.join('\n')}${isExtraNotEmpty ? '\n\n' : ''}${widget.item.body['content'] ?? 'no content'}',
|
'${extraContent.join('\n')}${isExtraNotEmpty ? '\n\n' : ''}${widget.item.body['content'] ?? 'no content'}',
|
||||||
'link': 'https://sn.solsynth.dev/posts/view/${widget.item.id}',
|
'link': 'https://solsynth.dev/posts/${widget.item.id}',
|
||||||
}),
|
}),
|
||||||
subject: 'postShareSubject'.trParams({
|
subject: 'postShareSubject'.trParams({
|
||||||
'username': widget.item.author.nick,
|
'username': widget.item.author.nick,
|
||||||
|
@ -107,11 +107,11 @@ PODS:
|
|||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- screen_brightness_macos (0.1.0):
|
- screen_brightness_macos (0.1.0):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- Sentry/HybridSDK (8.32.0)
|
- Sentry/HybridSDK (8.33.0)
|
||||||
- sentry_flutter (8.6.0):
|
- sentry_flutter (8.7.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- Sentry/HybridSDK (= 8.32.0)
|
- Sentry/HybridSDK (= 8.33.0)
|
||||||
- share_plus (0.0.1):
|
- share_plus (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
@ -252,8 +252,8 @@ SPEC CHECKSUMS:
|
|||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
protocol_handler_macos: d10a6c01d6373389ffd2278013ab4c47ed6d6daa
|
protocol_handler_macos: d10a6c01d6373389ffd2278013ab4c47ed6d6daa
|
||||||
screen_brightness_macos: 2d6d3af2165592d9a55ffcd95b7550970e41ebda
|
screen_brightness_macos: 2d6d3af2165592d9a55ffcd95b7550970e41ebda
|
||||||
Sentry: 96ae1dcdf01a644bc3a3b1dc279cecaf48a833fb
|
Sentry: 8560050221424aef0bebc8e31eedf00af80f90a6
|
||||||
sentry_flutter: 090351ce1ff5f96a4b33ef9455b7e3b28185387d
|
sentry_flutter: e26b861f744e5037a3faf9bf56603ec65d658a61
|
||||||
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
|
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
|
|
||||||
@NSApplicationMain
|
@main
|
||||||
class AppDelegate: FlutterAppDelegate {
|
class AppDelegate: FlutterAppDelegate {
|
||||||
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||||
return true
|
return true
|
||||||
|
75
pubspec.lock
75
pubspec.lock
@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
|
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "67.0.0"
|
version: "72.0.0"
|
||||||
_flutterfire_internals:
|
_flutterfire_internals:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -17,14 +17,19 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.40"
|
version: "1.3.40"
|
||||||
|
_macros:
|
||||||
|
dependency: transitive
|
||||||
|
description: dart
|
||||||
|
source: sdk
|
||||||
|
version: "0.3.2"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
|
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.4.1"
|
version: "6.7.0"
|
||||||
animations:
|
animations:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -117,18 +122,18 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7"
|
sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.11"
|
version: "2.4.12"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe
|
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.3.1"
|
version: "7.3.2"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -173,10 +178,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: carousel_slider
|
name: carousel_slider
|
||||||
sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42"
|
sha256: "7b006ec356205054af5beaef62e2221160ea36b90fb70a35e4deacd49d0349ae"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.1"
|
version: "5.0.0"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -634,10 +639,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: "2e8a801b1ded5ea001a4529c97b1f213dcb11c6b20668e081cafb23468593514"
|
sha256: a23c41ee57573e62fc2190a1f36a0480c4d90bde3a8a8d7126e5d5992fb53fb7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3"
|
version: "0.7.3+1"
|
||||||
flutter_markdown_selectionarea:
|
flutter_markdown_selectionarea:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -972,18 +977,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker
|
name: leak_tracker
|
||||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.4"
|
version: "10.0.5"
|
||||||
leak_tracker_flutter_testing:
|
leak_tracker_flutter_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker_flutter_testing
|
name: leak_tracker_flutter_testing
|
||||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.5"
|
||||||
leak_tracker_testing:
|
leak_tracker_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1032,6 +1037,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.0"
|
version: "1.5.0"
|
||||||
|
macros:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: macros
|
||||||
|
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2-main.4"
|
||||||
markdown:
|
markdown:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1060,10 +1073,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.0"
|
version: "0.11.1"
|
||||||
media_kit:
|
media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1140,10 +1153,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.12.0"
|
version: "1.15.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1548,18 +1561,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sentry
|
name: sentry
|
||||||
sha256: "76ad4fab90ff82427c26939bd79dc4df345a081e2b1cd5954b947e340b9af9a5"
|
sha256: "0f787e27ff617e4f88f7074977240406a9c5509444bac64a4dfa5b3200fb5632"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.0"
|
version: "8.7.0"
|
||||||
sentry_flutter:
|
sentry_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sentry_flutter
|
name: sentry_flutter
|
||||||
sha256: a7c92014701093a7c0a373e1a47c54ec428d8468d8bf2b793fee7ea1b085c21b
|
sha256: fbbb47d72ccca48be25bf3c2ced6ab6e872991af3a0ba78e54be8d138f2e053f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.0"
|
version: "8.7.0"
|
||||||
share_plus:
|
share_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1793,10 +1806,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0"
|
version: "0.7.2"
|
||||||
timeago:
|
timeago:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1873,10 +1886,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_linux
|
name: url_launcher_linux
|
||||||
sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
|
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "3.2.0"
|
||||||
url_launcher_macos:
|
url_launcher_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1929,10 +1942,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.1"
|
version: "14.2.4"
|
||||||
volume_controller:
|
volume_controller:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2038,5 +2051,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.4.0 <4.0.0"
|
dart: ">=3.5.0-259.0.dev <4.0.0"
|
||||||
flutter: ">=3.22.0"
|
flutter: ">=3.22.0"
|
||||||
|
@ -2,7 +2,7 @@ name: solian
|
|||||||
description: "The Solar Network App"
|
description: "The Solar Network App"
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
|
|
||||||
version: 1.2.1+9
|
version: 1.2.1+12
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.4 <4.0.0"
|
sdk: ">=3.3.4 <4.0.0"
|
||||||
@ -19,7 +19,7 @@ dependencies:
|
|||||||
flutter_markdown: ^0.7.1
|
flutter_markdown: ^0.7.1
|
||||||
flutter_animate: ^4.5.0
|
flutter_animate: ^4.5.0
|
||||||
flutter_secure_storage: ^9.2.1
|
flutter_secure_storage: ^9.2.1
|
||||||
carousel_slider: ^4.2.1
|
carousel_slider: ^5.0.0
|
||||||
url_launcher: ^6.2.6
|
url_launcher: ^6.2.6
|
||||||
infinite_scroll_pagination: ^4.0.0
|
infinite_scroll_pagination: ^4.0.0
|
||||||
image_picker: ^1.1.1
|
image_picker: ^1.1.1
|
||||||
|
Reference in New Issue
Block a user