Compare commits
2 Commits
9df4aba56c
...
c0680a3134
Author | SHA1 | Date | |
---|---|---|---|
c0680a3134 | |||
e080f49935 |
@ -69,6 +69,9 @@ PODS:
|
||||
- SDWebImage (5.19.1):
|
||||
- SDWebImage/Core (= 5.19.1)
|
||||
- SDWebImage/Core (5.19.1)
|
||||
- sqflite (0.0.3):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- SwiftyGif (5.4.5)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
@ -97,6 +100,7 @@ DEPENDENCIES:
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
@ -143,6 +147,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
screen_brightness_ios:
|
||||
:path: ".symlinks/plugins/screen_brightness_ios/ios"
|
||||
sqflite:
|
||||
:path: ".symlinks/plugins/sqflite/darwin"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
volume_controller:
|
||||
@ -172,6 +178,7 @@ SPEC CHECKSUMS:
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
||||
SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586
|
||||
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
||||
|
@ -6,6 +6,7 @@ import 'package:solian/providers/friend.dart';
|
||||
import 'package:solian/providers/navigation.dart';
|
||||
import 'package:solian/providers/notify.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/utils/theme.dart';
|
||||
import 'package:solian/utils/timeago.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/utils/video_player.dart';
|
||||
@ -24,25 +25,16 @@ void main() {
|
||||
class SolianApp extends StatelessWidget {
|
||||
const SolianApp({super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp.router(
|
||||
title: 'Solian',
|
||||
theme: ThemeData(
|
||||
brightness: Brightness.light,
|
||||
colorScheme: ColorScheme.fromSeed(brightness: Brightness.light, seedColor: Colors.indigo),
|
||||
useMaterial3: true,
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: ColorScheme.fromSeed(brightness: Brightness.dark, seedColor: Colors.indigo),
|
||||
useMaterial3: true,
|
||||
),
|
||||
theme: SolianTheme.build(Brightness.light),
|
||||
darkTheme: SolianTheme.build(Brightness.dark),
|
||||
themeMode: ThemeMode.system,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
routerConfig: router,
|
||||
routerConfig: SolianRouter.router,
|
||||
builder: (context, child) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:solian/models/call.dart';
|
||||
import 'package:solian/models/channel.dart';
|
||||
@ -8,18 +9,22 @@ import 'package:solian/screens/account/personalize.dart';
|
||||
import 'package:solian/screens/auth/signup.dart';
|
||||
import 'package:solian/screens/chat/call.dart';
|
||||
import 'package:solian/screens/chat/chat.dart';
|
||||
import 'package:solian/screens/chat/index.dart';
|
||||
import 'package:solian/screens/chat/manage.dart';
|
||||
import 'package:solian/screens/chat/channel/editor.dart';
|
||||
import 'package:solian/screens/chat/channel/member.dart';
|
||||
import 'package:solian/screens/chat/chat_list.dart';
|
||||
import 'package:solian/screens/chat/chat_detail.dart';
|
||||
import 'package:solian/screens/chat/channel/channel_editor.dart';
|
||||
import 'package:solian/screens/chat/channel/channel_member.dart';
|
||||
import 'package:solian/screens/explore.dart';
|
||||
import 'package:solian/screens/notification.dart';
|
||||
import 'package:solian/screens/posts/comment_editor.dart';
|
||||
import 'package:solian/screens/posts/moment_editor.dart';
|
||||
import 'package:solian/screens/posts/screen.dart';
|
||||
import 'package:solian/screens/auth/signin.dart';
|
||||
import 'package:solian/utils/theme.dart';
|
||||
import 'package:solian/widgets/empty.dart';
|
||||
import 'package:solian/widgets/layouts/two_column.dart';
|
||||
|
||||
final router = GoRouter(
|
||||
abstract class SolianRouter {
|
||||
static final router = GoRouter(
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
@ -31,22 +36,33 @@ final router = GoRouter(
|
||||
name: 'notification',
|
||||
builder: (context, state) => const NotificationScreen(),
|
||||
),
|
||||
ShellRoute(
|
||||
pageBuilder: (context, state, child) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
SolianTheme.isLargeScreen(context)
|
||||
? TwoColumnLayout(
|
||||
sideChild: const ChatListScreen(),
|
||||
mainChild: child,
|
||||
)
|
||||
: child,
|
||||
),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/chat',
|
||||
name: 'chat',
|
||||
builder: (context, state) => const ChatIndexScreen(),
|
||||
builder: (context, state) =>
|
||||
!SolianTheme.isLargeScreen(context) ? const ChatListScreen() : const PageEmptyWidget(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/chat/create',
|
||||
name: 'chat.channel.editor',
|
||||
builder: (context, state) =>
|
||||
ChannelEditorScreen(editing: state.extra as Channel?),
|
||||
builder: (context, state) => ChannelEditorScreen(editing: state.extra as Channel?),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/chat/c/:channel',
|
||||
name: 'chat.channel',
|
||||
builder: (context, state) =>
|
||||
ChatScreen(alias: state.pathParameters['channel'] as String),
|
||||
builder: (context, state) => ChatScreen(alias: state.pathParameters['channel'] as String),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/chat/c/:channel/call',
|
||||
@ -56,14 +72,14 @@ final router = GoRouter(
|
||||
GoRoute(
|
||||
path: '/chat/c/:channel/manage',
|
||||
name: 'chat.channel.manage',
|
||||
builder: (context, state) =>
|
||||
ChatManageScreen(channel: state.extra as Channel),
|
||||
builder: (context, state) => ChatDetailScreen(channel: state.extra as Channel),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/chat/c/:channel/member',
|
||||
name: 'chat.channel.member',
|
||||
builder: (context, state) =>
|
||||
ChatMemberScreen(channel: state.extra as Channel),
|
||||
builder: (context, state) => ChatMemberScreen(channel: state.extra as Channel),
|
||||
),
|
||||
],
|
||||
),
|
||||
GoRoute(
|
||||
path: '/account',
|
||||
@ -73,16 +89,14 @@ final router = GoRouter(
|
||||
GoRoute(
|
||||
path: '/posts/publish/moments',
|
||||
name: 'posts.moments.editor',
|
||||
builder: (context, state) =>
|
||||
MomentEditorScreen(editing: state.extra as Post?),
|
||||
builder: (context, state) => MomentEditorScreen(editing: state.extra as Post?),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/posts/publish/comments',
|
||||
name: 'posts.comments.editor',
|
||||
builder: (context, state) {
|
||||
final args = state.extra as CommentPostArguments;
|
||||
return CommentEditorScreen(
|
||||
editing: args.editing, related: args.related);
|
||||
return CommentEditorScreen(editing: args.editing, related: args.related);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
@ -114,4 +128,16 @@ final router = GoRouter(
|
||||
builder: (context, state) => const PersonalizeScreen(),
|
||||
),
|
||||
],
|
||||
);
|
||||
);
|
||||
|
||||
static Page defaultPageBuilder(
|
||||
BuildContext context,
|
||||
GoRouterState state,
|
||||
Widget child,
|
||||
) =>
|
||||
MaterialPage(
|
||||
key: state.pageKey,
|
||||
restorationId: state.pageKey.value,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/screens/account/friend.dart';
|
||||
import 'package:solian/screens/account/personalize.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/widgets/empty.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
|
||||
class AccountScreen extends StatefulWidget {
|
||||
const AccountScreen({super.key});
|
||||
@ -32,11 +32,11 @@ class _AccountScreenState extends State<AccountScreen> {
|
||||
case 'account.personalize':
|
||||
return const PersonalizeScreenWidget();
|
||||
default:
|
||||
return const SelectionEmptyWidget();
|
||||
return const PageEmptyWidget();
|
||||
}
|
||||
}
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: _title ?? AppLocalizations.of(context)!.account,
|
||||
noSafeArea: true,
|
||||
fixedAppBarColor: true,
|
||||
@ -60,7 +60,7 @@ class _AccountScreenState extends State<AccountScreen> {
|
||||
)
|
||||
: AccountScreenWidget(
|
||||
onSelect: (item, _) {
|
||||
router.pushNamed(item);
|
||||
SolianRouter.router.pushNamed(item);
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -139,7 +139,7 @@ class _AccountScreenWidgetState extends State<AccountScreenWidget> {
|
||||
title: AppLocalizations.of(context)!.signIn,
|
||||
caption: AppLocalizations.of(context)!.signInCaption,
|
||||
onTap: () {
|
||||
router.pushNamed('auth.sign-in').then((did) {
|
||||
SolianRouter.router.pushNamed('auth.sign-in').then((did) {
|
||||
auth.isAuthorized().then((value) {
|
||||
setState(() => _isAuthorized = value);
|
||||
});
|
||||
@ -151,7 +151,7 @@ class _AccountScreenWidgetState extends State<AccountScreenWidget> {
|
||||
title: AppLocalizations.of(context)!.signUp,
|
||||
caption: AppLocalizations.of(context)!.signUpCaption,
|
||||
onTap: () {
|
||||
router.pushNamed('auth.sign-up');
|
||||
SolianRouter.router.pushNamed('auth.sign-up');
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -6,9 +6,9 @@ import 'package:provider/provider.dart';
|
||||
import 'package:solian/models/friendship.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class FriendScreen extends StatelessWidget {
|
||||
@ -16,7 +16,7 @@ class FriendScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.friend,
|
||||
noSafeArea: true,
|
||||
hideDrawer: true,
|
||||
|
@ -7,7 +7,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class PersonalizeScreen extends StatelessWidget {
|
||||
@ -15,7 +15,7 @@ class PersonalizeScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.personalize,
|
||||
hideDrawer: true,
|
||||
child: const PersonalizeScreenWidget(),
|
||||
|
@ -5,7 +5,7 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class SignInScreen extends StatelessWidget {
|
||||
@ -21,7 +21,7 @@ class SignInScreen extends StatelessWidget {
|
||||
final password = _passwordController.value.text;
|
||||
if (username.isEmpty || password.isEmpty) return;
|
||||
auth.signin(context, username, password).then((_) {
|
||||
router.pop(true);
|
||||
SolianRouter.router.pop(true);
|
||||
}).catchError((e) {
|
||||
List<String> messages = e.toString().split('\n');
|
||||
if (messages.last.contains('risk')) {
|
||||
@ -61,7 +61,7 @@ class SignInScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.signIn,
|
||||
hideDrawer: true,
|
||||
child: Center(
|
||||
|
@ -5,7 +5,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class SignUpScreen extends StatelessWidget {
|
||||
@ -58,7 +58,7 @@ class SignUpScreen extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
).then((_) {
|
||||
router.replaceNamed('auth.sign-in');
|
||||
SolianRouter.router.replaceNamed('auth.sign-in');
|
||||
});
|
||||
} else {
|
||||
var message = utf8.decode(res.bodyBytes);
|
||||
@ -68,7 +68,7 @@ class SignUpScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.signUp,
|
||||
hideDrawer: true,
|
||||
child: Center(
|
||||
|
@ -3,10 +3,11 @@ import 'package:livekit_client/livekit_client.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:solian/models/call.dart';
|
||||
import 'package:solian/providers/chat.dart';
|
||||
import 'package:solian/widgets/chat/call/controls.dart';
|
||||
import 'package:solian/utils/theme.dart';
|
||||
import 'package:solian/widgets/chat/call/call_controls.dart';
|
||||
import 'package:solian/widgets/chat/call/participant.dart';
|
||||
import 'package:solian/widgets/chat/call/participant_menu.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
@ -127,8 +128,9 @@ class _ChatCallState extends State<ChatCall> {
|
||||
);
|
||||
}
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.chatCall,
|
||||
fixedAppBarColor: SolianTheme.isLargeScreen(context),
|
||||
hideDrawer: true,
|
||||
child: content,
|
||||
);
|
||||
|
@ -9,7 +9,7 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
@ -55,8 +55,8 @@ class _ChannelEditorScreenState extends State<ChannelEditorScreen> {
|
||||
var message = utf8.decode(res.bodyBytes);
|
||||
context.showErrorDialog(message);
|
||||
} else {
|
||||
if (router.canPop()) {
|
||||
router.pop(true);
|
||||
if (SolianRouter.router.canPop()) {
|
||||
SolianRouter.router.pop(true);
|
||||
}
|
||||
}
|
||||
setState(() => _isSubmitting = false);
|
||||
@ -67,8 +67,8 @@ class _ChannelEditorScreenState extends State<ChannelEditorScreen> {
|
||||
}
|
||||
|
||||
void cancelEditing() {
|
||||
if (router.canPop()) {
|
||||
router.pop(false);
|
||||
if (SolianRouter.router.canPop()) {
|
||||
SolianRouter.router.pop(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ class _ChannelEditorScreenState extends State<ChannelEditorScreen> {
|
||||
],
|
||||
);
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
hideDrawer: true,
|
||||
title: AppLocalizations.of(context)!.chatChannelOrganize,
|
||||
appBarActions: <Widget>[
|
@ -7,10 +7,10 @@ import 'package:solian/models/account.dart';
|
||||
import 'package:solian/models/channel.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'package:solian/widgets/account/friend_picker.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class ChatMemberScreen extends StatefulWidget {
|
||||
@ -141,7 +141,7 @@ class _ChatMemberScreenState extends State<ChatMemberScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.chatMember,
|
||||
noSafeArea: true,
|
||||
hideDrawer: true,
|
@ -10,12 +10,13 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/chat.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/utils/theme.dart';
|
||||
import 'package:solian/widgets/chat/channel_action.dart';
|
||||
import 'package:solian/widgets/chat/maintainer.dart';
|
||||
import 'package:solian/widgets/chat/chat_maintainer.dart';
|
||||
import 'package:solian/widgets/chat/message.dart';
|
||||
import 'package:solian/widgets/chat/message_action.dart';
|
||||
import 'package:solian/widgets/chat/message_editor.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class ChatScreen extends StatelessWidget {
|
||||
@ -27,9 +28,11 @@ class ChatScreen extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final chat = context.watch<ChatProvider>();
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: chat.focusChannel?.name ?? 'Loading...',
|
||||
hideDrawer: true,
|
||||
fixedAppBarColor: SolianTheme.isLargeScreen(context),
|
||||
appBarLeading: IconButton(icon: const Icon(Icons.tag), onPressed: () {}),
|
||||
appBarActions: chat.focusChannel != null
|
||||
? [
|
||||
ChannelCallAction(
|
||||
@ -197,7 +200,7 @@ class _ChatScreenWidgetState extends State<ChatScreenWidget> {
|
||||
TextButton(
|
||||
child: Text(AppLocalizations.of(context)!.chatCallJoin),
|
||||
onPressed: () {
|
||||
router.pushNamed(
|
||||
SolianRouter.router.pushNamed(
|
||||
'chat.channel.call',
|
||||
extra: _chat.ongoingCall,
|
||||
pathParameters: {'channel': widget.alias},
|
||||
@ -250,10 +253,4 @@ class _ChatScreenWidgetState extends State<ChatScreenWidget> {
|
||||
onCallEnded: () => _chat.setOngoingCall(null),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void deactivate() {
|
||||
_chat.unFocus();
|
||||
super.deactivate();
|
||||
}
|
||||
}
|
||||
|
@ -4,19 +4,19 @@ import 'package:solian/models/channel.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/widgets/chat/channel_deletion.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class ChatManageScreen extends StatefulWidget {
|
||||
class ChatDetailScreen extends StatefulWidget {
|
||||
final Channel channel;
|
||||
|
||||
const ChatManageScreen({super.key, required this.channel});
|
||||
const ChatDetailScreen({super.key, required this.channel});
|
||||
|
||||
@override
|
||||
State<ChatManageScreen> createState() => _ChatManageScreenState();
|
||||
State<ChatDetailScreen> createState() => _ChatDetailScreenState();
|
||||
}
|
||||
|
||||
class _ChatManageScreenState extends State<ChatManageScreen> {
|
||||
class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
||||
bool _isOwned = false;
|
||||
|
||||
void promptLeaveChannel() async {
|
||||
@ -27,8 +27,8 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
||||
isOwned: _isOwned,
|
||||
),
|
||||
);
|
||||
if (did == true && router.canPop()) {
|
||||
router.pop('disposed');
|
||||
if (did == true && SolianRouter.router.canPop()) {
|
||||
SolianRouter.router.pop('disposed');
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,16 +53,16 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
||||
leading: const Icon(Icons.settings),
|
||||
title: Text(AppLocalizations.of(context)!.settings),
|
||||
onTap: () async {
|
||||
router.pushNamed('chat.channel.editor', extra: widget.channel).then((did) {
|
||||
SolianRouter.router.pushNamed('chat.channel.editor', extra: widget.channel).then((did) {
|
||||
if (did == true) {
|
||||
if (router.canPop()) router.pop('refresh');
|
||||
if (SolianRouter.router.canPop()) SolianRouter.router.pop('refresh');
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.chatManage,
|
||||
hideDrawer: true,
|
||||
noSafeArea: true,
|
||||
@ -100,7 +100,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
||||
leading: const Icon(Icons.supervisor_account),
|
||||
title: Text(AppLocalizations.of(context)!.chatMember),
|
||||
onTap: () {
|
||||
router.pushNamed(
|
||||
SolianRouter.router.pushNamed(
|
||||
'chat.channel.member',
|
||||
extra: widget.channel,
|
||||
pathParameters: {'channel': widget.channel.alias},
|
@ -4,90 +4,47 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:solian/models/channel.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/chat.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/screens/chat/chat.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/chat/channel_action.dart';
|
||||
import 'package:solian/utils/theme.dart';
|
||||
import 'package:solian/widgets/chat/chat_new.dart';
|
||||
import 'package:solian/widgets/empty.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/widgets/notification_notifier.dart';
|
||||
import 'package:solian/widgets/signin_required.dart';
|
||||
|
||||
class ChatIndexScreen extends StatefulWidget {
|
||||
const ChatIndexScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ChatIndexScreen> createState() => _ChatIndexScreenState();
|
||||
}
|
||||
|
||||
class _ChatIndexScreenState extends State<ChatIndexScreen> {
|
||||
Channel? _selectedChannel;
|
||||
class ChatListScreen extends StatelessWidget {
|
||||
const ChatListScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final chat = context.watch<ChatProvider>();
|
||||
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final isLargeScreen = screenWidth >= 600;
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.chat,
|
||||
appBarActions: chat.focusChannel != null
|
||||
? [
|
||||
ChannelCallAction(
|
||||
call: chat.ongoingCall,
|
||||
channel: chat.focusChannel!,
|
||||
onUpdate: () => chat.fetchChannel(chat.focusChannel!.alias),
|
||||
),
|
||||
ChannelManageAction(
|
||||
channel: chat.focusChannel!,
|
||||
onUpdate: () => chat.fetchChannel(chat.focusChannel!.alias),
|
||||
),
|
||||
]
|
||||
: [const NotificationButton()],
|
||||
fixedAppBarColor: isLargeScreen,
|
||||
child: isLargeScreen
|
||||
? Row(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: ChatIndexScreenWidget(
|
||||
appBarActions: const [NotificationButton()],
|
||||
fixedAppBarColor: SolianTheme.isLargeScreen(context),
|
||||
child: ChatListWidget(
|
||||
onSelect: (item) {
|
||||
setState(() => _selectedChannel = item);
|
||||
SolianRouter.router.pushReplacementNamed(
|
||||
'chat.channel',
|
||||
pathParameters: {'channel': item.alias},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const VerticalDivider(thickness: 0.3, width: 0.3),
|
||||
Flexible(
|
||||
flex: 4,
|
||||
child: _selectedChannel == null
|
||||
? const SelectionEmptyWidget()
|
||||
: ChatScreenWidget(
|
||||
key: Key('c${_selectedChannel!.id}'),
|
||||
alias: _selectedChannel!.alias,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const ChatIndexScreenWidget(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatIndexScreenWidget extends StatefulWidget {
|
||||
class ChatListWidget extends StatefulWidget {
|
||||
final Function(Channel item)? onSelect;
|
||||
|
||||
const ChatIndexScreenWidget({super.key, this.onSelect});
|
||||
const ChatListWidget({super.key, this.onSelect});
|
||||
|
||||
@override
|
||||
State<ChatIndexScreenWidget> createState() => _ChatIndexScreenWidgetState();
|
||||
State<ChatListWidget> createState() => _ChatListWidgetState();
|
||||
}
|
||||
|
||||
class _ChatIndexScreenWidgetState extends State<ChatIndexScreenWidget> {
|
||||
class _ChatListWidgetState extends State<ChatListWidget> {
|
||||
List<Channel> _channels = List.empty();
|
||||
|
||||
Future<void> fetchChannels() async {
|
||||
@ -169,7 +126,7 @@ class _ChatIndexScreenWidgetState extends State<ChatIndexScreenWidget> {
|
||||
return;
|
||||
}
|
||||
|
||||
final result = await router.pushNamed(
|
||||
final result = await SolianRouter.router.pushNamed(
|
||||
'chat.channel',
|
||||
pathParameters: {
|
||||
'channel': element.alias,
|
@ -12,9 +12,9 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:solian/widgets/empty.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:solian/widgets/notification_notifier.dart';
|
||||
import 'package:solian/widgets/posts/item.dart';
|
||||
import 'package:solian/widgets/posts/post.dart';
|
||||
|
||||
class ExploreScreen extends StatefulWidget {
|
||||
const ExploreScreen({super.key});
|
||||
@ -31,7 +31,7 @@ class _ExploreScreenState extends State<ExploreScreen> {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final isLargeScreen = screenWidth >= 600;
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
noSafeArea: true,
|
||||
fixedAppBarColor: isLargeScreen,
|
||||
appBarActions: const [NotificationButton()],
|
||||
@ -51,7 +51,7 @@ class _ExploreScreenState extends State<ExploreScreen> {
|
||||
Flexible(
|
||||
flex: 4,
|
||||
child: _selectedPost == null
|
||||
? const SelectionEmptyWidget()
|
||||
? const PageEmptyWidget()
|
||||
: PostScreenWidget(
|
||||
key: Key('p${_selectedPost!.id}'),
|
||||
dataset: _selectedPost!.dataset,
|
||||
@ -62,7 +62,7 @@ class _ExploreScreenState extends State<ExploreScreen> {
|
||||
)
|
||||
: ExploreScreenWidget(
|
||||
onSelect: (item) {
|
||||
router.pushNamed(
|
||||
SolianRouter.router.pushNamed(
|
||||
'posts.screen',
|
||||
pathParameters: {
|
||||
'alias': item.alias,
|
||||
@ -130,7 +130,7 @@ class _ExploreScreenWidgetState extends State<ExploreScreenWidget> {
|
||||
return FloatingActionButton(
|
||||
child: const Icon(Icons.edit),
|
||||
onPressed: () async {
|
||||
final did = await router.pushNamed('posts.moments.editor');
|
||||
final did = await SolianRouter.router.pushNamed('posts.moments.editor');
|
||||
if (did == true) _pagingController.refresh();
|
||||
},
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/notify.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:solian/models/notification.dart' as model;
|
||||
@ -25,7 +25,7 @@ class _NotificationScreenState extends State<NotificationScreen> {
|
||||
nty.allRead();
|
||||
});
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
noSafeArea: true,
|
||||
hideDrawer: true,
|
||||
title: AppLocalizations.of(context)!.notification,
|
||||
@ -82,10 +82,10 @@ class NotificationItem extends StatelessWidget {
|
||||
const NotificationItem(
|
||||
{super.key, required this.index, required this.item, this.onDismiss});
|
||||
|
||||
bool hasLinks() => item.links != null && item.links!.isNotEmpty;
|
||||
bool get hasLinks => item.links != null && item.links!.isNotEmpty;
|
||||
|
||||
void showLinks(BuildContext context) {
|
||||
if (!hasLinks()) return;
|
||||
if (!hasLinks) return;
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
@ -170,7 +170,7 @@ class NotificationItem extends StatelessWidget {
|
||||
child: ListTile(
|
||||
title: Text(item.subject),
|
||||
subtitle: Text(item.content),
|
||||
trailing: hasLinks()
|
||||
trailing: hasLinks
|
||||
? TextButton(
|
||||
onPressed: () => showLinks(context),
|
||||
style: TextButton.styleFrom(shape: const CircleBorder()),
|
||||
|
@ -9,9 +9,9 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:solian/widgets/posts/attachment_editor.dart';
|
||||
|
||||
class CommentPostArguments {
|
||||
@ -78,16 +78,16 @@ class _CommentEditorScreenState extends State<CommentEditorScreen> {
|
||||
var message = utf8.decode(res.bodyBytes);
|
||||
context.showErrorDialog(message);
|
||||
} else {
|
||||
if (router.canPop()) {
|
||||
router.pop(true);
|
||||
if (SolianRouter.router.canPop()) {
|
||||
SolianRouter.router.pop(true);
|
||||
}
|
||||
}
|
||||
setState(() => _isSubmitting = false);
|
||||
}
|
||||
|
||||
void cancelEditing() {
|
||||
if (router.canPop()) {
|
||||
router.pop(false);
|
||||
if (SolianRouter.router.canPop()) {
|
||||
SolianRouter.router.pop(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ class _CommentEditorScreenState extends State<CommentEditorScreen> {
|
||||
],
|
||||
);
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
hideDrawer: true,
|
||||
title: AppLocalizations.of(context)!.newComment,
|
||||
appBarActions: <Widget>[
|
||||
|
@ -9,9 +9,9 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:solian/widgets/posts/attachment_editor.dart';
|
||||
|
||||
class MomentEditorScreen extends StatefulWidget {
|
||||
@ -68,16 +68,16 @@ class _MomentEditorScreenState extends State<MomentEditorScreen> {
|
||||
var message = utf8.decode(res.bodyBytes);
|
||||
context.showErrorDialog(message);
|
||||
} else {
|
||||
if (router.canPop()) {
|
||||
router.pop(true);
|
||||
if (SolianRouter.router.canPop()) {
|
||||
SolianRouter.router.pop(true);
|
||||
}
|
||||
}
|
||||
setState(() => _isSubmitting = false);
|
||||
}
|
||||
|
||||
void cancelEditing() {
|
||||
if (router.canPop()) {
|
||||
router.pop(false);
|
||||
if (SolianRouter.router.canPop()) {
|
||||
SolianRouter.router.pop(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ class _MomentEditorScreenState extends State<MomentEditorScreen> {
|
||||
],
|
||||
);
|
||||
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
hideDrawer: true,
|
||||
title: AppLocalizations.of(context)!.newMoment,
|
||||
appBarActions: <Widget>[
|
||||
|
@ -6,9 +6,9 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
import 'package:solian/models/post.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/exts.dart';
|
||||
import 'package:solian/widgets/indent_wrapper.dart';
|
||||
import 'package:solian/widgets/scaffold.dart';
|
||||
import 'package:solian/widgets/posts/comment_list.dart';
|
||||
import 'package:solian/widgets/posts/item.dart';
|
||||
import 'package:solian/widgets/posts/post.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class PostScreen extends StatelessWidget {
|
||||
@ -19,7 +19,7 @@ class PostScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndentWrapper(
|
||||
return IndentScaffold(
|
||||
title: AppLocalizations.of(context)!.post,
|
||||
noSafeArea: true,
|
||||
hideDrawer: true,
|
||||
|
39
lib/utils/platform.dart
Normal file
39
lib/utils/platform.dart
Normal file
@ -0,0 +1,39 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
abstract class PlatformInfo {
|
||||
static bool get isWeb => kIsWeb;
|
||||
|
||||
static bool get isLinux => !kIsWeb && Platform.isLinux;
|
||||
|
||||
static bool get isWindows => !kIsWeb && Platform.isWindows;
|
||||
|
||||
static bool get isMacOS => !kIsWeb && Platform.isMacOS;
|
||||
|
||||
static bool get isIOS => !kIsWeb && Platform.isIOS;
|
||||
|
||||
static bool get isAndroid => !kIsWeb && Platform.isAndroid;
|
||||
|
||||
static bool get isMobile => isAndroid || isIOS;
|
||||
|
||||
// Not first tier supported platform
|
||||
static bool get isBetaDesktop => isWindows || isLinux;
|
||||
|
||||
static bool get isDesktop => isLinux || isWindows || isMacOS;
|
||||
|
||||
static bool get useTouchscreen => !isMobile;
|
||||
|
||||
static bool get canCacheImage => isAndroid || isIOS || isMacOS;
|
||||
|
||||
static bool get canRecord => (isMobile || isMacOS);
|
||||
|
||||
static Future<String> getVersion() async {
|
||||
var version = kIsWeb ? 'Web' : 'Unknown';
|
||||
try {
|
||||
version = (await PackageInfo.fromPlatform()).version;
|
||||
} catch (_) {}
|
||||
return version;
|
||||
}
|
||||
}
|
17
lib/utils/theme.dart
Normal file
17
lib/utils/theme.dart
Normal file
@ -0,0 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
abstract class SolianTheme {
|
||||
static bool isLargeScreen(BuildContext context) =>
|
||||
MediaQuery.of(context).size.width > 640;
|
||||
|
||||
static ThemeData build(Brightness brightness) {
|
||||
return ThemeData(
|
||||
brightness: brightness,
|
||||
useMaterial3: true,
|
||||
colorScheme: ColorScheme.fromSeed(brightness: brightness, seedColor: Colors.indigo),
|
||||
snackBarTheme: const SnackBarThemeData(
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:solian/utils/platform.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
|
||||
class AccountAvatar extends StatelessWidget {
|
||||
@ -27,17 +29,19 @@ class AccountAvatar extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
if (direct == true) {
|
||||
final image = PlatformInfo.canCacheImage ? CachedNetworkImageProvider(source) : NetworkImage(source);
|
||||
return CircleAvatar(
|
||||
radius: radius,
|
||||
backgroundColor: backgroundColor,
|
||||
backgroundImage: NetworkImage(source),
|
||||
backgroundImage: image as ImageProvider,
|
||||
);
|
||||
} else {
|
||||
final url = getRequestUri('passport', '/api/avatar/$source').toString();
|
||||
final image = PlatformInfo.canCacheImage ? CachedNetworkImageProvider(url) : NetworkImage(url);
|
||||
return CircleAvatar(
|
||||
radius: radius,
|
||||
backgroundColor: backgroundColor,
|
||||
backgroundImage: NetworkImage(url),
|
||||
backgroundImage: image as ImageProvider,
|
||||
);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/friend.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
|
||||
class FriendPicker extends StatefulWidget {
|
||||
const FriendPicker({super.key});
|
||||
|
@ -76,7 +76,7 @@ class _ControlsWidgetState extends State<ControlsWidget> {
|
||||
if (chat.currentCall != null) {
|
||||
chat.currentCall!.deactivate();
|
||||
chat.currentCall!.dispose();
|
||||
router.pop();
|
||||
SolianRouter.router.pop();
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class CallOverlay extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
router.pushNamed(
|
||||
SolianRouter.router.pushNamed(
|
||||
'chat.channel.call',
|
||||
extra: chat.currentCall!.info,
|
||||
pathParameters: {'channel': chat.currentCall!.channel.alias},
|
||||
|
@ -5,7 +5,7 @@ import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:livekit_client/livekit_client.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
import 'package:solian/models/call.dart';
|
||||
import 'package:solian/widgets/chat/call/no_content.dart';
|
||||
import 'package:solian/widgets/chat/call/participant_no_content.dart';
|
||||
import 'package:solian/widgets/chat/call/participant_info.dart';
|
||||
import 'package:solian/widgets/chat/call/participant_stats.dart';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
class NoContentWidget extends StatefulWidget {
|
@ -97,14 +97,14 @@ class ChannelManageAction extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: () async {
|
||||
final result = await router.pushNamed(
|
||||
final result = await SolianRouter.router.pushNamed(
|
||||
'chat.channel.manage',
|
||||
extra: channel,
|
||||
pathParameters: {'channel': channel.alias},
|
||||
);
|
||||
switch (result) {
|
||||
case 'disposed':
|
||||
if (router.canPop()) router.pop('refresh');
|
||||
if (SolianRouter.router.canPop()) SolianRouter.router.pop('refresh');
|
||||
case 'refresh':
|
||||
onUpdate();
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class ChatNewAction extends StatelessWidget {
|
||||
leading: const Icon(Icons.add),
|
||||
title: Text(AppLocalizations.of(context)!.chatNewCreate),
|
||||
onTap: () {
|
||||
router.pushNamed('chat.channel.editor').then((did) {
|
||||
SolianRouter.router.pushNamed('chat.channel.editor').then((did) {
|
||||
if (did == true) {
|
||||
onUpdate();
|
||||
if (Navigator.canPop(context)) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:solian/models/message.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/chat/content.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'package:solian/widgets/chat/message_content.dart';
|
||||
import 'package:solian/widgets/posts/content/attachment.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
||||
import 'dart:math' as math;
|
||||
|
@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class SelectionEmptyWidget extends StatelessWidget {
|
||||
const SelectionEmptyWidget({super.key});
|
||||
class PageEmptyWidget extends StatelessWidget {
|
||||
const PageEmptyWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
return Material(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@ -18,6 +19,7 @@ class SelectionEmptyWidget extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/widgets/common_wrapper.dart';
|
||||
import 'package:solian/widgets/navigation_drawer.dart';
|
||||
|
||||
class IndentWrapper extends LayoutWrapper {
|
||||
final bool hideDrawer;
|
||||
final bool fixedAppBarColor;
|
||||
|
||||
const IndentWrapper({
|
||||
super.key,
|
||||
super.child,
|
||||
required super.title,
|
||||
super.floatingActionButton,
|
||||
super.appBarActions,
|
||||
this.hideDrawer = false,
|
||||
this.fixedAppBarColor = false,
|
||||
super.noSafeArea = false,
|
||||
}) : super();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final content = child ?? Container();
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: hideDrawer
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => router.pop(),
|
||||
)
|
||||
: null,
|
||||
title: Text(title),
|
||||
actions: appBarActions,
|
||||
centerTitle: false,
|
||||
elevation: fixedAppBarColor ? 4 : null,
|
||||
),
|
||||
floatingActionButton: floatingActionButton,
|
||||
drawer: const SolianNavigationDrawer(),
|
||||
body: noSafeArea ? content : SafeArea(child: content),
|
||||
);
|
||||
}
|
||||
}
|
31
lib/widgets/layouts/two_column.dart
Normal file
31
lib/widgets/layouts/two_column.dart
Normal file
@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:solian/widgets/empty.dart';
|
||||
|
||||
class TwoColumnLayout extends StatelessWidget {
|
||||
final Widget sideChild;
|
||||
final Widget? mainChild;
|
||||
|
||||
const TwoColumnLayout({
|
||||
super.key,
|
||||
required this.sideChild,
|
||||
required this.mainChild,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ScaffoldMessenger(
|
||||
child: Scaffold(
|
||||
body: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: sideChild,
|
||||
),
|
||||
const VerticalDivider(width: 0.3, thickness: 0.3),
|
||||
Expanded(child: mainChild ?? const PageEmptyWidget()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:solian/providers/navigation.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/utils/theme.dart';
|
||||
|
||||
class SolianNavigationDrawer extends StatefulWidget {
|
||||
const SolianNavigationDrawer({super.key});
|
||||
@ -17,7 +18,7 @@ class _SolianNavigationDrawerState extends State<SolianNavigationDrawer> {
|
||||
void _onSelect(String name, int idx) {
|
||||
setState(() => _selectedIndex = idx);
|
||||
context.read<NavigationProvider>().selectedIndex = idx;
|
||||
router.goNamed(name);
|
||||
SolianRouter.router.goNamed(name);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -59,6 +60,9 @@ class _SolianNavigationDrawerState extends State<SolianNavigationDrawer> {
|
||||
|
||||
return NavigationDrawer(
|
||||
selectedIndex: _selectedIndex,
|
||||
elevation: SolianTheme.isLargeScreen(context) ? 20 : 0,
|
||||
shadowColor: SolianTheme.isLargeScreen(context) ? Theme.of(context).shadowColor : null,
|
||||
surfaceTintColor: Theme.of(context).colorScheme.background,
|
||||
onDestinationSelected: (int idx) {
|
||||
final element = navigationItems[idx];
|
||||
_onSelect(element.$2, idx);
|
||||
|
@ -85,7 +85,7 @@ class _NotificationButtonState extends State<NotificationButton> {
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.notifications),
|
||||
onPressed: () {
|
||||
router.pushNamed('notification');
|
||||
SolianRouter.router.pushNamed('notification');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -10,7 +10,7 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/screens/posts/comment_editor.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:solian/widgets/posts/item.dart';
|
||||
import 'package:solian/widgets/posts/post.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class CommentList extends StatefulWidget {
|
||||
@ -120,7 +120,7 @@ class CommentListHeader extends StatelessWidget {
|
||||
if (snapshot.hasData && snapshot.data == true) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
final did = await router.pushNamed(
|
||||
final did = await SolianRouter.router.pushNamed(
|
||||
'posts.comments.editor',
|
||||
extra: CommentPostArguments(related: related),
|
||||
);
|
||||
|
@ -1,7 +1,9 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:solian/models/post.dart';
|
||||
import 'package:solian/utils/platform.dart';
|
||||
import 'package:solian/utils/service_url.dart';
|
||||
import 'package:flutter_carousel_widget/flutter_carousel_widget.dart';
|
||||
import 'package:solian/widgets/posts/attachment_screen.dart';
|
||||
@ -57,6 +59,7 @@ class _AttachmentItemState extends State<AttachmentItem> {
|
||||
Widget content;
|
||||
|
||||
if (widget.type == 1) {
|
||||
final image = PlatformInfo.canCacheImage ? CachedNetworkImageProvider(widget.url) : NetworkImage(widget.url);
|
||||
content = GestureDetector(
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(borderRadius),
|
||||
@ -64,8 +67,8 @@ class _AttachmentItemState extends State<AttachmentItem> {
|
||||
tag: tag,
|
||||
child: Stack(
|
||||
children: [
|
||||
Image.network(
|
||||
widget.url,
|
||||
Image(
|
||||
image: image as ImageProvider,
|
||||
key: Key(getTag()),
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
|
@ -1,12 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
import 'package:solian/models/post.dart';
|
||||
import 'package:solian/widgets/account/avatar.dart';
|
||||
import 'package:solian/widgets/account/account_avatar.dart';
|
||||
import 'package:solian/widgets/posts/comment_list.dart';
|
||||
import 'package:solian/widgets/posts/content/article.dart';
|
||||
import 'package:solian/widgets/posts/content/attachment.dart';
|
||||
import 'package:solian/widgets/posts/content/moment.dart';
|
||||
import 'package:solian/widgets/posts/item_action.dart';
|
||||
import 'package:solian/widgets/posts/post_action.dart';
|
||||
import 'package:solian/widgets/posts/reaction_list.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
@ -5,7 +5,7 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:solian/screens/posts/comment_editor.dart';
|
||||
import 'package:solian/widgets/posts/item_deletion.dart';
|
||||
import 'package:solian/widgets/posts/post_deletion.dart';
|
||||
|
||||
class PostItemAction extends StatelessWidget {
|
||||
final Post item;
|
||||
@ -23,17 +23,17 @@ class PostItemAction extends StatelessWidget {
|
||||
bool ok = false;
|
||||
switch (item.modelType) {
|
||||
case 'article':
|
||||
ok = await router.pushNamed(
|
||||
ok = await SolianRouter.router.pushNamed(
|
||||
'posts.articles.editor',
|
||||
extra: item,
|
||||
) as bool;
|
||||
case 'moment':
|
||||
ok = await router.pushNamed(
|
||||
ok = await SolianRouter.router.pushNamed(
|
||||
'posts.moments.editor',
|
||||
extra: item,
|
||||
) as bool;
|
||||
case 'comment':
|
||||
ok = await router.pushNamed(
|
||||
ok = await SolianRouter.router.pushNamed(
|
||||
'posts.comments.editor',
|
||||
extra: CommentPostArguments(editing: item),
|
||||
) as bool;
|
@ -1,19 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:solian/utils/theme.dart';
|
||||
import 'package:solian/widgets/navigation_drawer.dart';
|
||||
|
||||
class LayoutWrapper extends StatelessWidget {
|
||||
class IndentScaffold extends StatelessWidget {
|
||||
final Widget? child;
|
||||
final Widget? floatingActionButton;
|
||||
final Widget? appBarLeading;
|
||||
final List<Widget>? appBarActions;
|
||||
final bool noSafeArea;
|
||||
final bool hideDrawer;
|
||||
final bool fixedAppBarColor;
|
||||
final String title;
|
||||
|
||||
const LayoutWrapper({
|
||||
const IndentScaffold({
|
||||
super.key,
|
||||
this.child,
|
||||
required this.title,
|
||||
this.floatingActionButton,
|
||||
this.appBarLeading,
|
||||
this.appBarActions,
|
||||
this.hideDrawer = false,
|
||||
this.fixedAppBarColor = false,
|
||||
this.noSafeArea = false,
|
||||
});
|
||||
|
||||
@ -24,11 +31,14 @@ class LayoutWrapper extends StatelessWidget {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(title),
|
||||
leading: appBarLeading,
|
||||
actions: appBarActions,
|
||||
centerTitle: false,
|
||||
elevation: fixedAppBarColor ? 4 : null,
|
||||
),
|
||||
floatingActionButton: floatingActionButton,
|
||||
drawer: const SolianNavigationDrawer(),
|
||||
drawer: !hideDrawer ? const SolianNavigationDrawer() : null,
|
||||
drawerScrimColor: SolianTheme.isLargeScreen(context) ? Colors.transparent : null,
|
||||
body: noSafeArea ? content : SafeArea(child: content),
|
||||
);
|
||||
}
|
@ -32,7 +32,7 @@ class SignInRequiredScreen extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
router.goNamed('account');
|
||||
SolianRouter.router.goNamed('account');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
|
||||
@ -14,6 +15,9 @@
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
|
||||
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_drop
|
||||
file_selector_linux
|
||||
flutter_secure_storage_linux
|
||||
flutter_webrtc
|
||||
|
@ -6,6 +6,7 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import connectivity_plus
|
||||
import desktop_drop
|
||||
import device_info_plus
|
||||
import file_selector_macos
|
||||
import flutter_local_notifications
|
||||
@ -17,11 +18,13 @@ import media_kit_video
|
||||
import package_info_plus
|
||||
import path_provider_foundation
|
||||
import screen_brightness_macos
|
||||
import sqflite
|
||||
import url_launcher_macos
|
||||
import wakelock_plus
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||
DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
@ -33,6 +36,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
||||
}
|
||||
|
74
pubspec.lock
74
pubspec.lock
@ -41,6 +41,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cached_network_image
|
||||
sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.1"
|
||||
cached_network_image_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_platform_interface
|
||||
sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
cached_network_image_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_web
|
||||
sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -153,6 +177,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
desktop_drop:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: desktop_drop
|
||||
sha256: d55a010fe46c8e8fcff4ea4b451a9ff84a162217bdb3b2a0aa1479776205e15d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.4"
|
||||
device_info_plus:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -270,6 +302,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
flutter_cache_manager:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_cache_manager
|
||||
sha256: "395d6b7831f21f3b989ebedbb785545932adb9afe2622c1ffacf7f4b53a7e544"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.2"
|
||||
flutter_carousel_widget:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -749,8 +789,16 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
package_info_plus:
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: octo_image
|
||||
sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
package_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info_plus
|
||||
sha256: "2c582551839386fa7ddbc7770658be7c0f87f388a4bff72066478f597c34d17f"
|
||||
@ -933,6 +981,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: rxdart
|
||||
sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.27.7"
|
||||
safe_local_storage:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1026,6 +1082,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
sqflite:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite
|
||||
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3+1"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -68,6 +68,9 @@ dependencies:
|
||||
flutter_local_notifications: ^17.1.0
|
||||
draggable_float_widget: ^0.1.0
|
||||
file_picker: ^8.0.3
|
||||
package_info_plus: ^7.0.0
|
||||
cached_network_image: ^3.3.1
|
||||
desktop_drop: ^0.4.4
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
|
||||
@ -20,6 +21,8 @@
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
DesktopDropPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
connectivity_plus
|
||||
desktop_drop
|
||||
file_selector_windows
|
||||
flutter_secure_storage_windows
|
||||
flutter_webrtc
|
||||
|
Loading…
x
Reference in New Issue
Block a user