Compare commits
	
		
			5 Commits
		
	
	
		
			2.2.2+55
			...
			cb4a2598c8
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| cb4a2598c8 | |||
| 950612dc07 | |||
| cbd1eaf1af | |||
| ac41cbd99f | |||
| 9f9c90abc4 | 
| @@ -196,6 +196,10 @@ | |||||||
|   "settingsFeatures": "Features", |   "settingsFeatures": "Features", | ||||||
|   "settingsNotifyWithHaptic": "Haptic when Notified", |   "settingsNotifyWithHaptic": "Haptic when Notified", | ||||||
|   "settingsNotifyWithHapticDescription": "Vibrate lightly when a new notification appears in the foreground.", |   "settingsNotifyWithHapticDescription": "Vibrate lightly when a new notification appears in the foreground.", | ||||||
|  |   "settingsExpandPostLink": "Expand Post Link", | ||||||
|  |   "settingsExpandPostLinkDescription": "Expand the post link in the post list.", | ||||||
|  |   "settingsExpandChatLink": "Expand Chat Link", | ||||||
|  |   "settingsExpandChatLinkDescription": "Expand the chat link in the chat list.", | ||||||
|   "settingsNetwork": "Network", |   "settingsNetwork": "Network", | ||||||
|   "settingsNetworkServer": "HyperNet Server", |   "settingsNetworkServer": "HyperNet Server", | ||||||
|   "settingsNetworkServerDescription": "Set the HyperNet server address, choose ours or build your own.", |   "settingsNetworkServerDescription": "Set the HyperNet server address, choose ours or build your own.", | ||||||
|   | |||||||
| @@ -194,6 +194,10 @@ | |||||||
|   "settingsFeatures": "功能", |   "settingsFeatures": "功能", | ||||||
|   "settingsNotifyWithHaptic": "新通知时振动", |   "settingsNotifyWithHaptic": "新通知时振动", | ||||||
|   "settingsNotifyWithHapticDescription": "在应用在前台时收到新通知出现时出发轻量的振动。", |   "settingsNotifyWithHapticDescription": "在应用在前台时收到新通知出现时出发轻量的振动。", | ||||||
|  |   "settingsExpandPostLink": "展开帖子链接", | ||||||
|  |   "settingsExpandPostLinkDescription": "在帖子列表中展开显示帖子中的链接。", | ||||||
|  |   "settingsExpandChatLink": "展开聊天链接", | ||||||
|  |   "settingsExpandChatLinkDescription": "在聊天信息中展开显示内容中的链接。", | ||||||
|   "settingsNetwork": "网络", |   "settingsNetwork": "网络", | ||||||
|   "settingsNetworkServer": "HyperNet 服务器", |   "settingsNetworkServer": "HyperNet 服务器", | ||||||
|   "settingsNetworkServerDescription": "设置 HyperNet 服务器地址,选择我们提供的,或者自己搭建。", |   "settingsNetworkServerDescription": "设置 HyperNet 服务器地址,选择我们提供的,或者自己搭建。", | ||||||
|   | |||||||
| @@ -260,7 +260,7 @@ class _AppSplashScreenState extends State<_AppSplashScreen> { | |||||||
|     try { |     try { | ||||||
|       final cfg = context.read<ConfigProvider>(); |       final cfg = context.read<ConfigProvider>(); | ||||||
|       WidgetsBinding.instance.addPostFrameCallback((_) { |       WidgetsBinding.instance.addPostFrameCallback((_) { | ||||||
|         cfg.calcDrawerSize(context); |         cfg.calcDrawerSize(context, withMediaQuery: true); | ||||||
|       }); |       }); | ||||||
|       final home = context.read<HomeWidgetProvider>(); |       final home = context.read<HomeWidgetProvider>(); | ||||||
|       await home.initialize(); |       await home.initialize(); | ||||||
|   | |||||||
| @@ -15,6 +15,8 @@ const kAppBackgroundStoreKey = 'app_has_background'; | |||||||
| const kAppColorSchemeStoreKey = 'app_color_scheme'; | const kAppColorSchemeStoreKey = 'app_color_scheme'; | ||||||
| const kAppDrawerPreferCollapse = 'app_drawer_prefer_collapse'; | const kAppDrawerPreferCollapse = 'app_drawer_prefer_collapse'; | ||||||
| const kAppNotifyWithHaptic = 'app_notify_with_haptic'; | const kAppNotifyWithHaptic = 'app_notify_with_haptic'; | ||||||
|  | const kAppExpandPostLink = 'app_expand_post_link'; | ||||||
|  | const kAppExpandChatLink = 'app_expand_chat_link'; | ||||||
|  |  | ||||||
| const Map<String, FilterQuality> kImageQualityLevel = { | const Map<String, FilterQuality> kImageQualityLevel = { | ||||||
|   'settingsImageQualityLowest': FilterQuality.none, |   'settingsImageQualityLowest': FilterQuality.none, | ||||||
| @@ -39,14 +41,22 @@ class ConfigProvider extends ChangeNotifier { | |||||||
|   bool drawerIsCollapsed = false; |   bool drawerIsCollapsed = false; | ||||||
|   bool drawerIsExpanded = false; |   bool drawerIsExpanded = false; | ||||||
|  |  | ||||||
|   void calcDrawerSize(BuildContext context) { |   void calcDrawerSize(BuildContext context, {bool withMediaQuery = false}) { | ||||||
|  |     bool newDrawerIsCollapsed = false; | ||||||
|  |     bool newDrawerIsExpanded = false; | ||||||
|  |     if (withMediaQuery) { | ||||||
|  |       newDrawerIsCollapsed = MediaQuery.of(context).size.width < 450; | ||||||
|  |       newDrawerIsExpanded = MediaQuery.of(context).size.width >= 451; | ||||||
|  |     } else { | ||||||
|       final rpb = ResponsiveBreakpoints.of(context); |       final rpb = ResponsiveBreakpoints.of(context); | ||||||
|     final newDrawerIsCollapsed = rpb.smallerOrEqualTo(MOBILE); |       newDrawerIsCollapsed = rpb.smallerOrEqualTo(MOBILE); | ||||||
|     final newDrawerIsExpanded = rpb.largerThan(TABLET) |       newDrawerIsCollapsed = rpb.largerThan(TABLET) | ||||||
|           ? (prefs.getBool(kAppDrawerPreferCollapse) ?? false) |           ? (prefs.getBool(kAppDrawerPreferCollapse) ?? false) | ||||||
|               ? false |               ? false | ||||||
|               : true |               : true | ||||||
|           : false; |           : false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (newDrawerIsExpanded != drawerIsExpanded || newDrawerIsCollapsed != drawerIsCollapsed) { |     if (newDrawerIsExpanded != drawerIsExpanded || newDrawerIsCollapsed != drawerIsCollapsed) { | ||||||
|       drawerIsExpanded = newDrawerIsExpanded; |       drawerIsExpanded = newDrawerIsExpanded; | ||||||
|       drawerIsCollapsed = newDrawerIsCollapsed; |       drawerIsCollapsed = newDrawerIsCollapsed; | ||||||
|   | |||||||
| @@ -34,21 +34,30 @@ import 'package:surface/widgets/about.dart'; | |||||||
| import 'package:surface/widgets/navigation/app_background.dart'; | import 'package:surface/widgets/navigation/app_background.dart'; | ||||||
| import 'package:surface/widgets/navigation/app_scaffold.dart'; | import 'package:surface/widgets/navigation/app_scaffold.dart'; | ||||||
|  |  | ||||||
|  | Widget _fadeThroughTransition( | ||||||
|  |     BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { | ||||||
|  |   return FadeThroughTransition( | ||||||
|  |     animation: animation, | ||||||
|  |     secondaryAnimation: secondaryAnimation, | ||||||
|  |     fillColor: Colors.transparent, | ||||||
|  |     child: child, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
| final _appRoutes = [ | final _appRoutes = [ | ||||||
|   ShellRoute( |  | ||||||
|     builder: (context, state, child) => child, |  | ||||||
|     routes: [ |  | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/', |     path: '/', | ||||||
|     name: 'home', |     name: 'home', | ||||||
|         pageBuilder: (context, state) => NoTransitionPage( |     pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|  |       transitionsBuilder: _fadeThroughTransition, | ||||||
|       child: const HomeScreen(), |       child: const HomeScreen(), | ||||||
|     ), |     ), | ||||||
|   ), |   ), | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/posts', |     path: '/posts', | ||||||
|     name: 'explore', |     name: 'explore', | ||||||
|         pageBuilder: (context, state) => NoTransitionPage( |     pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|  |       transitionsBuilder: _fadeThroughTransition, | ||||||
|       child: const ExploreScreen(), |       child: const ExploreScreen(), | ||||||
|     ), |     ), | ||||||
|     routes: [ |     routes: [ | ||||||
| @@ -96,30 +105,15 @@ final _appRoutes = [ | |||||||
|     path: '/account', |     path: '/account', | ||||||
|     name: 'account', |     name: 'account', | ||||||
|     pageBuilder: (context, state) => CustomTransitionPage( |     pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|           transitionsBuilder: (context, animation, secondaryAnimation, child) { |       transitionsBuilder: _fadeThroughTransition, | ||||||
|             return FadeThroughTransition( |  | ||||||
|               animation: animation, |  | ||||||
|               secondaryAnimation: secondaryAnimation, |  | ||||||
|               fillColor: Colors.transparent, |  | ||||||
|               child: child, |  | ||||||
|             ); |  | ||||||
|           }, |  | ||||||
|       child: const AccountScreen(), |       child: const AccountScreen(), | ||||||
|     ), |     ), | ||||||
|         routes: [], |  | ||||||
|   ), |   ), | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/chat', |     path: '/chat', | ||||||
|     name: 'chat', |     name: 'chat', | ||||||
|     pageBuilder: (context, state) => CustomTransitionPage( |     pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|           transitionsBuilder: (context, animation, secondaryAnimation, child) { |       transitionsBuilder: _fadeThroughTransition, | ||||||
|             return FadeThroughTransition( |  | ||||||
|               animation: animation, |  | ||||||
|               secondaryAnimation: secondaryAnimation, |  | ||||||
|               fillColor: Colors.transparent, |  | ||||||
|               child: child, |  | ||||||
|             ); |  | ||||||
|           }, |  | ||||||
|       child: const ChatScreen(), |       child: const ChatScreen(), | ||||||
|     ), |     ), | ||||||
|     routes: [ |     routes: [ | ||||||
| @@ -165,46 +159,34 @@ final _appRoutes = [ | |||||||
|               animation: animation, |               animation: animation, | ||||||
|               secondaryAnimation: secondaryAnimation, |               secondaryAnimation: secondaryAnimation, | ||||||
|               fillColor: Colors.transparent, |               fillColor: Colors.transparent, | ||||||
|                   child: AppBackground( |  | ||||||
|               child: child, |               child: child, | ||||||
|                   ), |  | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|           GoRoute( |  | ||||||
|             path: '/:alias', |  | ||||||
|             name: 'realmDetail', |  | ||||||
|             builder: (context, state) => AppBackground( |  | ||||||
|               child: RealmDetailScreen(alias: state.pathParameters['alias']!), |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|     ], |     ], | ||||||
|   ), |   ), | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/realm', |     path: '/realm', | ||||||
|     name: 'realm', |     name: 'realm', | ||||||
|         pageBuilder: (context, state) => NoTransitionPage( |     pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|  |       transitionsBuilder: _fadeThroughTransition, | ||||||
|       child: const RealmScreen(), |       child: const RealmScreen(), | ||||||
|     ), |     ), | ||||||
|     routes: [ |     routes: [ | ||||||
|  |       GoRoute( | ||||||
|  |         path: '/:alias', | ||||||
|  |         name: 'realmDetail', | ||||||
|  |         builder: (context, state) => RealmDetailScreen(alias: state.pathParameters['alias']!), | ||||||
|  |       ), | ||||||
|       GoRoute( |       GoRoute( | ||||||
|         path: '/manage', |         path: '/manage', | ||||||
|         name: 'realmManage', |         name: 'realmManage', | ||||||
|         pageBuilder: (context, state) => CustomTransitionPage( |         pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|  |           transitionsBuilder: _fadeThroughTransition, | ||||||
|           child: RealmManageScreen( |           child: RealmManageScreen( | ||||||
|             editingRealmAlias: state.uri.queryParameters['editing'], |             editingRealmAlias: state.uri.queryParameters['editing'], | ||||||
|           ), |           ), | ||||||
|               transitionsBuilder: (context, animation, secondaryAnimation, child) { |  | ||||||
|                 return FadeThroughTransition( |  | ||||||
|                   animation: animation, |  | ||||||
|                   secondaryAnimation: secondaryAnimation, |  | ||||||
|                   fillColor: Colors.transparent, |  | ||||||
|                   child: AppBackground( |  | ||||||
|                     child: child, |  | ||||||
|                   ), |  | ||||||
|                 ); |  | ||||||
|               }, |  | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|     ], |     ], | ||||||
| @@ -212,7 +194,8 @@ final _appRoutes = [ | |||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/album', |     path: '/album', | ||||||
|     name: 'album', |     name: 'album', | ||||||
|         pageBuilder: (context, state) => NoTransitionPage( |     pageBuilder: (context, state) => CustomTransitionPage( | ||||||
|  |       transitionsBuilder: _fadeThroughTransition, | ||||||
|       child: const AlbumScreen(), |       child: const AlbumScreen(), | ||||||
|     ), |     ), | ||||||
|   ), |   ), | ||||||
| @@ -230,11 +213,6 @@ final _appRoutes = [ | |||||||
|       child: const NotificationScreen(), |       child: const NotificationScreen(), | ||||||
|     ), |     ), | ||||||
|   ), |   ), | ||||||
|     ], |  | ||||||
|   ), |  | ||||||
|   ShellRoute( |  | ||||||
|     builder: (context, state, child) => child, |  | ||||||
|     routes: [ |  | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/auth/login', |     path: '/auth/login', | ||||||
|     name: 'authLogin', |     name: 'authLogin', | ||||||
| @@ -272,8 +250,6 @@ final _appRoutes = [ | |||||||
|       name: state.pathParameters['name']!, |       name: state.pathParameters['name']!, | ||||||
|     ), |     ), | ||||||
|   ), |   ), | ||||||
|     ], |  | ||||||
|   ), |  | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/account/:name', |     path: '/account/:name', | ||||||
|     name: 'accountProfilePage', |     name: 'accountProfilePage', | ||||||
| @@ -281,26 +257,16 @@ final _appRoutes = [ | |||||||
|       child: UserScreen(name: state.pathParameters['name']!), |       child: UserScreen(name: state.pathParameters['name']!), | ||||||
|     ), |     ), | ||||||
|   ), |   ), | ||||||
|   ShellRoute( |  | ||||||
|     builder: (context, state, child) => child, |  | ||||||
|     routes: [ |  | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/settings', |     path: '/settings', | ||||||
|     name: 'settings', |     name: 'settings', | ||||||
|     builder: (context, state) => SettingsScreen(), |     builder: (context, state) => SettingsScreen(), | ||||||
|   ), |   ), | ||||||
|     ], |  | ||||||
|   ), |  | ||||||
|   ShellRoute( |  | ||||||
|     builder: (context, state, child) => child, |  | ||||||
|     routes: [ |  | ||||||
|   GoRoute( |   GoRoute( | ||||||
|     path: '/about', |     path: '/about', | ||||||
|     name: 'about', |     name: 'about', | ||||||
|     builder: (context, state) => AboutScreen(), |     builder: (context, state) => AboutScreen(), | ||||||
|   ), |   ), | ||||||
|     ], |  | ||||||
|   ), |  | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
| final appRouter = GoRouter( | final appRouter = GoRouter( | ||||||
|   | |||||||
| @@ -19,7 +19,6 @@ import 'package:surface/types/check_in.dart'; | |||||||
| import 'package:surface/types/post.dart'; | import 'package:surface/types/post.dart'; | ||||||
| import 'package:surface/widgets/account/account_image.dart'; | import 'package:surface/widgets/account/account_image.dart'; | ||||||
| import 'package:surface/widgets/dialog.dart'; | import 'package:surface/widgets/dialog.dart'; | ||||||
| import 'package:surface/widgets/navigation/app_scaffold.dart'; |  | ||||||
| import 'package:surface/widgets/universal_image.dart'; | import 'package:surface/widgets/universal_image.dart'; | ||||||
|  |  | ||||||
| const Map<String, (String, IconData, Color)> kBadgesMeta = { | const Map<String, (String, IconData, Color)> kBadgesMeta = { | ||||||
| @@ -596,7 +595,7 @@ class _UserScreenState extends State<UserScreen> with SingleTickerProviderStateM | |||||||
|                 subtitle: Text('@${ele.name}'), |                 subtitle: Text('@${ele.name}'), | ||||||
|                 trailing: const Icon(Symbols.chevron_right), |                 trailing: const Icon(Symbols.chevron_right), | ||||||
|                 onTap: () { |                 onTap: () { | ||||||
|                   GoRouter.of(context).pushNamed( |                   GoRouter.of(context).goNamed( | ||||||
|                     'postPublisher', |                     'postPublisher', | ||||||
|                     pathParameters: {'name': ele.name}, |                     pathParameters: {'name': ele.name}, | ||||||
|                   ); |                   ); | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ import 'package:surface/widgets/navigation/app_scaffold.dart'; | |||||||
| class CallRoomScreen extends StatefulWidget { | class CallRoomScreen extends StatefulWidget { | ||||||
|   final String scope; |   final String scope; | ||||||
|   final String alias; |   final String alias; | ||||||
|  |  | ||||||
|   const CallRoomScreen({super.key, required this.scope, required this.alias}); |   const CallRoomScreen({super.key, required this.scope, required this.alias}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -36,8 +37,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|     return Stack( |     return Stack( | ||||||
|       children: [ |       children: [ | ||||||
|         Container( |         Container( | ||||||
|           color: |           color: Theme.of(context).colorScheme.surfaceContainer.withOpacity(0.75), | ||||||
|               Theme.of(context).colorScheme.surfaceContainer.withOpacity(0.75), |  | ||||||
|           child: call.focusTrack != null |           child: call.focusTrack != null | ||||||
|               ? InteractiveParticipantWidget( |               ? InteractiveParticipantWidget( | ||||||
|                   isFixedAvatar: false, |                   isFixedAvatar: false, | ||||||
| @@ -72,8 +72,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|                       color: Theme.of(context).cardColor, |                       color: Theme.of(context).cardColor, | ||||||
|                       participant: track, |                       participant: track, | ||||||
|                       onTap: () { |                       onTap: () { | ||||||
|                         if (track.participant.sid != |                         if (track.participant.sid != call.focusTrack?.participant.sid) { | ||||||
|                             call.focusTrack?.participant.sid) { |  | ||||||
|                           call.setFocusTrack(track); |                           call.setFocusTrack(track); | ||||||
|                         } |                         } | ||||||
|                       }, |                       }, | ||||||
| @@ -115,14 +114,10 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|             child: ClipRRect( |             child: ClipRRect( | ||||||
|               borderRadius: const BorderRadius.all(Radius.circular(8)), |               borderRadius: const BorderRadius.all(Radius.circular(8)), | ||||||
|               child: InteractiveParticipantWidget( |               child: InteractiveParticipantWidget( | ||||||
|                 color: Theme.of(context) |                 color: Theme.of(context).colorScheme.surfaceContainerHigh.withOpacity(0.75), | ||||||
|                     .colorScheme |  | ||||||
|                     .surfaceContainerHigh |  | ||||||
|                     .withOpacity(0.75), |  | ||||||
|                 participant: track, |                 participant: track, | ||||||
|                 onTap: () { |                 onTap: () { | ||||||
|                   if (track.participant.sid != |                   if (track.participant.sid != call.focusTrack?.participant.sid) { | ||||||
|                       call.focusTrack?.participant.sid) { |  | ||||||
|                     call.setFocusTrack(track); |                     call.setFocusTrack(track); | ||||||
|                   } |                   } | ||||||
|                 }, |                 }, | ||||||
| @@ -160,24 +155,17 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|                 text: TextSpan(children: [ |                 text: TextSpan(children: [ | ||||||
|                   TextSpan( |                   TextSpan( | ||||||
|                     text: 'call'.tr(), |                     text: 'call'.tr(), | ||||||
|                     style: Theme.of(context) |                     style: Theme.of(context).textTheme.titleLarge!.copyWith(color: Colors.white), | ||||||
|                         .textTheme |  | ||||||
|                         .titleLarge! |  | ||||||
|                         .copyWith(color: Colors.white), |  | ||||||
|                   ), |                   ), | ||||||
|                   const TextSpan(text: '\n'), |                   const TextSpan(text: '\n'), | ||||||
|                   TextSpan( |                   TextSpan( | ||||||
|                     text: call.lastDuration.toString(), |                     text: call.lastDuration.toString(), | ||||||
|                     style: Theme.of(context) |                     style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.white), | ||||||
|                         .textTheme |  | ||||||
|                         .bodySmall! |  | ||||||
|                         .copyWith(color: Colors.white), |  | ||||||
|                   ), |                   ), | ||||||
|                 ]), |                 ]), | ||||||
|               ), |               ), | ||||||
|             ), |             ), | ||||||
|             body: SafeArea( |             body: GestureDetector( | ||||||
|               child: GestureDetector( |  | ||||||
|               behavior: HitTestBehavior.translucent, |               behavior: HitTestBehavior.translucent, | ||||||
|               child: Column( |               child: Column( | ||||||
|                 children: [ |                 children: [ | ||||||
| @@ -191,8 +179,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|                         Builder(builder: (context) { |                         Builder(builder: (context) { | ||||||
|                           final call = context.read<ChatCallProvider>(); |                           final call = context.read<ChatCallProvider>(); | ||||||
|                           final connectionQuality = |                           final connectionQuality = | ||||||
|                                 call.room.localParticipant?.connectionQuality ?? |                               call.room.localParticipant?.connectionQuality ?? livekit.ConnectionQuality.unknown; | ||||||
|                                     livekit.ConnectionQuality.unknown; |  | ||||||
|                           return Expanded( |                           return Expanded( | ||||||
|                             child: Column( |                             child: Column( | ||||||
|                               mainAxisSize: MainAxisSize.min, |                               mainAxisSize: MainAxisSize.min, | ||||||
| @@ -214,35 +201,24 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|                                   children: [ |                                   children: [ | ||||||
|                                     Text( |                                     Text( | ||||||
|                                       { |                                       { | ||||||
|                                           livekit.ConnectionState.disconnected: |                                         livekit.ConnectionState.disconnected: 'callStatusDisconnected'.tr(), | ||||||
|                                               'callStatusDisconnected'.tr(), |                                         livekit.ConnectionState.connected: 'callStatusConnected'.tr(), | ||||||
|                                           livekit.ConnectionState.connected: |                                         livekit.ConnectionState.connecting: 'callStatusConnecting'.tr(), | ||||||
|                                               'callStatusConnected'.tr(), |                                         livekit.ConnectionState.reconnecting: 'callStatusReconnecting'.tr(), | ||||||
|                                           livekit.ConnectionState.connecting: |  | ||||||
|                                               'callStatusConnecting'.tr(), |  | ||||||
|                                           livekit.ConnectionState.reconnecting: |  | ||||||
|                                               'callStatusReconnecting'.tr(), |  | ||||||
|                                       }[call.room.connectionState]!, |                                       }[call.room.connectionState]!, | ||||||
|                                     ), |                                     ), | ||||||
|                                     const Gap(6), |                                     const Gap(6), | ||||||
|                                       if (connectionQuality != |                                     if (connectionQuality != livekit.ConnectionQuality.unknown) | ||||||
|                                           livekit.ConnectionQuality.unknown) |  | ||||||
|                                       Icon( |                                       Icon( | ||||||
|                                         { |                                         { | ||||||
|                                             livekit.ConnectionQuality.excellent: |                                           livekit.ConnectionQuality.excellent: Icons.signal_cellular_alt, | ||||||
|                                                 Icons.signal_cellular_alt, |                                           livekit.ConnectionQuality.good: Icons.signal_cellular_alt_2_bar, | ||||||
|                                             livekit.ConnectionQuality.good: |                                           livekit.ConnectionQuality.poor: Icons.signal_cellular_alt_1_bar, | ||||||
|                                                 Icons.signal_cellular_alt_2_bar, |  | ||||||
|                                             livekit.ConnectionQuality.poor: |  | ||||||
|                                                 Icons.signal_cellular_alt_1_bar, |  | ||||||
|                                         }[connectionQuality], |                                         }[connectionQuality], | ||||||
|                                         color: { |                                         color: { | ||||||
|                                             livekit.ConnectionQuality.excellent: |                                           livekit.ConnectionQuality.excellent: Colors.green, | ||||||
|                                                 Colors.green, |                                           livekit.ConnectionQuality.good: Colors.orange, | ||||||
|                                             livekit.ConnectionQuality.good: |                                           livekit.ConnectionQuality.poor: Colors.red, | ||||||
|                                                 Colors.orange, |  | ||||||
|                                             livekit.ConnectionQuality.poor: |  | ||||||
|                                                 Colors.red, |  | ||||||
|                                         }[connectionQuality], |                                         }[connectionQuality], | ||||||
|                                         size: 16, |                                         size: 16, | ||||||
|                                       ) |                                       ) | ||||||
| @@ -264,9 +240,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|                         Row( |                         Row( | ||||||
|                           children: [ |                           children: [ | ||||||
|                             IconButton( |                             IconButton( | ||||||
|                                 icon: _layoutMode == 0 |                               icon: _layoutMode == 0 ? const Icon(Icons.view_list) : const Icon(Icons.grid_view), | ||||||
|                                     ? const Icon(Icons.view_list) |  | ||||||
|                                     : const Icon(Icons.grid_view), |  | ||||||
|                               onPressed: () { |                               onPressed: () { | ||||||
|                                 _switchLayout(); |                                 _switchLayout(); | ||||||
|                               }, |                               }, | ||||||
| @@ -278,8 +252,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|                   ), |                   ), | ||||||
|                   Expanded( |                   Expanded( | ||||||
|                     child: Material( |                     child: Material( | ||||||
|                         color: |                       color: Theme.of(context).colorScheme.surfaceContainerLow, | ||||||
|                             Theme.of(context).colorScheme.surfaceContainerLow, |  | ||||||
|                       child: Builder( |                       child: Builder( | ||||||
|                         builder: (context) { |                         builder: (context) { | ||||||
|                           switch (_layoutMode) { |                           switch (_layoutMode) { | ||||||
| @@ -304,7 +277,6 @@ class _CallRoomScreenState extends State<CallRoomScreen> { | |||||||
|               ), |               ), | ||||||
|               onTap: () {}, |               onTap: () {}, | ||||||
|             ), |             ), | ||||||
|             ), |  | ||||||
|           ); |           ); | ||||||
|         }); |         }); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -276,6 +276,30 @@ class _SettingsScreenState extends State<SettingsScreen> { | |||||||
|                     }); |                     }); | ||||||
|                   }, |                   }, | ||||||
|                 ), |                 ), | ||||||
|  |                 CheckboxListTile( | ||||||
|  |                   secondary: const Icon(Symbols.link), | ||||||
|  |                   title: Text('settingsExpandPostLink').tr(), | ||||||
|  |                   subtitle: Text('settingsExpandPostLinkDescription').tr(), | ||||||
|  |                   contentPadding: const EdgeInsets.only(left: 24, right: 17), | ||||||
|  |                   value: _prefs.getBool(kAppExpandPostLink) ?? true, | ||||||
|  |                   onChanged: (value) { | ||||||
|  |                     setState(() { | ||||||
|  |                       _prefs.setBool(kAppExpandPostLink, value ?? false); | ||||||
|  |                     }); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |                 CheckboxListTile( | ||||||
|  |                   secondary: const Icon(Symbols.chat), | ||||||
|  |                   title: Text('settingsExpandChatLink').tr(), | ||||||
|  |                   subtitle: Text('settingsExpandChatLinkDescription').tr(), | ||||||
|  |                   contentPadding: const EdgeInsets.only(left: 24, right: 17), | ||||||
|  |                   value: _prefs.getBool(kAppExpandChatLink) ?? true, | ||||||
|  |                   onChanged: (value) { | ||||||
|  |                     setState(() { | ||||||
|  |                       _prefs.setBool(kAppExpandChatLink, value ?? false); | ||||||
|  |                     }); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
|             Column( |             Column( | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import 'package:material_symbols_icons/symbols.dart'; | |||||||
| import 'package:popover/popover.dart'; | import 'package:popover/popover.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  | import 'package:surface/providers/config.dart'; | ||||||
| import 'package:surface/providers/user_directory.dart'; | import 'package:surface/providers/user_directory.dart'; | ||||||
| import 'package:surface/providers/userinfo.dart'; | import 'package:surface/providers/userinfo.dart'; | ||||||
| import 'package:surface/types/chat.dart'; | import 'package:surface/types/chat.dart'; | ||||||
| @@ -53,6 +54,8 @@ class ChatMessage extends StatelessWidget { | |||||||
|  |  | ||||||
|     final dateFormatter = DateFormat('MM/dd HH:mm'); |     final dateFormatter = DateFormat('MM/dd HH:mm'); | ||||||
|  |  | ||||||
|  |     final cfg = context.read<ConfigProvider>(); | ||||||
|  |  | ||||||
|     return SwipeTo( |     return SwipeTo( | ||||||
|       key: Key('chat-message-${data.id}'), |       key: Key('chat-message-${data.id}'), | ||||||
|       iconOnLeftSwipe: Symbols.reply, |       iconOnLeftSwipe: Symbols.reply, | ||||||
| @@ -192,7 +195,10 @@ class ChatMessage extends StatelessWidget { | |||||||
|                 ], |                 ], | ||||||
|               ).opacity(isPending ? 0.5 : 1), |               ).opacity(isPending ? 0.5 : 1), | ||||||
|             ), |             ), | ||||||
|             if (data.body['text'] != null && data.type == 'messages.new' && (data.body['text']?.isNotEmpty ?? false)) |             if (data.body['text'] != null && | ||||||
|  |                 data.type == 'messages.new' && | ||||||
|  |                 (data.body['text']?.isNotEmpty ?? false) && | ||||||
|  |                 (cfg.prefs.getBool(kAppExpandChatLink) ?? true)) | ||||||
|               LinkPreviewWidget(text: data.body['text']!), |               LinkPreviewWidget(text: data.body['text']!), | ||||||
|             if (data.preload?.attachments?.isNotEmpty ?? false) |             if (data.preload?.attachments?.isNotEmpty ?? false) | ||||||
|               AttachmentList( |               AttachmentList( | ||||||
|   | |||||||
| @@ -7,12 +7,11 @@ import 'package:marquee/marquee.dart'; | |||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| import 'package:responsive_framework/responsive_framework.dart'; | import 'package:responsive_framework/responsive_framework.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  | import 'package:surface/providers/link_preview.dart'; | ||||||
| import 'package:surface/types/link.dart'; | import 'package:surface/types/link.dart'; | ||||||
| import 'package:surface/widgets/universal_image.dart'; | import 'package:surface/widgets/universal_image.dart'; | ||||||
| import 'package:url_launcher/url_launcher_string.dart'; | import 'package:url_launcher/url_launcher_string.dart'; | ||||||
|  |  | ||||||
| import '../providers/link_preview.dart'; |  | ||||||
|  |  | ||||||
| class LinkPreviewWidget extends StatefulWidget { | class LinkPreviewWidget extends StatefulWidget { | ||||||
|   final String text; |   final String text; | ||||||
|  |  | ||||||
| @@ -81,8 +80,9 @@ class _LinkPreviewEntry extends StatelessWidget { | |||||||
|                   child: AspectRatio( |                   child: AspectRatio( | ||||||
|                     aspectRatio: 16 / 9, |                     aspectRatio: 16 / 9, | ||||||
|                     child: ClipRRect( |                     child: ClipRRect( | ||||||
|  |                       borderRadius: const BorderRadius.all(Radius.circular(8)), | ||||||
|                       child: AutoResizeUniversalImage( |                       child: AutoResizeUniversalImage( | ||||||
|                         meta.image!, |                         meta.image!.startsWith('//') ? 'https:${meta.image}' : meta.image!, | ||||||
|                         fit: BoxFit.contain, |                         fit: BoxFit.contain, | ||||||
|                       ), |                       ), | ||||||
|                     ), |                     ), | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| import 'dart:io'; | import 'dart:io'; | ||||||
|  |  | ||||||
| import 'package:bitsdojo_window/bitsdojo_window.dart'; | import 'package:bitsdojo_window/bitsdojo_window.dart'; | ||||||
| import 'package:easy_localization/easy_localization.dart'; |  | ||||||
| import 'package:flutter/foundation.dart'; | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| @@ -12,7 +11,6 @@ import 'package:styled_widget/styled_widget.dart'; | |||||||
| import 'package:surface/providers/config.dart'; | import 'package:surface/providers/config.dart'; | ||||||
| import 'package:surface/providers/navigation.dart'; | import 'package:surface/providers/navigation.dart'; | ||||||
| import 'package:surface/widgets/connection_indicator.dart'; | import 'package:surface/widgets/connection_indicator.dart'; | ||||||
| import 'package:surface/widgets/dialog.dart'; |  | ||||||
| import 'package:surface/widgets/navigation/app_background.dart'; | import 'package:surface/widgets/navigation/app_background.dart'; | ||||||
| import 'package:surface/widgets/navigation/app_bottom_navigation.dart'; | import 'package:surface/widgets/navigation/app_bottom_navigation.dart'; | ||||||
| import 'package:surface/widgets/navigation/app_drawer_navigation.dart'; | import 'package:surface/widgets/navigation/app_drawer_navigation.dart'; | ||||||
|   | |||||||
| @@ -203,6 +203,8 @@ class PostItem extends StatelessWidget { | |||||||
|         ?.where((ele) => ele?.mediaType != SnMediaType.image || data.type != 'article') |         ?.where((ele) => ele?.mediaType != SnMediaType.image || data.type != 'article') | ||||||
|         .toList(); |         .toList(); | ||||||
|  |  | ||||||
|  |     final cfg = context.read<ConfigProvider>(); | ||||||
|  |  | ||||||
|     return Column( |     return Column( | ||||||
|       crossAxisAlignment: CrossAxisAlignment.center, |       crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|       children: [ |       children: [ | ||||||
| @@ -261,7 +263,7 @@ class PostItem extends StatelessWidget { | |||||||
|             fit: showFullPost ? BoxFit.cover : BoxFit.contain, |             fit: showFullPost ? BoxFit.cover : BoxFit.contain, | ||||||
|             padding: const EdgeInsets.symmetric(horizontal: 12), |             padding: const EdgeInsets.symmetric(horizontal: 12), | ||||||
|           ), |           ), | ||||||
|         if (data.body['content'] != null) |         if (data.body['content'] != null && (cfg.prefs.getBool(kAppExpandPostLink) ?? true)) | ||||||
|           LinkPreviewWidget( |           LinkPreviewWidget( | ||||||
|             text: data.body['content'], |             text: data.body['content'], | ||||||
|           ).padding(horizontal: 4), |           ).padding(horizontal: 4), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user