Compare commits

...

13 Commits

Author SHA1 Message Date
LittleSheep
67d130dc34 🔨 Sync the CMakeLists in linux to update date with the v2 modified version 2025-08-16 18:09:45 +08:00
LittleSheep
7e923c77fe 💄 Change explore screen wide mode breakpoint 2025-08-16 18:03:23 +08:00
LittleSheep
a593b52812 ♻️ Adjust the firebase analytics observer guard 2025-08-16 17:20:03 +08:00
LittleSheep
520dc80303 🔀 Merge pull request #169 from Texas0295/v3
🐛 linux: guard FirebaseAnalyticsObserver when Firebase is not initialized
2025-08-16 17:18:20 +08:00
LittleSheep
001897bbcd Notification indicator 2025-08-16 17:14:26 +08:00
Texas0295
bab29c23e3 🐛 linux: guard FirebaseAnalyticsObserver when Firebase is not initialized 2025-08-16 16:58:12 +08:00
LittleSheep
76b39f2df3 Mark all as read 2025-08-16 11:47:29 +08:00
LittleSheep
509b3e145b 🐛 Fix category selection render error 2025-08-16 02:39:00 +08:00
LittleSheep
2b80ebc2d0 🐛 Fix markdown image in chat close #167 2025-08-16 02:14:44 +08:00
LittleSheep
0ab908dd2a Auto collapse featured post if read 2025-08-16 02:02:06 +08:00
LittleSheep
6007467e7a 🐛 Fixes due to changes in backend 2025-08-15 03:33:20 +08:00
LittleSheep
3745157c42 💄 Optimize snackbars 2025-08-15 00:09:05 +08:00
LittleSheep
94481ec7bd 💫 Chnaged tab page animations 2025-08-14 14:21:57 +08:00
24 changed files with 1192 additions and 938 deletions

View File

@@ -334,6 +334,7 @@
"walletCreate": "Create a Wallet", "walletCreate": "Create a Wallet",
"settingsServerUrl": "Server URL", "settingsServerUrl": "Server URL",
"settingsApplied": "The settings has been applied.", "settingsApplied": "The settings has been applied.",
"settingsCustomFontsHelper": "Use comma to seprate.",
"notifications": "Notifications", "notifications": "Notifications",
"posts": "Posts", "posts": "Posts",
"settingsBackgroundImage": "Background Image", "settingsBackgroundImage": "Background Image",

View File

@@ -300,6 +300,7 @@
"walletCreate": "创建钱包", "walletCreate": "创建钱包",
"settingsServerUrl": "服务器 URL", "settingsServerUrl": "服务器 URL",
"settingsApplied": "设置已应用。", "settingsApplied": "设置已应用。",
"settingsCustomFontsHelper": "用逗号分隔。",
"notifications": "通知", "notifications": "通知",
"posts": "帖子", "posts": "帖子",
"settingsBackgroundImage": "背景图片", "settingsBackgroundImage": "背景图片",

View File

@@ -245,7 +245,7 @@ PODS:
- PromisesObjC (= 2.4.0) - PromisesObjC (= 2.4.0)
- receive_sharing_intent (1.8.1): - receive_sharing_intent (1.8.1):
- Flutter - Flutter
- record_ios (1.0.0): - record_ios (1.1.0):
- Flutter - Flutter
- SAMKeychain (1.5.3) - SAMKeychain (1.5.3)
- SDWebImage (5.21.1): - SDWebImage (5.21.1):
@@ -510,7 +510,7 @@ SPEC CHECKSUMS:
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
SDWebImage: f29024626962457f3470184232766516dee8dfea SDWebImage: f29024626962457f3470184232766516dee8dfea
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a

View File

