diff --git a/ios/Podfile.lock b/ios/Podfile.lock index cebb63b..16b681a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -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 diff --git a/lib/main.dart b/lib/main.dart index 7e62ef9..e26472e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -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,21 +25,12 @@ 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, diff --git a/lib/screens/chat/chat.dart b/lib/screens/chat/chat.dart index e0b9e50..0a53a36 100644 --- a/lib/screens/chat/chat.dart +++ b/lib/screens/chat/chat.dart @@ -250,10 +250,4 @@ class _ChatScreenWidgetState extends State { onCallEnded: () => _chat.setOngoingCall(null), ); } - - @override - void deactivate() { - _chat.unFocus(); - super.deactivate(); - } } diff --git a/lib/screens/chat/index.dart b/lib/screens/chat/index.dart index 79e270a..2d90656 100644 --- a/lib/screens/chat/index.dart +++ b/lib/screens/chat/index.dart @@ -36,7 +36,7 @@ class _ChatIndexScreenState extends State { return IndentWrapper( title: AppLocalizations.of(context)!.chat, - appBarActions: chat.focusChannel != null + appBarActions: isLargeScreen && chat.focusChannel != null ? [ ChannelCallAction( call: chat.ongoingCall, diff --git a/lib/utils/platform.dart b/lib/utils/platform.dart new file mode 100644 index 0000000..5c7967e --- /dev/null +++ b/lib/utils/platform.dart @@ -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 getVersion() async { + var version = kIsWeb ? 'Web' : 'Unknown'; + try { + version = (await PackageInfo.fromPlatform()).version; + } catch (_) {} + return version; + } +} \ No newline at end of file diff --git a/lib/utils/theme.dart b/lib/utils/theme.dart new file mode 100644 index 0000000..415f184 --- /dev/null +++ b/lib/utils/theme.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +abstract class SolianTheme { + static bool isColumnMode(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, + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/account/avatar.dart b/lib/widgets/account/avatar.dart index 551649e..217ba1d 100644 --- a/lib/widgets/account/avatar.dart +++ b/lib/widgets/account/avatar.dart @@ -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, ); } } diff --git a/lib/widgets/posts/content/attachment.dart b/lib/widgets/posts/content/attachment.dart index 4bf8286..556990b 100644 --- a/lib/widgets/posts/content/attachment.dart +++ b/lib/widgets/posts/content/attachment.dart @@ -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 { 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 { tag: tag, child: Stack( children: [ - Image.network( - widget.url, + Image( + image: image as ImageProvider, key: Key(getTag()), width: double.infinity, height: double.infinity, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 884ab6e..f36e9b8 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -17,6 +17,7 @@ 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 @@ -33,6 +34,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")) } diff --git a/pubspec.lock b/pubspec.lock index e6b85e9..f81f119 100644 --- a/pubspec.lock +++ b/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: @@ -270,6 +294,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 +781,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 +973,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 +1074,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: diff --git a/pubspec.yaml b/pubspec.yaml index 728a7f2..20df4d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -68,6 +68,8 @@ 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 dev_dependencies: flutter_test: