✨ Friends overview basis
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:island/models/activity.dart';
|
||||||
import 'package:island/models/auth.dart';
|
import 'package:island/models/auth.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/models/wallet.dart';
|
import 'package:island/models/wallet.dart';
|
||||||
@@ -263,3 +264,15 @@ sealed class SnSocialCreditRecord with _$SnSocialCreditRecord {
|
|||||||
factory SnSocialCreditRecord.fromJson(Map<String, dynamic> json) =>
|
factory SnSocialCreditRecord.fromJson(Map<String, dynamic> json) =>
|
||||||
_$SnSocialCreditRecordFromJson(json);
|
_$SnSocialCreditRecordFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnFriendOverviewItem with _$SnFriendOverviewItem {
|
||||||
|
const factory SnFriendOverviewItem({
|
||||||
|
required SnAccount account,
|
||||||
|
required SnAccountStatus status,
|
||||||
|
required List<SnPresenceActivity> activities,
|
||||||
|
}) = _SnFriendOverviewItem;
|
||||||
|
|
||||||
|
factory SnFriendOverviewItem.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnFriendOverviewItemFromJson(json);
|
||||||
|
}
|
||||||
|
|||||||
@@ -3912,4 +3912,309 @@ as DateTime?,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$SnFriendOverviewItem {
|
||||||
|
|
||||||
|
SnAccount get account; SnAccountStatus get status; List<SnPresenceActivity> get activities;
|
||||||
|
/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnFriendOverviewItemCopyWith<SnFriendOverviewItem> get copyWith => _$SnFriendOverviewItemCopyWithImpl<SnFriendOverviewItem>(this as SnFriendOverviewItem, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this SnFriendOverviewItem to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnFriendOverviewItem&&(identical(other.account, account) || other.account == account)&&(identical(other.status, status) || other.status == status)&&const DeepCollectionEquality().equals(other.activities, activities));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,account,status,const DeepCollectionEquality().hash(activities));
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnFriendOverviewItem(account: $account, status: $status, activities: $activities)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $SnFriendOverviewItemCopyWith<$Res> {
|
||||||
|
factory $SnFriendOverviewItemCopyWith(SnFriendOverviewItem value, $Res Function(SnFriendOverviewItem) _then) = _$SnFriendOverviewItemCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
SnAccount account, SnAccountStatus status, List<SnPresenceActivity> activities
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$SnAccountCopyWith<$Res> get account;$SnAccountStatusCopyWith<$Res> get status;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$SnFriendOverviewItemCopyWithImpl<$Res>
|
||||||
|
implements $SnFriendOverviewItemCopyWith<$Res> {
|
||||||
|
_$SnFriendOverviewItemCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final SnFriendOverviewItem _self;
|
||||||
|
final $Res Function(SnFriendOverviewItem) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? account = null,Object? status = null,Object? activities = null,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
account: null == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnAccount,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnAccountStatus,activities: null == activities ? _self.activities : activities // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<SnPresenceActivity>,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAccountCopyWith<$Res> get account {
|
||||||
|
|
||||||
|
return $SnAccountCopyWith<$Res>(_self.account, (value) {
|
||||||
|
return _then(_self.copyWith(account: value));
|
||||||
|
});
|
||||||
|
}/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAccountStatusCopyWith<$Res> get status {
|
||||||
|
|
||||||
|
return $SnAccountStatusCopyWith<$Res>(_self.status, (value) {
|
||||||
|
return _then(_self.copyWith(status: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [SnFriendOverviewItem].
|
||||||
|
extension SnFriendOverviewItemPatterns on SnFriendOverviewItem {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnFriendOverviewItem value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFriendOverviewItem() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnFriendOverviewItem value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFriendOverviewItem():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnFriendOverviewItem value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFriendOverviewItem() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( SnAccount account, SnAccountStatus status, List<SnPresenceActivity> activities)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFriendOverviewItem() when $default != null:
|
||||||
|
return $default(_that.account,_that.status,_that.activities);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( SnAccount account, SnAccountStatus status, List<SnPresenceActivity> activities) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFriendOverviewItem():
|
||||||
|
return $default(_that.account,_that.status,_that.activities);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( SnAccount account, SnAccountStatus status, List<SnPresenceActivity> activities)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFriendOverviewItem() when $default != null:
|
||||||
|
return $default(_that.account,_that.status,_that.activities);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _SnFriendOverviewItem implements SnFriendOverviewItem {
|
||||||
|
const _SnFriendOverviewItem({required this.account, required this.status, required final List<SnPresenceActivity> activities}): _activities = activities;
|
||||||
|
factory _SnFriendOverviewItem.fromJson(Map<String, dynamic> json) => _$SnFriendOverviewItemFromJson(json);
|
||||||
|
|
||||||
|
@override final SnAccount account;
|
||||||
|
@override final SnAccountStatus status;
|
||||||
|
final List<SnPresenceActivity> _activities;
|
||||||
|
@override List<SnPresenceActivity> get activities {
|
||||||
|
if (_activities is EqualUnmodifiableListView) return _activities;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_activities);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SnFriendOverviewItemCopyWith<_SnFriendOverviewItem> get copyWith => __$SnFriendOverviewItemCopyWithImpl<_SnFriendOverviewItem>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$SnFriendOverviewItemToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnFriendOverviewItem&&(identical(other.account, account) || other.account == account)&&(identical(other.status, status) || other.status == status)&&const DeepCollectionEquality().equals(other._activities, _activities));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,account,status,const DeepCollectionEquality().hash(_activities));
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnFriendOverviewItem(account: $account, status: $status, activities: $activities)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SnFriendOverviewItemCopyWith<$Res> implements $SnFriendOverviewItemCopyWith<$Res> {
|
||||||
|
factory _$SnFriendOverviewItemCopyWith(_SnFriendOverviewItem value, $Res Function(_SnFriendOverviewItem) _then) = __$SnFriendOverviewItemCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
SnAccount account, SnAccountStatus status, List<SnPresenceActivity> activities
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@override $SnAccountCopyWith<$Res> get account;@override $SnAccountStatusCopyWith<$Res> get status;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$SnFriendOverviewItemCopyWithImpl<$Res>
|
||||||
|
implements _$SnFriendOverviewItemCopyWith<$Res> {
|
||||||
|
__$SnFriendOverviewItemCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _SnFriendOverviewItem _self;
|
||||||
|
final $Res Function(_SnFriendOverviewItem) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? account = null,Object? status = null,Object? activities = null,}) {
|
||||||
|
return _then(_SnFriendOverviewItem(
|
||||||
|
account: null == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnAccount,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnAccountStatus,activities: null == activities ? _self._activities : activities // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<SnPresenceActivity>,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAccountCopyWith<$Res> get account {
|
||||||
|
|
||||||
|
return $SnAccountCopyWith<$Res>(_self.account, (value) {
|
||||||
|
return _then(_self.copyWith(account: value));
|
||||||
|
});
|
||||||
|
}/// Create a copy of SnFriendOverviewItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAccountStatusCopyWith<$Res> get status {
|
||||||
|
|
||||||
|
return $SnAccountStatusCopyWith<$Res>(_self.status, (value) {
|
||||||
|
return _then(_self.copyWith(status: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dart format on
|
// dart format on
|
||||||
|
|||||||
@@ -449,3 +449,22 @@ Map<String, dynamic> _$SnSocialCreditRecordToJson(
|
|||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_SnFriendOverviewItem _$SnFriendOverviewItemFromJson(
|
||||||
|
Map<String, dynamic> json,
|
||||||
|
) => _SnFriendOverviewItem(
|
||||||
|
account: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||||
|
status: SnAccountStatus.fromJson(json['status'] as Map<String, dynamic>),
|
||||||
|
activities:
|
||||||
|
(json['activities'] as List<dynamic>)
|
||||||
|
.map((e) => SnPresenceActivity.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnFriendOverviewItemToJson(
|
||||||
|
_SnFriendOverviewItem instance,
|
||||||
|
) => <String, dynamic>{
|
||||||
|
'account': instance.account.toJson(),
|
||||||
|
'status': instance.status.toJson(),
|
||||||
|
'activities': instance.activities.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import 'package:island/pods/userinfo.dart';
|
|||||||
import 'package:island/screens/auth/login_modal.dart';
|
import 'package:island/screens/auth/login_modal.dart';
|
||||||
import 'package:island/screens/notification.dart';
|
import 'package:island/screens/notification.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/services/responsive.dart';
|
||||||
|
import 'package:island/widgets/account/friends_overview.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
import 'package:island/widgets/check_in.dart';
|
import 'package:island/widgets/check_in.dart';
|
||||||
@@ -341,6 +342,7 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
PostFeaturedList(),
|
PostFeaturedList(),
|
||||||
|
FriendsOverviewWidget(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
150
lib/widgets/account/friends_overview.dart
Normal file
150
lib/widgets/account/friends_overview.dart
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:island/models/account.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/pods/config.dart';
|
||||||
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
|
||||||
|
part 'friends_overview.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<List<SnFriendOverviewItem>> friendsOverview(Ref ref) async {
|
||||||
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
final resp = await apiClient.get('/pass/friends/overview');
|
||||||
|
return (resp.data as List<dynamic>)
|
||||||
|
.map((e) => SnFriendOverviewItem.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FriendsOverviewWidget extends ConsumerWidget {
|
||||||
|
const FriendsOverviewWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final friendsOverviewAsync = ref.watch(friendsOverviewProvider);
|
||||||
|
|
||||||
|
return friendsOverviewAsync.when(
|
||||||
|
data: (friends) {
|
||||||
|
// Filter for online friends
|
||||||
|
final onlineFriends =
|
||||||
|
friends.where((friend) => friend.status.isOnline).toList();
|
||||||
|
|
||||||
|
if (onlineFriends.isEmpty) {
|
||||||
|
return const SizedBox.shrink(); // Hide if no online friends
|
||||||
|
}
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
margin: EdgeInsets.zero,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [const Icon(Symbols.group), Text('Friends Online')],
|
||||||
|
).padding(horizontal: 16).height(48),
|
||||||
|
SizedBox(
|
||||||
|
height: 80,
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: const EdgeInsets.fromLTRB(8, 0, 8, 4),
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount: onlineFriends.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final friend = onlineFriends[index];
|
||||||
|
return _FriendTile(friend: friend);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading:
|
||||||
|
() => const SizedBox(
|
||||||
|
height: 80,
|
||||||
|
child: Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
error: (error, stack) => const SizedBox.shrink(), // Hide on error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FriendTile extends ConsumerWidget {
|
||||||
|
final SnFriendOverviewItem friend;
|
||||||
|
|
||||||
|
const _FriendTile({required this.friend});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final serverUrl = ref.watch(serverUrlProvider);
|
||||||
|
|
||||||
|
String? uri;
|
||||||
|
if (friend.account.profile.picture != null) {
|
||||||
|
uri = '$serverUrl/drive/files/${friend.account.profile.picture!.id}';
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
width: 60,
|
||||||
|
margin: const EdgeInsets.only(right: 12),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// Avatar with online indicator
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 24,
|
||||||
|
backgroundImage:
|
||||||
|
uri != null ? CachedNetworkImageProvider(uri) : null,
|
||||||
|
child:
|
||||||
|
uri == null
|
||||||
|
? Text(
|
||||||
|
friend.account.nick.isNotEmpty
|
||||||
|
? friend.account.nick[0].toUpperCase()
|
||||||
|
: friend.account.name[0].toUpperCase(),
|
||||||
|
style: theme.textTheme.titleMedium?.copyWith(
|
||||||
|
color: theme.colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
// Online indicator
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
width: 12,
|
||||||
|
height: 12,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.green,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(
|
||||||
|
color: theme.colorScheme.surface,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Gap(4),
|
||||||
|
// Name (truncated if too long)
|
||||||
|
Text(
|
||||||
|
friend.account.nick.isNotEmpty
|
||||||
|
? friend.account.nick
|
||||||
|
: friend.account.name,
|
||||||
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).center();
|
||||||
|
}
|
||||||
|
}
|
||||||
30
lib/widgets/account/friends_overview.g.dart
Normal file
30
lib/widgets/account/friends_overview.g.dart
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'friends_overview.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$friendsOverviewHash() => r'5ef86c6849804c97abd3df094f120c7dd5e938db';
|
||||||
|
|
||||||
|
/// See also [friendsOverview].
|
||||||
|
@ProviderFor(friendsOverview)
|
||||||
|
final friendsOverviewProvider =
|
||||||
|
AutoDisposeFutureProvider<List<SnFriendOverviewItem>>.internal(
|
||||||
|
friendsOverview,
|
||||||
|
name: r'friendsOverviewProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$friendsOverviewHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
typedef FriendsOverviewRef =
|
||||||
|
AutoDisposeFutureProviderRef<List<SnFriendOverviewItem>>;
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||||
Reference in New Issue
Block a user