@@ -11,8 +11,8 @@ sealed class SnScrappedLink with _$SnScrappedLink {
required String title, required String title,
required String? description, required String? description,
required String? imageUrl, required String? imageUrl,
required String faviconUrl, required String? faviconUrl,
required String siteName, required String? siteName,
required String? contentType, required String? contentType,
required String? author, required String? author,
required DateTime? publishedDate, required DateTime? publishedDate,

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc /// @nodoc
mixin _$SnScrappedLink { mixin _$SnScrappedLink {
String get type; String get url; String get title; String? get description; String? get imageUrl; String get faviconUrl; String get siteName; String? get contentType; String? get author; DateTime? get publishedDate; String get type; String get url; String get title; String? get description; String? get imageUrl; String? get faviconUrl; String? get siteName; String? get contentType; String? get author; DateTime? get publishedDate;
/// Create a copy of SnScrappedLink /// Create a copy of SnScrappedLink
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -48,7 +48,7 @@ abstract mixin class $SnScrappedLinkCopyWith<$Res> {
factory $SnScrappedLinkCopyWith(SnScrappedLink value, $Res Function(SnScrappedLink) _then) = _$SnScrappedLinkCopyWithImpl; factory $SnScrappedLinkCopyWith(SnScrappedLink value, $Res Function(SnScrappedLink) _then) = _$SnScrappedLinkCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
}); });
@@ -65,16 +65,16 @@ class _$SnScrappedLinkCopyWithImpl<$Res>
/// Create a copy of SnScrappedLink /// Create a copy of SnScrappedLink
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) { @pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
as String?,faviconUrl: null == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
as String,siteName: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable as String?,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,
@@ -159,7 +159,7 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _SnScrappedLink() when $default != null: case _SnScrappedLink() when $default != null:
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _: return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
@@ -180,7 +180,7 @@ return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUr
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnScrappedLink(): case _SnScrappedLink():
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);} return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);}
@@ -197,7 +197,7 @@ return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUr
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnScrappedLink() when $default != null: case _SnScrappedLink() when $default != null:
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _: return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
@@ -220,8 +220,8 @@ class _SnScrappedLink implements SnScrappedLink {
@override final String title; @override final String title;
@override final String? description; @override final String? description;
@override final String? imageUrl; @override final String? imageUrl;
@override final String faviconUrl; @override final String? faviconUrl;
@override final String siteName; @override final String? siteName;
@override final String? contentType; @override final String? contentType;
@override final String? author; @override final String? author;
@override final DateTime? publishedDate; @override final DateTime? publishedDate;
@@ -259,7 +259,7 @@ abstract mixin class _$SnScrappedLinkCopyWith<$Res> implements $SnScrappedLinkCo
factory _$SnScrappedLinkCopyWith(_SnScrappedLink value, $Res Function(_SnScrappedLink) _then) = __$SnScrappedLinkCopyWithImpl; factory _$SnScrappedLinkCopyWith(_SnScrappedLink value, $Res Function(_SnScrappedLink) _then) = __$SnScrappedLinkCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
}); });
@@ -276,16 +276,16 @@ class __$SnScrappedLinkCopyWithImpl<$Res>
/// Create a copy of SnScrappedLink /// Create a copy of SnScrappedLink
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) { @override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
return _then(_SnScrappedLink( return _then(_SnScrappedLink(
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
as String?,faviconUrl: null == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
as String,siteName: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable as String?,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,

View File

@@ -13,8 +13,8 @@ _SnScrappedLink _$SnScrappedLinkFromJson(Map<String, dynamic> json) =>
title: json['title'] as String, title: json['title'] as String,
description: json['description'] as String?, description: json['description'] as String?,
imageUrl: json['image_url'] as String?, imageUrl: json['image_url'] as String?,
faviconUrl: json['favicon_url'] as String, faviconUrl: json['favicon_url'] as String?,
siteName: json['site_name'] as String, siteName: json['site_name'] as String?,
contentType: json['content_type'] as String?, contentType: json['content_type'] as String?,
author: json['author'] as String?, author: json['author'] as String?,
publishedDate: publishedDate:

View File

@@ -23,6 +23,8 @@ const kAppSoundEffects = 'app_sound_effects';
const kAppAprilFoolFeatures = 'app_april_fool_features'; const kAppAprilFoolFeatures = 'app_april_fool_features';
const kAppWindowSize = 'app_window_size'; const kAppWindowSize = 'app_window_size';
const kAppEnterToSend = 'app_enter_to_send'; const kAppEnterToSend = 'app_enter_to_send';
const kFeaturedPostsCollapsedId =
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
const Map<String, FilterQuality> kImageQualityLevel = { const Map<String, FilterQuality> kImageQualityLevel = {
'settingsImageQualityLowest': FilterQuality.none, 'settingsImageQualityLowest': FilterQuality.none,

View File

@@ -1,6 +1,8 @@
import 'dart:io' show Platform;
import 'package:animations/animations.dart';
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/screens/about.dart'; import 'package:island/screens/about.dart';
@@ -56,12 +58,34 @@ final rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>(); final _shellNavigatorKey = GlobalKey<NavigatorState>();
final _tabsShellKey = GlobalKey<NavigatorState>(); final _tabsShellKey = GlobalKey<NavigatorState>();
Widget _tabPagesTransitionBuilder(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return FadeThroughTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
fillColor: Theme.of(context).colorScheme.surface,
child: child,
);
}
bool get _supportsAnalytics =>
kIsWeb ||
Platform.isAndroid ||
Platform.isIOS ||
Platform.isMacOS ||
Platform.isWindows;
// Provider for the router // Provider for the router
final routerProvider = Provider<GoRouter>((ref) { final routerProvider = Provider<GoRouter>((ref) {
return GoRouter( return GoRouter(
navigatorKey: rootNavigatorKey, navigatorKey: rootNavigatorKey,
initialLocation: '/', initialLocation: '/',
observers: [ observers: [
if (_supportsAnalytics)
FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance), FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance),
], ],
routes: [ routes: [
@@ -339,7 +363,12 @@ final routerProvider = Provider<GoRouter>((ref) {
GoRoute( GoRoute(
name: 'explore', name: 'explore',
path: '/', path: '/',
builder: (context, state) => const ExploreScreen(), pageBuilder:
(context, state) => CustomTransitionPage(
key: const ValueKey('explore'),
child: const ExploreScreen(),
transitionsBuilder: _tabPagesTransitionBuilder,
),
), ),
GoRoute( GoRoute(
name: 'postSearch', name: 'postSearch',
@@ -389,8 +418,12 @@ final routerProvider = Provider<GoRouter>((ref) {
// Chat tab // Chat tab
ShellRoute( ShellRoute(
builder: pageBuilder:
(context, state, child) => ChatShellScreen(child: child), (context, state, child) => CustomTransitionPage(
key: const ValueKey('chat'),
child: ChatShellScreen(child: child),
transitionsBuilder: _tabPagesTransitionBuilder,
),
routes: [ routes: [
GoRoute( GoRoute(
name: 'chatList', name: 'chatList',
@@ -433,7 +466,12 @@ final routerProvider = Provider<GoRouter>((ref) {
GoRoute( GoRoute(
name: 'realmList', name: 'realmList',
path: '/realms', path: '/realms',
builder: (context, state) => const RealmListScreen(), pageBuilder:
(context, state) => CustomTransitionPage(
key: const ValueKey('realms'),
child: const RealmListScreen(),
transitionsBuilder: _tabPagesTransitionBuilder,
),
routes: [ routes: [
GoRoute( GoRoute(
name: 'realmNew', name: 'realmNew',
@@ -461,8 +499,12 @@ final routerProvider = Provider<GoRouter>((ref) {
// Account tab // Account tab
ShellRoute( ShellRoute(
builder: pageBuilder:
(context, state, child) => AccountShellScreen(child: child), (context, state, child) => CustomTransitionPage(
key: const ValueKey('account'),
child: AccountShellScreen(child: child),
transitionsBuilder: _tabPagesTransitionBuilder,
),
routes: [ routes: [
GoRoute( GoRoute(
name: 'account', name: 'account',

View File

@@ -178,7 +178,8 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
context, context,
icon: Symbols.label, icon: Symbols.label,
label: 'aboutDeviceName'.tr(), label: 'aboutDeviceName'.tr(),
value: _deviceInfo?.data['name'], value:
_deviceInfo?.data['name'] ?? 'unknown'.tr(),
), ),
_buildInfoItem( _buildInfoItem(
context, context,

View File

@@ -11,6 +11,7 @@ import 'package:island/models/realm.dart';
import 'package:island/models/webfeed.dart'; import 'package:island/models/webfeed.dart';
import 'package:island/pods/event_calendar.dart'; import 'package:island/pods/event_calendar.dart';
import 'package:island/pods/userinfo.dart'; import 'package:island/pods/userinfo.dart';
import 'package:island/screens/notification.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/fortune_graph.dart'; import 'package:island/widgets/account/fortune_graph.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
@@ -30,6 +31,33 @@ import 'package:styled_widget/styled_widget.dart';
part 'explore.g.dart'; part 'explore.g.dart';
Widget notificationIndicatorWidget(
BuildContext context, {
required int count,
EdgeInsets? margin,
}) => Card(
margin: margin,
child: ListTile(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
leading: const Icon(Symbols.notifications),
title: Row(
children: [
Text('notifications').tr().fontSize(14),
const Gap(8),
Badge(label: Text(count.toString())),
],
),
trailing: const Icon(Symbols.chevron_right),
minTileHeight: 40,
contentPadding: EdgeInsets.only(left: 16, right: 15),
onTap: () {
GoRouter.of(context).pushNamed('notifications');
},
),
);
class ExploreScreen extends HookConsumerWidget { class ExploreScreen extends HookConsumerWidget {
const ExploreScreen({super.key}); const ExploreScreen({super.key});
@@ -77,6 +105,10 @@ class ExploreScreen extends HookConsumerWidget {
final user = ref.watch(userInfoProvider); final user = ref.watch(userInfoProvider);
final notificationCount = ref.watch(
notificationUnreadCountNotifierProvider,
);
return AppScaffold( return AppScaffold(
isNoBackground: false, isNoBackground: false,
appBar: AppBar( appBar: AppBar(
@@ -185,7 +217,7 @@ class ExploreScreen extends HookConsumerWidget {
floatingActionButtonLocation: TabbedFabLocation(context), floatingActionButtonLocation: TabbedFabLocation(context),
body: Builder( body: Builder(
builder: (context) { builder: (context) {
final isWider = isWiderScreen(context); final isWide = isWideScreen(context);
final bodyView = _buildActivityList( final bodyView = _buildActivityList(
context, context,
@@ -193,13 +225,15 @@ class ExploreScreen extends HookConsumerWidget {
currentFilter.value, currentFilter.value,
); );
if (isWider) { if (isWide) {
return Row( return Row(
children: [ children: [
Flexible(flex: 3, child: bodyView.padding(left: 8)), Flexible(flex: 3, child: bodyView.padding(left: 8)),
if (user.value != null) if (user.value != null)
Flexible( Flexible(
flex: 2, flex: 2,
child: Align(
alignment: Alignment.topCenter,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
@@ -215,13 +249,28 @@ class ExploreScreen extends HookConsumerWidget {
); );
}, },
), ),
if (notificationCount.value != null &&
notificationCount.value! > 0)
notificationIndicatorWidget(
context,
count: notificationCount.value ?? 0,
margin: EdgeInsets.only(
left: 8,
right: 12,
top: 8,
),
),
PostFeaturedList().padding( PostFeaturedList().padding(
left: 8, left: 8,
right: 12, right: 12,
top: 8, top: 8,
), ),
FortuneGraphWidget( FortuneGraphWidget(
margin: EdgeInsets.only(left: 8, right: 12, top: 8), margin: EdgeInsets.only(
left: 8,
right: 12,
top: 8,
),
events: events, events: events,
constrainWidth: true, constrainWidth: true,
onPointSelected: onDaySelected, onPointSelected: onDaySelected,
@@ -229,6 +278,7 @@ class ExploreScreen extends HookConsumerWidget {
], ],
), ),
), ),
),
) )
else else
Flexible( Flexible(
@@ -268,7 +318,7 @@ class ExploreScreen extends HookConsumerWidget {
activityListNotifierProvider(filter).notifier, activityListNotifierProvider(filter).notifier,
); );
final isWider = isWiderScreen(context); final isWide = isWideScreen(context);
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh), onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
@@ -283,7 +333,7 @@ class ExploreScreen extends HookConsumerWidget {
widgetCount: widgetCount, widgetCount: widgetCount,
endItemView: endItemView, endItemView: endItemView,
activitiesNotifier: activitiesNotifier, activitiesNotifier: activitiesNotifier,
contentOnly: isWider || filter != null, contentOnly: isWide || filter != null,
), ),
), ),
), ),
@@ -380,6 +430,10 @@ class _ActivityListView extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(userInfoProvider); final user = ref.watch(userInfoProvider);
final notificationCount = ref.watch(
notificationUnreadCountNotifierProvider,
);
return CustomScrollView( return CustomScrollView(
slivers: [ slivers: [
SliverGap(12), SliverGap(12),
@@ -393,6 +447,14 @@ class _ActivityListView extends HookConsumerWidget {
SliverToBoxAdapter( SliverToBoxAdapter(
child: PostFeaturedList().padding(horizontal: 8, bottom: 4, top: 4), child: PostFeaturedList().padding(horizontal: 8, bottom: 4, top: 4),
), ),
if (!contentOnly)
SliverToBoxAdapter(
child: notificationIndicatorWidget(
context,
count: notificationCount.value ?? 0,
margin: EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
),
),
SliverList.builder( SliverList.builder(
itemCount: widgetCount, itemCount: widgetCount,
itemBuilder: (context, index) { itemBuilder: (context, index) {

View File

@@ -3,14 +3,17 @@ import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/account.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/websocket.dart'; import 'package:island/pods/websocket.dart';
import 'package:island/route.dart'; import 'package:island/route.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/markdown.dart'; import 'package:island/widgets/content/markdown.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:relative_time/relative_time.dart'; import 'package:relative_time/relative_time.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
@@ -62,6 +65,10 @@ class NotificationUnreadCountNotifier
final current = await future; final current = await future;
state = AsyncData(math.max(current - count, 0)); state = AsyncData(math.max(current - count, 0));
} }
void clear() async {
state = AsyncData(0);
}
} }
@riverpod @riverpod
@@ -111,8 +118,27 @@ class NotificationScreen extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
Future<void> markAllRead() async {
showLoadingModal(context);
final apiClient = ref.watch(apiClientProvider);
await apiClient.post('/pusher/notifications/all/read');
if (!context.mounted) return;
hideLoadingModal(context);
ref.invalidate(notificationListNotifierProvider);
ref.watch(notificationUnreadCountNotifierProvider.notifier).clear();
}
return AppScaffold( return AppScaffold(
appBar: AppBar(title: const Text('notifications').tr()), appBar: AppBar(
title: const Text('notifications').tr(),
actions: [
IconButton(
onPressed: markAllRead,
icon: const Icon(Symbols.mark_as_unread),
),
const Gap(8),
],
),
body: PagingHelperView( body: PagingHelperView(
provider: notificationListNotifierProvider, provider: notificationListNotifierProvider,
futureRefreshable: notificationListNotifierProvider.future, futureRefreshable: notificationListNotifierProvider.future,

View File

@@ -51,12 +51,12 @@ class PostSearchNotifier
final offset = cursor == null ? 0 : int.parse(cursor); final offset = cursor == null ? 0 : int.parse(cursor);
final response = await client.get( final response = await client.get(
'/sphere/posts/search', '/sphere/posts',
queryParameters: { queryParameters: {
'query': _currentQuery, 'query': _currentQuery,
'offset': offset, 'offset': offset,
'take': _pageSize, 'take': _pageSize,
'useVector': false, 'vector': false,
}, },
); );

View File

@@ -26,7 +26,12 @@ StreamSubscription<WebSocketPacket> setupNotificationListener(
final notification = SnNotification.fromJson(pkt.data!); final notification = SnNotification.fromJson(pkt.data!);
showTopSnackBar( showTopSnackBar(
globalOverlay.currentState!, globalOverlay.currentState!,
NotificationCard(notification: notification), Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 480),
child: NotificationCard(notification: notification),
),
),
onTap: () { onTap: () {
if (notification.meta['action_uri'] != null) { if (notification.meta['action_uri'] != null) {
var uri = notification.meta['action_uri'] as String; var uri = notification.meta['action_uri'] as String;
@@ -53,9 +58,9 @@ StreamSubscription<WebSocketPacket> setupNotificationListener(
(Platform.isMacOS || (Platform.isMacOS ||
Platform.isWindows || Platform.isWindows ||
Platform.isLinux)) Platform.isLinux))
? 24 ? 28
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
: MediaQuery.of(context).padding.top + 8, : MediaQuery.of(context).padding.top + 16,
bottom: 16, bottom: 16,
), ),
); );

View File

@@ -162,7 +162,7 @@ class AccountSessionSheet extends HookConsumerWidget {
try { try {
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
await apiClient.patch( await apiClient.patch(
'/accounts/me/devices/$sessionId/label', '/id/accounts/me/devices/$sessionId/label',
data: jsonEncode(label), data: jsonEncode(label),
); );
ref.invalidate(authDevicesProvider); ref.invalidate(authDevicesProvider);

View File

@@ -11,7 +11,12 @@ export 'content/alert.native.dart'
void showSnackBar(String message, {SnackBarAction? action}) { void showSnackBar(String message, {SnackBarAction? action}) {
showTopSnackBar( showTopSnackBar(
globalOverlay.currentState!, globalOverlay.currentState!,
Card(child: Text(message).padding(horizontal: 20, vertical: 16)), ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 480),
child: Center(
child: Card(child: Text(message).padding(horizontal: 20, vertical: 16)),
),
),
snackBarPosition: SnackBarPosition.bottom, snackBarPosition: SnackBarPosition.bottom,
); );
} }

View File

@@ -57,11 +57,11 @@ class EmbedLinkWidget extends StatelessWidget {
Row( Row(
children: [ children: [
// Favicon // Favicon
if (link.faviconUrl.isNotEmpty) ...[ if (link.faviconUrl?.isNotEmpty ?? false) ...[
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
child: UniversalImage( child: UniversalImage(
uri: link.faviconUrl, uri: link.faviconUrl!,
width: 16, width: 16,
height: 16, height: 16,
fit: BoxFit.cover, fit: BoxFit.cover,
@@ -80,8 +80,8 @@ class EmbedLinkWidget extends StatelessWidget {
// Site name // Site name
Expanded( Expanded(
child: Text( child: Text(
link.siteName.isNotEmpty (link.siteName?.isNotEmpty ?? false)
? link.siteName ? link.siteName!
: Uri.parse(link.url).host, : Uri.parse(link.url).host,
style: theme.textTheme.bodySmall?.copyWith( style: theme.textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant, color: colorScheme.onSurfaceVariant,

View File

@@ -183,9 +183,15 @@ class MarkdownTextContent extends HookConsumerWidget {
); );
} }
} }
final content = ConstrainedBox( final content = ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: 360), constraints: BoxConstraints(maxHeight: 360),
child: UniversalImage(uri: uri.toString(), fit: BoxFit.contain), child: UniversalImage(
uri: uri.toString(),
fit: BoxFit.contain,
),
),
); );
return content; return content;
}, },

View File

@@ -244,7 +244,6 @@ class ComposeSettingsSheet extends HookConsumerWidget {
), ),
// Categories field // Categories field
// FIXME: Sometimes the entire dropdown crashes: 'package:flutter/src/rendering/stack.dart': Failed assertion: line 799 pos 12: 'firstChild == null || child != null': is not true.
DropdownButtonFormField2<SnPostCategory>( DropdownButtonFormField2<SnPostCategory>(
isExpanded: true, isExpanded: true,
decoration: InputDecoration( decoration: InputDecoration(
@@ -306,7 +305,7 @@ class ComposeSettingsSheet extends HookConsumerWidget {
value: currentCategories.isEmpty ? null : currentCategories.last, value: currentCategories.isEmpty ? null : currentCategories.last,
onChanged: (_) {}, onChanged: (_) {},
selectedItemBuilder: (context) { selectedItemBuilder: (context) {
return currentCategories.map((item) { return (postCategories.value ?? []).map((item) {
return SingleChildScrollView( return SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Row( child: Row(

View File

@@ -7,6 +7,7 @@ import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:island/widgets/post/post_item.dart'; import 'package:island/widgets/post/post_item.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:island/pods/config.dart'; // Import config.dart for shared preferences keys and provider
part 'post_featured.g.dart'; part 'post_featured.g.dart';
@@ -25,7 +26,13 @@ class PostFeaturedList extends HookConsumerWidget {
final featuredPostsAsync = ref.watch(featuredPostsProvider); final featuredPostsAsync = ref.watch(featuredPostsProvider);
final pageViewController = usePageController(); final pageViewController = usePageController();
final prefs = ref.watch(sharedPreferencesProvider);
final pageViewCurrent = useState(0); final pageViewCurrent = useState(0);
final previousFirstPostId = useState<String?>(null);
final storedCollapsedId = useState<String?>(
prefs.getString(kFeaturedPostsCollapsedId),
);
final isCollapsed = useState(false);
useEffect(() { useEffect(() {
pageViewController.addListener(() { pageViewController.addListener(() {
@@ -34,6 +41,59 @@ class PostFeaturedList extends HookConsumerWidget {
return null; return null;
}, [pageViewController]); }, [pageViewController]);
// Log isCollapsed state changes
useEffect(() {
debugPrint(
'PostFeaturedList: isCollapsed changed to ${isCollapsed.value}',
);
return null;
}, [isCollapsed.value]);
useEffect(() {
if (featuredPostsAsync.hasValue && featuredPostsAsync.value!.isNotEmpty) {
final currentFirstPostId = featuredPostsAsync.value!.first.id;
debugPrint(
'PostFeaturedList: Current first post ID: $currentFirstPostId',
);
debugPrint(
'PostFeaturedList: Previous first post ID: ${previousFirstPostId.value}',
);
debugPrint(
'PostFeaturedList: Stored collapsed ID: ${storedCollapsedId.value}',
);
if (previousFirstPostId.value == null) {
// Initial load
previousFirstPostId.value = currentFirstPostId;
isCollapsed.value = (storedCollapsedId.value == currentFirstPostId);
debugPrint(
'PostFeaturedList: Initial load. isCollapsed set to ${isCollapsed.value}',
);
} else if (previousFirstPostId.value != currentFirstPostId) {
// First post changed, expand by default
previousFirstPostId.value = currentFirstPostId;
isCollapsed.value = false;
prefs.remove(
kFeaturedPostsCollapsedId,
); // Clear stored ID if post changes
debugPrint(
'PostFeaturedList: First post changed. isCollapsed set to false.',
);
} else {
// Same first post, maintain current collapse state
// No change needed for isCollapsed.value unless manually toggled
debugPrint(
'PostFeaturedList: Same first post. Maintaining current collapse state.',
);
}
} else {
debugPrint(
'PostFeaturedList: featuredPostsAsync has no value or is empty.',
);
}
return null;
}, [featuredPostsAsync.value]);
return ClipRRect( return ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)), borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Card( child: Card(
@@ -73,10 +133,48 @@ class PostFeaturedList extends HookConsumerWidget {
}, },
icon: const Icon(Symbols.arrow_right), icon: const Icon(Symbols.arrow_right),
), ),
IconButton(
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
constraints: const BoxConstraints(),
onPressed: () {
isCollapsed.value = !isCollapsed.value;
debugPrint(
'PostFeaturedList: Manual toggle. isCollapsed set to ${isCollapsed.value}',
);
if (isCollapsed.value &&
featuredPostsAsync.hasValue &&
featuredPostsAsync.value!.isNotEmpty) {
prefs.setString(
kFeaturedPostsCollapsedId,
featuredPostsAsync.value!.first.id,
);
debugPrint(
'PostFeaturedList: Stored collapsed ID: ${featuredPostsAsync.value!.first.id}',
);
} else {
prefs.remove(kFeaturedPostsCollapsedId);
debugPrint(
'PostFeaturedList: Removed stored collapsed ID.',
);
}
},
icon: Icon(
isCollapsed.value
? Symbols.expand_more
: Symbols.expand_less,
),
),
], ],
).padding(horizontal: 16, vertical: 8), ).padding(horizontal: 16, vertical: 8),
featuredPostsAsync.when( AnimatedSize(
loading: () => const Center(child: CircularProgressIndicator()), duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: Visibility(
visible: !isCollapsed.value,
child: featuredPostsAsync.when(
loading:
() => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')), error: (error, stack) => Center(child: Text('Error: $error')),
data: (posts) { data: (posts) {
return SizedBox( return SizedBox(
@@ -97,6 +195,8 @@ class PostFeaturedList extends HookConsumerWidget {
); );
}, },
), ),
),
),
], ],
), ),
), ),

View File

@@ -879,7 +879,8 @@ class _LinkPreview extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Favicon and image // Favicon and image
if (embed.imageUrl != null || embed.faviconUrl.isNotEmpty) if (embed.imageUrl != null ||
(embed.faviconUrl?.isNotEmpty ?? false))
Container( Container(
width: 60, width: 60,
height: 60, height: 60,
@@ -899,11 +900,14 @@ class _LinkPreview extends ConsumerWidget {
errorBuilder: (context, error, stackTrace) { errorBuilder: (context, error, stackTrace) {
return _buildFaviconFallback( return _buildFaviconFallback(
context, context,
embed.faviconUrl, embed.faviconUrl ?? '',
); );
}, },
) )
: _buildFaviconFallback(context, embed.faviconUrl), : _buildFaviconFallback(
context,
embed.faviconUrl ?? '',
),
), ),
), ),
// Content // Content
@@ -912,9 +916,9 @@ class _LinkPreview extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Site name // Site name
if (embed.siteName.isNotEmpty) if (embed.siteName?.isNotEmpty ?? false)
Text( Text(
embed.siteName, embed.siteName!,
style: Theme.of(context).textTheme.labelSmall?.copyWith( style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),

View File

@@ -41,7 +41,7 @@ endif()
# of modifying this function. # of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET) function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror) target_compile_options(${TARGET} PRIVATE -Wall -Wextra)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>") target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>") target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction() endfunction()

View File

@@ -195,7 +195,7 @@ PODS:
- PromisesObjC (2.4.0) - PromisesObjC (2.4.0)
- PromisesSwift (2.4.0): - PromisesSwift (2.4.0):
- PromisesObjC (= 2.4.0) - PromisesObjC (= 2.4.0)
- record_macos (1.0.0): - record_macos (1.1.0):
- FlutterMacOS - FlutterMacOS
- SAMKeychain (1.5.3) - SAMKeychain (1.5.3)
- share_plus (0.0.1): - share_plus (0.0.1):
@@ -422,7 +422,7 @@ SPEC CHECKSUMS:
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
record_macos: 295d70bd5fb47145df78df7b80e6697cd18403c0 record_macos: 43194b6c06ca6f8fa132e2acea72b202b92a0f5b
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7

View File

@@ -1281,10 +1281,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_picker_platform_interface name: image_picker_platform_interface
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.1" version: "2.11.0"
image_picker_windows: image_picker_windows:
dependency: transitive dependency: transitive
description: description:
@@ -1897,58 +1897,58 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: record name: record
sha256: daeb3f9b3fea9797094433fe6e49a879d8e4ca4207740bc6dc7e4a58764f0817 sha256: "3d08502b77edf2a864aa6e4cd7874b983d42a80f3689431da053cc5e85c1ad21"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.1.0"
record_android: record_android:
dependency: transitive dependency: transitive
description: description:
name: record_android name: record_android
sha256: "97d7122455f30de89a01c6c244c839085be6b12abca251fc0e78f67fed73628b" sha256: "8b170e33d9866f9b51e01a767d7e1ecb97b9ecd629950bd87a47c79359ec57f8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.3" version: "1.4.0"
record_ios: record_ios:
dependency: transitive dependency: transitive
description: description:
name: record_ios name: record_ios
sha256: "73706ebbece6150654c9d6f57897cf9b622c581148304132ba85dba15df0fdfb" sha256: ad97d0a75933c44bcf5aff648e86e32fc05eb61f8fbef190f14968c8eaf86692
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.1.0"
record_linux: record_linux:
dependency: transitive dependency: transitive
description: description:
name: record_linux name: record_linux
sha256: "0626678a092c75ce6af1e32fe7fd1dea709b92d308bc8e3b6d6348e2430beb95" sha256: "785e8e8d6db109aa606d0669d95aaae416458aaa39782bb0abe0bee74eee17d7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.2.0"
record_macos: record_macos:
dependency: transitive dependency: transitive
description: description:
name: record_macos name: record_macos
sha256: "02240833fde16c33fcf2c589f3e08d4394b704761b4a3bb609d872ff3043fbbd" sha256: f1399bca76a1634da109e5b0cba764ed8332a2b4da49c704c66d2c553405ed81
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.1.0"
record_platform_interface: record_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: record_platform_interface name: record_platform_interface
sha256: c1ad38f51e4af88a085b3e792a22c685cb3e7c23fc37aa7ce44c4cf18f25fe89 sha256: b0065fdf1ec28f5a634d676724d388a77e43ce7646fb049949f58c69f3fcb4ed
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.4.0"
record_web: record_web:
dependency: transitive dependency: transitive
description: description:
name: record_web name: record_web
sha256: a12856d0b3dd03d336b4b10d7520a8b3e21649a06a8f95815318feaa8f07adbb sha256: "4f0adf20c9ccafcc02d71111fd91fba1ca7b17a7453902593e5a9b25b74a5c56"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.9" version: "1.2.0"
record_windows: record_windows:
dependency: transitive dependency: transitive
description: description:
@@ -2568,10 +2568,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics_compiler name: vector_graphics_compiler
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" sha256: ca81fdfaf62a5ab45d7296614aea108d2c7d0efca8393e96174bf4d51e6725b0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.17" version: "1.1.18"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:

View File

@@ -75,7 +75,7 @@ dependencies:
image_picker: ^1.1.2 image_picker: ^1.1.2
file_picker: ^10.3.1 file_picker: ^10.3.1
riverpod_annotation: ^2.6.1 riverpod_annotation: ^2.6.1
image_picker_platform_interface: ^2.10.1 image_picker_platform_interface: ^2.11.0
image_picker_android: ^0.8.12+25 image_picker_android: ^0.8.12+25
super_context_menu: ^0.9.1 super_context_menu: ^0.9.1
modal_bottom_sheet: ^3.0.0 modal_bottom_sheet: ^3.0.0
@@ -107,7 +107,7 @@ dependencies:
livekit_client: ^2.5.0+hotfix.1 livekit_client: ^2.5.0+hotfix.1
pasteboard: ^0.4.0 pasteboard: ^0.4.0
flutter_colorpicker: ^1.1.0 flutter_colorpicker: ^1.1.0
record: ^6.0.0 record: ^6.1.0
qr_flutter: ^4.1.0 qr_flutter: ^4.1.0
flutter_otp_text_field: ^1.5.1+1 flutter_otp_text_field: ^1.5.1+1
palette_generator: ^0.3.3+7 palette_generator: ^0.3.3+7